2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
9 * Portions Copyright (c) 2007-2008 Sine Nomine Associates
12 #include <afsconfig.h>
13 #include <afs/param.h>
20 #include <afs/afsint.h>
21 #include <afs/prs_fs.h>
25 #include <afs/cellconfig.h>
28 #include <afs/ihandle.h>
30 #include <afs/ntops.h>
32 #include <afs/vnode.h>
33 #include <afs/volume.h>
34 #include <afs/volume_inline.h>
35 #include <afs/partition.h>
37 #include <afs/daemon_com.h>
38 #include <afs/fssync.h>
40 #include "afs/audit.h"
42 #include <afs/afsutil.h>
43 #include <afs/com_err.h>
44 #include <afs/vol_prototypes.h>
45 #include <afs/errors.h>
48 #include "voltrans_inline.h"
51 #include "volser_internal.h"
53 #include "dumpstuff.h"
56 extern struct afsconf_dir *tdir;
57 extern int DoPreserveVolumeStats;
59 extern void LogError(afs_int32 errcode);
61 /* Forward declarations */
62 static int GetPartName(afs_int32 partid, char *pname);
64 #define OneDay (24*60*60)
70 afs_int32 localTid = 1;
72 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
73 struct diskPartition64 *);
74 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
75 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
76 afs_int32, afs_uint32, afs_uint32 *,
78 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
79 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
80 afs_int32, char *, afs_uint32 *);
81 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
82 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
83 afs_int32, afs_int32 *);
84 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
86 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
87 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
88 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
89 struct destServer *destination, afs_int32,
90 struct restoreCookie *cookie);
91 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
92 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
93 struct restoreCookie *);
94 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
95 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
96 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
97 struct volser_status *);
98 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
99 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
100 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
101 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
102 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
104 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
106 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
108 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
110 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
111 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
112 afs_int32, afs_uint32, afs_uint32,
114 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
117 * Return the host address of the caller as a string.
119 * @param[in] acid incoming rx call
120 * @param[out] buffer buffer to be filled with the addess string
122 * @return address as formatted by inet_ntoa
125 callerAddress(struct rx_call *acid, char *buffer)
127 afs_uint32 ip = rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid)));
128 return afs_inet_ntoa_r(ip, buffer);
131 /* this call unlocks all of the partition locks we've set */
135 struct DiskPartition64 *tp;
136 for (tp = DiskPartitionList; tp; tp = tp->next) {
137 if (tp->lock_fd != INVALID_FD) {
138 OS_CLOSE(tp->lock_fd);
139 tp->lock_fd = INVALID_FD;
150 code = VPFullUnlock_r();
155 /* get partition id from a name */
157 PartitionID(char *aname)
165 return -1; /* unknown */
167 /* otherwise check for vicepa or /vicepa, or just plain "a" */
169 if (!strncmp(aname, "/vicep", 6)) {
170 strncpy(ascii, aname + 6, 2);
172 return -1; /* bad partition name */
173 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
174 * from 0. Do the appropriate conversion */
176 /* one char name, 0..25 */
177 if (ascii[0] < 'a' || ascii[0] > 'z')
178 return -1; /* wrongo */
179 return ascii[0] - 'a';
181 /* two char name, 26 .. <whatever> */
182 if (ascii[0] < 'a' || ascii[0] > 'z')
183 return -1; /* wrongo */
184 if (ascii[1] < 'a' || ascii[1] > 'z')
185 return -1; /* just as bad */
186 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
187 if (code > VOLMAXPARTS)
194 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
198 /* It's better using the Generic VFORMAT since otherwise we have to make changes to too many places... The 14 char limitation in names hits us again in AIX; print in field of 9 digits (still 10 for the rest), right justified with 0 padding */
199 snprintf(aname, asize, VFORMAT, (unsigned long)avol);
204 ConvertPartition(int apartno, char *aname, int asize)
210 strcpy(aname, "/vicep");
212 aname[6] = 'a' + apartno;
216 aname[6] = 'a' + (apartno / 26);
217 aname[7] = 'a' + (apartno % 26);
223 #ifdef AFS_DEMAND_ATTACH_FS
224 /* normally we should use the regular salvaging functions from the volume
225 * package, but this is a special case where we have a volume ID, but no
226 * volume structure to give the volume package */
228 SalvageUnknownVolume(VolumeId volid, char *part)
232 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
233 afs_printable_uint32_lu(volid), part);
235 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
236 FSYNC_SALVAGE, NULL);
238 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
239 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
243 #endif /* AFS_DEMAND_ATTACH_FS */
245 static struct Volume *
246 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
251 vp = VAttachVolumeByName(ec, partition, name, mode);
253 #ifdef AFS_DEMAND_ATTACH_FS
257 * The fileserver will take care of keeping track of how many
258 * demand-salvages have been performed, and will force the volume to
259 * ERROR if we've done too many. The limit on This loop is just a
260 * failsafe to prevent trying to salvage forever. We want to attempt
261 * attachment at least SALVAGE_COUNT_MAX times, since we want to
262 * avoid prematurely exiting this loop, if we can.
264 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
265 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
266 vp = VAttachVolumeByName(ec, partition, name, mode);
269 if (*ec == VSALVAGING) {
273 #endif /* AFS_DEMAND_ATTACH_FS */
278 static struct Volume *
279 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
284 vp = VAttachVolume(ec, avolid, amode);
286 #ifdef AFS_DEMAND_ATTACH_FS
289 /* see comment above in VAttachVolumeByName_retry */
290 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
291 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
292 vp = VAttachVolume(ec, avolid, amode);
295 if (*ec == VSALVAGING) {
299 #endif /* AFS_DEMAND_ATTACH_FS */
304 /* the only attach function that takes a partition is "...ByName", so we use it */
305 static struct Volume *
306 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
308 char pbuf[30], vbuf[20];
310 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
314 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
319 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
322 /* Adapted from the file server; create a root directory for this volume */
324 ViceCreateRoot(Volume *vp)
327 struct acl_accessList *ACL;
329 Inode inodeNumber, AFS_UNUSED nearInode;
330 struct VnodeDiskObject *vnode;
331 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
337 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
340 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
342 V_pref(vp, nearInode);
344 IH_CREATE(V_linkHandle(vp), V_device(vp),
345 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
347 if (!VALID_INO(inodeNumber)) {
348 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
353 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
354 did.Volume = V_id(vp);
355 did.Vnode = (VnodeId) 1;
358 osi_Assert(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
359 DFlush(); /* flush all modified dir buffers out */
360 DZap(&dir); /* Remove all buffers for this dir */
361 length = afs_dir_Length(&dir); /* Remember size of this directory */
363 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
365 /* build a single entry ACL that gives all rights to system:administrators */
366 /* this section of code assumes that access list format is not going to
369 ACL = VVnodeDiskACL(vnode);
370 ACL->size = sizeof(struct acl_accessList);
371 ACL->version = ACL_ACLVERSION;
375 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
376 ACL->entries[0].rights =
377 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
378 | PRSFS_LOCK | PRSFS_ADMINISTER;
380 vnode->type = vDirectory;
382 vnode->modeBits = 0777;
383 vnode->linkCount = 2;
384 VNDISK_SET_LEN(vnode, length);
385 vnode->uniquifier = 1;
386 V_uniquifier(vp) = vnode->uniquifier + 1;
387 vnode->dataVersion = 1;
388 VNDISK_SET_INO(vnode, inodeNumber);
389 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
393 vnode->vnodeMagic = vcp->magic;
395 IH_INIT(h, vp->device, V_parentId(vp),
396 vp->vnodeIndex[vLarge].handle->ih_ino);
398 osi_Assert(fdP != NULL);
399 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
400 osi_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
401 FDH_REALLYCLOSE(fdP);
403 VNDISK_GET_LEN(length, vnode);
404 V_diskused(vp) = nBlocks(length);
411 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
415 struct diskPartition64 *dp = (struct diskPartition64 *)
416 malloc(sizeof(struct diskPartition64));
418 code = VolPartitionInfo(acid, pname, dp);
420 strncpy(partition->name, dp->name, 32);
421 strncpy(partition->devName, dp->devName, 32);
422 partition->lock_fd = dp->lock_fd;
423 partition->free=RoundInt64ToInt32(dp->free);
424 partition->minFree=RoundInt64ToInt32(dp->minFree);
427 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
432 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
437 code = VolPartitionInfo(acid, pname, partition);
438 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
443 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
446 struct DiskPartition64 *dp;
449 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
452 dp = VGetPartition(pname, 0);
454 strncpy(partition->name, dp->name, 32);
455 strncpy(partition->devName, dp->devName, 32);
456 partition->lock_fd = (int)dp->lock_fd;
457 partition->free = dp->free;
458 partition->minFree = dp->totalUsable;
461 return VOLSERILLEGAL_PARTITION;
464 /* obliterate a volume completely, and slowly. */
466 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
470 code = VolNukeVolume(acid, apartID, avolID);
471 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
476 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
483 char caller[MAXKTCNAMELEN];
485 /* check for access */
486 if (!afsconf_SuperUser(tdir, acid, caller))
487 return VOLSERBAD_ACCESS;
490 Log("%s on %s is executing VolNukeVolume %u\n", caller,
491 callerAddress(acid, buffer), avolID);
494 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
496 /* we first try to attach the volume in update mode, so that the file
497 * server doesn't try to use it (and abort) while (or after) we delete it.
498 * If we don't get the volume, that's fine, too. We just won't put it back.
500 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
501 code = nuke(partName, avolID);
503 VDetachVolume(&verror, tvp);
507 /* create a new volume, with name aname, on the specified partition (1..n)
508 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
509 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
510 * for the volume id (useful for things like volume restore).
511 * Return the new volume id in *avolid.
514 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
515 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
521 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
522 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
523 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
529 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
530 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
535 Error junk; /* discardable error code */
537 afs_int32 doCreateRoot = 1;
538 struct volser_trans *tt;
540 char caller[MAXKTCNAMELEN];
542 if (strlen(aname) > 31)
543 return VOLSERBADNAME;
544 if (!afsconf_SuperUser(tdir, acid, caller))
545 return VOLSERBAD_ACCESS;
548 Log("%s on %s is executing CreateVolume '%s'\n", caller,
549 callerAddress(acid, buffer), aname);
551 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
552 return error; /*a standard unix error */
553 if (atype != readwriteVolume && atype != readonlyVolume
554 && atype != backupVolume)
556 if ((volumeID = *avolid) == 0) {
558 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
562 if ((aparent == volumeID) && (atype == readwriteVolume)) {
567 tt = NewTrans(volumeID, apart);
569 Log("1 createvolume: failed to create trans\n");
570 return VOLSERVOLBUSY; /* volume already busy! */
572 vp = VCreateVolume(&error, ppath, volumeID, aparent);
574 #ifdef AFS_DEMAND_ATTACH_FS
575 if (error != VVOLEXISTS && error != EXDEV) {
576 SalvageUnknownVolume(volumeID, ppath);
579 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
584 V_uniquifier(vp) = 1;
585 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
586 V_inService(vp) = V_blessed(vp) = 1;
588 AssignVolumeName(&V_disk(vp), aname, 0);
590 error = ViceCreateRoot(vp);
592 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
593 "error code %u\n", (unsigned)error);
595 V_needsSalvaged(vp) = 1;
596 VDetachVolume(&junk, vp);
600 V_destroyMe(vp) = DESTROY_ME;
602 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
603 VUpdateVolume(&error, vp);
605 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
608 VDetachVolume(&junk, vp); /* rather return the real error code */
614 TSetRxCall_r(tt, acid, "CreateVolume");
615 VTRANS_OBJ_UNLOCK(tt);
616 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
619 return VOLSERTRELE_ERROR;
623 /* delete the volume associated with this transaction */
625 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
629 code = VolDeleteVolume(acid, atrans);
630 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
635 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
637 struct volser_trans *tt;
639 char caller[MAXKTCNAMELEN];
641 if (!afsconf_SuperUser(tdir, acid, caller))
642 return VOLSERBAD_ACCESS;
643 tt = FindTrans(atrans);
646 if (tt->vflags & VTDeleted) {
647 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
653 Log("%s on %s is executing Delete Volume %u\n", caller,
654 callerAddress(acid, buffer), tt->volid);
656 TSetRxCall(tt, acid, "DeleteVolume");
657 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
658 V_destroyMe(tt->volume) = DESTROY_ME;
659 if (tt->volume->needsPutBack) {
660 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
663 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
665 VTRANS_OBJ_UNLOCK(tt);
667 return VOLSERTRELE_ERROR;
669 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
670 return 0; /* vpurgevolume doesn't set an error code */
673 /* make a clone of the volume associated with atrans, possibly giving it a new
674 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
675 * for the clone's id). The new clone is given the name newName. Finally,
676 * due to efficiency considerations, if purgeId is non-zero, we purge that
677 * volume when doing the clone operation. This may be useful when making
678 * new backup volumes, for instance since the net result of a clone and a
679 * purge generally leaves many inode ref counts the same, while doing them
680 * separately would result in far more iincs and idecs being peformed
681 * (and they are slow operations).
683 /* for efficiency reasons, sometimes faster to piggyback a purge here */
685 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
686 afs_int32 newType, char *newName, afs_uint32 *newNumber)
690 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
691 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
692 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
698 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
699 afs_int32 newType, char *newName, afs_uint32 *newNumber)
702 struct Volume *originalvp, *purgevp, *newvp;
704 struct volser_trans *tt, *ttc;
705 char caller[MAXKTCNAMELEN];
706 #ifdef AFS_DEMAND_ATTACH_FS
707 struct Volume *salv_vp = NULL;
710 if (strlen(newName) > 31)
711 return VOLSERBADNAME;
712 if (!afsconf_SuperUser(tdir, acid, caller))
713 return VOLSERBAD_ACCESS; /*not a super user */
716 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
717 callerAddress(acid, buffer), newName);
720 originalvp = (Volume *) 0;
721 purgevp = (Volume *) 0;
722 newvp = (Volume *) 0;
723 tt = ttc = (struct volser_trans *)0;
725 if (!newNumber || !*newNumber) {
726 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
731 tt = FindTrans(atrans);
734 if (tt->vflags & VTDeleted) {
735 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
739 ttc = NewTrans(newId, tt->partition);
740 if (!ttc) { /* someone is messing with the clone already */
742 return VOLSERVOLBUSY;
744 TSetRxCall(tt, acid, "Clone");
748 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
750 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
756 originalvp = tt->volume;
757 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
758 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
764 if (originalvp->device != purgevp->device) {
765 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
769 if (V_type(purgevp) != readonlyVolume) {
770 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
774 if (V_parentId(originalvp) != V_parentId(purgevp)) {
775 Log("1 Volser: Clone: Volume %u and volume %u were not originally cloned from the same parent; aborted\n", purgeId, tt->volid);
782 #ifdef AFS_DEMAND_ATTACH_FS
783 salv_vp = originalvp;
786 if (purgeId == newId) {
790 VCreateVolume(&error, originalvp->partition->name, newId,
791 V_parentId(originalvp));
793 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
794 newvp = (Volume *) 0;
798 if (newType == readonlyVolume)
799 V_cloneId(originalvp) = newId;
800 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
803 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
804 CloneVolume(&error, originalvp, newvp, purgevp);
805 purgevp = NULL; /* clone releases it, maybe even if error */
807 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
811 if (newType == readonlyVolume) {
812 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
813 V_type(newvp) = readonlyVolume;
814 } else if (newType == backupVolume) {
815 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
816 V_type(newvp) = backupVolume;
817 V_backupId(originalvp) = newId;
819 strcpy(newvp->header->diskstuff.name, newName);
820 V_creationDate(newvp) = V_copyDate(newvp);
821 ClearVolumeStats(&V_disk(newvp));
822 V_destroyMe(newvp) = DESTROY_ME;
823 V_inService(newvp) = 0;
824 if (newType == backupVolume) {
825 V_backupDate(originalvp) = V_copyDate(newvp);
826 V_backupDate(newvp) = V_copyDate(newvp);
829 VUpdateVolume(&error, newvp);
831 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
835 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
837 VUpdateVolume(&error, originalvp);
839 Log("1 Volser: Clone: original update %u\n", error);
844 #ifdef AFS_DEMAND_ATTACH_FS
848 tt = (struct volser_trans *)0;
849 error = VOLSERTRELE_ERROR;
857 VDetachVolume(&code, purgevp);
859 VDetachVolume(&code, newvp);
866 #ifdef AFS_DEMAND_ATTACH_FS
867 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
868 V_needsSalvaged(salv_vp) = 1;
870 #endif /* AFS_DEMAND_ATTACH_FS */
874 /* reclone this volume into the specified id */
876 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
880 code = VolReClone(acid, atrans, cloneId);
881 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
887 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
889 struct Volume *originalvp, *clonevp;
892 struct volser_trans *tt, *ttc;
893 char caller[MAXKTCNAMELEN];
894 VolumeDiskData saved_header;
896 /*not a super user */
897 if (!afsconf_SuperUser(tdir, acid, caller))
898 return VOLSERBAD_ACCESS;
901 Log("%s on %s is executing Reclone Volume %u\n", caller,
902 callerAddress(acid, buffer), cloneId);
905 clonevp = originalvp = (Volume *) 0;
906 tt = (struct volser_trans *)0;
908 tt = FindTrans(atrans);
911 if (tt->vflags & VTDeleted) {
912 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
916 ttc = NewTrans(cloneId, tt->partition);
917 if (!ttc) { /* someone is messing with the clone already */
919 return VOLSERVOLBUSY;
921 TSetRxCall(tt, acid, "ReClone");
923 originalvp = tt->volume;
924 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
925 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
931 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
933 Log("1 Volser: can't attach clone %d\n", cloneId);
937 newType = V_type(clonevp); /* type of the new volume */
939 if (originalvp->device != clonevp->device) {
940 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
945 if (V_parentId(originalvp) != V_parentId(clonevp)) {
946 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
951 if (DoPreserveVolumeStats) {
952 CopyVolumeStats(&V_disk(clonevp), &saved_header);
956 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
958 CloneVolume(&error, originalvp, clonevp, clonevp);
960 Log("1 Volser: Clone: reclone operation failed with code %d\n",
966 /* fix up volume name and type, CloneVolume just propagated RW's */
967 if (newType == readonlyVolume) {
968 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
969 V_type(clonevp) = readonlyVolume;
970 } else if (newType == backupVolume) {
971 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
972 V_type(clonevp) = backupVolume;
973 V_backupId(originalvp) = cloneId;
975 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
977 /* update the creationDate, since this represents the last cloning date
978 * for ROs. But do not update copyDate; let it stay so we can identify
979 * when the clone was first created. */
980 V_creationDate(clonevp) = time(0);
981 if (DoPreserveVolumeStats) {
982 CopyVolumeStats(&saved_header, &V_disk(clonevp));
984 ClearVolumeStats(&V_disk(clonevp));
986 V_destroyMe(clonevp) = 0;
987 V_inService(clonevp) = 0;
988 if (newType == backupVolume) {
989 V_backupDate(originalvp) = V_creationDate(clonevp);
990 V_backupDate(clonevp) = V_creationDate(clonevp);
992 V_inUse(clonevp) = 0;
993 VUpdateVolume(&error, clonevp);
995 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
999 /* VUpdateVolume succeeded. Mark it in service so there's no window
1000 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
1001 * specialStatus; this is a reclone and this volume started online
1003 V_inService(clonevp) = 1;
1004 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
1006 VUpdateVolume(&error, originalvp);
1008 Log("1 Volser: Clone: original update %u\n", error);
1014 tt = (struct volser_trans *)0;
1015 error = VOLSERTRELE_ERROR;
1019 DeleteTrans(ttc, 1);
1022 struct DiskPartition64 *tpartp = originalvp->partition;
1023 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1029 VDetachVolume(&code, clonevp);
1035 DeleteTrans(ttc, 1);
1039 /* create a new transaction, associated with volume and partition. Type of
1040 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1041 * See volser.h for definition of iflags (the constants are named IT*).
1044 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1045 afs_int32 iflags, afs_int32 *ttid)
1049 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1050 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1056 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1057 afs_int32 iflags, afs_int32 *ttid)
1059 struct volser_trans *tt;
1064 char caller[MAXKTCNAMELEN];
1066 if (!afsconf_SuperUser(tdir, acid, caller))
1067 return VOLSERBAD_ACCESS; /*not a super user */
1068 if (iflags & ITCreate)
1070 else if (iflags & ITBusy)
1072 else if (iflags & ITReadOnly)
1074 else if (iflags & ITOffline)
1077 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1082 tt = NewTrans(volume, partition);
1084 /* can't create a transaction? put the volume back */
1085 Log("1 transcreate: can't create transaction\n");
1086 return VOLSERVOLBUSY;
1088 tv = XAttachVolume(&error, volume, partition, mode);
1092 VDetachVolume(&code, tv);
1096 VTRANS_OBJ_LOCK(tt);
1099 tt->iflags = iflags;
1101 TSetRxCall_r(tt, NULL, "TransCreate");
1102 VTRANS_OBJ_UNLOCK(tt);
1104 return VOLSERTRELE_ERROR;
1109 /* using aindex as a 0-based index, return the aindex'th volume on this server
1110 * Both the volume number and partition number (one-based) are returned.
1113 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1118 code = VolGetNthVolume(acid, aindex, avolume, apart);
1119 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1124 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1127 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1131 /* return the volume flags (VT* constants in volser.h) associated with this
1135 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1139 code = VolGetFlags(acid, atid, aflags);
1140 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1145 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1147 struct volser_trans *tt;
1149 tt = FindTrans(atid);
1152 if (tt->vflags & VTDeleted) {
1153 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1158 TSetRxCall(tt, acid, "GetFlags");
1159 *aflags = tt->vflags;
1162 return VOLSERTRELE_ERROR;
1167 /* Change the volume flags (VT* constants in volser.h) associated with this
1168 * transaction. Effects take place immediately on volume, although volume
1169 * remains attached as usual by the transaction.
1172 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1176 code = VolSetFlags(acid, atid, aflags);
1177 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1183 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1185 struct volser_trans *tt;
1188 char caller[MAXKTCNAMELEN];
1190 if (!afsconf_SuperUser(tdir, acid, caller))
1191 return VOLSERBAD_ACCESS; /*not a super user */
1192 /* find the trans */
1193 tt = FindTrans(atid);
1196 if (tt->vflags & VTDeleted) {
1197 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1202 TSetRxCall(tt, acid, "SetFlags");
1203 vp = tt->volume; /* pull volume out of transaction */
1205 /* check if we're allowed to make any updates */
1206 if (tt->iflags & ITReadOnly) {
1211 /* handle delete-on-salvage flag */
1212 if (aflags & VTDeleteOnSalvage) {
1213 V_destroyMe(tt->volume) = DESTROY_ME;
1215 V_destroyMe(tt->volume) = 0;
1218 if (aflags & VTOutOfService) {
1219 V_inService(vp) = 0;
1221 V_inService(vp) = 1;
1223 VUpdateVolume(&error, vp);
1224 VTRANS_OBJ_LOCK(tt);
1225 tt->vflags = aflags;
1227 VTRANS_OBJ_UNLOCK(tt);
1228 if (TRELE(tt) && !error)
1229 return VOLSERTRELE_ERROR;
1234 /* dumpS the volume associated with a particular transaction from a particular
1235 * date. Send the dump to a different transaction (destTrans) on the server
1236 * specified by the destServer structure.
1239 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1240 struct destServer *destination, afs_int32 destTrans,
1241 struct restoreCookie *cookie)
1246 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1247 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1248 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1253 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1254 struct destServer *destination, afs_int32 destTrans,
1255 struct restoreCookie *cookie)
1257 struct volser_trans *tt;
1259 struct rx_connection *tcon;
1260 struct rx_call *tcall;
1262 struct rx_securityClass *securityObject;
1263 afs_int32 securityIndex;
1264 char caller[MAXKTCNAMELEN];
1266 if (!afsconf_SuperUser(tdir, acid, caller))
1267 return VOLSERBAD_ACCESS; /*not a super user */
1268 /* initialize things */
1269 tcon = (struct rx_connection *)0;
1270 tt = (struct volser_trans *)0;
1272 /* find the local transaction */
1273 tt = FindTrans(fromTrans);
1276 if (tt->vflags & VTDeleted) {
1277 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1282 TSetRxCall(tt, NULL, "Forward");
1284 /* get auth info for the this connection (uses afs from ticket file) */
1285 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1291 /* make an rpc connection to the other server */
1293 rx_NewConnection(htonl(destination->destHost),
1294 htons(destination->destPort), VOLSERVICE_ID,
1295 securityObject, securityIndex);
1301 tcall = rx_NewCall(tcon);
1302 TSetRxCall(tt, tcall, "Forward");
1303 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1304 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1309 /* these next calls implictly call rx_Write when writing out data */
1310 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1313 EndAFSVolRestore(tcall); /* probably doesn't do much */
1315 code = rx_EndCall(tcall, 0);
1316 rx_DestroyConnection(tcon); /* done with the connection */
1321 return VOLSERTRELE_ERROR;
1327 (void)rx_EndCall(tcall, 0);
1328 rx_DestroyConnection(tcon);
1337 /* Start a dump and send it to multiple places simultaneously.
1338 * If this returns an error (eg, return ENOENT), it means that
1339 * none of the releases worked. If this returns 0, that means
1340 * that one or more of the releases worked, and the caller has
1341 * to examine the results array to see which one(s).
1342 * This will only do EITHER incremental or full, not both, so it's
1343 * the caller's responsibility to be sure that all the destinations
1344 * need just an incremental (and from the same time), if that's
1348 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1349 fromDate, manyDests *destinations, afs_int32 spare,
1350 struct restoreCookie *cookie, manyResults *results)
1352 afs_int32 securityIndex;
1353 struct rx_securityClass *securityObject;
1354 char caller[MAXKTCNAMELEN];
1355 struct volser_trans *tt;
1356 afs_int32 ec, code, *codes;
1357 struct rx_connection **tcons;
1358 struct rx_call **tcalls;
1360 int i, is_incremental;
1363 memset(results, 0, sizeof(manyResults));
1364 i = results->manyResults_len = destinations->manyDests_len;
1365 results->manyResults_val = codes =
1366 (afs_int32 *) malloc(i * sizeof(afs_int32));
1368 if (!results || !results->manyResults_val)
1371 if (!afsconf_SuperUser(tdir, acid, caller))
1372 return VOLSERBAD_ACCESS; /*not a super user */
1373 tt = FindTrans(fromTrans);
1376 if (tt->vflags & VTDeleted) {
1377 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1382 TSetRxCall(tt, NULL, "ForwardMulti");
1384 /* (fromDate == 0) ==> full dump */
1385 is_incremental = (fromDate ? 1 : 0);
1388 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1392 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1398 /* get auth info for this connection (uses afs from ticket file) */
1399 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1401 goto fail; /* in order to audit each failure */
1404 /* make connections to all the other servers */
1405 for (i = 0; i < destinations->manyDests_len; i++) {
1406 struct replica *dest = &(destinations->manyDests_val[i]);
1408 rx_NewConnection(htonl(dest->server.destHost),
1409 htons(dest->server.destPort), VOLSERVICE_ID,
1410 securityObject, securityIndex);
1412 codes[i] = ENOTCONN;
1414 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1415 codes[i] = ENOTCONN;
1418 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1421 (void)rx_EndCall(tcalls[i], 0);
1423 rx_DestroyConnection(tcons[i]);
1430 /* these next calls implictly call rx_Write when writing out data */
1431 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1435 for (i--; i >= 0; i--) {
1436 struct replica *dest = &(destinations->manyDests_val[i]);
1438 if (!code && tcalls[i] && !codes[i]) {
1439 EndAFSVolRestore(tcalls[i]);
1442 ec = rx_EndCall(tcalls[i], 0);
1447 rx_DestroyConnection(tcons[i]); /* done with the connection */
1450 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1451 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1452 dest->trans, AUD_END);
1459 if (TRELE(tt) && !code) /* return the first code if it's set */
1460 return VOLSERTRELE_ERROR;
1467 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1471 code = VolDump(acid, fromTrans, fromDate, 0);
1472 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1477 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1482 code = VolDump(acid, fromTrans, fromDate, flags);
1483 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1488 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1492 struct volser_trans *tt;
1493 char caller[MAXKTCNAMELEN];
1495 if (!afsconf_SuperUser(tdir, acid, caller))
1496 return VOLSERBAD_ACCESS; /*not a super user */
1497 tt = FindTrans(fromTrans);
1500 if (tt->vflags & VTDeleted) {
1501 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1505 TSetRxCall(tt, acid, "Dump");
1506 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1507 ? 0 : 1); /* squirt out the volume's data, too */
1516 return VOLSERTRELE_ERROR;
1522 * Ha! No more helper process!
1525 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1526 struct restoreCookie *cookie)
1530 code = VolRestore(acid, atrans, aflags, cookie);
1531 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1536 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1537 struct restoreCookie *cookie)
1539 struct volser_trans *tt;
1540 afs_int32 code, tcode;
1541 char caller[MAXKTCNAMELEN];
1543 if (!afsconf_SuperUser(tdir, acid, caller))
1544 return VOLSERBAD_ACCESS; /*not a super user */
1545 tt = FindTrans(atrans);
1548 if (tt->vflags & VTDeleted) {
1549 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1553 TSetRxCall(tt, acid, "Restore");
1555 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1557 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1558 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1562 return (code ? code : tcode);
1565 /* end a transaction, returning the transaction's final error code in rcode */
1567 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1571 code = VolEndTrans(acid, destTrans, rcode);
1572 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1577 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1579 struct volser_trans *tt;
1580 char caller[MAXKTCNAMELEN];
1582 if (!afsconf_SuperUser(tdir, acid, caller))
1583 return VOLSERBAD_ACCESS; /*not a super user */
1584 tt = FindTrans(destTrans);
1588 *rcode = tt->returnCode;
1589 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1595 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1599 code = VolSetForwarding(acid, atid, anewsite);
1600 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1601 htonl(anewsite), AUD_END);
1606 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1608 struct volser_trans *tt;
1609 char caller[MAXKTCNAMELEN];
1612 if (!afsconf_SuperUser(tdir, acid, caller))
1613 return VOLSERBAD_ACCESS; /*not a super user */
1614 tt = FindTrans(atid);
1617 if (tt->vflags & VTDeleted) {
1618 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1623 TSetRxCall(tt, acid, "SetForwarding");
1624 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1627 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1630 return VOLSERTRELE_ERROR;
1636 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1637 struct volser_status *astatus)
1641 code = VolGetStatus(acid, atrans, astatus);
1642 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1647 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1648 struct volser_status *astatus)
1651 struct VolumeDiskData *td;
1652 struct volser_trans *tt;
1655 tt = FindTrans(atrans);
1658 if (tt->vflags & VTDeleted) {
1659 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1664 TSetRxCall(tt, acid, "GetStatus");
1672 td = &tv->header->diskstuff;
1673 astatus->volID = td->id;
1674 astatus->nextUnique = td->uniquifier;
1675 astatus->type = td->type;
1676 astatus->parentID = td->parentId;
1677 astatus->cloneID = td->cloneId;
1678 astatus->backupID = td->backupId;
1679 astatus->restoredFromID = td->restoredFromId;
1680 astatus->maxQuota = td->maxquota;
1681 astatus->minQuota = td->minquota;
1682 astatus->owner = td->owner;
1683 astatus->creationDate = td->creationDate;
1684 astatus->accessDate = td->accessDate;
1685 astatus->updateDate = td->updateDate;
1686 astatus->expirationDate = td->expirationDate;
1687 astatus->backupDate = td->backupDate;
1688 astatus->copyDate = td->copyDate;
1691 return VOLSERTRELE_ERROR;
1697 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1698 struct volintInfo *astatus)
1702 code = VolSetInfo(acid, atrans, astatus);
1703 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1708 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1709 struct volintInfo *astatus)
1712 struct VolumeDiskData *td;
1713 struct volser_trans *tt;
1714 char caller[MAXKTCNAMELEN];
1717 if (!afsconf_SuperUser(tdir, acid, caller))
1718 return VOLSERBAD_ACCESS; /*not a super user */
1719 tt = FindTrans(atrans);
1722 if (tt->vflags & VTDeleted) {
1723 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1727 TSetRxCall(tt, acid, "SetStatus");
1735 td = &tv->header->diskstuff;
1737 * Add more fields as necessary
1739 if (astatus->maxquota != -1)
1740 td->maxquota = astatus->maxquota;
1741 if (astatus->dayUse != -1)
1742 td->dayUse = astatus->dayUse;
1743 if (astatus->creationDate != -1)
1744 td->creationDate = astatus->creationDate;
1745 if (astatus->updateDate != -1)
1746 td->updateDate = astatus->updateDate;
1747 if (astatus->spare2 != -1)
1748 td->volUpdateCounter = (unsigned int)astatus->spare2;
1749 VUpdateVolume(&error, tv);
1752 return VOLSERTRELE_ERROR;
1758 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1762 code = VolGetName(acid, atrans, aname);
1763 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1768 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1771 struct VolumeDiskData *td;
1772 struct volser_trans *tt;
1775 /* We need to at least fill it in */
1776 *aname = (char *)malloc(1);
1779 tt = FindTrans(atrans);
1782 if (tt->vflags & VTDeleted) {
1783 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1787 TSetRxCall(tt, acid, "GetName");
1795 td = &tv->header->diskstuff;
1796 len = strlen(td->name) + 1; /* don't forget the null */
1802 *aname = (char *)realloc(*aname, len);
1803 strcpy(*aname, td->name);
1806 return VOLSERTRELE_ERROR;
1811 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1814 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1815 afs_uint32 parentId, afs_uint32 cloneId)
1821 /*return a list of all partitions on the server. The non mounted
1822 *partitions are returned as -1 in the corresponding slot in partIds*/
1824 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1828 code = VolListPartitions(acid, partIds);
1829 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1834 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1839 strcpy(namehead, "/vicep"); /*7 including null terminator */
1841 /* Just return attached partitions. */
1843 for (i = 0; i < 26; i++) {
1844 namehead[6] = i + 'a';
1845 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1851 /*return a list of all partitions on the server. The non mounted
1852 *partitions are returned as -1 in the corresponding slot in partIds*/
1854 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1858 code = XVolListPartitions(acid, pEntries);
1859 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1864 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1867 struct partList partList;
1868 struct DiskPartition64 *dp;
1871 strcpy(namehead, "/vicep"); /*7 including null terminator */
1873 /* Only report attached partitions */
1874 for (i = 0; i < VOLMAXPARTS; i++) {
1875 #ifdef AFS_DEMAND_ATTACH_FS
1876 dp = VGetPartitionById(i, 0);
1879 namehead[6] = i + 'a';
1885 namehead[6] = 'a' + (k / 26);
1886 namehead[7] = 'a' + (k % 26);
1889 dp = VGetPartition(namehead, 0);
1892 partList.partId[j++] = i;
1895 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1896 if (!pEntries->partEntries_val)
1898 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1900 pEntries->partEntries_len = j;
1902 pEntries->partEntries_val = NULL;
1903 pEntries->partEntries_len = 0;
1909 /*return the name of the next volume header in the directory associated with dirp and dp.
1910 *the volume id is returned in volid, and volume header name is returned in volname*/
1912 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1916 dp = readdir(dirp); /*read next entry in the directory */
1918 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1919 *volid = VolumeNumber(dp->d_name);
1920 strcpy(volname, dp->d_name);
1921 return 0; /*return the name of the file representing a volume */
1923 strcpy(volname, "");
1924 return 0; /*volname doesnot represent a volume */
1927 strcpy(volname, "EOD");
1928 return 0; /*end of directory */
1934 * volint vol info structure type.
1937 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1938 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1939 } volint_info_type_t;
1942 * handle to various on-wire vol info types.
1945 volint_info_type_t volinfo_type;
1951 } volint_info_handle_t;
1954 * store value to a field at the appropriate location in on-wire structure.
1956 #define VOLINT_INFO_STORE(handle, name, val) \
1958 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1959 (handle)->volinfo_ptr.base->name = (val); \
1961 (handle)->volinfo_ptr.ext->name = (val); \
1966 * get pointer to appropriate offset of field in on-wire structure.
1968 #define VOLINT_INFO_PTR(handle, name) \
1969 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1970 &((handle)->volinfo_ptr.base->name) : \
1971 &((handle)->volinfo_ptr.ext->name))
1974 * fill in appropriate type of on-wire volume metadata structure.
1976 * @param vp pointer to volume object
1977 * @param handle pointer to wire format handle object
1979 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1980 * @pre handle object must have a valid pointer and enumeration value
1982 * @note passing a NULL value for vp means that the fileserver doesn't
1983 * know about this particular volume, thus implying it is offline.
1985 * @return operation status
1990 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1992 unsigned int numStatBytes, now;
1993 struct VolumeDiskData *hdr = &vp->header->diskstuff;
1995 /*read in the relevant info */
1996 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1997 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1998 VOLINT_INFO_STORE(handle, volid, hdr->id);
1999 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2000 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2001 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2002 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2003 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2004 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2005 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2006 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2007 now = FT_ApproxTime();
2008 if ((now - hdr->dayUseDate) > OneDay) {
2009 VOLINT_INFO_STORE(handle, dayUse, 0);
2011 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2013 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2014 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2015 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2016 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2018 #ifdef AFS_DEMAND_ATTACH_FS
2020 * for DAFS, we "lie" about volume state --
2021 * instead of returning the raw state from the disk header,
2022 * we compute state based upon the fileserver's internal
2023 * in-core state enumeration value reported to us via fssync,
2024 * along with the blessed and inService flags from the header.
2025 * -- tkeiser 11/27/2007
2028 /* Conditions that offline status is based on:
2029 volume is unattached state
2030 volume state is in (one of several error states)
2031 volume not in service
2032 volume is not marked as blessed (not on hold)
2033 volume in salvage req. state
2034 volume needsSalvaged
2035 next op would set volume offline
2036 next op would not leave volume online (based on several conditions)
2039 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2040 VIsErrorState(V_attachState(vp)) ||
2043 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2044 hdr->needsSalvaged ||
2045 (vp->pending_vol_op &&
2046 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2047 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2050 VOLINT_INFO_STORE(handle, inUse, 0);
2052 VOLINT_INFO_STORE(handle, inUse, 1);
2055 /* offline status based on program type, where != fileServer enum (1) is offline */
2056 if (hdr->inUse == fileServer) {
2057 VOLINT_INFO_STORE(handle, inUse, 1);
2059 VOLINT_INFO_STORE(handle, inUse, 0);
2064 switch(handle->volinfo_type) {
2065 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2066 case VOLINT_INFO_TYPE_BASE:
2068 #ifdef AFS_DEMAND_ATTACH_FS
2069 /* see comment above where we set inUse bit */
2070 if (hdr->needsSalvaged ||
2071 (vp && VIsErrorState(V_attachState(vp)))) {
2072 handle->volinfo_ptr.base->needsSalvaged = 1;
2074 handle->volinfo_ptr.base->needsSalvaged = 0;
2077 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2079 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2080 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2081 handle->volinfo_ptr.base->spare1 =
2082 (long)hdr->weekUse[0] +
2083 (long)hdr->weekUse[1] +
2084 (long)hdr->weekUse[2] +
2085 (long)hdr->weekUse[3] +
2086 (long)hdr->weekUse[4] +
2087 (long)hdr->weekUse[5] +
2088 (long)hdr->weekUse[6];
2089 handle->volinfo_ptr.base->flags = 0;
2090 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2091 handle->volinfo_ptr.base->spare3 = 0;
2095 case VOLINT_INFO_TYPE_EXT:
2097 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2098 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2101 * Copy out the stat fields in a single operation.
2103 if ((now - hdr->dayUseDate) > OneDay) {
2104 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2107 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2108 (char *)&(hdr->stat_reads[0]),
2117 #ifdef AFS_DEMAND_ATTACH_FS
2120 * get struct Volume out of the fileserver.
2122 * @param[in] volumeId volumeId for which we want state information
2123 * @param[in] pname partition name string
2124 * @param[inout] vp pointer to pointer to Volume object which
2125 * will be populated (see note)
2127 * @return operation status
2129 * @retval non-zero failure
2131 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2136 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2141 res.hdr.response_len = sizeof(res.hdr);
2142 res.payload.buf = *vp;
2143 res.payload.len = sizeof(Volume);
2145 code = FSYNC_VolOp(volumeId,
2151 if (code != SYNC_OK) {
2152 switch (res.hdr.reason) {
2153 case FSYNC_WRONG_PART:
2154 case FSYNC_UNKNOWN_VOLID:
2167 * mode of volume list operation.
2170 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2171 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2172 } vol_info_list_mode_t;
2175 * abstract interface to populate wire-format volume metadata structures.
2177 * @param[in] partId partition id
2178 * @param[in] volumeId volume id
2179 * @param[in] pname partition name
2180 * @param[in] volname volume file name
2181 * @param[in] handle handle to on-wire volume metadata object
2182 * @param[in] mode listing mode
2184 * @return operation status
2186 * @retval -2 DESTROY_ME flag is set
2187 * @retval -1 general failure; some data filled in
2188 * @retval -3 couldn't create vtrans; some data filled in
2191 GetVolInfo(afs_uint32 partId,
2192 afs_uint32 volumeId,
2195 volint_info_handle_t * handle,
2196 vol_info_list_mode_t mode)
2200 struct volser_trans *ttc = NULL;
2201 struct Volume *fill_tv, *tv = NULL;
2202 #ifdef AFS_DEMAND_ATTACH_FS
2203 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2204 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2205 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2206 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2208 /* Set up response handle for pending_vol_op */
2209 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2210 fs_res.payload.buf = fs_res_buf;
2211 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2214 ttc = NewTrans(volumeId, partId);
2217 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2218 VOLINT_INFO_STORE(handle, volid, volumeId);
2222 /* Get volume from volserver */
2223 if (mode == VOL_INFO_LIST_MULTIPLE)
2224 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2226 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2228 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2229 volumeId, pname, volname, error);
2234 * please note that destroyMe and needsSalvaged checks used to be ordered
2235 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2236 * more correct to check destroyMe before needsSalvaged.
2237 * -- tkeiser 11/28/2007
2240 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2242 case VOL_INFO_LIST_MULTIPLE:
2246 case VOL_INFO_LIST_SINGLE:
2247 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2248 volumeId, pname, volname);
2255 if (tv->header->diskstuff.needsSalvaged) {
2256 /*this volume will be salvaged */
2257 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2258 volumeId, pname, volname);
2261 #ifdef AFS_DEMAND_ATTACH_FS
2262 /* If using DAFS, get volume from fsserver */
2263 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2268 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2269 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2270 /* If we if the pending vol op */
2271 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2272 fs_tv->pending_vol_op=&pending_vol_op_res;
2274 fs_tv->pending_vol_op=NULL;
2277 /* populate the header from the volserver copy */
2278 fs_tv->header=tv->header;
2280 /* When using DAFS, use the fs volume info, populated with required structures */
2283 /* When not using DAFS, just use the local volume info */
2287 /* ok, we have all the data we need; fill in the on-wire struct */
2288 code = FillVolInfo(fill_tv, handle);
2292 VOLINT_INFO_STORE(handle, status, 0);
2293 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2294 VOLINT_INFO_STORE(handle, volid, volumeId);
2297 VDetachVolume(&error, tv);
2300 VOLINT_INFO_STORE(handle, status, 0);
2301 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2302 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2303 volumeId, pname, volname);
2307 DeleteTrans(ttc, 1);
2314 /*return the header information about the <volid> */
2316 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2317 afs_uint32 volumeId, volEntries *volumeInfo)
2321 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2322 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2327 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2328 afs_uint32 volumeId, volEntries *volumeInfo)
2330 struct DiskPartition64 *partP;
2331 char pname[9], volname[20];
2336 volint_info_handle_t handle;
2338 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2339 if (!volumeInfo->volEntries_val)
2341 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2343 volumeInfo->volEntries_len = 1;
2344 if (GetPartName(partid, pname))
2345 return VOLSERILLEGAL_PARTITION;
2346 if (!(partP = VGetPartition(pname, 0)))
2347 return VOLSERILLEGAL_PARTITION;
2348 dirp = opendir(VPartitionPath(partP));
2350 return VOLSERILLEGAL_PARTITION;
2352 strcpy(volname, "");
2354 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2356 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2357 GetNextVol(dirp, volname, &volid);
2358 continue; /*back to while loop */
2361 if (volid == volumeId) { /*copy other things too */
2366 GetNextVol(dirp, volname, &volid);
2370 #ifndef AFS_PTHREAD_ENV
2371 IOMGR_Poll(); /*make sure that the client does not time out */
2374 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2375 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2377 code = GetVolInfo(partid,
2382 VOL_INFO_LIST_SINGLE);
2387 return code ? ENODEV: 0;
2392 /*------------------------------------------------------------------------
2393 * EXPORTED SAFSVolXListOneVolume
2396 * Returns extended info on volume a_volID on partition a_partID.
2399 * a_rxCidP : Pointer to the Rx call we're performing.
2400 * a_partID : Partition for which we want the extended list.
2401 * a_volID : Volume ID we wish to know about.
2402 * a_volumeXInfoP : Ptr to the extended info blob.
2405 * 0 Successful operation
2406 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2409 * Nothing interesting.
2413 *------------------------------------------------------------------------*/
2416 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2417 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2421 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2422 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2427 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2428 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2429 { /*SAFSVolXListOneVolume */
2431 struct DiskPartition64 *partP; /*Ptr to partition */
2432 char pname[9], volname[20]; /*Partition, volume names */
2433 DIR *dirp; /*Partition directory ptr */
2434 afs_uint32 currVolID; /*Current volume ID */
2435 int found = 0; /*Did we find the volume we need? */
2437 volint_info_handle_t handle;
2440 * Set up our pointers for action, marking our structure to hold exactly
2441 * one entry. Also, assume we'll fail in our quest.
2443 a_volumeXInfoP->volXEntries_val =
2444 (volintXInfo *) malloc(sizeof(volintXInfo));
2445 if (!a_volumeXInfoP->volXEntries_val)
2447 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2449 a_volumeXInfoP->volXEntries_len = 1;
2453 * If the partition name we've been given is bad, bogue out.
2455 if (GetPartName(a_partID, pname))
2456 return (VOLSERILLEGAL_PARTITION);
2459 * Open the directory representing the given AFS parttion. If we can't
2462 if (!(partP = VGetPartition(pname, 0)))
2463 return VOLSERILLEGAL_PARTITION;
2464 dirp = opendir(VPartitionPath(partP));
2466 return (VOLSERILLEGAL_PARTITION);
2468 strcpy(volname, "");
2471 * Sweep through the partition directory, looking for the desired entry.
2472 * First, of course, figure out how many stat bytes to copy out of each
2475 while (strcmp(volname, "EOD") && !found) {
2477 * If this is not a volume, move on to the next entry in the
2478 * partition's directory.
2480 if (!strcmp(volname, "")) {
2481 GetNextVol(dirp, volname, &currVolID);
2485 if (currVolID == a_volID) {
2487 * We found the volume entry we're interested. Pull out the
2488 * extended information, remembering to poll (so that the client
2489 * doesn't time out) and to set up a transaction on the volume.
2493 } /*Found desired volume */
2495 GetNextVol(dirp, volname, &currVolID);
2499 #ifndef AFS_PTHREAD_ENV
2503 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2504 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2506 code = GetVolInfo(a_partID,
2511 VOL_INFO_LIST_SINGLE);
2516 * Clean up before going to dinner: close the partition directory,
2517 * return the proper value.
2521 return code ? ENODEV: 0;
2524 } /*SAFSVolXListOneVolume */
2526 /*returns all the volumes on partition partid. If flags = 1 then all the
2527 * relevant info about the volumes is also returned */
2529 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2530 volEntries *volumeInfo)
2534 code = VolListVolumes(acid, partid, flags, volumeInfo);
2535 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2540 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2541 volEntries *volumeInfo)
2544 struct DiskPartition64 *partP;
2545 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2546 char pname[9], volname[20];
2550 volint_info_handle_t handle;
2552 volumeInfo->volEntries_val =
2553 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2554 if (!volumeInfo->volEntries_val)
2556 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2558 pntr = volumeInfo->volEntries_val;
2559 volumeInfo->volEntries_len = 0;
2560 if (GetPartName(partid, pname))
2561 return VOLSERILLEGAL_PARTITION;
2562 if (!(partP = VGetPartition(pname, 0)))
2563 return VOLSERILLEGAL_PARTITION;
2564 dirp = opendir(VPartitionPath(partP));
2566 return VOLSERILLEGAL_PARTITION;
2567 strcpy(volname, "");
2569 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2571 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2572 GetNextVol(dirp, volname, &volid);
2573 continue; /*back to while loop */
2576 if (flags) { /*copy other things too */
2577 #ifndef AFS_PTHREAD_ENV
2578 IOMGR_Poll(); /*make sure that the client does not time out */
2581 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2582 handle.volinfo_ptr.base = pntr;
2585 code = GetVolInfo(partid,
2590 VOL_INFO_LIST_MULTIPLE);
2591 if (code == -2) { /* DESTROY_ME flag set */
2595 pntr->volid = volid;
2596 /*just volids are needed */
2600 volumeInfo->volEntries_len += 1;
2601 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2602 /*running out of space, allocate more space */
2603 allocSize = (allocSize * 3) / 2;
2605 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2606 allocSize * sizeof(volintInfo));
2609 return VOLSERNO_MEMORY;
2611 volumeInfo->volEntries_val = pntr; /* point to new block */
2612 /* set pntr to the right position */
2613 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2618 GetNextVol(dirp, volname, &volid);
2626 /*------------------------------------------------------------------------
2627 * EXPORTED SAFSVolXListVolumes
2630 * Returns all the volumes on partition a_partID. If a_flags
2631 * is set to 1, then all the relevant extended volume information
2635 * a_rxCidP : Pointer to the Rx call we're performing.
2636 * a_partID : Partition for which we want the extended list.
2637 * a_flags : Various flags.
2638 * a_volumeXInfoP : Ptr to the extended info blob.
2641 * 0 Successful operation
2642 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2643 * VOLSERNO_MEMORY if we ran out of memory allocating
2647 * Nothing interesting.
2651 *------------------------------------------------------------------------*/
2654 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2655 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2659 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2660 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2665 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2666 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2667 { /*SAFSVolXListVolumes */
2669 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2670 struct DiskPartition64 *partP; /*Ptr to partition */
2671 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2672 char pname[9], volname[20]; /*Partition, volume names */
2673 DIR *dirp; /*Partition directory ptr */
2674 afs_uint32 volid; /*Current volume ID */
2676 volint_info_handle_t handle;
2679 * Allocate a large array of extended volume info structures, then
2680 * set it up for action.
2682 a_volumeXInfoP->volXEntries_val =
2683 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2684 if (!a_volumeXInfoP->volXEntries_val)
2686 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2688 xInfoP = a_volumeXInfoP->volXEntries_val;
2689 a_volumeXInfoP->volXEntries_len = 0;
2692 * If the partition name we've been given is bad, bogue out.
2694 if (GetPartName(a_partID, pname))
2695 return (VOLSERILLEGAL_PARTITION);
2698 * Open the directory representing the given AFS parttion. If we can't
2701 if (!(partP = VGetPartition(pname, 0)))
2702 return VOLSERILLEGAL_PARTITION;
2703 dirp = opendir(VPartitionPath(partP));
2705 return (VOLSERILLEGAL_PARTITION);
2706 strcpy(volname, "");
2709 * Sweep through the partition directory, acting on each entry. First,
2710 * of course, figure out how many stat bytes to copy out of each volume.
2712 while (strcmp(volname, "EOD")) {
2715 * If this is not a volume, move on to the next entry in the
2716 * partition's directory.
2718 if (!strcmp(volname, "")) {
2719 GetNextVol(dirp, volname, &volid);
2725 * Full info about the volume desired. Poll to make sure the
2726 * client doesn't time out, then start up a new transaction.
2728 #ifndef AFS_PTHREAD_ENV
2732 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2733 handle.volinfo_ptr.ext = xInfoP;
2735 code = GetVolInfo(a_partID,
2740 VOL_INFO_LIST_MULTIPLE);
2741 if (code == -2) { /* DESTROY_ME flag set */
2746 * Just volume IDs are needed.
2748 xInfoP->volid = volid;
2752 * Bump the pointer in the data area we're building, along with
2753 * the count of the number of entries it contains.
2756 (a_volumeXInfoP->volXEntries_len)++;
2757 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2759 * We're running out of space in the area we've built. Grow it.
2761 allocSize = (allocSize * 3) / 2;
2762 xInfoP = (volintXInfo *)
2763 realloc((char *)a_volumeXInfoP->volXEntries_val,
2764 (allocSize * sizeof(volintXInfo)));
2765 if (xInfoP == NULL) {
2767 * Bummer, no memory. Bag it, tell our caller what went wrong.
2770 return (VOLSERNO_MEMORY);
2774 * Memory reallocation worked. Correct our pointers so they
2775 * now point to the new block and the current open position within
2778 a_volumeXInfoP->volXEntries_val = xInfoP;
2780 a_volumeXInfoP->volXEntries_val +
2781 a_volumeXInfoP->volXEntries_len;
2785 GetNextVol(dirp, volname, &volid);
2786 } /*Sweep through the partition directory */
2789 * We've examined all entries in the partition directory. Close it,
2790 * delete our transaction (if any), and go home happy.
2795 } /*SAFSVolXListVolumes */
2797 /*this call is used to monitor the status of volser for debugging purposes.
2798 *information about all the active transactions is returned in transInfo*/
2800 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2804 code = VolMonitor(acid, transInfo);
2805 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2810 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2812 transDebugInfo *pntr;
2813 afs_int32 allocSize = 50;
2814 struct volser_trans *tt, *nt, *allTrans;
2816 transInfo->transDebugEntries_val =
2817 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2818 if (!transInfo->transDebugEntries_val)
2820 pntr = transInfo->transDebugEntries_val;
2821 transInfo->transDebugEntries_len = 0;
2824 allTrans = TransList();
2825 if (allTrans == (struct volser_trans *)0)
2826 goto done; /*no active transactions */
2827 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2829 VTRANS_OBJ_LOCK(tt);
2830 pntr->tid = tt->tid;
2831 pntr->time = tt->time;
2832 pntr->creationTime = tt->creationTime;
2833 pntr->returnCode = tt->returnCode;
2834 pntr->volid = tt->volid;
2835 pntr->partition = tt->partition;
2836 pntr->iflags = tt->iflags;
2837 pntr->vflags = tt->vflags;
2838 pntr->tflags = tt->tflags;
2839 strcpy(pntr->lastProcName, tt->lastProcName);
2840 pntr->callValid = 0;
2841 if (tt->rxCallPtr) { /*record call related info */
2842 pntr->callValid = 1;
2844 pntr->readNext = tt->rxCallPtr->rnext;
2845 pntr->transmitNext = tt->rxCallPtr->tnext;
2846 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2847 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2850 VTRANS_OBJ_UNLOCK(tt);
2852 transInfo->transDebugEntries_len += 1;
2853 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2854 allocSize = (allocSize * 3) / 2;
2856 (transDebugInfo *) realloc((char *)transInfo->
2857 transDebugEntries_val,
2859 sizeof(transDebugInfo));
2860 transInfo->transDebugEntries_val = pntr;
2862 transInfo->transDebugEntries_val +
2863 transInfo->transDebugEntries_len;
2864 /*set pntr to right position */
2875 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2876 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2877 afs_uint32 backupId)
2881 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2882 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2883 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2889 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2890 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2891 afs_uint32 backupId)
2895 struct volser_trans *tt;
2896 char caller[MAXKTCNAMELEN];
2898 if (strlen(name) > 31)
2899 return VOLSERBADNAME;
2900 if (!afsconf_SuperUser(tdir, acid, caller))
2901 return VOLSERBAD_ACCESS; /*not a super user */
2902 /* find the trans */
2903 tt = FindTrans(atid);
2906 if (tt->vflags & VTDeleted) {
2907 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2911 TSetRxCall(tt, acid, "SetIdsTypes");
2915 V_backupId(tv) = backupId;
2916 V_cloneId(tv) = cloneId;
2917 V_parentId(tv) = pId;
2918 strcpy((&V_disk(tv))->name, name);
2919 VUpdateVolume(&error, tv);
2921 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2926 if (TRELE(tt) && !error)
2927 return VOLSERTRELE_ERROR;
2932 if (TRELE(tt) && !error)
2933 return VOLSERTRELE_ERROR;
2938 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2942 code = VolSetDate(acid, atid, cdate);
2943 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2949 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2953 struct volser_trans *tt;
2954 char caller[MAXKTCNAMELEN];
2956 if (!afsconf_SuperUser(tdir, acid, caller))
2957 return VOLSERBAD_ACCESS; /*not a super user */
2958 /* find the trans */
2959 tt = FindTrans(atid);
2962 if (tt->vflags & VTDeleted) {
2963 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2967 TSetRxCall(tt, acid, "SetDate");
2970 V_creationDate(tv) = cdate;
2971 VUpdateVolume(&error, tv);
2973 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2978 if (TRELE(tt) && !error)
2979 return VOLSERTRELE_ERROR;
2984 if (TRELE(tt) && !error)
2985 return VOLSERTRELE_ERROR;
2990 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2991 afs_uint32 volumeId)
2996 char caller[MAXKTCNAMELEN];
2998 struct volser_trans *ttc;
2999 char pname[16], volname[20];
3000 struct DiskPartition64 *partP;
3001 afs_int32 ret = ENODEV;
3004 if (!afsconf_SuperUser(tdir, acid, caller))
3005 return VOLSERBAD_ACCESS; /*not a super user */
3006 if (GetPartName(partId, pname))
3007 return VOLSERILLEGAL_PARTITION;
3008 if (!(partP = VGetPartition(pname, 0)))
3009 return VOLSERILLEGAL_PARTITION;
3010 dirp = opendir(VPartitionPath(partP));
3012 return VOLSERILLEGAL_PARTITION;
3013 strcpy(volname, "");
3014 ttc = (struct volser_trans *)0;
3016 while (strcmp(volname, "EOD")) {
3017 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3018 GetNextVol(dirp, volname, &volid);
3019 continue; /*back to while loop */
3022 if (volid == volumeId) { /*copy other things too */
3023 #ifndef AFS_PTHREAD_ENV
3024 IOMGR_Poll(); /*make sure that the client doesnot time out */
3026 ttc = NewTrans(volumeId, partId);
3028 return VOLSERVOLBUSY;
3030 #ifdef AFS_NAMEI_ENV
3031 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3033 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3037 GetNextVol(dirp, volname, &volid);
3041 DeleteTrans(ttc, 1);
3042 ttc = (struct volser_trans *)0;
3051 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3052 struct volintSize *size)
3055 struct volser_trans *tt;
3056 char caller[MAXKTCNAMELEN];
3058 if (!afsconf_SuperUser(tdir, acid, caller))
3059 return VOLSERBAD_ACCESS; /*not a super user */
3060 tt = FindTrans(fromTrans);
3063 if (tt->vflags & VTDeleted) {
3067 TSetRxCall(tt, acid, "GetSize");
3068 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3071 return VOLSERTRELE_ERROR;
3073 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3078 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3079 afs_uint32 where, afs_int32 verbose)
3081 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3083 Volume *vol=0, *newvol=0;
3084 struct volser_trans *tt = 0, *tt2 = 0;
3085 char caller[MAXKTCNAMELEN];
3088 if (!afsconf_SuperUser(tdir, acall, caller))
3091 vol = VAttachVolume(&code, vid, V_VOLUPD);
3097 newvol = VAttachVolume(&code, new, V_VOLUPD);
3099 VDetachVolume(&code2, vol);
3104 if (V_device(vol) != V_device(newvol)
3105 || V_uniquifier(newvol) != 2) {
3106 if (V_device(vol) != V_device(newvol)) {
3107 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3109 rx_Write(acall, line, strlen(line));
3111 if (V_uniquifier(newvol) != 2) {
3112 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3113 rx_Write(acall, line, strlen(line));
3116 rx_Write(acall, line, 1);
3117 VDetachVolume(&code2, vol);
3118 VDetachVolume(&code2, newvol);
3121 tt = NewTrans(vid, V_device(vol));
3123 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3124 rx_Write(acall, line, strlen(line));
3126 rx_Write(acall, line, 1);
3127 VDetachVolume(&code2, vol);
3128 VDetachVolume(&code2, newvol);
3129 return VOLSERVOLBUSY;
3131 VTRANS_OBJ_LOCK(tt);
3132 tt->iflags = ITBusy;
3134 TSetRxCall_r(tt, NULL, "SplitVolume");
3135 VTRANS_OBJ_UNLOCK(tt);
3137 tt2 = NewTrans(new, V_device(newvol));
3139 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3140 rx_Write(acall, line, strlen(line));
3142 rx_Write(acall, line, 1);
3144 VDetachVolume(&code2, vol);
3145 VDetachVolume(&code2, newvol);
3146 return VOLSERVOLBUSY;
3148 VTRANS_OBJ_LOCK(tt2);
3149 tt2->iflags = ITBusy;
3151 TSetRxCall_r(tt2, NULL, "SplitVolume");
3152 VTRANS_OBJ_UNLOCK(tt2);
3154 code = split_volume(acall, vol, newvol, where, verbose);
3156 VDetachVolume(&code2, vol);
3158 VDetachVolume(&code2, newvol);
3159 DeleteTrans(tt2, 1);
3166 /* GetPartName - map partid (a decimal number) into pname (a string)
3167 * Since for NT we actually want to return the drive name, we map through the
3171 GetPartName(afs_int32 partid, char *pname)
3176 strcpy(pname, "/vicep");
3177 pname[6] = 'a' + partid;
3180 } else if (partid < VOLMAXPARTS) {
3181 strcpy(pname, "/vicep");
3183 pname[6] = 'a' + (partid / 26);
3184 pname[7] = 'a' + (partid % 26);