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>
17 #include <sys/types.h>
26 #include <netinet/in.h>
35 #include <afs/afsint.h>
37 #ifdef AFS_PTHREAD_ENV
39 #else /* AFS_PTHREAD_ENV */
40 #include <afs/assert.h>
41 #endif /* AFS_PTHREAD_ENV */
42 #include <afs/prs_fs.h>
46 #include <afs/cellconfig.h>
49 #include <afs/ihandle.h>
51 #include <afs/ntops.h>
53 #include <afs/vnode.h>
54 #include <afs/volume.h>
55 #include <afs/volume_inline.h>
56 #include <afs/partition.h>
58 #include <afs/daemon_com.h>
59 #include <afs/fssync.h>
61 #include "afs/audit.h"
63 #include <afs/afsutil.h>
64 #include <afs/vol_prototypes.h>
65 #include <afs/errors.h>
68 #include "voltrans_inline.h"
71 #include "volser_internal.h"
73 #include "dumpstuff.h"
76 extern struct afsconf_dir *tdir;
78 extern void LogError(afs_int32 errcode);
80 /* Forward declarations */
81 static int GetPartName(afs_int32 partid, char *pname);
83 #define OneDay (24*60*60)
89 afs_int32 localTid = 1;
91 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
92 struct diskPartition64 *);
93 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
94 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
95 afs_int32, afs_uint32, afs_uint32 *,
97 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
98 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
99 afs_int32, char *, afs_uint32 *);
100 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
101 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
102 afs_int32, afs_int32 *);
103 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
105 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
106 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
107 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
108 struct destServer *destination, afs_int32,
109 struct restoreCookie *cookie);
110 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
111 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
112 struct restoreCookie *);
113 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
114 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
115 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
116 struct volser_status *);
117 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
118 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
119 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
120 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
121 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
123 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
125 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
127 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
129 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
130 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
131 afs_int32, afs_uint32, afs_uint32,
133 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
135 /* this call unlocks all of the partition locks we've set */
139 register struct DiskPartition64 *tp;
140 for (tp = DiskPartitionList; tp; tp = tp->next) {
141 if (tp->lock_fd != INVALID_FD) {
142 close(tp->lock_fd); /* releases flock held on this partition */
143 tp->lock_fd = INVALID_FD;
154 code = VPFullUnlock_r();
159 /* get partition id from a name */
161 PartitionID(char *aname)
164 register int code = 0;
169 return -1; /* unknown */
171 /* otherwise check for vicepa or /vicepa, or just plain "a" */
173 if (!strncmp(aname, "/vicep", 6)) {
174 strncpy(ascii, aname + 6, 2);
176 return -1; /* bad partition name */
177 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
178 * from 0. Do the appropriate conversion */
180 /* one char name, 0..25 */
181 if (ascii[0] < 'a' || ascii[0] > 'z')
182 return -1; /* wrongo */
183 return ascii[0] - 'a';
185 /* two char name, 26 .. <whatever> */
186 if (ascii[0] < 'a' || ascii[0] > 'z')
187 return -1; /* wrongo */
188 if (ascii[1] < 'a' || ascii[1] > 'z')
189 return -1; /* just as bad */
190 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
191 if (code > VOLMAXPARTS)
198 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
202 /* 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 */
203 (void)afs_snprintf(aname, asize, VFORMAT, (unsigned long)avol);
208 ConvertPartition(int apartno, char *aname, int asize)
214 strcpy(aname, "/vicep");
216 aname[6] = 'a' + apartno;
220 aname[6] = 'a' + (apartno / 26);
221 aname[7] = 'a' + (apartno % 26);
227 static struct Volume *
228 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
233 vp = VAttachVolumeByName(ec, partition, name, mode);
235 #ifdef AFS_DEMAND_ATTACH_FS
239 * The fileserver will take care of keeping track of how many
240 * demand-salvages have been performed, and will force the volume to
241 * ERROR if we've done too many. The limit on This loop is just a
242 * failsafe to prevent trying to salvage forever. We want to attempt
243 * attachment at least SALVAGE_COUNT_MAX times, since we want to
244 * avoid prematurely exiting this loop, if we can.
246 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
247 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
248 vp = VAttachVolumeByName(ec, partition, name, mode);
251 if (*ec == VSALVAGING) {
255 #endif /* AFS_DEMAND_ATTACH_FS */
260 static struct Volume *
261 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
266 vp = VAttachVolume(ec, avolid, amode);
268 #ifdef AFS_DEMAND_ATTACH_FS
271 /* see comment above in VAttachVolumeByName_retry */
272 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
273 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
274 vp = VAttachVolume(ec, avolid, amode);
277 if (*ec == VSALVAGING) {
281 #endif /* AFS_DEMAND_ATTACH_FS */
286 /* the only attach function that takes a partition is "...ByName", so we use it */
287 static struct Volume *
288 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
290 char pbuf[30], vbuf[20];
292 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
296 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
301 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
304 /* Adapted from the file server; create a root directory for this volume */
306 ViceCreateRoot(Volume *vp)
309 struct acl_accessList *ACL;
311 Inode inodeNumber, nearInode;
312 struct VnodeDiskObject *vnode;
313 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
319 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
322 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
324 V_pref(vp, nearInode);
326 IH_CREATE(V_linkHandle(vp), V_device(vp),
327 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
329 assert(VALID_INO(inodeNumber));
331 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
332 did.Volume = V_id(vp);
333 did.Vnode = (VnodeId) 1;
336 assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
337 DFlush(); /* flush all modified dir buffers out */
338 DZap((afs_int32 *)&dir); /* Remove all buffers for this dir */
339 length = Length(&dir); /* Remember size of this directory */
341 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
343 /* build a single entry ACL that gives all rights to system:administrators */
344 /* this section of code assumes that access list format is not going to
347 ACL = VVnodeDiskACL(vnode);
348 ACL->size = sizeof(struct acl_accessList);
349 ACL->version = ACL_ACLVERSION;
353 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
354 ACL->entries[0].rights =
355 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
356 | PRSFS_LOCK | PRSFS_ADMINISTER;
358 vnode->type = vDirectory;
360 vnode->modeBits = 0777;
361 vnode->linkCount = 2;
362 VNDISK_SET_LEN(vnode, length);
363 vnode->uniquifier = 1;
364 V_uniquifier(vp) = vnode->uniquifier + 1;
365 vnode->dataVersion = 1;
366 VNDISK_SET_INO(vnode, inodeNumber);
367 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
371 vnode->vnodeMagic = vcp->magic;
373 IH_INIT(h, vp->device, V_parentId(vp),
374 vp->vnodeIndex[vLarge].handle->ih_ino);
377 code = FDH_SEEK(fdP, vnodeIndexOffset(vcp, 1), SEEK_SET);
379 code = FDH_WRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE);
380 assert(code == SIZEOF_LARGEDISKVNODE);
381 FDH_REALLYCLOSE(fdP);
383 VNDISK_GET_LEN(length, vnode);
384 V_diskused(vp) = nBlocks(length);
391 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
395 struct diskPartition64 *dp = (struct diskPartition64 *)
396 malloc(sizeof(struct diskPartition64));
398 code = VolPartitionInfo(acid, pname, dp);
400 strncpy(partition->name, dp->name, 32);
401 strncpy(partition->devName, dp->devName, 32);
402 partition->lock_fd = dp->lock_fd;
403 partition->free=RoundInt64ToInt32(dp->free);
404 partition->minFree=RoundInt64ToInt32(dp->minFree);
407 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
412 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
417 code = VolPartitionInfo(acid, pname, partition);
418 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
423 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
426 register struct DiskPartition64 *dp;
429 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
432 dp = VGetPartition(pname, 0);
434 strncpy(partition->name, dp->name, 32);
435 strncpy(partition->devName, dp->devName, 32);
436 partition->lock_fd = (int)dp->lock_fd;
437 partition->free = dp->free;
438 partition->minFree = dp->totalUsable;
441 return VOLSERILLEGAL_PARTITION;
444 /* obliterate a volume completely, and slowly. */
446 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
450 code = VolNukeVolume(acid, apartID, avolID);
451 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
456 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
461 register afs_int32 code;
463 char caller[MAXKTCNAMELEN];
465 /* check for access */
466 if (!afsconf_SuperUser(tdir, acid, caller))
467 return VOLSERBAD_ACCESS;
469 Log("%s is executing VolNukeVolume %u\n", caller, avolID);
471 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
473 /* we first try to attach the volume in update mode, so that the file
474 * server doesn't try to use it (and abort) while (or after) we delete it.
475 * If we don't get the volume, that's fine, too. We just won't put it back.
477 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
478 code = nuke(partName, avolID);
480 VDetachVolume(&verror, tvp);
484 /* create a new volume, with name aname, on the specified partition (1..n)
485 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
486 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
487 * for the volume id (useful for things like volume restore).
488 * Return the new volume id in *avolid.
491 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
492 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
498 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
499 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
500 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
506 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
507 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
512 Error junk; /* discardable error code */
514 afs_int32 doCreateRoot = 1;
515 register struct volser_trans *tt;
517 char caller[MAXKTCNAMELEN];
519 if (strlen(aname) > 31)
520 return VOLSERBADNAME;
521 if (!afsconf_SuperUser(tdir, acid, caller))
522 return VOLSERBAD_ACCESS;
524 Log("%s is executing CreateVolume '%s'\n", caller, aname);
525 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
526 return error; /*a standard unix error */
527 if (atype != readwriteVolume && atype != readonlyVolume
528 && atype != backupVolume)
530 if ((volumeID = *avolid) == 0) {
532 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
536 if ((aparent == volumeID) && (atype == readwriteVolume)) {
541 tt = NewTrans(volumeID, apart);
543 Log("1 createvolume: failed to create trans\n");
544 return VOLSERVOLBUSY; /* volume already busy! */
546 vp = VCreateVolume(&error, ppath, volumeID, aparent);
548 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
553 V_uniquifier(vp) = 1;
554 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
555 V_inService(vp) = V_blessed(vp) = 1;
557 AssignVolumeName(&V_disk(vp), aname, 0);
560 V_destroyMe(vp) = DESTROY_ME;
562 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
563 VUpdateVolume(&error, vp);
565 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
568 VDetachVolume(&junk, vp); /* rather return the real error code */
574 TSetRxCall_r(tt, acid, "CreateVolume");
575 VTRANS_OBJ_UNLOCK(tt);
576 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
579 return VOLSERTRELE_ERROR;
583 /* delete the volume associated with this transaction */
585 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
589 code = VolDeleteVolume(acid, atrans);
590 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
595 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
597 register struct volser_trans *tt;
599 char caller[MAXKTCNAMELEN];
601 if (!afsconf_SuperUser(tdir, acid, caller))
602 return VOLSERBAD_ACCESS;
603 tt = FindTrans(atrans);
606 if (tt->vflags & VTDeleted) {
607 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
612 Log("%s is executing Delete Volume %u\n", caller, tt->volid);
613 TSetRxCall(tt, acid, "DeleteVolume");
614 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
615 V_destroyMe(tt->volume) = DESTROY_ME; /* so endtrans does the right fssync opcode */
617 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
619 VTRANS_OBJ_UNLOCK(tt);
621 return VOLSERTRELE_ERROR;
623 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
624 return 0; /* vpurgevolume doesn't set an error code */
627 /* make a clone of the volume associated with atrans, possibly giving it a new
628 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
629 * for the clone's id). The new clone is given the name newName. Finally,
630 * due to efficiency considerations, if purgeId is non-zero, we purge that
631 * volume when doing the clone operation. This may be useful when making
632 * new backup volumes, for instance since the net result of a clone and a
633 * purge generally leaves many inode ref counts the same, while doing them
634 * separately would result in far more iincs and idecs being peformed
635 * (and they are slow operations).
637 /* for efficiency reasons, sometimes faster to piggyback a purge here */
639 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
640 afs_int32 newType, char *newName, afs_uint32 *newNumber)
644 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
645 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
646 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
652 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
653 afs_int32 newType, char *newName, afs_uint32 *newNumber)
656 register struct Volume *originalvp, *purgevp, *newvp;
658 register struct volser_trans *tt, *ttc;
659 char caller[MAXKTCNAMELEN];
661 if (strlen(newName) > 31)
662 return VOLSERBADNAME;
663 if (!afsconf_SuperUser(tdir, acid, caller))
664 return VOLSERBAD_ACCESS; /*not a super user */
666 Log("%s is executing Clone Volume new name=%s\n", caller, newName);
668 originalvp = (Volume *) 0;
669 purgevp = (Volume *) 0;
670 newvp = (Volume *) 0;
671 tt = ttc = (struct volser_trans *)0;
673 if (!newNumber || !*newNumber) {
674 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
679 if (newType != readonlyVolume && newType != backupVolume)
681 tt = FindTrans(atrans);
684 if (tt->vflags & VTDeleted) {
685 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
689 ttc = NewTrans(newId, tt->partition);
690 if (!ttc) { /* someone is messing with the clone already */
692 return VOLSERVOLBUSY;
694 TSetRxCall(tt, acid, "Clone");
698 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
700 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
706 originalvp = tt->volume;
707 if ((V_type(originalvp) == backupVolume)
708 || (V_type(originalvp) == readonlyVolume)) {
709 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
713 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
714 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
720 if (originalvp->device != purgevp->device) {
721 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
725 if (V_type(purgevp) != readonlyVolume) {
726 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
730 if (V_type(originalvp) == readonlyVolume
731 && V_parentId(originalvp) != V_parentId(purgevp)) {
732 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
736 if (V_type(originalvp) == readwriteVolume
737 && tt->volid != V_parentId(purgevp)) {
738 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
747 VCreateVolume(&error, originalvp->partition->name, newId,
748 V_parentId(originalvp));
750 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
751 newvp = (Volume *) 0;
754 if (newType == readonlyVolume)
755 V_cloneId(originalvp) = newId;
756 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
759 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
760 CloneVolume(&error, originalvp, newvp, purgevp);
761 purgevp = NULL; /* clone releases it, maybe even if error */
763 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
767 if (newType == readonlyVolume) {
768 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
769 V_type(newvp) = readonlyVolume;
770 } else if (newType == backupVolume) {
771 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
772 V_type(newvp) = backupVolume;
773 V_backupId(originalvp) = newId;
775 strcpy(newvp->header->diskstuff.name, newName);
776 V_creationDate(newvp) = V_copyDate(newvp);
777 ClearVolumeStats(&V_disk(newvp));
778 V_destroyMe(newvp) = DESTROY_ME;
779 V_inService(newvp) = 0;
780 if (newType == backupVolume) {
781 V_backupDate(originalvp) = V_copyDate(newvp);
782 V_backupDate(newvp) = V_copyDate(newvp);
785 VUpdateVolume(&error, newvp);
787 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
791 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
793 VUpdateVolume(&error, originalvp);
795 Log("1 Volser: Clone: original update %u\n", error);
801 tt = (struct volser_trans *)0;
802 error = VOLSERTRELE_ERROR;
810 VDetachVolume(&code, purgevp);
812 VDetachVolume(&code, newvp);
822 /* reclone this volume into the specified id */
824 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
828 code = VolReClone(acid, atrans, cloneId);
829 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
835 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
837 register struct Volume *originalvp, *clonevp;
840 register struct volser_trans *tt, *ttc;
841 char caller[MAXKTCNAMELEN];
843 /*not a super user */
844 if (!afsconf_SuperUser(tdir, acid, caller))
845 return VOLSERBAD_ACCESS;
847 Log("%s is executing Reclone Volume %u\n", caller, cloneId);
849 clonevp = originalvp = (Volume *) 0;
850 tt = (struct volser_trans *)0;
852 tt = FindTrans(atrans);
855 if (tt->vflags & VTDeleted) {
856 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
860 ttc = NewTrans(cloneId, tt->partition);
861 if (!ttc) { /* someone is messing with the clone already */
863 return VOLSERVOLBUSY;
865 TSetRxCall(tt, acid, "ReClone");
867 originalvp = tt->volume;
868 if ((V_type(originalvp) == backupVolume)
869 || (V_type(originalvp) == readonlyVolume)) {
870 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
874 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
875 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
881 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
883 Log("1 Volser: can't attach clone %d\n", cloneId);
887 newType = V_type(clonevp); /* type of the new volume */
889 if (originalvp->device != clonevp->device) {
890 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
895 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
896 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
900 if (V_type(originalvp) == readonlyVolume
901 && V_parentId(originalvp) != V_parentId(clonevp)) {
902 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
906 if (V_type(originalvp) == readwriteVolume
907 && tt->volid != V_parentId(clonevp)) {
908 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
914 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
916 CloneVolume(&error, originalvp, clonevp, clonevp);
918 Log("1 Volser: Clone: reclone operation failed with code %d\n",
924 /* fix up volume name and type, CloneVolume just propagated RW's */
925 if (newType == readonlyVolume) {
926 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
927 V_type(clonevp) = readonlyVolume;
928 } else if (newType == backupVolume) {
929 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
930 V_type(clonevp) = backupVolume;
931 V_backupId(originalvp) = cloneId;
933 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
935 /* pretend recloned volume is a totally new instance */
936 V_copyDate(clonevp) = time(0);
937 V_creationDate(clonevp) = V_copyDate(clonevp);
938 ClearVolumeStats(&V_disk(clonevp));
939 V_destroyMe(clonevp) = 0;
940 V_inService(clonevp) = 0;
941 if (newType == backupVolume) {
942 V_backupDate(originalvp) = V_copyDate(clonevp);
943 V_backupDate(clonevp) = V_copyDate(clonevp);
945 V_inUse(clonevp) = 0;
946 VUpdateVolume(&error, clonevp);
948 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
952 /* VUpdateVolume succeeded. Mark it in service so there's no window
953 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
954 * specialStatus; this is a reclone and this volume started online
956 V_inService(clonevp) = 1;
957 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
959 VUpdateVolume(&error, originalvp);
961 Log("1 Volser: Clone: original update %u\n", error);
967 tt = (struct volser_trans *)0;
968 error = VOLSERTRELE_ERROR;
975 struct DiskPartition64 *tpartp = originalvp->partition;
976 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
982 VDetachVolume(&code, clonevp);
992 /* create a new transaction, associated with volume and partition. Type of
993 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
994 * See volser.h for definition of iflags (the constants are named IT*).
997 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
998 afs_int32 iflags, afs_int32 *ttid)
1002 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1003 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1009 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1010 afs_int32 iflags, afs_int32 *ttid)
1012 register struct volser_trans *tt;
1013 register Volume *tv;
1017 char caller[MAXKTCNAMELEN];
1019 if (!afsconf_SuperUser(tdir, acid, caller))
1020 return VOLSERBAD_ACCESS; /*not a super user */
1021 if (iflags & ITCreate)
1023 else if (iflags & ITBusy)
1025 else if (iflags & ITReadOnly)
1027 else if (iflags & ITOffline)
1030 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1035 tt = NewTrans(volume, partition);
1037 /* can't create a transaction? put the volume back */
1038 Log("1 transcreate: can't create transaction\n");
1039 return VOLSERVOLBUSY;
1041 tv = XAttachVolume(&error, volume, partition, mode);
1045 VDetachVolume(&code, tv);
1049 VTRANS_OBJ_LOCK(tt);
1052 tt->iflags = iflags;
1054 TSetRxCall_r(tt, NULL, "TransCreate");
1055 VTRANS_OBJ_UNLOCK(tt);
1057 return VOLSERTRELE_ERROR;
1062 /* using aindex as a 0-based index, return the aindex'th volume on this server
1063 * Both the volume number and partition number (one-based) are returned.
1066 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1071 code = VolGetNthVolume(acid, aindex, avolume, apart);
1072 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1077 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1080 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1084 /* return the volume flags (VT* constants in volser.h) associated with this
1088 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1092 code = VolGetFlags(acid, atid, aflags);
1093 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1098 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1100 register struct volser_trans *tt;
1102 tt = FindTrans(atid);
1105 if (tt->vflags & VTDeleted) {
1106 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1111 TSetRxCall(tt, acid, "GetFlags");
1112 *aflags = tt->vflags;
1115 return VOLSERTRELE_ERROR;
1120 /* Change the volume flags (VT* constants in volser.h) associated with this
1121 * transaction. Effects take place immediately on volume, although volume
1122 * remains attached as usual by the transaction.
1125 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1129 code = VolSetFlags(acid, atid, aflags);
1130 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1136 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1138 register struct volser_trans *tt;
1139 register struct Volume *vp;
1141 char caller[MAXKTCNAMELEN];
1143 if (!afsconf_SuperUser(tdir, acid, caller))
1144 return VOLSERBAD_ACCESS; /*not a super user */
1145 /* find the trans */
1146 tt = FindTrans(atid);
1149 if (tt->vflags & VTDeleted) {
1150 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1155 TSetRxCall(tt, acid, "SetFlags");
1156 vp = tt->volume; /* pull volume out of transaction */
1158 /* check if we're allowed to make any updates */
1159 if (tt->iflags & ITReadOnly) {
1164 /* handle delete-on-salvage flag */
1165 if (aflags & VTDeleteOnSalvage) {
1166 V_destroyMe(tt->volume) = DESTROY_ME;
1168 V_destroyMe(tt->volume) = 0;
1171 if (aflags & VTOutOfService) {
1172 V_inService(vp) = 0;
1174 V_inService(vp) = 1;
1176 VUpdateVolume(&error, vp);
1177 VTRANS_OBJ_LOCK(tt);
1178 tt->vflags = aflags;
1180 VTRANS_OBJ_UNLOCK(tt);
1181 if (TRELE(tt) && !error)
1182 return VOLSERTRELE_ERROR;
1187 /* dumpS the volume associated with a particular transaction from a particular
1188 * date. Send the dump to a different transaction (destTrans) on the server
1189 * specified by the destServer structure.
1192 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1193 struct destServer *destination, afs_int32 destTrans,
1194 struct restoreCookie *cookie)
1199 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1200 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1201 destination->destHost, AUD_LONG, destTrans, AUD_END);
1206 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1207 struct destServer *destination, afs_int32 destTrans,
1208 struct restoreCookie *cookie)
1210 register struct volser_trans *tt;
1211 register afs_int32 code;
1212 register struct rx_connection *tcon;
1213 struct rx_call *tcall;
1214 register struct Volume *vp;
1215 struct rx_securityClass *securityObject;
1216 afs_int32 securityIndex;
1217 char caller[MAXKTCNAMELEN];
1219 if (!afsconf_SuperUser(tdir, acid, caller))
1220 return VOLSERBAD_ACCESS; /*not a super user */
1221 /* initialize things */
1222 tcon = (struct rx_connection *)0;
1223 tt = (struct volser_trans *)0;
1225 /* find the local transaction */
1226 tt = FindTrans(fromTrans);
1229 if (tt->vflags & VTDeleted) {
1230 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1235 TSetRxCall(tt, NULL, "Forward");
1237 /* get auth info for the this connection (uses afs from ticket file) */
1238 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1244 /* make an rpc connection to the other server */
1246 rx_NewConnection(htonl(destination->destHost),
1247 htons(destination->destPort), VOLSERVICE_ID,
1248 securityObject, securityIndex);
1254 tcall = rx_NewCall(tcon);
1255 TSetRxCall(tt, tcall, "Forward");
1256 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1257 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1262 /* these next calls implictly call rx_Write when writing out data */
1263 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1266 EndAFSVolRestore(tcall); /* probably doesn't do much */
1268 code = rx_EndCall(tcall, 0);
1269 rx_DestroyConnection(tcon); /* done with the connection */
1274 return VOLSERTRELE_ERROR;
1280 (void)rx_EndCall(tcall, 0);
1281 rx_DestroyConnection(tcon);
1290 /* Start a dump and send it to multiple places simultaneously.
1291 * If this returns an error (eg, return ENOENT), it means that
1292 * none of the releases worked. If this returns 0, that means
1293 * that one or more of the releases worked, and the caller has
1294 * to examine the results array to see which one(s).
1295 * This will only do EITHER incremental or full, not both, so it's
1296 * the caller's responsibility to be sure that all the destinations
1297 * need just an incremental (and from the same time), if that's
1301 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1302 fromDate, manyDests *destinations, afs_int32 spare,
1303 struct restoreCookie *cookie, manyResults *results)
1305 afs_int32 securityIndex;
1306 struct rx_securityClass *securityObject;
1307 char caller[MAXKTCNAMELEN];
1308 struct volser_trans *tt;
1309 afs_int32 ec, code, *codes;
1310 struct rx_connection **tcons;
1311 struct rx_call **tcalls;
1313 int i, is_incremental;
1316 memset(results, 0, sizeof(manyResults));
1317 i = results->manyResults_len = destinations->manyDests_len;
1318 results->manyResults_val = codes =
1319 (afs_int32 *) malloc(i * sizeof(afs_int32));
1321 if (!results || !results->manyResults_val)
1324 if (!afsconf_SuperUser(tdir, acid, caller))
1325 return VOLSERBAD_ACCESS; /*not a super user */
1326 tt = FindTrans(fromTrans);
1329 if (tt->vflags & VTDeleted) {
1330 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1335 TSetRxCall(tt, NULL, "ForwardMulti");
1337 /* (fromDate == 0) ==> full dump */
1338 is_incremental = (fromDate ? 1 : 0);
1341 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1345 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1351 /* get auth info for this connection (uses afs from ticket file) */
1352 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1354 goto fail; /* in order to audit each failure */
1357 /* make connections to all the other servers */
1358 for (i = 0; i < destinations->manyDests_len; i++) {
1359 struct replica *dest = &(destinations->manyDests_val[i]);
1361 rx_NewConnection(htonl(dest->server.destHost),
1362 htons(dest->server.destPort), VOLSERVICE_ID,
1363 securityObject, securityIndex);
1365 codes[i] = ENOTCONN;
1367 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1368 codes[i] = ENOTCONN;
1371 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1374 (void)rx_EndCall(tcalls[i], 0);
1376 rx_DestroyConnection(tcons[i]);
1383 /* these next calls implictly call rx_Write when writing out data */
1384 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1388 for (i--; i >= 0; i--) {
1389 struct replica *dest = &(destinations->manyDests_val[i]);
1391 if (!code && tcalls[i] && !codes[i]) {
1392 EndAFSVolRestore(tcalls[i]);
1395 ec = rx_EndCall(tcalls[i], 0);
1400 rx_DestroyConnection(tcons[i]); /* done with the connection */
1403 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1404 fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG,
1405 dest->trans, AUD_END);
1412 if (TRELE(tt) && !code) /* return the first code if it's set */
1413 return VOLSERTRELE_ERROR;
1420 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1424 code = VolDump(acid, fromTrans, fromDate, 0);
1425 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1430 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1435 code = VolDump(acid, fromTrans, fromDate, flags);
1436 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1441 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1445 register struct volser_trans *tt;
1446 char caller[MAXKTCNAMELEN];
1448 if (!afsconf_SuperUser(tdir, acid, caller))
1449 return VOLSERBAD_ACCESS; /*not a super user */
1450 tt = FindTrans(fromTrans);
1453 if (tt->vflags & VTDeleted) {
1454 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1458 TSetRxCall(tt, acid, "Dump");
1459 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1460 ? 0 : 1); /* squirt out the volume's data, too */
1469 return VOLSERTRELE_ERROR;
1475 * Ha! No more helper process!
1478 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1479 struct restoreCookie *cookie)
1483 code = VolRestore(acid, atrans, aflags, cookie);
1484 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1489 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1490 struct restoreCookie *cookie)
1492 register struct volser_trans *tt;
1493 register afs_int32 code, tcode;
1494 char caller[MAXKTCNAMELEN];
1496 if (!afsconf_SuperUser(tdir, acid, caller))
1497 return VOLSERBAD_ACCESS; /*not a super user */
1498 tt = FindTrans(atrans);
1501 if (tt->vflags & VTDeleted) {
1502 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1506 TSetRxCall(tt, acid, "Restore");
1508 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1510 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1511 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1515 return (code ? code : tcode);
1518 /* end a transaction, returning the transaction's final error code in rcode */
1520 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1524 code = VolEndTrans(acid, destTrans, rcode);
1525 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1530 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1532 register struct volser_trans *tt;
1533 char caller[MAXKTCNAMELEN];
1535 if (!afsconf_SuperUser(tdir, acid, caller))
1536 return VOLSERBAD_ACCESS; /*not a super user */
1537 tt = FindTrans(destTrans);
1541 *rcode = tt->returnCode;
1542 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1548 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1552 code = VolSetForwarding(acid, atid, anewsite);
1553 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1559 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1561 register struct volser_trans *tt;
1562 char caller[MAXKTCNAMELEN];
1565 if (!afsconf_SuperUser(tdir, acid, caller))
1566 return VOLSERBAD_ACCESS; /*not a super user */
1567 tt = FindTrans(atid);
1570 if (tt->vflags & VTDeleted) {
1571 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1576 TSetRxCall(tt, acid, "SetForwarding");
1577 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1580 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1583 return VOLSERTRELE_ERROR;
1589 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1590 register struct volser_status *astatus)
1594 code = VolGetStatus(acid, atrans, astatus);
1595 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1600 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1601 register struct volser_status *astatus)
1603 register struct Volume *tv;
1604 register struct VolumeDiskData *td;
1605 struct volser_trans *tt;
1608 tt = FindTrans(atrans);
1611 if (tt->vflags & VTDeleted) {
1612 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1617 TSetRxCall(tt, acid, "GetStatus");
1625 td = &tv->header->diskstuff;
1626 astatus->volID = td->id;
1627 astatus->nextUnique = td->uniquifier;
1628 astatus->type = td->type;
1629 astatus->parentID = td->parentId;
1630 astatus->cloneID = td->cloneId;
1631 astatus->backupID = td->backupId;
1632 astatus->restoredFromID = td->restoredFromId;
1633 astatus->maxQuota = td->maxquota;
1634 astatus->minQuota = td->minquota;
1635 astatus->owner = td->owner;
1636 astatus->creationDate = td->creationDate;
1637 astatus->accessDate = td->accessDate;
1638 astatus->updateDate = td->updateDate;
1639 astatus->expirationDate = td->expirationDate;
1640 astatus->backupDate = td->backupDate;
1641 astatus->copyDate = td->copyDate;
1644 return VOLSERTRELE_ERROR;
1650 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1651 register struct volintInfo *astatus)
1655 code = VolSetInfo(acid, atrans, astatus);
1656 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1661 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1662 register struct volintInfo *astatus)
1664 register struct Volume *tv;
1665 register struct VolumeDiskData *td;
1666 struct volser_trans *tt;
1667 char caller[MAXKTCNAMELEN];
1670 if (!afsconf_SuperUser(tdir, acid, caller))
1671 return VOLSERBAD_ACCESS; /*not a super user */
1672 tt = FindTrans(atrans);
1675 if (tt->vflags & VTDeleted) {
1676 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1680 TSetRxCall(tt, acid, "SetStatus");
1688 td = &tv->header->diskstuff;
1690 * Add more fields as necessary
1692 if (astatus->maxquota != -1)
1693 td->maxquota = astatus->maxquota;
1694 if (astatus->dayUse != -1)
1695 td->dayUse = astatus->dayUse;
1696 if (astatus->creationDate != -1)
1697 td->creationDate = astatus->creationDate;
1698 if (astatus->updateDate != -1)
1699 td->updateDate = astatus->updateDate;
1700 if (astatus->spare2 != -1)
1701 td->volUpdateCounter = (unsigned int)astatus->spare2;
1702 VUpdateVolume(&error, tv);
1705 return VOLSERTRELE_ERROR;
1711 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1715 code = VolGetName(acid, atrans, aname);
1716 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1721 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1723 register struct Volume *tv;
1724 register struct VolumeDiskData *td;
1725 struct volser_trans *tt;
1728 /* We need to at least fill it in */
1729 *aname = (char *)malloc(1);
1732 tt = FindTrans(atrans);
1735 if (tt->vflags & VTDeleted) {
1736 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1740 TSetRxCall(tt, acid, "GetName");
1748 td = &tv->header->diskstuff;
1749 len = strlen(td->name) + 1; /* don't forget the null */
1755 *aname = (char *)realloc(*aname, len);
1756 strcpy(*aname, td->name);
1759 return VOLSERTRELE_ERROR;
1764 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1767 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1768 afs_uint32 parentId, afs_uint32 cloneId)
1774 /*return a list of all partitions on the server. The non mounted
1775 *partitions are returned as -1 in the corresponding slot in partIds*/
1777 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1781 code = VolListPartitions(acid, partIds);
1782 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1787 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1792 strcpy(namehead, "/vicep"); /*7 including null terminator */
1794 /* Just return attached partitions. */
1796 for (i = 0; i < 26; i++) {
1797 namehead[6] = i + 'a';
1798 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1804 /*return a list of all partitions on the server. The non mounted
1805 *partitions are returned as -1 in the corresponding slot in partIds*/
1807 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1811 code = XVolListPartitions(acid, pEntries);
1812 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1817 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1820 struct partList partList;
1821 struct DiskPartition64 *dp;
1824 strcpy(namehead, "/vicep"); /*7 including null terminator */
1826 /* Only report attached partitions */
1827 for (i = 0; i < VOLMAXPARTS; i++) {
1828 #ifdef AFS_DEMAND_ATTACH_FS
1829 dp = VGetPartitionById(i, 0);
1832 namehead[6] = i + 'a';
1838 namehead[6] = 'a' + (k / 26);
1839 namehead[7] = 'a' + (k % 26);
1842 dp = VGetPartition(namehead, 0);
1845 partList.partId[j++] = i;
1847 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1848 if (!pEntries->partEntries_val)
1850 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1852 pEntries->partEntries_len = j;
1857 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1859 ExtractVolId(char vname[])
1862 char name[VOLSER_MAXVOLNAME + 1];
1864 strcpy(name, vname);
1866 while (name[i] == 'V' || name[i] == '0')
1869 name[11] = '\0'; /* smash the "." */
1870 return (atol(&name[i]));
1873 /*return the name of the next volume header in the directory associated with dirp and dp.
1874 *the volume id is returned in volid, and volume header name is returned in volname*/
1876 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1880 dp = readdir(dirp); /*read next entry in the directory */
1882 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1883 *volid = ExtractVolId(dp->d_name);
1884 strcpy(volname, dp->d_name);
1885 return 0; /*return the name of the file representing a volume */
1887 strcpy(volname, "");
1888 return 0; /*volname doesnot represent a volume */
1891 strcpy(volname, "EOD");
1892 return 0; /*end of directory */
1898 * volint vol info structure type.
1901 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1902 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1903 } volint_info_type_t;
1906 * handle to various on-wire vol info types.
1909 volint_info_type_t volinfo_type;
1915 } volint_info_handle_t;
1918 * store value to a field at the appropriate location in on-wire structure.
1920 #define VOLINT_INFO_STORE(handle, name, val) \
1922 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1923 (handle)->volinfo_ptr.base->name = (val); \
1925 (handle)->volinfo_ptr.ext->name = (val); \
1930 * get pointer to appropriate offset of field in on-wire structure.
1932 #define VOLINT_INFO_PTR(handle, name) \
1933 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1934 &((handle)->volinfo_ptr.base->name) : \
1935 &((handle)->volinfo_ptr.ext->name))
1938 * fill in appropriate type of on-wire volume metadata structure.
1940 * @param vp pointer to volume object
1941 * @param handle pointer to wire format handle object
1943 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1944 * @pre handle object must have a valid pointer and enumeration value
1946 * @note passing a NULL value for vp means that the fileserver doesn't
1947 * know about this particular volume, thus implying it is offline.
1949 * @return operation status
1954 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1956 unsigned int numStatBytes, now;
1957 register struct VolumeDiskData *hdr = &vp->header->diskstuff;
1959 /*read in the relevant info */
1960 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1961 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1962 VOLINT_INFO_STORE(handle, volid, hdr->id);
1963 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1964 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
1965 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
1966 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
1967 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
1968 VOLINT_INFO_STORE(handle, size, hdr->diskused);
1969 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
1970 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
1971 now = FT_ApproxTime();
1972 if ((now - hdr->dayUseDate) > OneDay) {
1973 VOLINT_INFO_STORE(handle, dayUse, 0);
1975 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
1977 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
1978 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
1979 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
1980 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
1982 #ifdef AFS_DEMAND_ATTACH_FS
1984 * for DAFS, we "lie" about volume state --
1985 * instead of returning the raw state from the disk header,
1986 * we compute state based upon the fileserver's internal
1987 * in-core state enumeration value reported to us via fssync,
1988 * along with the blessed and inService flags from the header.
1989 * -- tkeiser 11/27/2007
1992 /* Conditions that offline status is based on:
1993 volume is unattached state
1994 volume state is in (one of several error states)
1995 volume not in service
1996 volume is not marked as blessed (not on hold)
1997 volume in salvage req. state
1998 volume needsSalvaged
1999 next op would set volume offline
2000 next op would not leave volume online (based on several conditions)
2003 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2004 VIsErrorState(V_attachState(vp)) ||
2007 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2008 hdr->needsSalvaged ||
2009 (vp->pending_vol_op &&
2010 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2011 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2014 VOLINT_INFO_STORE(handle, inUse, 0);
2016 VOLINT_INFO_STORE(handle, inUse, 1);
2019 /* offline status based on program type, where != fileServer enum (1) is offline */
2020 if (hdr->inUse == fileServer) {
2021 VOLINT_INFO_STORE(handle, inUse, 1);
2023 VOLINT_INFO_STORE(handle, inUse, 0);
2028 switch(handle->volinfo_type) {
2029 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2030 case VOLINT_INFO_TYPE_BASE:
2032 #ifdef AFS_DEMAND_ATTACH_FS
2033 /* see comment above where we set inUse bit */
2034 if (hdr->needsSalvaged ||
2035 (vp && VIsErrorState(V_attachState(vp)))) {
2036 handle->volinfo_ptr.base->needsSalvaged = 1;
2038 handle->volinfo_ptr.base->needsSalvaged = 0;
2041 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2043 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2044 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2045 handle->volinfo_ptr.base->spare1 =
2046 (long)hdr->weekUse[0] +
2047 (long)hdr->weekUse[1] +
2048 (long)hdr->weekUse[2] +
2049 (long)hdr->weekUse[3] +
2050 (long)hdr->weekUse[4] +
2051 (long)hdr->weekUse[5] +
2052 (long)hdr->weekUse[6];
2053 handle->volinfo_ptr.base->flags = 0;
2054 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2055 handle->volinfo_ptr.base->spare3 = 0;
2059 case VOLINT_INFO_TYPE_EXT:
2061 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2062 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2065 * Copy out the stat fields in a single operation.
2067 if ((now - hdr->dayUseDate) > OneDay) {
2068 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2071 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2072 (char *)&(hdr->stat_reads[0]),
2081 #ifdef AFS_DEMAND_ATTACH_FS
2084 * get struct Volume out of the fileserver.
2086 * @param[in] volumeId volumeId for which we want state information
2087 * @param[in] pname partition name string
2088 * @param[inout] vp pointer to pointer to Volume object which
2089 * will be populated (see note)
2091 * @return operation status
2093 * @retval non-zero failure
2095 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2100 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2105 res.hdr.response_len = sizeof(res.hdr);
2106 res.payload.buf = *vp;
2107 res.payload.len = sizeof(Volume);
2109 code = FSYNC_VolOp(volumeId,
2115 if (code != SYNC_OK) {
2116 switch (res.hdr.reason) {
2117 case FSYNC_WRONG_PART:
2118 case FSYNC_UNKNOWN_VOLID:
2131 * mode of volume list operation.
2134 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2135 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2136 } vol_info_list_mode_t;
2139 * abstract interface to populate wire-format volume metadata structures.
2141 * @param[in] partId partition id
2142 * @param[in] volumeId volume id
2143 * @param[in] pname partition name
2144 * @param[in] volname volume file name
2145 * @param[in] handle handle to on-wire volume metadata object
2146 * @param[in] mode listing mode
2148 * @return operation status
2150 * @retval -2 DESTROY_ME flag is set
2151 * @retval -1 general failure; some data filled in
2152 * @retval -3 couldn't create vtrans; some data filled in
2155 GetVolInfo(afs_uint32 partId,
2156 afs_uint32 volumeId,
2159 volint_info_handle_t * handle,
2160 vol_info_list_mode_t mode)
2164 struct volser_trans *ttc = NULL;
2165 struct Volume *fill_tv, *tv = NULL;
2166 #ifdef AFS_DEMAND_ATTACH_FS
2167 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2168 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2169 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2170 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2172 /* Set up response handle for pending_vol_op */
2173 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2174 fs_res.payload.buf = fs_res_buf;
2175 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2178 ttc = NewTrans(volumeId, partId);
2181 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2182 VOLINT_INFO_STORE(handle, volid, volumeId);
2186 /* Get volume from volserver */
2187 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2189 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2190 volumeId, pname, volname, error);
2195 * please note that destroyMe and needsSalvaged checks used to be ordered
2196 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2197 * more correct to check destroyMe before needsSalvaged.
2198 * -- tkeiser 11/28/2007
2201 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2203 case VOL_INFO_LIST_MULTIPLE:
2207 case VOL_INFO_LIST_SINGLE:
2208 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2209 volumeId, pname, volname);
2216 if (tv->header->diskstuff.needsSalvaged) {
2217 /*this volume will be salvaged */
2218 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2219 volumeId, pname, volname);
2222 #ifdef AFS_DEMAND_ATTACH_FS
2223 /* If using DAFS, get volume from fsserver */
2224 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2229 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2230 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2231 /* If we if the pending vol op */
2232 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2233 fs_tv->pending_vol_op=&pending_vol_op_res;
2235 fs_tv->pending_vol_op=NULL;
2238 /* populate the header from the volserver copy */
2239 fs_tv->header=tv->header;
2241 /* When using DAFS, use the fs volume info, populated with required structures */
2244 /* When not using DAFS, just use the local volume info */
2248 /* ok, we have all the data we need; fill in the on-wire struct */
2249 code = FillVolInfo(fill_tv, handle);
2253 VOLINT_INFO_STORE(handle, status, 0);
2254 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2255 VOLINT_INFO_STORE(handle, volid, volumeId);
2258 VDetachVolume(&error, tv);
2261 VOLINT_INFO_STORE(handle, status, 0);
2262 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2263 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2264 volumeId, pname, volname);
2268 DeleteTrans(ttc, 1);
2275 /*return the header information about the <volid> */
2277 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2278 afs_uint32 volumeId, volEntries *volumeInfo)
2282 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2283 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2288 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2289 afs_uint32 volumeId, volEntries *volumeInfo)
2292 struct DiskPartition64 *partP;
2293 char pname[9], volname[20];
2298 volint_info_handle_t handle;
2300 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2301 if (!volumeInfo->volEntries_val)
2303 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2305 pntr = volumeInfo->volEntries_val;
2306 volumeInfo->volEntries_len = 1;
2307 if (GetPartName(partid, pname))
2308 return VOLSERILLEGAL_PARTITION;
2309 if (!(partP = VGetPartition(pname, 0)))
2310 return VOLSERILLEGAL_PARTITION;
2311 dirp = opendir(VPartitionPath(partP));
2313 return VOLSERILLEGAL_PARTITION;
2315 strcpy(volname, "");
2317 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2319 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2320 GetNextVol(dirp, volname, &volid);
2321 continue; /*back to while loop */
2324 if (volid == volumeId) { /*copy other things too */
2329 GetNextVol(dirp, volname, &volid);
2333 #ifndef AFS_PTHREAD_ENV
2334 IOMGR_Poll(); /*make sure that the client does not time out */
2337 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2338 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2340 code = GetVolInfo(partid,
2345 VOL_INFO_LIST_SINGLE);
2349 return (found) ? 0 : ENODEV;
2352 /*------------------------------------------------------------------------
2353 * EXPORTED SAFSVolXListOneVolume
2356 * Returns extended info on volume a_volID on partition a_partID.
2359 * a_rxCidP : Pointer to the Rx call we're performing.
2360 * a_partID : Partition for which we want the extended list.
2361 * a_volID : Volume ID we wish to know about.
2362 * a_volumeXInfoP : Ptr to the extended info blob.
2365 * 0 Successful operation
2366 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2369 * Nothing interesting.
2373 *------------------------------------------------------------------------*/
2376 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2377 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2381 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2382 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2387 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2388 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2389 { /*SAFSVolXListOneVolume */
2391 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2392 struct DiskPartition64 *partP; /*Ptr to partition */
2393 char pname[9], volname[20]; /*Partition, volume names */
2394 DIR *dirp; /*Partition directory ptr */
2395 afs_uint32 currVolID; /*Current volume ID */
2396 int found = 0; /*Did we find the volume we need? */
2398 volint_info_handle_t handle;
2401 * Set up our pointers for action, marking our structure to hold exactly
2402 * one entry. Also, assume we'll fail in our quest.
2404 a_volumeXInfoP->volXEntries_val =
2405 (volintXInfo *) malloc(sizeof(volintXInfo));
2406 if (!a_volumeXInfoP->volXEntries_val)
2408 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2410 xInfoP = a_volumeXInfoP->volXEntries_val;
2411 a_volumeXInfoP->volXEntries_len = 1;
2415 * If the partition name we've been given is bad, bogue out.
2417 if (GetPartName(a_partID, pname))
2418 return (VOLSERILLEGAL_PARTITION);
2421 * Open the directory representing the given AFS parttion. If we can't
2424 if (!(partP = VGetPartition(pname, 0)))
2425 return VOLSERILLEGAL_PARTITION;
2426 dirp = opendir(VPartitionPath(partP));
2428 return (VOLSERILLEGAL_PARTITION);
2430 strcpy(volname, "");
2433 * Sweep through the partition directory, looking for the desired entry.
2434 * First, of course, figure out how many stat bytes to copy out of each
2437 while (strcmp(volname, "EOD") && !found) {
2439 * If this is not a volume, move on to the next entry in the
2440 * partition's directory.
2442 if (!strcmp(volname, "")) {
2443 GetNextVol(dirp, volname, &currVolID);
2447 if (currVolID == a_volID) {
2449 * We found the volume entry we're interested. Pull out the
2450 * extended information, remembering to poll (so that the client
2451 * doesn't time out) and to set up a transaction on the volume.
2455 } /*Found desired volume */
2457 GetNextVol(dirp, volname, &currVolID);
2461 #ifndef AFS_PTHREAD_ENV
2465 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2466 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2468 code = GetVolInfo(a_partID,
2473 VOL_INFO_LIST_SINGLE);
2478 * Clean up before going to dinner: close the partition directory,
2479 * return the proper value.
2482 return (found) ? 0 : ENODEV;
2483 } /*SAFSVolXListOneVolume */
2485 /*returns all the volumes on partition partid. If flags = 1 then all the
2486 * relevant info about the volumes is also returned */
2488 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2489 volEntries *volumeInfo)
2493 code = VolListVolumes(acid, partid, flags, volumeInfo);
2494 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2499 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2500 volEntries *volumeInfo)
2503 struct DiskPartition64 *partP;
2504 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2505 char pname[9], volname[20];
2509 volint_info_handle_t handle;
2511 volumeInfo->volEntries_val =
2512 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2513 if (!volumeInfo->volEntries_val)
2515 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2517 pntr = volumeInfo->volEntries_val;
2518 volumeInfo->volEntries_len = 0;
2519 if (GetPartName(partid, pname))
2520 return VOLSERILLEGAL_PARTITION;
2521 if (!(partP = VGetPartition(pname, 0)))
2522 return VOLSERILLEGAL_PARTITION;
2523 dirp = opendir(VPartitionPath(partP));
2525 return VOLSERILLEGAL_PARTITION;
2526 strcpy(volname, "");
2528 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2530 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2531 GetNextVol(dirp, volname, &volid);
2532 continue; /*back to while loop */
2535 if (flags) { /*copy other things too */
2536 #ifndef AFS_PTHREAD_ENV
2537 IOMGR_Poll(); /*make sure that the client does not time out */
2540 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2541 handle.volinfo_ptr.base = pntr;
2544 code = GetVolInfo(partid,
2549 VOL_INFO_LIST_MULTIPLE);
2550 if (code == -2) { /* DESTROY_ME flag set */
2554 pntr->volid = volid;
2555 /*just volids are needed */
2559 volumeInfo->volEntries_len += 1;
2560 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2561 /*running out of space, allocate more space */
2562 allocSize = (allocSize * 3) / 2;
2564 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2565 allocSize * sizeof(volintInfo));
2568 return VOLSERNO_MEMORY;
2570 volumeInfo->volEntries_val = pntr; /* point to new block */
2571 /* set pntr to the right position */
2572 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2577 GetNextVol(dirp, volname, &volid);
2585 /*------------------------------------------------------------------------
2586 * EXPORTED SAFSVolXListVolumes
2589 * Returns all the volumes on partition a_partID. If a_flags
2590 * is set to 1, then all the relevant extended volume information
2594 * a_rxCidP : Pointer to the Rx call we're performing.
2595 * a_partID : Partition for which we want the extended list.
2596 * a_flags : Various flags.
2597 * a_volumeXInfoP : Ptr to the extended info blob.
2600 * 0 Successful operation
2601 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2602 * VOLSERNO_MEMORY if we ran out of memory allocating
2606 * Nothing interesting.
2610 *------------------------------------------------------------------------*/
2613 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2614 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2618 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2619 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2624 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2625 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2626 { /*SAFSVolXListVolumes */
2628 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2629 struct DiskPartition64 *partP; /*Ptr to partition */
2630 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2631 char pname[9], volname[20]; /*Partition, volume names */
2632 DIR *dirp; /*Partition directory ptr */
2633 afs_uint32 volid; /*Current volume ID */
2635 volint_info_handle_t handle;
2638 * Allocate a large array of extended volume info structures, then
2639 * set it up for action.
2641 a_volumeXInfoP->volXEntries_val =
2642 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2643 if (!a_volumeXInfoP->volXEntries_val)
2645 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2647 xInfoP = a_volumeXInfoP->volXEntries_val;
2648 a_volumeXInfoP->volXEntries_len = 0;
2651 * If the partition name we've been given is bad, bogue out.
2653 if (GetPartName(a_partID, pname))
2654 return (VOLSERILLEGAL_PARTITION);
2657 * Open the directory representing the given AFS parttion. If we can't
2660 if (!(partP = VGetPartition(pname, 0)))
2661 return VOLSERILLEGAL_PARTITION;
2662 dirp = opendir(VPartitionPath(partP));
2664 return (VOLSERILLEGAL_PARTITION);
2665 strcpy(volname, "");
2668 * Sweep through the partition directory, acting on each entry. First,
2669 * of course, figure out how many stat bytes to copy out of each volume.
2671 while (strcmp(volname, "EOD")) {
2674 * If this is not a volume, move on to the next entry in the
2675 * partition's directory.
2677 if (!strcmp(volname, "")) {
2678 GetNextVol(dirp, volname, &volid);
2684 * Full info about the volume desired. Poll to make sure the
2685 * client doesn't time out, then start up a new transaction.
2687 #ifndef AFS_PTHREAD_ENV
2691 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2692 handle.volinfo_ptr.ext = xInfoP;
2694 code = GetVolInfo(a_partID,
2699 VOL_INFO_LIST_MULTIPLE);
2700 if (code == -2) { /* DESTROY_ME flag set */
2705 * Just volume IDs are needed.
2707 xInfoP->volid = volid;
2711 * Bump the pointer in the data area we're building, along with
2712 * the count of the number of entries it contains.
2715 (a_volumeXInfoP->volXEntries_len)++;
2716 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2718 * We're running out of space in the area we've built. Grow it.
2720 allocSize = (allocSize * 3) / 2;
2721 xInfoP = (volintXInfo *)
2722 realloc((char *)a_volumeXInfoP->volXEntries_val,
2723 (allocSize * sizeof(volintXInfo)));
2724 if (xInfoP == NULL) {
2726 * Bummer, no memory. Bag it, tell our caller what went wrong.
2729 return (VOLSERNO_MEMORY);
2733 * Memory reallocation worked. Correct our pointers so they
2734 * now point to the new block and the current open position within
2737 a_volumeXInfoP->volXEntries_val = xInfoP;
2739 a_volumeXInfoP->volXEntries_val +
2740 a_volumeXInfoP->volXEntries_len;
2744 GetNextVol(dirp, volname, &volid);
2745 } /*Sweep through the partition directory */
2748 * We've examined all entries in the partition directory. Close it,
2749 * delete our transaction (if any), and go home happy.
2754 } /*SAFSVolXListVolumes */
2756 /*this call is used to monitor the status of volser for debugging purposes.
2757 *information about all the active transactions is returned in transInfo*/
2759 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2763 code = VolMonitor(acid, transInfo);
2764 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2769 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2771 transDebugInfo *pntr;
2772 afs_int32 allocSize = 50;
2773 struct volser_trans *tt, *nt, *allTrans;
2775 transInfo->transDebugEntries_val =
2776 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2777 if (!transInfo->transDebugEntries_val)
2779 pntr = transInfo->transDebugEntries_val;
2780 transInfo->transDebugEntries_len = 0;
2783 allTrans = TransList();
2784 if (allTrans == (struct volser_trans *)0)
2785 goto done; /*no active transactions */
2786 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2788 VTRANS_OBJ_LOCK(tt);
2789 pntr->tid = tt->tid;
2790 pntr->time = tt->time;
2791 pntr->creationTime = tt->creationTime;
2792 pntr->returnCode = tt->returnCode;
2793 pntr->volid = tt->volid;
2794 pntr->partition = tt->partition;
2795 pntr->iflags = tt->iflags;
2796 pntr->vflags = tt->vflags;
2797 pntr->tflags = tt->tflags;
2798 strcpy(pntr->lastProcName, tt->lastProcName);
2799 pntr->callValid = 0;
2800 if (tt->rxCallPtr) { /*record call related info */
2801 pntr->callValid = 1;
2802 pntr->readNext = tt->rxCallPtr->rnext;
2803 pntr->transmitNext = tt->rxCallPtr->tnext;
2804 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2805 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2807 VTRANS_OBJ_UNLOCK(tt);
2809 transInfo->transDebugEntries_len += 1;
2810 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2811 allocSize = (allocSize * 3) / 2;
2813 (transDebugInfo *) realloc((char *)transInfo->
2814 transDebugEntries_val,
2816 sizeof(transDebugInfo));
2817 transInfo->transDebugEntries_val = pntr;
2819 transInfo->transDebugEntries_val +
2820 transInfo->transDebugEntries_len;
2821 /*set pntr to right position */
2832 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2833 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2834 afs_uint32 backupId)
2838 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2839 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2840 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2846 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2847 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2848 afs_uint32 backupId)
2852 register struct volser_trans *tt;
2853 char caller[MAXKTCNAMELEN];
2855 if (strlen(name) > 31)
2856 return VOLSERBADNAME;
2857 if (!afsconf_SuperUser(tdir, acid, caller))
2858 return VOLSERBAD_ACCESS; /*not a super user */
2859 /* find the trans */
2860 tt = FindTrans(atid);
2863 if (tt->vflags & VTDeleted) {
2864 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2868 TSetRxCall(tt, acid, "SetIdsTypes");
2872 V_backupId(tv) = backupId;
2873 V_cloneId(tv) = cloneId;
2874 V_parentId(tv) = pId;
2875 strcpy((&V_disk(tv))->name, name);
2876 VUpdateVolume(&error, tv);
2878 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2883 if (TRELE(tt) && !error)
2884 return VOLSERTRELE_ERROR;
2889 if (TRELE(tt) && !error)
2890 return VOLSERTRELE_ERROR;
2895 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2899 code = VolSetDate(acid, atid, cdate);
2900 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2906 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2910 register struct volser_trans *tt;
2911 char caller[MAXKTCNAMELEN];
2913 if (!afsconf_SuperUser(tdir, acid, caller))
2914 return VOLSERBAD_ACCESS; /*not a super user */
2915 /* find the trans */
2916 tt = FindTrans(atid);
2919 if (tt->vflags & VTDeleted) {
2920 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2924 TSetRxCall(tt, acid, "SetDate");
2927 V_creationDate(tv) = cdate;
2928 VUpdateVolume(&error, tv);
2930 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2935 if (TRELE(tt) && !error)
2936 return VOLSERTRELE_ERROR;
2941 if (TRELE(tt) && !error)
2942 return VOLSERTRELE_ERROR;
2947 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2948 afs_uint32 volumeId)
2953 char caller[MAXKTCNAMELEN];
2955 register struct volser_trans *ttc;
2956 char pname[16], volname[20];
2957 struct DiskPartition64 *partP;
2958 afs_int32 ret = ENODEV;
2961 if (!afsconf_SuperUser(tdir, acid, caller))
2962 return VOLSERBAD_ACCESS; /*not a super user */
2963 if (GetPartName(partId, pname))
2964 return VOLSERILLEGAL_PARTITION;
2965 if (!(partP = VGetPartition(pname, 0)))
2966 return VOLSERILLEGAL_PARTITION;
2967 dirp = opendir(VPartitionPath(partP));
2969 return VOLSERILLEGAL_PARTITION;
2970 strcpy(volname, "");
2971 ttc = (struct volser_trans *)0;
2973 while (strcmp(volname, "EOD")) {
2974 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2975 GetNextVol(dirp, volname, &volid);
2976 continue; /*back to while loop */
2979 if (volid == volumeId) { /*copy other things too */
2980 #ifndef AFS_PTHREAD_ENV
2981 IOMGR_Poll(); /*make sure that the client doesnot time out */
2983 ttc = NewTrans(volumeId, partId);
2985 return VOLSERVOLBUSY;
2987 #ifdef AFS_NAMEI_ENV
2988 ret = namei_ConvertROtoRWvolume(pname, volumeId);
2990 ret = inode_ConvertROtoRWvolume(pname, volumeId);
2994 GetNextVol(dirp, volname, &volid);
2998 DeleteTrans(ttc, 1);
2999 ttc = (struct volser_trans *)0;
3008 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3009 register struct volintSize *size)
3012 register struct volser_trans *tt;
3013 char caller[MAXKTCNAMELEN];
3015 if (!afsconf_SuperUser(tdir, acid, caller))
3016 return VOLSERBAD_ACCESS; /*not a super user */
3017 tt = FindTrans(fromTrans);
3020 if (tt->vflags & VTDeleted) {
3024 TSetRxCall(tt, acid, "GetSize");
3025 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3028 return VOLSERTRELE_ERROR;
3030 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3035 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3036 afs_uint32 where, afs_int32 verbose)
3038 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3040 Volume *vol=0, *newvol=0;
3041 struct volser_trans *tt = 0, *tt2 = 0;
3042 char caller[MAXKTCNAMELEN];
3045 if (!afsconf_SuperUser(tdir, acall, caller))
3048 vol = VAttachVolume(&code, vid, V_VOLUPD);
3054 newvol = VAttachVolume(&code, new, V_VOLUPD);
3056 VDetachVolume(&code2, vol);
3061 if (V_device(vol) != V_device(newvol)
3062 || V_uniquifier(newvol) != 2) {
3063 if (V_device(vol) != V_device(newvol)) {
3064 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3066 rx_Write(acall, line, strlen(line));
3068 if (V_uniquifier(newvol) != 2) {
3069 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3070 rx_Write(acall, line, strlen(line));
3073 rx_Write(acall, line, 1);
3074 VDetachVolume(&code2, vol);
3075 VDetachVolume(&code2, newvol);
3078 tt = NewTrans(vid, V_device(vol));
3080 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3081 rx_Write(acall, line, strlen(line));
3083 rx_Write(acall, line, 1);
3084 VDetachVolume(&code2, vol);
3085 VDetachVolume(&code2, newvol);
3086 return VOLSERVOLBUSY;
3088 VTRANS_OBJ_LOCK(tt);
3089 tt->iflags = ITBusy;
3091 TSetRxCall_r(tt, NULL, "SplitVolume");
3092 VTRANS_OBJ_UNLOCK(tt);
3094 tt2 = NewTrans(new, V_device(newvol));
3096 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3097 rx_Write(acall, line, strlen(line));
3099 rx_Write(acall, line, 1);
3101 VDetachVolume(&code2, vol);
3102 VDetachVolume(&code2, newvol);
3103 return VOLSERVOLBUSY;
3105 VTRANS_OBJ_LOCK(tt2);
3106 tt2->iflags = ITBusy;
3108 TSetRxCall_r(tt2, NULL, "SplitVolume");
3109 VTRANS_OBJ_UNLOCK(tt2);
3111 code = split_volume(acall, vol, newvol, where, verbose);
3113 VDetachVolume(&code2, vol);
3115 VDetachVolume(&code2, newvol);
3116 DeleteTrans(tt2, 1);
3123 /* GetPartName - map partid (a decimal number) into pname (a string)
3124 * Since for NT we actually want to return the drive name, we map through the
3128 GetPartName(afs_int32 partid, char *pname)
3133 strcpy(pname, "/vicep");
3134 pname[6] = 'a' + partid;
3137 } else if (partid < VOLMAXPARTS) {
3138 strcpy(pname, "/vicep");
3140 pname[6] = 'a' + (partid / 26);
3141 pname[7] = 'a' + (partid % 26);