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 = calloc(1, SIZEOF_LARGEDISKVNODE);
341 V_pref(vp, nearInode);
343 IH_CREATE(V_linkHandle(vp), V_device(vp),
344 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
346 if (!VALID_INO(inodeNumber)) {
347 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
352 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
353 did.Volume = V_id(vp);
354 did.Vnode = (VnodeId) 1;
357 osi_Assert(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
358 DFlush(); /* flush all modified dir buffers out */
359 DZap(&dir); /* Remove all buffers for this dir */
360 length = afs_dir_Length(&dir); /* Remember size of this directory */
362 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
364 /* build a single entry ACL that gives all rights to system:administrators */
365 /* this section of code assumes that access list format is not going to
368 ACL = VVnodeDiskACL(vnode);
369 ACL->size = sizeof(struct acl_accessList);
370 ACL->version = ACL_ACLVERSION;
374 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
375 ACL->entries[0].rights =
376 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
377 | PRSFS_LOCK | PRSFS_ADMINISTER;
379 vnode->type = vDirectory;
381 vnode->modeBits = 0777;
382 vnode->linkCount = 2;
383 VNDISK_SET_LEN(vnode, length);
384 vnode->uniquifier = 1;
385 V_uniquifier(vp) = vnode->uniquifier + 1;
386 vnode->dataVersion = 1;
387 VNDISK_SET_INO(vnode, inodeNumber);
388 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
392 vnode->vnodeMagic = vcp->magic;
394 IH_INIT(h, vp->device, V_parentId(vp),
395 vp->vnodeIndex[vLarge].handle->ih_ino);
397 osi_Assert(fdP != NULL);
398 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
399 osi_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
400 FDH_REALLYCLOSE(fdP);
402 VNDISK_GET_LEN(length, vnode);
403 V_diskused(vp) = nBlocks(length);
410 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
414 struct diskPartition64 *dp = malloc(sizeof(struct diskPartition64));
416 code = VolPartitionInfo(acid, pname, dp);
418 strncpy(partition->name, dp->name, 32);
419 strncpy(partition->devName, dp->devName, 32);
420 partition->lock_fd = dp->lock_fd;
421 partition->free=RoundInt64ToInt32(dp->free);
422 partition->minFree=RoundInt64ToInt32(dp->minFree);
425 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
430 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
435 code = VolPartitionInfo(acid, pname, partition);
436 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
441 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
444 struct DiskPartition64 *dp;
447 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
450 dp = VGetPartition(pname, 0);
452 strncpy(partition->name, dp->name, 32);
453 strncpy(partition->devName, dp->devName, 32);
454 partition->lock_fd = (int)dp->lock_fd;
455 partition->free = dp->free;
456 partition->minFree = dp->totalUsable;
459 return VOLSERILLEGAL_PARTITION;
462 /* obliterate a volume completely, and slowly. */
464 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
468 code = VolNukeVolume(acid, apartID, avolID);
469 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
474 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
481 char caller[MAXKTCNAMELEN];
483 /* check for access */
484 if (!afsconf_SuperUser(tdir, acid, caller))
485 return VOLSERBAD_ACCESS;
488 Log("%s on %s is executing VolNukeVolume %u\n", caller,
489 callerAddress(acid, buffer), avolID);
492 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
494 /* we first try to attach the volume in update mode, so that the file
495 * server doesn't try to use it (and abort) while (or after) we delete it.
496 * If we don't get the volume, that's fine, too. We just won't put it back.
498 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
499 code = nuke(partName, avolID);
501 VDetachVolume(&verror, tvp);
505 /* create a new volume, with name aname, on the specified partition (1..n)
506 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
507 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
508 * for the volume id (useful for things like volume restore).
509 * Return the new volume id in *avolid.
512 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
513 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
519 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
520 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
521 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
527 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
528 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
533 Error junk; /* discardable error code */
535 afs_int32 doCreateRoot = 1;
536 struct volser_trans *tt;
538 char caller[MAXKTCNAMELEN];
540 if (strlen(aname) > 31)
541 return VOLSERBADNAME;
542 if (!afsconf_SuperUser(tdir, acid, caller))
543 return VOLSERBAD_ACCESS;
546 Log("%s on %s is executing CreateVolume '%s'\n", caller,
547 callerAddress(acid, buffer), aname);
549 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
550 return error; /*a standard unix error */
551 if (atype != readwriteVolume && atype != readonlyVolume
552 && atype != backupVolume)
554 if ((volumeID = *avolid) == 0) {
556 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
560 if ((aparent == volumeID) && (atype == readwriteVolume)) {
565 tt = NewTrans(volumeID, apart);
567 Log("1 createvolume: failed to create trans\n");
568 return VOLSERVOLBUSY; /* volume already busy! */
570 vp = VCreateVolume(&error, ppath, volumeID, aparent);
572 #ifdef AFS_DEMAND_ATTACH_FS
573 if (error != VVOLEXISTS && error != EXDEV) {
574 SalvageUnknownVolume(volumeID, ppath);
577 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
582 V_uniquifier(vp) = 1;
583 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
584 V_inService(vp) = V_blessed(vp) = 1;
586 AssignVolumeName(&V_disk(vp), aname, 0);
588 error = ViceCreateRoot(vp);
590 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
591 "error code %u\n", (unsigned)error);
593 V_needsSalvaged(vp) = 1;
594 VDetachVolume(&junk, vp);
598 V_destroyMe(vp) = DESTROY_ME;
600 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
601 VUpdateVolume(&error, vp);
603 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
606 VDetachVolume(&junk, vp); /* rather return the real error code */
612 TSetRxCall_r(tt, acid, "CreateVolume");
613 VTRANS_OBJ_UNLOCK(tt);
614 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
617 return VOLSERTRELE_ERROR;
621 /* delete the volume associated with this transaction */
623 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
627 code = VolDeleteVolume(acid, atrans);
628 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
633 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
635 struct volser_trans *tt;
637 char caller[MAXKTCNAMELEN];
639 if (!afsconf_SuperUser(tdir, acid, caller))
640 return VOLSERBAD_ACCESS;
641 tt = FindTrans(atrans);
644 if (tt->vflags & VTDeleted) {
645 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
651 Log("%s on %s is executing Delete Volume %u\n", caller,
652 callerAddress(acid, buffer), tt->volid);
654 TSetRxCall(tt, acid, "DeleteVolume");
655 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
656 V_destroyMe(tt->volume) = DESTROY_ME;
657 if (tt->volume->needsPutBack) {
658 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
661 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
663 VTRANS_OBJ_UNLOCK(tt);
665 return VOLSERTRELE_ERROR;
667 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
668 return 0; /* vpurgevolume doesn't set an error code */
671 /* make a clone of the volume associated with atrans, possibly giving it a new
672 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
673 * for the clone's id). The new clone is given the name newName. Finally,
674 * due to efficiency considerations, if purgeId is non-zero, we purge that
675 * volume when doing the clone operation. This may be useful when making
676 * new backup volumes, for instance since the net result of a clone and a
677 * purge generally leaves many inode ref counts the same, while doing them
678 * separately would result in far more iincs and idecs being peformed
679 * (and they are slow operations).
681 /* for efficiency reasons, sometimes faster to piggyback a purge here */
683 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
684 afs_int32 newType, char *newName, afs_uint32 *newNumber)
688 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
689 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
690 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
696 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
697 afs_int32 newType, char *newName, afs_uint32 *newNumber)
700 struct Volume *originalvp, *purgevp, *newvp;
702 struct volser_trans *tt, *ttc;
703 char caller[MAXKTCNAMELEN];
704 #ifdef AFS_DEMAND_ATTACH_FS
705 struct Volume *salv_vp = NULL;
708 if (strlen(newName) > 31)
709 return VOLSERBADNAME;
710 if (!afsconf_SuperUser(tdir, acid, caller))
711 return VOLSERBAD_ACCESS; /*not a super user */
714 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
715 callerAddress(acid, buffer), newName);
718 originalvp = (Volume *) 0;
719 purgevp = (Volume *) 0;
720 newvp = (Volume *) 0;
721 tt = ttc = (struct volser_trans *)0;
723 if (!newNumber || !*newNumber) {
724 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
729 tt = FindTrans(atrans);
732 if (tt->vflags & VTDeleted) {
733 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
737 ttc = NewTrans(newId, tt->partition);
738 if (!ttc) { /* someone is messing with the clone already */
740 return VOLSERVOLBUSY;
742 TSetRxCall(tt, acid, "Clone");
746 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
748 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
754 originalvp = tt->volume;
755 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
756 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
762 if (originalvp->device != purgevp->device) {
763 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
767 if (V_type(purgevp) != readonlyVolume) {
768 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
772 if (V_parentId(originalvp) != V_parentId(purgevp)) {
773 Log("1 Volser: Clone: Volume %u and volume %u were not originally cloned from the same parent; aborted\n", purgeId, tt->volid);
780 #ifdef AFS_DEMAND_ATTACH_FS
781 salv_vp = originalvp;
784 if (purgeId == newId) {
788 VCreateVolume(&error, originalvp->partition->name, newId,
789 V_parentId(originalvp));
791 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
792 newvp = (Volume *) 0;
796 if (newType == readonlyVolume)
797 V_cloneId(originalvp) = newId;
798 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
801 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
802 CloneVolume(&error, originalvp, newvp, purgevp);
803 purgevp = NULL; /* clone releases it, maybe even if error */
805 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
809 if (newType == readonlyVolume) {
810 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
811 V_type(newvp) = readonlyVolume;
812 } else if (newType == backupVolume) {
813 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
814 V_type(newvp) = backupVolume;
815 V_backupId(originalvp) = newId;
817 strcpy(newvp->header->diskstuff.name, newName);
818 V_creationDate(newvp) = V_copyDate(newvp);
819 ClearVolumeStats(&V_disk(newvp));
820 V_destroyMe(newvp) = DESTROY_ME;
821 V_inService(newvp) = 0;
822 if (newType == backupVolume) {
823 V_backupDate(originalvp) = V_copyDate(newvp);
824 V_backupDate(newvp) = V_copyDate(newvp);
827 VUpdateVolume(&error, newvp);
829 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
833 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
835 VUpdateVolume(&error, originalvp);
837 Log("1 Volser: Clone: original update %u\n", error);
842 #ifdef AFS_DEMAND_ATTACH_FS
846 tt = (struct volser_trans *)0;
847 error = VOLSERTRELE_ERROR;
855 VDetachVolume(&code, purgevp);
857 VDetachVolume(&code, newvp);
864 #ifdef AFS_DEMAND_ATTACH_FS
865 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
866 V_needsSalvaged(salv_vp) = 1;
868 #endif /* AFS_DEMAND_ATTACH_FS */
872 /* reclone this volume into the specified id */
874 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
878 code = VolReClone(acid, atrans, cloneId);
879 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
885 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
887 struct Volume *originalvp, *clonevp;
890 struct volser_trans *tt, *ttc;
891 char caller[MAXKTCNAMELEN];
892 VolumeDiskData saved_header;
894 /*not a super user */
895 if (!afsconf_SuperUser(tdir, acid, caller))
896 return VOLSERBAD_ACCESS;
899 Log("%s on %s is executing Reclone Volume %u\n", caller,
900 callerAddress(acid, buffer), cloneId);
903 clonevp = originalvp = (Volume *) 0;
904 tt = (struct volser_trans *)0;
906 tt = FindTrans(atrans);
909 if (tt->vflags & VTDeleted) {
910 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
914 ttc = NewTrans(cloneId, tt->partition);
915 if (!ttc) { /* someone is messing with the clone already */
917 return VOLSERVOLBUSY;
919 TSetRxCall(tt, acid, "ReClone");
921 originalvp = tt->volume;
922 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
923 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
929 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
931 Log("1 Volser: can't attach clone %d\n", cloneId);
935 newType = V_type(clonevp); /* type of the new volume */
937 if (originalvp->device != clonevp->device) {
938 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
943 if (V_parentId(originalvp) != V_parentId(clonevp)) {
944 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
949 if (DoPreserveVolumeStats) {
950 CopyVolumeStats(&V_disk(clonevp), &saved_header);
954 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
956 CloneVolume(&error, originalvp, clonevp, clonevp);
958 Log("1 Volser: Clone: reclone operation failed with code %d\n",
964 /* fix up volume name and type, CloneVolume just propagated RW's */
965 if (newType == readonlyVolume) {
966 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
967 V_type(clonevp) = readonlyVolume;
968 } else if (newType == backupVolume) {
969 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
970 V_type(clonevp) = backupVolume;
971 V_backupId(originalvp) = cloneId;
973 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
975 /* update the creationDate, since this represents the last cloning date
976 * for ROs. But do not update copyDate; let it stay so we can identify
977 * when the clone was first created. */
978 V_creationDate(clonevp) = time(0);
979 if (DoPreserveVolumeStats) {
980 CopyVolumeStats(&saved_header, &V_disk(clonevp));
982 ClearVolumeStats(&V_disk(clonevp));
984 V_destroyMe(clonevp) = 0;
985 V_inService(clonevp) = 0;
986 if (newType == backupVolume) {
987 V_backupDate(originalvp) = V_creationDate(clonevp);
988 V_backupDate(clonevp) = V_creationDate(clonevp);
990 V_inUse(clonevp) = 0;
991 VUpdateVolume(&error, clonevp);
993 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
997 /* VUpdateVolume succeeded. Mark it in service so there's no window
998 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
999 * specialStatus; this is a reclone and this volume started online
1001 V_inService(clonevp) = 1;
1002 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
1004 VUpdateVolume(&error, originalvp);
1006 Log("1 Volser: Clone: original update %u\n", error);
1012 tt = (struct volser_trans *)0;
1013 error = VOLSERTRELE_ERROR;
1017 DeleteTrans(ttc, 1);
1020 struct DiskPartition64 *tpartp = originalvp->partition;
1021 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1027 VDetachVolume(&code, clonevp);
1033 DeleteTrans(ttc, 1);
1037 /* create a new transaction, associated with volume and partition. Type of
1038 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1039 * See volser.h for definition of iflags (the constants are named IT*).
1042 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1043 afs_int32 iflags, afs_int32 *ttid)
1047 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1048 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1054 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1055 afs_int32 iflags, afs_int32 *ttid)
1057 struct volser_trans *tt;
1062 char caller[MAXKTCNAMELEN];
1064 if (!afsconf_SuperUser(tdir, acid, caller))
1065 return VOLSERBAD_ACCESS; /*not a super user */
1066 if (iflags & ITCreate)
1068 else if (iflags & ITBusy)
1070 else if (iflags & ITReadOnly)
1072 else if (iflags & ITOffline)
1075 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1080 tt = NewTrans(volume, partition);
1082 /* can't create a transaction? put the volume back */
1083 Log("1 transcreate: can't create transaction\n");
1084 return VOLSERVOLBUSY;
1086 tv = XAttachVolume(&error, volume, partition, mode);
1090 VDetachVolume(&code, tv);
1094 VTRANS_OBJ_LOCK(tt);
1097 tt->iflags = iflags;
1099 TSetRxCall_r(tt, NULL, "TransCreate");
1100 VTRANS_OBJ_UNLOCK(tt);
1102 return VOLSERTRELE_ERROR;
1107 /* using aindex as a 0-based index, return the aindex'th volume on this server
1108 * Both the volume number and partition number (one-based) are returned.
1111 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1116 code = VolGetNthVolume(acid, aindex, avolume, apart);
1117 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1122 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1125 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1129 /* return the volume flags (VT* constants in volser.h) associated with this
1133 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1137 code = VolGetFlags(acid, atid, aflags);
1138 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1143 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1145 struct volser_trans *tt;
1147 tt = FindTrans(atid);
1150 if (tt->vflags & VTDeleted) {
1151 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1156 TSetRxCall(tt, acid, "GetFlags");
1157 *aflags = tt->vflags;
1160 return VOLSERTRELE_ERROR;
1165 /* Change the volume flags (VT* constants in volser.h) associated with this
1166 * transaction. Effects take place immediately on volume, although volume
1167 * remains attached as usual by the transaction.
1170 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1174 code = VolSetFlags(acid, atid, aflags);
1175 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1181 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1183 struct volser_trans *tt;
1186 char caller[MAXKTCNAMELEN];
1188 if (!afsconf_SuperUser(tdir, acid, caller))
1189 return VOLSERBAD_ACCESS; /*not a super user */
1190 /* find the trans */
1191 tt = FindTrans(atid);
1194 if (tt->vflags & VTDeleted) {
1195 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1200 TSetRxCall(tt, acid, "SetFlags");
1201 vp = tt->volume; /* pull volume out of transaction */
1203 /* check if we're allowed to make any updates */
1204 if (tt->iflags & ITReadOnly) {
1209 /* handle delete-on-salvage flag */
1210 if (aflags & VTDeleteOnSalvage) {
1211 V_destroyMe(tt->volume) = DESTROY_ME;
1213 V_destroyMe(tt->volume) = 0;
1216 if (aflags & VTOutOfService) {
1217 V_inService(vp) = 0;
1219 V_inService(vp) = 1;
1221 VUpdateVolume(&error, vp);
1222 VTRANS_OBJ_LOCK(tt);
1223 tt->vflags = aflags;
1225 VTRANS_OBJ_UNLOCK(tt);
1226 if (TRELE(tt) && !error)
1227 return VOLSERTRELE_ERROR;
1232 /* dumpS the volume associated with a particular transaction from a particular
1233 * date. Send the dump to a different transaction (destTrans) on the server
1234 * specified by the destServer structure.
1237 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1238 struct destServer *destination, afs_int32 destTrans,
1239 struct restoreCookie *cookie)
1244 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1245 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1246 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1251 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1252 struct destServer *destination, afs_int32 destTrans,
1253 struct restoreCookie *cookie)
1255 struct volser_trans *tt;
1257 struct rx_connection *tcon;
1258 struct rx_call *tcall;
1260 struct rx_securityClass *securityObject;
1261 afs_int32 securityIndex;
1262 char caller[MAXKTCNAMELEN];
1264 if (!afsconf_SuperUser(tdir, acid, caller))
1265 return VOLSERBAD_ACCESS; /*not a super user */
1266 /* initialize things */
1267 tcon = (struct rx_connection *)0;
1268 tt = (struct volser_trans *)0;
1270 /* find the local transaction */
1271 tt = FindTrans(fromTrans);
1274 if (tt->vflags & VTDeleted) {
1275 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1280 TSetRxCall(tt, NULL, "Forward");
1282 /* get auth info for the this connection (uses afs from ticket file) */
1283 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1289 /* make an rpc connection to the other server */
1291 rx_NewConnection(htonl(destination->destHost),
1292 htons(destination->destPort), VOLSERVICE_ID,
1293 securityObject, securityIndex);
1299 tcall = rx_NewCall(tcon);
1300 TSetRxCall(tt, tcall, "Forward");
1301 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1302 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1307 /* these next calls implictly call rx_Write when writing out data */
1308 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1311 EndAFSVolRestore(tcall); /* probably doesn't do much */
1313 code = rx_EndCall(tcall, 0);
1314 rx_DestroyConnection(tcon); /* done with the connection */
1319 return VOLSERTRELE_ERROR;
1325 (void)rx_EndCall(tcall, 0);
1326 rx_DestroyConnection(tcon);
1335 /* Start a dump and send it to multiple places simultaneously.
1336 * If this returns an error (eg, return ENOENT), it means that
1337 * none of the releases worked. If this returns 0, that means
1338 * that one or more of the releases worked, and the caller has
1339 * to examine the results array to see which one(s).
1340 * This will only do EITHER incremental or full, not both, so it's
1341 * the caller's responsibility to be sure that all the destinations
1342 * need just an incremental (and from the same time), if that's
1346 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1347 fromDate, manyDests *destinations, afs_int32 spare,
1348 struct restoreCookie *cookie, manyResults *results)
1350 afs_int32 securityIndex;
1351 struct rx_securityClass *securityObject;
1352 char caller[MAXKTCNAMELEN];
1353 struct volser_trans *tt;
1354 afs_int32 ec, code, *codes;
1355 struct rx_connection **tcons;
1356 struct rx_call **tcalls;
1358 int i, is_incremental;
1361 memset(results, 0, sizeof(manyResults));
1362 i = results->manyResults_len = destinations->manyDests_len;
1363 results->manyResults_val = codes = malloc(i * sizeof(afs_int32));
1365 if (!results || !results->manyResults_val)
1368 if (!afsconf_SuperUser(tdir, acid, caller))
1369 return VOLSERBAD_ACCESS; /*not a super user */
1370 tt = FindTrans(fromTrans);
1373 if (tt->vflags & VTDeleted) {
1374 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1379 TSetRxCall(tt, NULL, "ForwardMulti");
1381 /* (fromDate == 0) ==> full dump */
1382 is_incremental = (fromDate ? 1 : 0);
1384 tcons = malloc(i * sizeof(struct rx_connection *));
1388 tcalls = malloc(i * sizeof(struct rx_call *));
1394 /* get auth info for this connection (uses afs from ticket file) */
1395 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1397 goto fail; /* in order to audit each failure */
1400 /* make connections to all the other servers */
1401 for (i = 0; i < destinations->manyDests_len; i++) {
1402 struct replica *dest = &(destinations->manyDests_val[i]);
1404 rx_NewConnection(htonl(dest->server.destHost),
1405 htons(dest->server.destPort), VOLSERVICE_ID,
1406 securityObject, securityIndex);
1408 codes[i] = ENOTCONN;
1410 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1411 codes[i] = ENOTCONN;
1414 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1417 (void)rx_EndCall(tcalls[i], 0);
1419 rx_DestroyConnection(tcons[i]);
1426 /* these next calls implictly call rx_Write when writing out data */
1427 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1431 for (i--; i >= 0; i--) {
1432 struct replica *dest = &(destinations->manyDests_val[i]);
1434 if (!code && tcalls[i] && !codes[i]) {
1435 EndAFSVolRestore(tcalls[i]);
1438 ec = rx_EndCall(tcalls[i], 0);
1443 rx_DestroyConnection(tcons[i]); /* done with the connection */
1446 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1447 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1448 dest->trans, AUD_END);
1455 if (TRELE(tt) && !code) /* return the first code if it's set */
1456 return VOLSERTRELE_ERROR;
1463 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1467 code = VolDump(acid, fromTrans, fromDate, 0);
1468 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1473 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1478 code = VolDump(acid, fromTrans, fromDate, flags);
1479 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1484 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1488 struct volser_trans *tt;
1489 char caller[MAXKTCNAMELEN];
1491 if (!afsconf_SuperUser(tdir, acid, caller))
1492 return VOLSERBAD_ACCESS; /*not a super user */
1493 tt = FindTrans(fromTrans);
1496 if (tt->vflags & VTDeleted) {
1497 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1501 TSetRxCall(tt, acid, "Dump");
1502 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1503 ? 0 : 1); /* squirt out the volume's data, too */
1512 return VOLSERTRELE_ERROR;
1518 * Ha! No more helper process!
1521 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1522 struct restoreCookie *cookie)
1526 code = VolRestore(acid, atrans, aflags, cookie);
1527 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1532 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1533 struct restoreCookie *cookie)
1535 struct volser_trans *tt;
1536 afs_int32 code, tcode;
1537 char caller[MAXKTCNAMELEN];
1539 if (!afsconf_SuperUser(tdir, acid, caller))
1540 return VOLSERBAD_ACCESS; /*not a super user */
1541 tt = FindTrans(atrans);
1544 if (tt->vflags & VTDeleted) {
1545 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1549 TSetRxCall(tt, acid, "Restore");
1551 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1553 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1554 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1558 return (code ? code : tcode);
1561 /* end a transaction, returning the transaction's final error code in rcode */
1563 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1567 code = VolEndTrans(acid, destTrans, rcode);
1568 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1573 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1575 struct volser_trans *tt;
1576 char caller[MAXKTCNAMELEN];
1578 if (!afsconf_SuperUser(tdir, acid, caller))
1579 return VOLSERBAD_ACCESS; /*not a super user */
1580 tt = FindTrans(destTrans);
1584 *rcode = tt->returnCode;
1585 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1591 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1595 code = VolSetForwarding(acid, atid, anewsite);
1596 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1597 htonl(anewsite), AUD_END);
1602 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1604 struct volser_trans *tt;
1605 char caller[MAXKTCNAMELEN];
1608 if (!afsconf_SuperUser(tdir, acid, caller))
1609 return VOLSERBAD_ACCESS; /*not a super user */
1610 tt = FindTrans(atid);
1613 if (tt->vflags & VTDeleted) {
1614 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1619 TSetRxCall(tt, acid, "SetForwarding");
1620 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1623 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1626 return VOLSERTRELE_ERROR;
1632 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1633 struct volser_status *astatus)
1637 code = VolGetStatus(acid, atrans, astatus);
1638 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1643 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1644 struct volser_status *astatus)
1647 struct VolumeDiskData *td;
1648 struct volser_trans *tt;
1651 tt = FindTrans(atrans);
1654 if (tt->vflags & VTDeleted) {
1655 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1660 TSetRxCall(tt, acid, "GetStatus");
1668 td = &tv->header->diskstuff;
1669 astatus->volID = td->id;
1670 astatus->nextUnique = td->uniquifier;
1671 astatus->type = td->type;
1672 astatus->parentID = td->parentId;
1673 astatus->cloneID = td->cloneId;
1674 astatus->backupID = td->backupId;
1675 astatus->restoredFromID = td->restoredFromId;
1676 astatus->maxQuota = td->maxquota;
1677 astatus->minQuota = td->minquota;
1678 astatus->owner = td->owner;
1679 astatus->creationDate = td->creationDate;
1680 astatus->accessDate = td->accessDate;
1681 astatus->updateDate = td->updateDate;
1682 astatus->expirationDate = td->expirationDate;
1683 astatus->backupDate = td->backupDate;
1684 astatus->copyDate = td->copyDate;
1687 return VOLSERTRELE_ERROR;
1693 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1694 struct volintInfo *astatus)
1698 code = VolSetInfo(acid, atrans, astatus);
1699 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1704 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1705 struct volintInfo *astatus)
1708 struct VolumeDiskData *td;
1709 struct volser_trans *tt;
1710 char caller[MAXKTCNAMELEN];
1713 if (!afsconf_SuperUser(tdir, acid, caller))
1714 return VOLSERBAD_ACCESS; /*not a super user */
1715 tt = FindTrans(atrans);
1718 if (tt->vflags & VTDeleted) {
1719 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1723 TSetRxCall(tt, acid, "SetStatus");
1731 td = &tv->header->diskstuff;
1733 * Add more fields as necessary
1735 if (astatus->maxquota != -1)
1736 td->maxquota = astatus->maxquota;
1737 if (astatus->dayUse != -1)
1738 td->dayUse = astatus->dayUse;
1739 if (astatus->creationDate != -1)
1740 td->creationDate = astatus->creationDate;
1741 if (astatus->updateDate != -1)
1742 td->updateDate = astatus->updateDate;
1743 if (astatus->spare2 != -1)
1744 td->volUpdateCounter = (unsigned int)astatus->spare2;
1745 VUpdateVolume(&error, tv);
1748 return VOLSERTRELE_ERROR;
1754 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1758 code = VolGetName(acid, atrans, aname);
1759 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1764 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1767 struct VolumeDiskData *td;
1768 struct volser_trans *tt;
1771 /* We need to at least fill it in */
1775 tt = FindTrans(atrans);
1778 if (tt->vflags & VTDeleted) {
1779 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1783 TSetRxCall(tt, acid, "GetName");
1791 td = &tv->header->diskstuff;
1792 len = strlen(td->name) + 1; /* don't forget the null */
1798 *aname = realloc(*aname, len);
1799 strcpy(*aname, td->name);
1802 return VOLSERTRELE_ERROR;
1807 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1810 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1811 afs_uint32 parentId, afs_uint32 cloneId)
1817 /*return a list of all partitions on the server. The non mounted
1818 *partitions are returned as -1 in the corresponding slot in partIds*/
1820 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1824 code = VolListPartitions(acid, partIds);
1825 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1830 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1835 strcpy(namehead, "/vicep"); /*7 including null terminator */
1837 /* Just return attached partitions. */
1839 for (i = 0; i < 26; i++) {
1840 namehead[6] = i + 'a';
1841 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1847 /*return a list of all partitions on the server. The non mounted
1848 *partitions are returned as -1 in the corresponding slot in partIds*/
1850 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1854 code = XVolListPartitions(acid, pEntries);
1855 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1860 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1863 struct partList partList;
1864 struct DiskPartition64 *dp;
1867 strcpy(namehead, "/vicep"); /*7 including null terminator */
1869 /* Only report attached partitions */
1870 for (i = 0; i < VOLMAXPARTS; i++) {
1871 #ifdef AFS_DEMAND_ATTACH_FS
1872 dp = VGetPartitionById(i, 0);
1875 namehead[6] = i + 'a';
1881 namehead[6] = 'a' + (k / 26);
1882 namehead[7] = 'a' + (k % 26);
1885 dp = VGetPartition(namehead, 0);
1888 partList.partId[j++] = i;
1891 pEntries->partEntries_val = malloc(j * sizeof(int));
1892 if (!pEntries->partEntries_val)
1894 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1896 pEntries->partEntries_len = j;
1898 pEntries->partEntries_val = NULL;
1899 pEntries->partEntries_len = 0;
1905 /*return the name of the next volume header in the directory associated with dirp and dp.
1906 *the volume id is returned in volid, and volume header name is returned in volname*/
1908 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1912 dp = readdir(dirp); /*read next entry in the directory */
1914 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1915 *volid = VolumeNumber(dp->d_name);
1916 strcpy(volname, dp->d_name);
1917 return 0; /*return the name of the file representing a volume */
1919 strcpy(volname, "");
1920 return 0; /*volname doesnot represent a volume */
1923 strcpy(volname, "EOD");
1924 return 0; /*end of directory */
1930 * volint vol info structure type.
1933 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1934 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1935 } volint_info_type_t;
1938 * handle to various on-wire vol info types.
1941 volint_info_type_t volinfo_type;
1947 } volint_info_handle_t;
1950 * store value to a field at the appropriate location in on-wire structure.
1952 #define VOLINT_INFO_STORE(handle, name, val) \
1954 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1955 (handle)->volinfo_ptr.base->name = (val); \
1957 (handle)->volinfo_ptr.ext->name = (val); \
1962 * get pointer to appropriate offset of field in on-wire structure.
1964 #define VOLINT_INFO_PTR(handle, name) \
1965 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1966 &((handle)->volinfo_ptr.base->name) : \
1967 &((handle)->volinfo_ptr.ext->name))
1970 * fill in appropriate type of on-wire volume metadata structure.
1972 * @param vp pointer to volume object
1973 * @param handle pointer to wire format handle object
1975 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1976 * @pre handle object must have a valid pointer and enumeration value
1978 * @note passing a NULL value for vp means that the fileserver doesn't
1979 * know about this particular volume, thus implying it is offline.
1981 * @return operation status
1986 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1988 unsigned int numStatBytes, now;
1989 struct VolumeDiskData *hdr = &vp->header->diskstuff;
1991 /*read in the relevant info */
1992 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1993 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1994 VOLINT_INFO_STORE(handle, volid, hdr->id);
1995 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1996 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
1997 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
1998 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
1999 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2000 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2001 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2002 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2003 now = FT_ApproxTime();
2004 if ((now - hdr->dayUseDate) > OneDay) {
2005 VOLINT_INFO_STORE(handle, dayUse, 0);
2007 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2009 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2010 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2011 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2012 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2014 #ifdef AFS_DEMAND_ATTACH_FS
2016 * for DAFS, we "lie" about volume state --
2017 * instead of returning the raw state from the disk header,
2018 * we compute state based upon the fileserver's internal
2019 * in-core state enumeration value reported to us via fssync,
2020 * along with the blessed and inService flags from the header.
2021 * -- tkeiser 11/27/2007
2024 /* Conditions that offline status is based on:
2025 volume is unattached state
2026 volume state is in (one of several error states)
2027 volume not in service
2028 volume is not marked as blessed (not on hold)
2029 volume in salvage req. state
2030 volume needsSalvaged
2031 next op would set volume offline
2032 next op would not leave volume online (based on several conditions)
2035 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2036 VIsErrorState(V_attachState(vp)) ||
2039 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2040 hdr->needsSalvaged ||
2041 (vp->pending_vol_op &&
2042 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2043 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2046 VOLINT_INFO_STORE(handle, inUse, 0);
2048 VOLINT_INFO_STORE(handle, inUse, 1);
2051 /* offline status based on program type, where != fileServer enum (1) is offline */
2052 if (hdr->inUse == fileServer) {
2053 VOLINT_INFO_STORE(handle, inUse, 1);
2055 VOLINT_INFO_STORE(handle, inUse, 0);
2060 switch(handle->volinfo_type) {
2061 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2062 case VOLINT_INFO_TYPE_BASE:
2064 #ifdef AFS_DEMAND_ATTACH_FS
2065 /* see comment above where we set inUse bit */
2066 if (hdr->needsSalvaged ||
2067 (vp && VIsErrorState(V_attachState(vp)))) {
2068 handle->volinfo_ptr.base->needsSalvaged = 1;
2070 handle->volinfo_ptr.base->needsSalvaged = 0;
2073 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2075 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2076 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2077 handle->volinfo_ptr.base->spare1 =
2078 (long)hdr->weekUse[0] +
2079 (long)hdr->weekUse[1] +
2080 (long)hdr->weekUse[2] +
2081 (long)hdr->weekUse[3] +
2082 (long)hdr->weekUse[4] +
2083 (long)hdr->weekUse[5] +
2084 (long)hdr->weekUse[6];
2085 handle->volinfo_ptr.base->flags = 0;
2086 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2087 handle->volinfo_ptr.base->spare3 = 0;
2091 case VOLINT_INFO_TYPE_EXT:
2093 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2094 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2097 * Copy out the stat fields in a single operation.
2099 if ((now - hdr->dayUseDate) > OneDay) {
2100 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2103 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2104 (char *)&(hdr->stat_reads[0]),
2113 #ifdef AFS_DEMAND_ATTACH_FS
2116 * get struct Volume out of the fileserver.
2118 * @param[in] volumeId volumeId for which we want state information
2119 * @param[in] pname partition name string
2120 * @param[inout] vp pointer to pointer to Volume object which
2121 * will be populated (see note)
2123 * @return operation status
2125 * @retval non-zero failure
2127 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2132 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2137 res.hdr.response_len = sizeof(res.hdr);
2138 res.payload.buf = *vp;
2139 res.payload.len = sizeof(Volume);
2141 code = FSYNC_VolOp(volumeId,
2147 if (code != SYNC_OK) {
2148 switch (res.hdr.reason) {
2149 case FSYNC_WRONG_PART:
2150 case FSYNC_UNKNOWN_VOLID:
2163 * mode of volume list operation.
2166 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2167 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2168 } vol_info_list_mode_t;
2171 * abstract interface to populate wire-format volume metadata structures.
2173 * @param[in] partId partition id
2174 * @param[in] volumeId volume id
2175 * @param[in] pname partition name
2176 * @param[in] volname volume file name
2177 * @param[in] handle handle to on-wire volume metadata object
2178 * @param[in] mode listing mode
2180 * @return operation status
2182 * @retval -2 DESTROY_ME flag is set
2183 * @retval -1 general failure; some data filled in
2184 * @retval -3 couldn't create vtrans; some data filled in
2187 GetVolInfo(afs_uint32 partId,
2188 afs_uint32 volumeId,
2191 volint_info_handle_t * handle,
2192 vol_info_list_mode_t mode)
2196 struct volser_trans *ttc = NULL;
2197 struct Volume *fill_tv, *tv = NULL;
2198 #ifdef AFS_DEMAND_ATTACH_FS
2199 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2200 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2201 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2202 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2204 /* Set up response handle for pending_vol_op */
2205 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2206 fs_res.payload.buf = fs_res_buf;
2207 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2210 ttc = NewTrans(volumeId, partId);
2213 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2214 VOLINT_INFO_STORE(handle, volid, volumeId);
2218 /* Get volume from volserver */
2219 if (mode == VOL_INFO_LIST_MULTIPLE)
2220 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2222 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2224 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2225 volumeId, pname, volname, error);
2230 * please note that destroyMe and needsSalvaged checks used to be ordered
2231 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2232 * more correct to check destroyMe before needsSalvaged.
2233 * -- tkeiser 11/28/2007
2236 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2238 case VOL_INFO_LIST_MULTIPLE:
2242 case VOL_INFO_LIST_SINGLE:
2243 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2244 volumeId, pname, volname);
2251 if (tv->header->diskstuff.needsSalvaged) {
2252 /*this volume will be salvaged */
2253 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2254 volumeId, pname, volname);
2257 #ifdef AFS_DEMAND_ATTACH_FS
2258 /* If using DAFS, get volume from fsserver */
2259 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2264 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2265 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2266 /* If we if the pending vol op */
2267 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2268 fs_tv->pending_vol_op=&pending_vol_op_res;
2270 fs_tv->pending_vol_op=NULL;
2273 /* populate the header from the volserver copy */
2274 fs_tv->header=tv->header;
2276 /* When using DAFS, use the fs volume info, populated with required structures */
2279 /* When not using DAFS, just use the local volume info */
2283 /* ok, we have all the data we need; fill in the on-wire struct */
2284 code = FillVolInfo(fill_tv, handle);
2288 VOLINT_INFO_STORE(handle, status, 0);
2289 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2290 VOLINT_INFO_STORE(handle, volid, volumeId);
2293 VDetachVolume(&error, tv);
2296 VOLINT_INFO_STORE(handle, status, 0);
2297 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2298 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2299 volumeId, pname, volname);
2303 DeleteTrans(ttc, 1);
2310 /*return the header information about the <volid> */
2312 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2313 afs_uint32 volumeId, volEntries *volumeInfo)
2317 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2318 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2323 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2324 afs_uint32 volumeId, volEntries *volumeInfo)
2326 struct DiskPartition64 *partP;
2327 char pname[9], volname[20];
2332 volint_info_handle_t handle;
2334 volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2335 if (!volumeInfo->volEntries_val)
2338 volumeInfo->volEntries_len = 1;
2339 if (GetPartName(partid, pname))
2340 return VOLSERILLEGAL_PARTITION;
2341 if (!(partP = VGetPartition(pname, 0)))
2342 return VOLSERILLEGAL_PARTITION;
2343 dirp = opendir(VPartitionPath(partP));
2345 return VOLSERILLEGAL_PARTITION;
2347 strcpy(volname, "");
2349 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2351 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2352 GetNextVol(dirp, volname, &volid);
2353 continue; /*back to while loop */
2356 if (volid == volumeId) { /*copy other things too */
2361 GetNextVol(dirp, volname, &volid);
2365 #ifndef AFS_PTHREAD_ENV
2366 IOMGR_Poll(); /*make sure that the client does not time out */
2369 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2370 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2372 code = GetVolInfo(partid,
2377 VOL_INFO_LIST_SINGLE);
2382 return code ? ENODEV: 0;
2387 /*------------------------------------------------------------------------
2388 * EXPORTED SAFSVolXListOneVolume
2391 * Returns extended info on volume a_volID on partition a_partID.
2394 * a_rxCidP : Pointer to the Rx call we're performing.
2395 * a_partID : Partition for which we want the extended list.
2396 * a_volID : Volume ID we wish to know about.
2397 * a_volumeXInfoP : Ptr to the extended info blob.
2400 * 0 Successful operation
2401 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2404 * Nothing interesting.
2408 *------------------------------------------------------------------------*/
2411 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2412 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2416 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2417 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2422 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2423 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2424 { /*SAFSVolXListOneVolume */
2426 struct DiskPartition64 *partP; /*Ptr to partition */
2427 char pname[9], volname[20]; /*Partition, volume names */
2428 DIR *dirp; /*Partition directory ptr */
2429 afs_uint32 currVolID; /*Current volume ID */
2430 int found = 0; /*Did we find the volume we need? */
2432 volint_info_handle_t handle;
2435 * Set up our pointers for action, marking our structure to hold exactly
2436 * one entry. Also, assume we'll fail in our quest.
2438 a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2439 if (!a_volumeXInfoP->volXEntries_val)
2442 a_volumeXInfoP->volXEntries_len = 1;
2446 * If the partition name we've been given is bad, bogue out.
2448 if (GetPartName(a_partID, pname))
2449 return (VOLSERILLEGAL_PARTITION);
2452 * Open the directory representing the given AFS parttion. If we can't
2455 if (!(partP = VGetPartition(pname, 0)))
2456 return VOLSERILLEGAL_PARTITION;
2457 dirp = opendir(VPartitionPath(partP));
2459 return (VOLSERILLEGAL_PARTITION);
2461 strcpy(volname, "");
2464 * Sweep through the partition directory, looking for the desired entry.
2465 * First, of course, figure out how many stat bytes to copy out of each
2468 while (strcmp(volname, "EOD") && !found) {
2470 * If this is not a volume, move on to the next entry in the
2471 * partition's directory.
2473 if (!strcmp(volname, "")) {
2474 GetNextVol(dirp, volname, &currVolID);
2478 if (currVolID == a_volID) {
2480 * We found the volume entry we're interested. Pull out the
2481 * extended information, remembering to poll (so that the client
2482 * doesn't time out) and to set up a transaction on the volume.
2486 } /*Found desired volume */
2488 GetNextVol(dirp, volname, &currVolID);
2492 #ifndef AFS_PTHREAD_ENV
2496 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2497 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2499 code = GetVolInfo(a_partID,
2504 VOL_INFO_LIST_SINGLE);
2509 * Clean up before going to dinner: close the partition directory,
2510 * return the proper value.
2514 return code ? ENODEV: 0;
2517 } /*SAFSVolXListOneVolume */
2519 /*returns all the volumes on partition partid. If flags = 1 then all the
2520 * relevant info about the volumes is also returned */
2522 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2523 volEntries *volumeInfo)
2527 code = VolListVolumes(acid, partid, flags, volumeInfo);
2528 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2533 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2534 volEntries *volumeInfo)
2537 struct DiskPartition64 *partP;
2538 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2539 char pname[9], volname[20];
2543 volint_info_handle_t handle;
2545 volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2546 if (!volumeInfo->volEntries_val)
2549 pntr = volumeInfo->volEntries_val;
2550 volumeInfo->volEntries_len = 0;
2551 if (GetPartName(partid, pname))
2552 return VOLSERILLEGAL_PARTITION;
2553 if (!(partP = VGetPartition(pname, 0)))
2554 return VOLSERILLEGAL_PARTITION;
2555 dirp = opendir(VPartitionPath(partP));
2557 return VOLSERILLEGAL_PARTITION;
2558 strcpy(volname, "");
2560 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2562 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2563 GetNextVol(dirp, volname, &volid);
2564 continue; /*back to while loop */
2567 if (flags) { /*copy other things too */
2568 #ifndef AFS_PTHREAD_ENV
2569 IOMGR_Poll(); /*make sure that the client does not time out */
2572 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2573 handle.volinfo_ptr.base = pntr;
2576 code = GetVolInfo(partid,
2581 VOL_INFO_LIST_MULTIPLE);
2582 if (code == -2) { /* DESTROY_ME flag set */
2586 pntr->volid = volid;
2587 /*just volids are needed */
2591 volumeInfo->volEntries_len += 1;
2592 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2593 /*running out of space, allocate more space */
2594 allocSize = (allocSize * 3) / 2;
2595 pntr = realloc(volumeInfo->volEntries_val,
2596 allocSize * sizeof(volintInfo));
2599 return VOLSERNO_MEMORY;
2601 volumeInfo->volEntries_val = pntr; /* point to new block */
2602 /* set pntr to the right position */
2603 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2608 GetNextVol(dirp, volname, &volid);
2616 /*------------------------------------------------------------------------
2617 * EXPORTED SAFSVolXListVolumes
2620 * Returns all the volumes on partition a_partID. If a_flags
2621 * is set to 1, then all the relevant extended volume information
2625 * a_rxCidP : Pointer to the Rx call we're performing.
2626 * a_partID : Partition for which we want the extended list.
2627 * a_flags : Various flags.
2628 * a_volumeXInfoP : Ptr to the extended info blob.
2631 * 0 Successful operation
2632 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2633 * VOLSERNO_MEMORY if we ran out of memory allocating
2637 * Nothing interesting.
2641 *------------------------------------------------------------------------*/
2644 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2645 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2649 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2650 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2655 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2656 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2657 { /*SAFSVolXListVolumes */
2659 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2660 struct DiskPartition64 *partP; /*Ptr to partition */
2661 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2662 char pname[9], volname[20]; /*Partition, volume names */
2663 DIR *dirp; /*Partition directory ptr */
2664 afs_uint32 volid; /*Current volume ID */
2666 volint_info_handle_t handle;
2669 * Allocate a large array of extended volume info structures, then
2670 * set it up for action.
2672 a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2673 if (!a_volumeXInfoP->volXEntries_val)
2676 xInfoP = a_volumeXInfoP->volXEntries_val;
2677 a_volumeXInfoP->volXEntries_len = 0;
2680 * If the partition name we've been given is bad, bogue out.
2682 if (GetPartName(a_partID, pname))
2683 return (VOLSERILLEGAL_PARTITION);
2686 * Open the directory representing the given AFS parttion. If we can't
2689 if (!(partP = VGetPartition(pname, 0)))
2690 return VOLSERILLEGAL_PARTITION;
2691 dirp = opendir(VPartitionPath(partP));
2693 return (VOLSERILLEGAL_PARTITION);
2694 strcpy(volname, "");
2697 * Sweep through the partition directory, acting on each entry. First,
2698 * of course, figure out how many stat bytes to copy out of each volume.
2700 while (strcmp(volname, "EOD")) {
2703 * If this is not a volume, move on to the next entry in the
2704 * partition's directory.
2706 if (!strcmp(volname, "")) {
2707 GetNextVol(dirp, volname, &volid);
2713 * Full info about the volume desired. Poll to make sure the
2714 * client doesn't time out, then start up a new transaction.
2716 #ifndef AFS_PTHREAD_ENV
2720 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2721 handle.volinfo_ptr.ext = xInfoP;
2723 code = GetVolInfo(a_partID,
2728 VOL_INFO_LIST_MULTIPLE);
2729 if (code == -2) { /* DESTROY_ME flag set */
2734 * Just volume IDs are needed.
2736 xInfoP->volid = volid;
2740 * Bump the pointer in the data area we're building, along with
2741 * the count of the number of entries it contains.
2744 (a_volumeXInfoP->volXEntries_len)++;
2745 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2747 * We're running out of space in the area we've built. Grow it.
2749 allocSize = (allocSize * 3) / 2;
2750 xInfoP = (volintXInfo *)
2751 realloc((char *)a_volumeXInfoP->volXEntries_val,
2752 (allocSize * sizeof(volintXInfo)));
2753 if (xInfoP == NULL) {
2755 * Bummer, no memory. Bag it, tell our caller what went wrong.
2758 return (VOLSERNO_MEMORY);
2762 * Memory reallocation worked. Correct our pointers so they
2763 * now point to the new block and the current open position within
2766 a_volumeXInfoP->volXEntries_val = xInfoP;
2768 a_volumeXInfoP->volXEntries_val +
2769 a_volumeXInfoP->volXEntries_len;
2773 GetNextVol(dirp, volname, &volid);
2774 } /*Sweep through the partition directory */
2777 * We've examined all entries in the partition directory. Close it,
2778 * delete our transaction (if any), and go home happy.
2783 } /*SAFSVolXListVolumes */
2785 /*this call is used to monitor the status of volser for debugging purposes.
2786 *information about all the active transactions is returned in transInfo*/
2788 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2792 code = VolMonitor(acid, transInfo);
2793 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2798 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2800 transDebugInfo *pntr;
2801 afs_int32 allocSize = 50;
2802 struct volser_trans *tt, *nt, *allTrans;
2804 transInfo->transDebugEntries_val =
2805 malloc(allocSize * sizeof(transDebugInfo));
2806 if (!transInfo->transDebugEntries_val)
2808 pntr = transInfo->transDebugEntries_val;
2809 transInfo->transDebugEntries_len = 0;
2812 allTrans = TransList();
2813 if (allTrans == (struct volser_trans *)0)
2814 goto done; /*no active transactions */
2815 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2817 VTRANS_OBJ_LOCK(tt);
2818 pntr->tid = tt->tid;
2819 pntr->time = tt->time;
2820 pntr->creationTime = tt->creationTime;
2821 pntr->returnCode = tt->returnCode;
2822 pntr->volid = tt->volid;
2823 pntr->partition = tt->partition;
2824 pntr->iflags = tt->iflags;
2825 pntr->vflags = tt->vflags;
2826 pntr->tflags = tt->tflags;
2827 strcpy(pntr->lastProcName, tt->lastProcName);
2828 pntr->callValid = 0;
2829 if (tt->rxCallPtr) { /*record call related info */
2830 pntr->callValid = 1;
2832 pntr->readNext = tt->rxCallPtr->rnext;
2833 pntr->transmitNext = tt->rxCallPtr->tnext;
2834 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2835 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2838 VTRANS_OBJ_UNLOCK(tt);
2840 transInfo->transDebugEntries_len += 1;
2841 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2842 allocSize = (allocSize * 3) / 2;
2843 pntr = realloc(transInfo->transDebugEntries_val,
2844 allocSize * sizeof(transDebugInfo));
2845 transInfo->transDebugEntries_val = pntr;
2847 transInfo->transDebugEntries_val +
2848 transInfo->transDebugEntries_len;
2849 /*set pntr to right position */
2860 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2861 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2862 afs_uint32 backupId)
2866 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2867 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2868 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2874 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2875 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2876 afs_uint32 backupId)
2880 struct volser_trans *tt;
2881 char caller[MAXKTCNAMELEN];
2883 if (strlen(name) > 31)
2884 return VOLSERBADNAME;
2885 if (!afsconf_SuperUser(tdir, acid, caller))
2886 return VOLSERBAD_ACCESS; /*not a super user */
2887 /* find the trans */
2888 tt = FindTrans(atid);
2891 if (tt->vflags & VTDeleted) {
2892 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2896 TSetRxCall(tt, acid, "SetIdsTypes");
2900 V_backupId(tv) = backupId;
2901 V_cloneId(tv) = cloneId;
2902 V_parentId(tv) = pId;
2903 strcpy((&V_disk(tv))->name, name);
2904 VUpdateVolume(&error, tv);
2906 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2911 if (TRELE(tt) && !error)
2912 return VOLSERTRELE_ERROR;
2917 if (TRELE(tt) && !error)
2918 return VOLSERTRELE_ERROR;
2923 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2927 code = VolSetDate(acid, atid, cdate);
2928 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2934 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2938 struct volser_trans *tt;
2939 char caller[MAXKTCNAMELEN];
2941 if (!afsconf_SuperUser(tdir, acid, caller))
2942 return VOLSERBAD_ACCESS; /*not a super user */
2943 /* find the trans */
2944 tt = FindTrans(atid);
2947 if (tt->vflags & VTDeleted) {
2948 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2952 TSetRxCall(tt, acid, "SetDate");
2955 V_creationDate(tv) = cdate;
2956 VUpdateVolume(&error, tv);
2958 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2963 if (TRELE(tt) && !error)
2964 return VOLSERTRELE_ERROR;
2969 if (TRELE(tt) && !error)
2970 return VOLSERTRELE_ERROR;
2975 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2976 afs_uint32 volumeId)
2981 char caller[MAXKTCNAMELEN];
2983 struct volser_trans *ttc;
2984 char pname[16], volname[20];
2985 struct DiskPartition64 *partP;
2986 afs_int32 ret = ENODEV;
2989 if (!afsconf_SuperUser(tdir, acid, caller))
2990 return VOLSERBAD_ACCESS; /*not a super user */
2991 if (GetPartName(partId, pname))
2992 return VOLSERILLEGAL_PARTITION;
2993 if (!(partP = VGetPartition(pname, 0)))
2994 return VOLSERILLEGAL_PARTITION;
2995 dirp = opendir(VPartitionPath(partP));
2997 return VOLSERILLEGAL_PARTITION;
2998 strcpy(volname, "");
2999 ttc = (struct volser_trans *)0;
3001 while (strcmp(volname, "EOD")) {
3002 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3003 GetNextVol(dirp, volname, &volid);
3004 continue; /*back to while loop */
3007 if (volid == volumeId) { /*copy other things too */
3008 #ifndef AFS_PTHREAD_ENV
3009 IOMGR_Poll(); /*make sure that the client doesnot time out */
3011 ttc = NewTrans(volumeId, partId);
3013 return VOLSERVOLBUSY;
3015 #ifdef AFS_NAMEI_ENV
3016 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3018 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3022 GetNextVol(dirp, volname, &volid);
3026 DeleteTrans(ttc, 1);
3027 ttc = (struct volser_trans *)0;
3036 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3037 struct volintSize *size)
3040 struct volser_trans *tt;
3041 char caller[MAXKTCNAMELEN];
3043 if (!afsconf_SuperUser(tdir, acid, caller))
3044 return VOLSERBAD_ACCESS; /*not a super user */
3045 tt = FindTrans(fromTrans);
3048 if (tt->vflags & VTDeleted) {
3052 TSetRxCall(tt, acid, "GetSize");
3053 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3056 return VOLSERTRELE_ERROR;
3058 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3063 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3064 afs_uint32 where, afs_int32 verbose)
3066 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3068 Volume *vol=0, *newvol=0;
3069 struct volser_trans *tt = 0, *tt2 = 0;
3070 char caller[MAXKTCNAMELEN];
3073 if (!afsconf_SuperUser(tdir, acall, caller))
3076 vol = VAttachVolume(&code, vid, V_VOLUPD);
3082 newvol = VAttachVolume(&code, new, V_VOLUPD);
3084 VDetachVolume(&code2, vol);
3089 if (V_device(vol) != V_device(newvol)
3090 || V_uniquifier(newvol) != 2) {
3091 if (V_device(vol) != V_device(newvol)) {
3092 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3094 rx_Write(acall, line, strlen(line));
3096 if (V_uniquifier(newvol) != 2) {
3097 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3098 rx_Write(acall, line, strlen(line));
3101 rx_Write(acall, line, 1);
3102 VDetachVolume(&code2, vol);
3103 VDetachVolume(&code2, newvol);
3106 tt = NewTrans(vid, V_device(vol));
3108 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3109 rx_Write(acall, line, strlen(line));
3111 rx_Write(acall, line, 1);
3112 VDetachVolume(&code2, vol);
3113 VDetachVolume(&code2, newvol);
3114 return VOLSERVOLBUSY;
3116 VTRANS_OBJ_LOCK(tt);
3117 tt->iflags = ITBusy;
3119 TSetRxCall_r(tt, NULL, "SplitVolume");
3120 VTRANS_OBJ_UNLOCK(tt);
3122 tt2 = NewTrans(new, V_device(newvol));
3124 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3125 rx_Write(acall, line, strlen(line));
3127 rx_Write(acall, line, 1);
3129 VDetachVolume(&code2, vol);
3130 VDetachVolume(&code2, newvol);
3131 return VOLSERVOLBUSY;
3133 VTRANS_OBJ_LOCK(tt2);
3134 tt2->iflags = ITBusy;
3136 TSetRxCall_r(tt2, NULL, "SplitVolume");
3137 VTRANS_OBJ_UNLOCK(tt2);
3139 code = split_volume(acall, vol, newvol, where, verbose);
3141 VDetachVolume(&code2, vol);
3143 VDetachVolume(&code2, newvol);
3144 DeleteTrans(tt2, 1);
3151 /* GetPartName - map partid (a decimal number) into pname (a string)
3152 * Since for NT we actually want to return the drive name, we map through the
3156 GetPartName(afs_int32 partid, char *pname)
3161 strcpy(pname, "/vicep");
3162 pname[6] = 'a' + partid;
3165 } else if (partid < VOLMAXPARTS) {
3166 strcpy(pname, "/vicep");
3168 pname[6] = 'a' + (partid / 26);
3169 pname[7] = 'a' + (partid % 26);