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/afs_assert.h>
22 #include <afs/prs_fs.h>
26 #include <afs/cellconfig.h>
29 #include <afs/ihandle.h>
31 #include <afs/ntops.h>
33 #include <afs/vnode.h>
34 #include <afs/volume.h>
35 #include <afs/volume_inline.h>
36 #include <afs/partition.h>
38 #include <afs/daemon_com.h>
39 #include <afs/fssync.h>
41 #include "afs/audit.h"
43 #include <afs/afsutil.h>
44 #include <afs/com_err.h>
45 #include <afs/vol_prototypes.h>
46 #include <afs/errors.h>
49 #include "voltrans_inline.h"
52 #include "volser_internal.h"
54 #include "dumpstuff.h"
57 extern struct afsconf_dir *tdir;
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);
116 /* this call unlocks all of the partition locks we've set */
120 struct DiskPartition64 *tp;
121 for (tp = DiskPartitionList; tp; tp = tp->next) {
122 if (tp->lock_fd != INVALID_FD) {
123 OS_CLOSE(tp->lock_fd);
124 tp->lock_fd = INVALID_FD;
135 code = VPFullUnlock_r();
140 /* get partition id from a name */
142 PartitionID(char *aname)
150 return -1; /* unknown */
152 /* otherwise check for vicepa or /vicepa, or just plain "a" */
154 if (!strncmp(aname, "/vicep", 6)) {
155 strncpy(ascii, aname + 6, 2);
157 return -1; /* bad partition name */
158 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
159 * from 0. Do the appropriate conversion */
161 /* one char name, 0..25 */
162 if (ascii[0] < 'a' || ascii[0] > 'z')
163 return -1; /* wrongo */
164 return ascii[0] - 'a';
166 /* two char name, 26 .. <whatever> */
167 if (ascii[0] < 'a' || ascii[0] > 'z')
168 return -1; /* wrongo */
169 if (ascii[1] < 'a' || ascii[1] > 'z')
170 return -1; /* just as bad */
171 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
172 if (code > VOLMAXPARTS)
179 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
183 /* 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 */
184 snprintf(aname, asize, VFORMAT, (unsigned long)avol);
189 ConvertPartition(int apartno, char *aname, int asize)
195 strcpy(aname, "/vicep");
197 aname[6] = 'a' + apartno;
201 aname[6] = 'a' + (apartno / 26);
202 aname[7] = 'a' + (apartno % 26);
208 #ifdef AFS_DEMAND_ATTACH_FS
209 /* normally we should use the regular salvaging functions from the volume
210 * package, but this is a special case where we have a volume ID, but no
211 * volume structure to give the volume package */
213 SalvageUnknownVolume(VolumeId volid, char *part)
217 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
218 afs_printable_uint32_lu(volid), part);
220 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
221 FSYNC_SALVAGE, NULL);
223 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
224 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
228 #endif /* AFS_DEMAND_ATTACH_FS */
230 static struct Volume *
231 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
236 vp = VAttachVolumeByName(ec, partition, name, mode);
238 #ifdef AFS_DEMAND_ATTACH_FS
242 * The fileserver will take care of keeping track of how many
243 * demand-salvages have been performed, and will force the volume to
244 * ERROR if we've done too many. The limit on This loop is just a
245 * failsafe to prevent trying to salvage forever. We want to attempt
246 * attachment at least SALVAGE_COUNT_MAX times, since we want to
247 * avoid prematurely exiting this loop, if we can.
249 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
250 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
251 vp = VAttachVolumeByName(ec, partition, name, mode);
254 if (*ec == VSALVAGING) {
258 #endif /* AFS_DEMAND_ATTACH_FS */
263 static struct Volume *
264 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
269 vp = VAttachVolume(ec, avolid, amode);
271 #ifdef AFS_DEMAND_ATTACH_FS
274 /* see comment above in VAttachVolumeByName_retry */
275 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
276 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
277 vp = VAttachVolume(ec, avolid, amode);
280 if (*ec == VSALVAGING) {
284 #endif /* AFS_DEMAND_ATTACH_FS */
289 /* the only attach function that takes a partition is "...ByName", so we use it */
290 static struct Volume *
291 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
293 char pbuf[30], vbuf[20];
295 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
299 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
304 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
307 /* Adapted from the file server; create a root directory for this volume */
309 ViceCreateRoot(Volume *vp)
312 struct acl_accessList *ACL;
314 Inode inodeNumber, AFS_UNUSED nearInode;
315 struct VnodeDiskObject *vnode;
316 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
322 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
325 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
327 V_pref(vp, nearInode);
329 IH_CREATE(V_linkHandle(vp), V_device(vp),
330 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
332 if (!VALID_INO(inodeNumber)) {
333 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
338 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
339 did.Volume = V_id(vp);
340 did.Vnode = (VnodeId) 1;
343 osi_Assert(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
344 DFlush(); /* flush all modified dir buffers out */
345 DZap(&dir); /* Remove all buffers for this dir */
346 length = afs_dir_Length(&dir); /* Remember size of this directory */
348 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
350 /* build a single entry ACL that gives all rights to system:administrators */
351 /* this section of code assumes that access list format is not going to
354 ACL = VVnodeDiskACL(vnode);
355 ACL->size = sizeof(struct acl_accessList);
356 ACL->version = ACL_ACLVERSION;
360 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
361 ACL->entries[0].rights =
362 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
363 | PRSFS_LOCK | PRSFS_ADMINISTER;
365 vnode->type = vDirectory;
367 vnode->modeBits = 0777;
368 vnode->linkCount = 2;
369 VNDISK_SET_LEN(vnode, length);
370 vnode->uniquifier = 1;
371 V_uniquifier(vp) = vnode->uniquifier + 1;
372 vnode->dataVersion = 1;
373 VNDISK_SET_INO(vnode, inodeNumber);
374 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
378 vnode->vnodeMagic = vcp->magic;
380 IH_INIT(h, vp->device, V_parentId(vp),
381 vp->vnodeIndex[vLarge].handle->ih_ino);
383 osi_Assert(fdP != NULL);
384 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
385 osi_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
386 FDH_REALLYCLOSE(fdP);
388 VNDISK_GET_LEN(length, vnode);
389 V_diskused(vp) = nBlocks(length);
396 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
400 struct diskPartition64 *dp = (struct diskPartition64 *)
401 malloc(sizeof(struct diskPartition64));
403 code = VolPartitionInfo(acid, pname, dp);
405 strncpy(partition->name, dp->name, 32);
406 strncpy(partition->devName, dp->devName, 32);
407 partition->lock_fd = dp->lock_fd;
408 partition->free=RoundInt64ToInt32(dp->free);
409 partition->minFree=RoundInt64ToInt32(dp->minFree);
412 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
417 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
422 code = VolPartitionInfo(acid, pname, partition);
423 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
428 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
431 struct DiskPartition64 *dp;
434 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
437 dp = VGetPartition(pname, 0);
439 strncpy(partition->name, dp->name, 32);
440 strncpy(partition->devName, dp->devName, 32);
441 partition->lock_fd = (int)dp->lock_fd;
442 partition->free = dp->free;
443 partition->minFree = dp->totalUsable;
446 return VOLSERILLEGAL_PARTITION;
449 /* obliterate a volume completely, and slowly. */
451 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
455 code = VolNukeVolume(acid, apartID, avolID);
456 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
461 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
468 char caller[MAXKTCNAMELEN];
470 /* check for access */
471 if (!afsconf_SuperUser(tdir, acid, caller))
472 return VOLSERBAD_ACCESS;
474 Log("%s is executing VolNukeVolume %u\n", caller, avolID);
476 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
478 /* we first try to attach the volume in update mode, so that the file
479 * server doesn't try to use it (and abort) while (or after) we delete it.
480 * If we don't get the volume, that's fine, too. We just won't put it back.
482 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
483 code = nuke(partName, avolID);
485 VDetachVolume(&verror, tvp);
489 /* create a new volume, with name aname, on the specified partition (1..n)
490 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
491 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
492 * for the volume id (useful for things like volume restore).
493 * Return the new volume id in *avolid.
496 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
497 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
503 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
504 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
505 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
511 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
512 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
517 Error junk; /* discardable error code */
519 afs_int32 doCreateRoot = 1;
520 struct volser_trans *tt;
522 char caller[MAXKTCNAMELEN];
524 if (strlen(aname) > 31)
525 return VOLSERBADNAME;
526 if (!afsconf_SuperUser(tdir, acid, caller))
527 return VOLSERBAD_ACCESS;
529 Log("%s is executing CreateVolume '%s'\n", caller, aname);
530 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
531 return error; /*a standard unix error */
532 if (atype != readwriteVolume && atype != readonlyVolume
533 && atype != backupVolume)
535 if ((volumeID = *avolid) == 0) {
537 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
541 if ((aparent == volumeID) && (atype == readwriteVolume)) {
546 tt = NewTrans(volumeID, apart);
548 Log("1 createvolume: failed to create trans\n");
549 return VOLSERVOLBUSY; /* volume already busy! */
551 vp = VCreateVolume(&error, ppath, volumeID, aparent);
553 #ifdef AFS_DEMAND_ATTACH_FS
554 if (error != VVOLEXISTS && error != EXDEV) {
555 SalvageUnknownVolume(volumeID, ppath);
558 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
563 V_uniquifier(vp) = 1;
564 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
565 V_inService(vp) = V_blessed(vp) = 1;
567 AssignVolumeName(&V_disk(vp), aname, 0);
569 error = ViceCreateRoot(vp);
571 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
572 "error code %u\n", (unsigned)error);
574 V_needsSalvaged(vp) = 1;
575 VDetachVolume(&junk, vp);
579 V_destroyMe(vp) = DESTROY_ME;
581 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
582 VUpdateVolume(&error, vp);
584 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
587 VDetachVolume(&junk, vp); /* rather return the real error code */
593 TSetRxCall_r(tt, acid, "CreateVolume");
594 VTRANS_OBJ_UNLOCK(tt);
595 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
598 return VOLSERTRELE_ERROR;
602 /* delete the volume associated with this transaction */
604 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
608 code = VolDeleteVolume(acid, atrans);
609 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
614 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
616 struct volser_trans *tt;
618 char caller[MAXKTCNAMELEN];
620 if (!afsconf_SuperUser(tdir, acid, caller))
621 return VOLSERBAD_ACCESS;
622 tt = FindTrans(atrans);
625 if (tt->vflags & VTDeleted) {
626 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
631 Log("%s is executing Delete Volume %u\n", caller, tt->volid);
632 TSetRxCall(tt, acid, "DeleteVolume");
633 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
634 V_destroyMe(tt->volume) = DESTROY_ME;
635 if (tt->volume->needsPutBack) {
636 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
639 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
641 VTRANS_OBJ_UNLOCK(tt);
643 return VOLSERTRELE_ERROR;
645 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
646 return 0; /* vpurgevolume doesn't set an error code */
649 /* make a clone of the volume associated with atrans, possibly giving it a new
650 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
651 * for the clone's id). The new clone is given the name newName. Finally,
652 * due to efficiency considerations, if purgeId is non-zero, we purge that
653 * volume when doing the clone operation. This may be useful when making
654 * new backup volumes, for instance since the net result of a clone and a
655 * purge generally leaves many inode ref counts the same, while doing them
656 * separately would result in far more iincs and idecs being peformed
657 * (and they are slow operations).
659 /* for efficiency reasons, sometimes faster to piggyback a purge here */
661 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
662 afs_int32 newType, char *newName, afs_uint32 *newNumber)
666 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
667 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
668 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
674 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
675 afs_int32 newType, char *newName, afs_uint32 *newNumber)
678 struct Volume *originalvp, *purgevp, *newvp;
680 struct volser_trans *tt, *ttc;
681 char caller[MAXKTCNAMELEN];
682 #ifdef AFS_DEMAND_ATTACH_FS
683 struct Volume *salv_vp = NULL;
686 if (strlen(newName) > 31)
687 return VOLSERBADNAME;
688 if (!afsconf_SuperUser(tdir, acid, caller))
689 return VOLSERBAD_ACCESS; /*not a super user */
691 Log("%s is executing Clone Volume new name=%s\n", caller, newName);
693 originalvp = (Volume *) 0;
694 purgevp = (Volume *) 0;
695 newvp = (Volume *) 0;
696 tt = ttc = (struct volser_trans *)0;
698 if (!newNumber || !*newNumber) {
699 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
704 if (newType != readonlyVolume && newType != backupVolume)
706 tt = FindTrans(atrans);
709 if (tt->vflags & VTDeleted) {
710 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
714 ttc = NewTrans(newId, tt->partition);
715 if (!ttc) { /* someone is messing with the clone already */
717 return VOLSERVOLBUSY;
719 TSetRxCall(tt, acid, "Clone");
723 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
725 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
731 originalvp = tt->volume;
732 if ((V_type(originalvp) == backupVolume)
733 || (V_type(originalvp) == readonlyVolume)) {
734 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
738 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
739 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
745 if (originalvp->device != purgevp->device) {
746 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
750 if (V_type(purgevp) != readonlyVolume) {
751 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
755 if (V_type(originalvp) == readonlyVolume
756 && V_parentId(originalvp) != V_parentId(purgevp)) {
757 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
761 if (V_type(originalvp) == readwriteVolume
762 && tt->volid != V_parentId(purgevp)) {
763 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
770 #ifdef AFS_DEMAND_ATTACH_FS
771 salv_vp = originalvp;
775 VCreateVolume(&error, originalvp->partition->name, newId,
776 V_parentId(originalvp));
778 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
779 newvp = (Volume *) 0;
782 if (newType == readonlyVolume)
783 V_cloneId(originalvp) = newId;
784 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
787 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
788 CloneVolume(&error, originalvp, newvp, purgevp);
789 purgevp = NULL; /* clone releases it, maybe even if error */
791 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
795 if (newType == readonlyVolume) {
796 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
797 V_type(newvp) = readonlyVolume;
798 } else if (newType == backupVolume) {
799 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
800 V_type(newvp) = backupVolume;
801 V_backupId(originalvp) = newId;
803 strcpy(newvp->header->diskstuff.name, newName);
804 V_creationDate(newvp) = V_copyDate(newvp);
805 ClearVolumeStats(&V_disk(newvp));
806 V_destroyMe(newvp) = DESTROY_ME;
807 V_inService(newvp) = 0;
808 if (newType == backupVolume) {
809 V_backupDate(originalvp) = V_copyDate(newvp);
810 V_backupDate(newvp) = V_copyDate(newvp);
813 VUpdateVolume(&error, newvp);
815 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
819 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
821 VUpdateVolume(&error, originalvp);
823 Log("1 Volser: Clone: original update %u\n", error);
828 #ifdef AFS_DEMAND_ATTACH_FS
832 tt = (struct volser_trans *)0;
833 error = VOLSERTRELE_ERROR;
841 VDetachVolume(&code, purgevp);
843 VDetachVolume(&code, newvp);
850 #ifdef AFS_DEMAND_ATTACH_FS
851 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
852 V_needsSalvaged(salv_vp) = 1;
854 #endif /* AFS_DEMAND_ATTACH_FS */
858 /* reclone this volume into the specified id */
860 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
864 code = VolReClone(acid, atrans, cloneId);
865 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
871 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
873 struct Volume *originalvp, *clonevp;
876 struct volser_trans *tt, *ttc;
877 char caller[MAXKTCNAMELEN];
879 /*not a super user */
880 if (!afsconf_SuperUser(tdir, acid, caller))
881 return VOLSERBAD_ACCESS;
883 Log("%s is executing Reclone Volume %u\n", caller, cloneId);
885 clonevp = originalvp = (Volume *) 0;
886 tt = (struct volser_trans *)0;
888 tt = FindTrans(atrans);
891 if (tt->vflags & VTDeleted) {
892 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
896 ttc = NewTrans(cloneId, tt->partition);
897 if (!ttc) { /* someone is messing with the clone already */
899 return VOLSERVOLBUSY;
901 TSetRxCall(tt, acid, "ReClone");
903 originalvp = tt->volume;
904 if ((V_type(originalvp) == backupVolume)
905 || (V_type(originalvp) == readonlyVolume)) {
906 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
910 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
911 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
917 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
919 Log("1 Volser: can't attach clone %d\n", cloneId);
923 newType = V_type(clonevp); /* type of the new volume */
925 if (originalvp->device != clonevp->device) {
926 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
931 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
932 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
936 if (V_type(originalvp) == readonlyVolume
937 && V_parentId(originalvp) != V_parentId(clonevp)) {
938 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
942 if (V_type(originalvp) == readwriteVolume
943 && tt->volid != V_parentId(clonevp)) {
944 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
950 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
952 CloneVolume(&error, originalvp, clonevp, clonevp);
954 Log("1 Volser: Clone: reclone operation failed with code %d\n",
960 /* fix up volume name and type, CloneVolume just propagated RW's */
961 if (newType == readonlyVolume) {
962 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
963 V_type(clonevp) = readonlyVolume;
964 } else if (newType == backupVolume) {
965 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
966 V_type(clonevp) = backupVolume;
967 V_backupId(originalvp) = cloneId;
969 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
971 /* pretend recloned volume is a totally new instance */
972 V_copyDate(clonevp) = time(0);
973 V_creationDate(clonevp) = V_copyDate(clonevp);
974 ClearVolumeStats(&V_disk(clonevp));
975 V_destroyMe(clonevp) = 0;
976 V_inService(clonevp) = 0;
977 if (newType == backupVolume) {
978 V_backupDate(originalvp) = V_copyDate(clonevp);
979 V_backupDate(clonevp) = V_copyDate(clonevp);
981 V_inUse(clonevp) = 0;
982 VUpdateVolume(&error, clonevp);
984 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
988 /* VUpdateVolume succeeded. Mark it in service so there's no window
989 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
990 * specialStatus; this is a reclone and this volume started online
992 V_inService(clonevp) = 1;
993 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
995 VUpdateVolume(&error, originalvp);
997 Log("1 Volser: Clone: original update %u\n", error);
1003 tt = (struct volser_trans *)0;
1004 error = VOLSERTRELE_ERROR;
1008 DeleteTrans(ttc, 1);
1011 struct DiskPartition64 *tpartp = originalvp->partition;
1012 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1018 VDetachVolume(&code, clonevp);
1024 DeleteTrans(ttc, 1);
1028 /* create a new transaction, associated with volume and partition. Type of
1029 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1030 * See volser.h for definition of iflags (the constants are named IT*).
1033 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1034 afs_int32 iflags, afs_int32 *ttid)
1038 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1039 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1045 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1046 afs_int32 iflags, afs_int32 *ttid)
1048 struct volser_trans *tt;
1053 char caller[MAXKTCNAMELEN];
1055 if (!afsconf_SuperUser(tdir, acid, caller))
1056 return VOLSERBAD_ACCESS; /*not a super user */
1057 if (iflags & ITCreate)
1059 else if (iflags & ITBusy)
1061 else if (iflags & ITReadOnly)
1063 else if (iflags & ITOffline)
1066 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1071 tt = NewTrans(volume, partition);
1073 /* can't create a transaction? put the volume back */
1074 Log("1 transcreate: can't create transaction\n");
1075 return VOLSERVOLBUSY;
1077 tv = XAttachVolume(&error, volume, partition, mode);
1081 VDetachVolume(&code, tv);
1085 VTRANS_OBJ_LOCK(tt);
1088 tt->iflags = iflags;
1090 TSetRxCall_r(tt, NULL, "TransCreate");
1091 VTRANS_OBJ_UNLOCK(tt);
1093 return VOLSERTRELE_ERROR;
1098 /* using aindex as a 0-based index, return the aindex'th volume on this server
1099 * Both the volume number and partition number (one-based) are returned.
1102 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1107 code = VolGetNthVolume(acid, aindex, avolume, apart);
1108 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1113 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1116 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1120 /* return the volume flags (VT* constants in volser.h) associated with this
1124 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1128 code = VolGetFlags(acid, atid, aflags);
1129 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1134 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1136 struct volser_trans *tt;
1138 tt = FindTrans(atid);
1141 if (tt->vflags & VTDeleted) {
1142 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1147 TSetRxCall(tt, acid, "GetFlags");
1148 *aflags = tt->vflags;
1151 return VOLSERTRELE_ERROR;
1156 /* Change the volume flags (VT* constants in volser.h) associated with this
1157 * transaction. Effects take place immediately on volume, although volume
1158 * remains attached as usual by the transaction.
1161 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1165 code = VolSetFlags(acid, atid, aflags);
1166 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1172 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1174 struct volser_trans *tt;
1177 char caller[MAXKTCNAMELEN];
1179 if (!afsconf_SuperUser(tdir, acid, caller))
1180 return VOLSERBAD_ACCESS; /*not a super user */
1181 /* find the trans */
1182 tt = FindTrans(atid);
1185 if (tt->vflags & VTDeleted) {
1186 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1191 TSetRxCall(tt, acid, "SetFlags");
1192 vp = tt->volume; /* pull volume out of transaction */
1194 /* check if we're allowed to make any updates */
1195 if (tt->iflags & ITReadOnly) {
1200 /* handle delete-on-salvage flag */
1201 if (aflags & VTDeleteOnSalvage) {
1202 V_destroyMe(tt->volume) = DESTROY_ME;
1204 V_destroyMe(tt->volume) = 0;
1207 if (aflags & VTOutOfService) {
1208 V_inService(vp) = 0;
1210 V_inService(vp) = 1;
1212 VUpdateVolume(&error, vp);
1213 VTRANS_OBJ_LOCK(tt);
1214 tt->vflags = aflags;
1216 VTRANS_OBJ_UNLOCK(tt);
1217 if (TRELE(tt) && !error)
1218 return VOLSERTRELE_ERROR;
1223 /* dumpS the volume associated with a particular transaction from a particular
1224 * date. Send the dump to a different transaction (destTrans) on the server
1225 * specified by the destServer structure.
1228 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1229 struct destServer *destination, afs_int32 destTrans,
1230 struct restoreCookie *cookie)
1235 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1236 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1237 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1242 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1243 struct destServer *destination, afs_int32 destTrans,
1244 struct restoreCookie *cookie)
1246 struct volser_trans *tt;
1248 struct rx_connection *tcon;
1249 struct rx_call *tcall;
1251 struct rx_securityClass *securityObject;
1252 afs_int32 securityIndex;
1253 char caller[MAXKTCNAMELEN];
1255 if (!afsconf_SuperUser(tdir, acid, caller))
1256 return VOLSERBAD_ACCESS; /*not a super user */
1257 /* initialize things */
1258 tcon = (struct rx_connection *)0;
1259 tt = (struct volser_trans *)0;
1261 /* find the local transaction */
1262 tt = FindTrans(fromTrans);
1265 if (tt->vflags & VTDeleted) {
1266 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1271 TSetRxCall(tt, NULL, "Forward");
1273 /* get auth info for the this connection (uses afs from ticket file) */
1274 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1280 /* make an rpc connection to the other server */
1282 rx_NewConnection(htonl(destination->destHost),
1283 htons(destination->destPort), VOLSERVICE_ID,
1284 securityObject, securityIndex);
1290 tcall = rx_NewCall(tcon);
1291 TSetRxCall(tt, tcall, "Forward");
1292 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1293 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1298 /* these next calls implictly call rx_Write when writing out data */
1299 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1302 EndAFSVolRestore(tcall); /* probably doesn't do much */
1304 code = rx_EndCall(tcall, 0);
1305 rx_DestroyConnection(tcon); /* done with the connection */
1310 return VOLSERTRELE_ERROR;
1316 (void)rx_EndCall(tcall, 0);
1317 rx_DestroyConnection(tcon);
1326 /* Start a dump and send it to multiple places simultaneously.
1327 * If this returns an error (eg, return ENOENT), it means that
1328 * none of the releases worked. If this returns 0, that means
1329 * that one or more of the releases worked, and the caller has
1330 * to examine the results array to see which one(s).
1331 * This will only do EITHER incremental or full, not both, so it's
1332 * the caller's responsibility to be sure that all the destinations
1333 * need just an incremental (and from the same time), if that's
1337 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1338 fromDate, manyDests *destinations, afs_int32 spare,
1339 struct restoreCookie *cookie, manyResults *results)
1341 afs_int32 securityIndex;
1342 struct rx_securityClass *securityObject;
1343 char caller[MAXKTCNAMELEN];
1344 struct volser_trans *tt;
1345 afs_int32 ec, code, *codes;
1346 struct rx_connection **tcons;
1347 struct rx_call **tcalls;
1349 int i, is_incremental;
1352 memset(results, 0, sizeof(manyResults));
1353 i = results->manyResults_len = destinations->manyDests_len;
1354 results->manyResults_val = codes =
1355 (afs_int32 *) malloc(i * sizeof(afs_int32));
1357 if (!results || !results->manyResults_val)
1360 if (!afsconf_SuperUser(tdir, acid, caller))
1361 return VOLSERBAD_ACCESS; /*not a super user */
1362 tt = FindTrans(fromTrans);
1365 if (tt->vflags & VTDeleted) {
1366 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1371 TSetRxCall(tt, NULL, "ForwardMulti");
1373 /* (fromDate == 0) ==> full dump */
1374 is_incremental = (fromDate ? 1 : 0);
1377 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1381 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1387 /* get auth info for this connection (uses afs from ticket file) */
1388 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1390 goto fail; /* in order to audit each failure */
1393 /* make connections to all the other servers */
1394 for (i = 0; i < destinations->manyDests_len; i++) {
1395 struct replica *dest = &(destinations->manyDests_val[i]);
1397 rx_NewConnection(htonl(dest->server.destHost),
1398 htons(dest->server.destPort), VOLSERVICE_ID,
1399 securityObject, securityIndex);
1401 codes[i] = ENOTCONN;
1403 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1404 codes[i] = ENOTCONN;
1407 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1410 (void)rx_EndCall(tcalls[i], 0);
1412 rx_DestroyConnection(tcons[i]);
1419 /* these next calls implictly call rx_Write when writing out data */
1420 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1424 for (i--; i >= 0; i--) {
1425 struct replica *dest = &(destinations->manyDests_val[i]);
1427 if (!code && tcalls[i] && !codes[i]) {
1428 EndAFSVolRestore(tcalls[i]);
1431 ec = rx_EndCall(tcalls[i], 0);
1436 rx_DestroyConnection(tcons[i]); /* done with the connection */
1439 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1440 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1441 dest->trans, AUD_END);
1448 if (TRELE(tt) && !code) /* return the first code if it's set */
1449 return VOLSERTRELE_ERROR;
1456 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1460 code = VolDump(acid, fromTrans, fromDate, 0);
1461 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1466 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1471 code = VolDump(acid, fromTrans, fromDate, flags);
1472 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1477 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1481 struct volser_trans *tt;
1482 char caller[MAXKTCNAMELEN];
1484 if (!afsconf_SuperUser(tdir, acid, caller))
1485 return VOLSERBAD_ACCESS; /*not a super user */
1486 tt = FindTrans(fromTrans);
1489 if (tt->vflags & VTDeleted) {
1490 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1494 TSetRxCall(tt, acid, "Dump");
1495 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1496 ? 0 : 1); /* squirt out the volume's data, too */
1505 return VOLSERTRELE_ERROR;
1511 * Ha! No more helper process!
1514 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1515 struct restoreCookie *cookie)
1519 code = VolRestore(acid, atrans, aflags, cookie);
1520 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1525 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1526 struct restoreCookie *cookie)
1528 struct volser_trans *tt;
1529 afs_int32 code, tcode;
1530 char caller[MAXKTCNAMELEN];
1532 if (!afsconf_SuperUser(tdir, acid, caller))
1533 return VOLSERBAD_ACCESS; /*not a super user */
1534 tt = FindTrans(atrans);
1537 if (tt->vflags & VTDeleted) {
1538 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1542 TSetRxCall(tt, acid, "Restore");
1544 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1546 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1547 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1551 return (code ? code : tcode);
1554 /* end a transaction, returning the transaction's final error code in rcode */
1556 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1560 code = VolEndTrans(acid, destTrans, rcode);
1561 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1566 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1568 struct volser_trans *tt;
1569 char caller[MAXKTCNAMELEN];
1571 if (!afsconf_SuperUser(tdir, acid, caller))
1572 return VOLSERBAD_ACCESS; /*not a super user */
1573 tt = FindTrans(destTrans);
1577 *rcode = tt->returnCode;
1578 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1584 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1588 code = VolSetForwarding(acid, atid, anewsite);
1589 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1590 htonl(anewsite), AUD_END);
1595 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1597 struct volser_trans *tt;
1598 char caller[MAXKTCNAMELEN];
1601 if (!afsconf_SuperUser(tdir, acid, caller))
1602 return VOLSERBAD_ACCESS; /*not a super user */
1603 tt = FindTrans(atid);
1606 if (tt->vflags & VTDeleted) {
1607 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1612 TSetRxCall(tt, acid, "SetForwarding");
1613 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1616 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1619 return VOLSERTRELE_ERROR;
1625 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1626 struct volser_status *astatus)
1630 code = VolGetStatus(acid, atrans, astatus);
1631 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1636 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1637 struct volser_status *astatus)
1640 struct VolumeDiskData *td;
1641 struct volser_trans *tt;
1644 tt = FindTrans(atrans);
1647 if (tt->vflags & VTDeleted) {
1648 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1653 TSetRxCall(tt, acid, "GetStatus");
1661 td = &tv->header->diskstuff;
1662 astatus->volID = td->id;
1663 astatus->nextUnique = td->uniquifier;
1664 astatus->type = td->type;
1665 astatus->parentID = td->parentId;
1666 astatus->cloneID = td->cloneId;
1667 astatus->backupID = td->backupId;
1668 astatus->restoredFromID = td->restoredFromId;
1669 astatus->maxQuota = td->maxquota;
1670 astatus->minQuota = td->minquota;
1671 astatus->owner = td->owner;
1672 astatus->creationDate = td->creationDate;
1673 astatus->accessDate = td->accessDate;
1674 astatus->updateDate = td->updateDate;
1675 astatus->expirationDate = td->expirationDate;
1676 astatus->backupDate = td->backupDate;
1677 astatus->copyDate = td->copyDate;
1680 return VOLSERTRELE_ERROR;
1686 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1687 struct volintInfo *astatus)
1691 code = VolSetInfo(acid, atrans, astatus);
1692 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1697 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1698 struct volintInfo *astatus)
1701 struct VolumeDiskData *td;
1702 struct volser_trans *tt;
1703 char caller[MAXKTCNAMELEN];
1706 if (!afsconf_SuperUser(tdir, acid, caller))
1707 return VOLSERBAD_ACCESS; /*not a super user */
1708 tt = FindTrans(atrans);
1711 if (tt->vflags & VTDeleted) {
1712 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1716 TSetRxCall(tt, acid, "SetStatus");
1724 td = &tv->header->diskstuff;
1726 * Add more fields as necessary
1728 if (astatus->maxquota != -1)
1729 td->maxquota = astatus->maxquota;
1730 if (astatus->dayUse != -1)
1731 td->dayUse = astatus->dayUse;
1732 if (astatus->creationDate != -1)
1733 td->creationDate = astatus->creationDate;
1734 if (astatus->updateDate != -1)
1735 td->updateDate = astatus->updateDate;
1736 if (astatus->spare2 != -1)
1737 td->volUpdateCounter = (unsigned int)astatus->spare2;
1738 VUpdateVolume(&error, tv);
1741 return VOLSERTRELE_ERROR;
1747 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1751 code = VolGetName(acid, atrans, aname);
1752 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1757 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1760 struct VolumeDiskData *td;
1761 struct volser_trans *tt;
1764 /* We need to at least fill it in */
1765 *aname = (char *)malloc(1);
1768 tt = FindTrans(atrans);
1771 if (tt->vflags & VTDeleted) {
1772 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1776 TSetRxCall(tt, acid, "GetName");
1784 td = &tv->header->diskstuff;
1785 len = strlen(td->name) + 1; /* don't forget the null */
1791 *aname = (char *)realloc(*aname, len);
1792 strcpy(*aname, td->name);
1795 return VOLSERTRELE_ERROR;
1800 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1803 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1804 afs_uint32 parentId, afs_uint32 cloneId)
1810 /*return a list of all partitions on the server. The non mounted
1811 *partitions are returned as -1 in the corresponding slot in partIds*/
1813 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1817 code = VolListPartitions(acid, partIds);
1818 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1823 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1828 strcpy(namehead, "/vicep"); /*7 including null terminator */
1830 /* Just return attached partitions. */
1832 for (i = 0; i < 26; i++) {
1833 namehead[6] = i + 'a';
1834 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1840 /*return a list of all partitions on the server. The non mounted
1841 *partitions are returned as -1 in the corresponding slot in partIds*/
1843 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1847 code = XVolListPartitions(acid, pEntries);
1848 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1853 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1856 struct partList partList;
1857 struct DiskPartition64 *dp;
1860 strcpy(namehead, "/vicep"); /*7 including null terminator */
1862 /* Only report attached partitions */
1863 for (i = 0; i < VOLMAXPARTS; i++) {
1864 #ifdef AFS_DEMAND_ATTACH_FS
1865 dp = VGetPartitionById(i, 0);
1868 namehead[6] = i + 'a';
1874 namehead[6] = 'a' + (k / 26);
1875 namehead[7] = 'a' + (k % 26);
1878 dp = VGetPartition(namehead, 0);
1881 partList.partId[j++] = i;
1884 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1885 if (!pEntries->partEntries_val)
1887 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1889 pEntries->partEntries_len = j;
1891 pEntries->partEntries_val = NULL;
1892 pEntries->partEntries_len = 0;
1898 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1900 ExtractVolId(char vname[])
1903 char name[VOLSER_MAXVOLNAME + 1];
1905 strcpy(name, vname);
1907 while (name[i] == 'V' || name[i] == '0')
1910 name[11] = '\0'; /* smash the "." */
1911 return (atol(&name[i]));
1914 /*return the name of the next volume header in the directory associated with dirp and dp.
1915 *the volume id is returned in volid, and volume header name is returned in volname*/
1917 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1921 dp = readdir(dirp); /*read next entry in the directory */
1923 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1924 *volid = ExtractVolId(dp->d_name);
1925 strcpy(volname, dp->d_name);
1926 return 0; /*return the name of the file representing a volume */
1928 strcpy(volname, "");
1929 return 0; /*volname doesnot represent a volume */
1932 strcpy(volname, "EOD");
1933 return 0; /*end of directory */
1939 * volint vol info structure type.
1942 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1943 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1944 } volint_info_type_t;
1947 * handle to various on-wire vol info types.
1950 volint_info_type_t volinfo_type;
1956 } volint_info_handle_t;
1959 * store value to a field at the appropriate location in on-wire structure.
1961 #define VOLINT_INFO_STORE(handle, name, val) \
1963 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1964 (handle)->volinfo_ptr.base->name = (val); \
1966 (handle)->volinfo_ptr.ext->name = (val); \
1971 * get pointer to appropriate offset of field in on-wire structure.
1973 #define VOLINT_INFO_PTR(handle, name) \
1974 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1975 &((handle)->volinfo_ptr.base->name) : \
1976 &((handle)->volinfo_ptr.ext->name))
1979 * fill in appropriate type of on-wire volume metadata structure.
1981 * @param vp pointer to volume object
1982 * @param handle pointer to wire format handle object
1984 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1985 * @pre handle object must have a valid pointer and enumeration value
1987 * @note passing a NULL value for vp means that the fileserver doesn't
1988 * know about this particular volume, thus implying it is offline.
1990 * @return operation status
1995 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1997 unsigned int numStatBytes, now;
1998 struct VolumeDiskData *hdr = &vp->header->diskstuff;
2000 /*read in the relevant info */
2001 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2002 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
2003 VOLINT_INFO_STORE(handle, volid, hdr->id);
2004 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2005 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2006 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2007 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2008 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2009 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2010 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2011 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2012 now = FT_ApproxTime();
2013 if ((now - hdr->dayUseDate) > OneDay) {
2014 VOLINT_INFO_STORE(handle, dayUse, 0);
2016 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2018 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2019 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2020 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2021 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2023 #ifdef AFS_DEMAND_ATTACH_FS
2025 * for DAFS, we "lie" about volume state --
2026 * instead of returning the raw state from the disk header,
2027 * we compute state based upon the fileserver's internal
2028 * in-core state enumeration value reported to us via fssync,
2029 * along with the blessed and inService flags from the header.
2030 * -- tkeiser 11/27/2007
2033 /* Conditions that offline status is based on:
2034 volume is unattached state
2035 volume state is in (one of several error states)
2036 volume not in service
2037 volume is not marked as blessed (not on hold)
2038 volume in salvage req. state
2039 volume needsSalvaged
2040 next op would set volume offline
2041 next op would not leave volume online (based on several conditions)
2044 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2045 VIsErrorState(V_attachState(vp)) ||
2048 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2049 hdr->needsSalvaged ||
2050 (vp->pending_vol_op &&
2051 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2052 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2055 VOLINT_INFO_STORE(handle, inUse, 0);
2057 VOLINT_INFO_STORE(handle, inUse, 1);
2060 /* offline status based on program type, where != fileServer enum (1) is offline */
2061 if (hdr->inUse == fileServer) {
2062 VOLINT_INFO_STORE(handle, inUse, 1);
2064 VOLINT_INFO_STORE(handle, inUse, 0);
2069 switch(handle->volinfo_type) {
2070 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2071 case VOLINT_INFO_TYPE_BASE:
2073 #ifdef AFS_DEMAND_ATTACH_FS
2074 /* see comment above where we set inUse bit */
2075 if (hdr->needsSalvaged ||
2076 (vp && VIsErrorState(V_attachState(vp)))) {
2077 handle->volinfo_ptr.base->needsSalvaged = 1;
2079 handle->volinfo_ptr.base->needsSalvaged = 0;
2082 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2084 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2085 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2086 handle->volinfo_ptr.base->spare1 =
2087 (long)hdr->weekUse[0] +
2088 (long)hdr->weekUse[1] +
2089 (long)hdr->weekUse[2] +
2090 (long)hdr->weekUse[3] +
2091 (long)hdr->weekUse[4] +
2092 (long)hdr->weekUse[5] +
2093 (long)hdr->weekUse[6];
2094 handle->volinfo_ptr.base->flags = 0;
2095 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2096 handle->volinfo_ptr.base->spare3 = 0;
2100 case VOLINT_INFO_TYPE_EXT:
2102 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2103 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2106 * Copy out the stat fields in a single operation.
2108 if ((now - hdr->dayUseDate) > OneDay) {
2109 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2112 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2113 (char *)&(hdr->stat_reads[0]),
2122 #ifdef AFS_DEMAND_ATTACH_FS
2125 * get struct Volume out of the fileserver.
2127 * @param[in] volumeId volumeId for which we want state information
2128 * @param[in] pname partition name string
2129 * @param[inout] vp pointer to pointer to Volume object which
2130 * will be populated (see note)
2132 * @return operation status
2134 * @retval non-zero failure
2136 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2141 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2146 res.hdr.response_len = sizeof(res.hdr);
2147 res.payload.buf = *vp;
2148 res.payload.len = sizeof(Volume);
2150 code = FSYNC_VolOp(volumeId,
2156 if (code != SYNC_OK) {
2157 switch (res.hdr.reason) {
2158 case FSYNC_WRONG_PART:
2159 case FSYNC_UNKNOWN_VOLID:
2172 * mode of volume list operation.
2175 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2176 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2177 } vol_info_list_mode_t;
2180 * abstract interface to populate wire-format volume metadata structures.
2182 * @param[in] partId partition id
2183 * @param[in] volumeId volume id
2184 * @param[in] pname partition name
2185 * @param[in] volname volume file name
2186 * @param[in] handle handle to on-wire volume metadata object
2187 * @param[in] mode listing mode
2189 * @return operation status
2191 * @retval -2 DESTROY_ME flag is set
2192 * @retval -1 general failure; some data filled in
2193 * @retval -3 couldn't create vtrans; some data filled in
2196 GetVolInfo(afs_uint32 partId,
2197 afs_uint32 volumeId,
2200 volint_info_handle_t * handle,
2201 vol_info_list_mode_t mode)
2205 struct volser_trans *ttc = NULL;
2206 struct Volume *fill_tv, *tv = NULL;
2207 #ifdef AFS_DEMAND_ATTACH_FS
2208 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2209 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2210 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2211 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2213 /* Set up response handle for pending_vol_op */
2214 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2215 fs_res.payload.buf = fs_res_buf;
2216 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2219 ttc = NewTrans(volumeId, partId);
2222 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2223 VOLINT_INFO_STORE(handle, volid, volumeId);
2227 /* Get volume from volserver */
2228 if (mode == VOL_INFO_LIST_MULTIPLE)
2229 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2231 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2233 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2234 volumeId, pname, volname, error);
2239 * please note that destroyMe and needsSalvaged checks used to be ordered
2240 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2241 * more correct to check destroyMe before needsSalvaged.
2242 * -- tkeiser 11/28/2007
2245 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2247 case VOL_INFO_LIST_MULTIPLE:
2251 case VOL_INFO_LIST_SINGLE:
2252 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2253 volumeId, pname, volname);
2260 if (tv->header->diskstuff.needsSalvaged) {
2261 /*this volume will be salvaged */
2262 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2263 volumeId, pname, volname);
2266 #ifdef AFS_DEMAND_ATTACH_FS
2267 /* If using DAFS, get volume from fsserver */
2268 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2273 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2274 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2275 /* If we if the pending vol op */
2276 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2277 fs_tv->pending_vol_op=&pending_vol_op_res;
2279 fs_tv->pending_vol_op=NULL;
2282 /* populate the header from the volserver copy */
2283 fs_tv->header=tv->header;
2285 /* When using DAFS, use the fs volume info, populated with required structures */
2288 /* When not using DAFS, just use the local volume info */
2292 /* ok, we have all the data we need; fill in the on-wire struct */
2293 code = FillVolInfo(fill_tv, handle);
2297 VOLINT_INFO_STORE(handle, status, 0);
2298 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2299 VOLINT_INFO_STORE(handle, volid, volumeId);
2302 VDetachVolume(&error, tv);
2305 VOLINT_INFO_STORE(handle, status, 0);
2306 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2307 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2308 volumeId, pname, volname);
2312 DeleteTrans(ttc, 1);
2319 /*return the header information about the <volid> */
2321 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2322 afs_uint32 volumeId, volEntries *volumeInfo)
2326 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2327 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2332 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2333 afs_uint32 volumeId, volEntries *volumeInfo)
2335 struct DiskPartition64 *partP;
2336 char pname[9], volname[20];
2341 volint_info_handle_t handle;
2343 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2344 if (!volumeInfo->volEntries_val)
2346 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2348 volumeInfo->volEntries_len = 1;
2349 if (GetPartName(partid, pname))
2350 return VOLSERILLEGAL_PARTITION;
2351 if (!(partP = VGetPartition(pname, 0)))
2352 return VOLSERILLEGAL_PARTITION;
2353 dirp = opendir(VPartitionPath(partP));
2355 return VOLSERILLEGAL_PARTITION;
2357 strcpy(volname, "");
2359 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2361 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2362 GetNextVol(dirp, volname, &volid);
2363 continue; /*back to while loop */
2366 if (volid == volumeId) { /*copy other things too */
2371 GetNextVol(dirp, volname, &volid);
2375 #ifndef AFS_PTHREAD_ENV
2376 IOMGR_Poll(); /*make sure that the client does not time out */
2379 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2380 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2382 code = GetVolInfo(partid,
2387 VOL_INFO_LIST_SINGLE);
2392 return code ? ENODEV: 0;
2397 /*------------------------------------------------------------------------
2398 * EXPORTED SAFSVolXListOneVolume
2401 * Returns extended info on volume a_volID on partition a_partID.
2404 * a_rxCidP : Pointer to the Rx call we're performing.
2405 * a_partID : Partition for which we want the extended list.
2406 * a_volID : Volume ID we wish to know about.
2407 * a_volumeXInfoP : Ptr to the extended info blob.
2410 * 0 Successful operation
2411 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2414 * Nothing interesting.
2418 *------------------------------------------------------------------------*/
2421 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2422 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2426 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2427 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2432 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2433 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2434 { /*SAFSVolXListOneVolume */
2436 struct DiskPartition64 *partP; /*Ptr to partition */
2437 char pname[9], volname[20]; /*Partition, volume names */
2438 DIR *dirp; /*Partition directory ptr */
2439 afs_uint32 currVolID; /*Current volume ID */
2440 int found = 0; /*Did we find the volume we need? */
2442 volint_info_handle_t handle;
2445 * Set up our pointers for action, marking our structure to hold exactly
2446 * one entry. Also, assume we'll fail in our quest.
2448 a_volumeXInfoP->volXEntries_val =
2449 (volintXInfo *) malloc(sizeof(volintXInfo));
2450 if (!a_volumeXInfoP->volXEntries_val)
2452 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2454 a_volumeXInfoP->volXEntries_len = 1;
2458 * If the partition name we've been given is bad, bogue out.
2460 if (GetPartName(a_partID, pname))
2461 return (VOLSERILLEGAL_PARTITION);
2464 * Open the directory representing the given AFS parttion. If we can't
2467 if (!(partP = VGetPartition(pname, 0)))
2468 return VOLSERILLEGAL_PARTITION;
2469 dirp = opendir(VPartitionPath(partP));
2471 return (VOLSERILLEGAL_PARTITION);
2473 strcpy(volname, "");
2476 * Sweep through the partition directory, looking for the desired entry.
2477 * First, of course, figure out how many stat bytes to copy out of each
2480 while (strcmp(volname, "EOD") && !found) {
2482 * If this is not a volume, move on to the next entry in the
2483 * partition's directory.
2485 if (!strcmp(volname, "")) {
2486 GetNextVol(dirp, volname, &currVolID);
2490 if (currVolID == a_volID) {
2492 * We found the volume entry we're interested. Pull out the
2493 * extended information, remembering to poll (so that the client
2494 * doesn't time out) and to set up a transaction on the volume.
2498 } /*Found desired volume */
2500 GetNextVol(dirp, volname, &currVolID);
2504 #ifndef AFS_PTHREAD_ENV
2508 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2509 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2511 code = GetVolInfo(a_partID,
2516 VOL_INFO_LIST_SINGLE);
2521 * Clean up before going to dinner: close the partition directory,
2522 * return the proper value.
2526 return code ? ENODEV: 0;
2529 } /*SAFSVolXListOneVolume */
2531 /*returns all the volumes on partition partid. If flags = 1 then all the
2532 * relevant info about the volumes is also returned */
2534 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2535 volEntries *volumeInfo)
2539 code = VolListVolumes(acid, partid, flags, volumeInfo);
2540 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2545 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2546 volEntries *volumeInfo)
2549 struct DiskPartition64 *partP;
2550 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2551 char pname[9], volname[20];
2555 volint_info_handle_t handle;
2557 volumeInfo->volEntries_val =
2558 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2559 if (!volumeInfo->volEntries_val)
2561 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2563 pntr = volumeInfo->volEntries_val;
2564 volumeInfo->volEntries_len = 0;
2565 if (GetPartName(partid, pname))
2566 return VOLSERILLEGAL_PARTITION;
2567 if (!(partP = VGetPartition(pname, 0)))
2568 return VOLSERILLEGAL_PARTITION;
2569 dirp = opendir(VPartitionPath(partP));
2571 return VOLSERILLEGAL_PARTITION;
2572 strcpy(volname, "");
2574 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2576 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2577 GetNextVol(dirp, volname, &volid);
2578 continue; /*back to while loop */
2581 if (flags) { /*copy other things too */
2582 #ifndef AFS_PTHREAD_ENV
2583 IOMGR_Poll(); /*make sure that the client does not time out */
2586 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2587 handle.volinfo_ptr.base = pntr;
2590 code = GetVolInfo(partid,
2595 VOL_INFO_LIST_MULTIPLE);
2596 if (code == -2) { /* DESTROY_ME flag set */
2600 pntr->volid = volid;
2601 /*just volids are needed */
2605 volumeInfo->volEntries_len += 1;
2606 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2607 /*running out of space, allocate more space */
2608 allocSize = (allocSize * 3) / 2;
2610 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2611 allocSize * sizeof(volintInfo));
2614 return VOLSERNO_MEMORY;
2616 volumeInfo->volEntries_val = pntr; /* point to new block */
2617 /* set pntr to the right position */
2618 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2623 GetNextVol(dirp, volname, &volid);
2631 /*------------------------------------------------------------------------
2632 * EXPORTED SAFSVolXListVolumes
2635 * Returns all the volumes on partition a_partID. If a_flags
2636 * is set to 1, then all the relevant extended volume information
2640 * a_rxCidP : Pointer to the Rx call we're performing.
2641 * a_partID : Partition for which we want the extended list.
2642 * a_flags : Various flags.
2643 * a_volumeXInfoP : Ptr to the extended info blob.
2646 * 0 Successful operation
2647 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2648 * VOLSERNO_MEMORY if we ran out of memory allocating
2652 * Nothing interesting.
2656 *------------------------------------------------------------------------*/
2659 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2660 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2664 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2665 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2670 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2671 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2672 { /*SAFSVolXListVolumes */
2674 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2675 struct DiskPartition64 *partP; /*Ptr to partition */
2676 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2677 char pname[9], volname[20]; /*Partition, volume names */
2678 DIR *dirp; /*Partition directory ptr */
2679 afs_uint32 volid; /*Current volume ID */
2681 volint_info_handle_t handle;
2684 * Allocate a large array of extended volume info structures, then
2685 * set it up for action.
2687 a_volumeXInfoP->volXEntries_val =
2688 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2689 if (!a_volumeXInfoP->volXEntries_val)
2691 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2693 xInfoP = a_volumeXInfoP->volXEntries_val;
2694 a_volumeXInfoP->volXEntries_len = 0;
2697 * If the partition name we've been given is bad, bogue out.
2699 if (GetPartName(a_partID, pname))
2700 return (VOLSERILLEGAL_PARTITION);
2703 * Open the directory representing the given AFS parttion. If we can't
2706 if (!(partP = VGetPartition(pname, 0)))
2707 return VOLSERILLEGAL_PARTITION;
2708 dirp = opendir(VPartitionPath(partP));
2710 return (VOLSERILLEGAL_PARTITION);
2711 strcpy(volname, "");
2714 * Sweep through the partition directory, acting on each entry. First,
2715 * of course, figure out how many stat bytes to copy out of each volume.
2717 while (strcmp(volname, "EOD")) {
2720 * If this is not a volume, move on to the next entry in the
2721 * partition's directory.
2723 if (!strcmp(volname, "")) {
2724 GetNextVol(dirp, volname, &volid);
2730 * Full info about the volume desired. Poll to make sure the
2731 * client doesn't time out, then start up a new transaction.
2733 #ifndef AFS_PTHREAD_ENV
2737 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2738 handle.volinfo_ptr.ext = xInfoP;
2740 code = GetVolInfo(a_partID,
2745 VOL_INFO_LIST_MULTIPLE);
2746 if (code == -2) { /* DESTROY_ME flag set */
2751 * Just volume IDs are needed.
2753 xInfoP->volid = volid;
2757 * Bump the pointer in the data area we're building, along with
2758 * the count of the number of entries it contains.
2761 (a_volumeXInfoP->volXEntries_len)++;
2762 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2764 * We're running out of space in the area we've built. Grow it.
2766 allocSize = (allocSize * 3) / 2;
2767 xInfoP = (volintXInfo *)
2768 realloc((char *)a_volumeXInfoP->volXEntries_val,
2769 (allocSize * sizeof(volintXInfo)));
2770 if (xInfoP == NULL) {
2772 * Bummer, no memory. Bag it, tell our caller what went wrong.
2775 return (VOLSERNO_MEMORY);
2779 * Memory reallocation worked. Correct our pointers so they
2780 * now point to the new block and the current open position within
2783 a_volumeXInfoP->volXEntries_val = xInfoP;
2785 a_volumeXInfoP->volXEntries_val +
2786 a_volumeXInfoP->volXEntries_len;
2790 GetNextVol(dirp, volname, &volid);
2791 } /*Sweep through the partition directory */
2794 * We've examined all entries in the partition directory. Close it,
2795 * delete our transaction (if any), and go home happy.
2800 } /*SAFSVolXListVolumes */
2802 /*this call is used to monitor the status of volser for debugging purposes.
2803 *information about all the active transactions is returned in transInfo*/
2805 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2809 code = VolMonitor(acid, transInfo);
2810 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2815 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2817 transDebugInfo *pntr;
2818 afs_int32 allocSize = 50;
2819 struct volser_trans *tt, *nt, *allTrans;
2821 transInfo->transDebugEntries_val =
2822 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2823 if (!transInfo->transDebugEntries_val)
2825 pntr = transInfo->transDebugEntries_val;
2826 transInfo->transDebugEntries_len = 0;
2829 allTrans = TransList();
2830 if (allTrans == (struct volser_trans *)0)
2831 goto done; /*no active transactions */
2832 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2834 VTRANS_OBJ_LOCK(tt);
2835 pntr->tid = tt->tid;
2836 pntr->time = tt->time;
2837 pntr->creationTime = tt->creationTime;
2838 pntr->returnCode = tt->returnCode;
2839 pntr->volid = tt->volid;
2840 pntr->partition = tt->partition;
2841 pntr->iflags = tt->iflags;
2842 pntr->vflags = tt->vflags;
2843 pntr->tflags = tt->tflags;
2844 strcpy(pntr->lastProcName, tt->lastProcName);
2845 pntr->callValid = 0;
2846 if (tt->rxCallPtr) { /*record call related info */
2847 pntr->callValid = 1;
2848 pntr->readNext = tt->rxCallPtr->rnext;
2849 pntr->transmitNext = tt->rxCallPtr->tnext;
2850 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2851 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2853 VTRANS_OBJ_UNLOCK(tt);
2855 transInfo->transDebugEntries_len += 1;
2856 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2857 allocSize = (allocSize * 3) / 2;
2859 (transDebugInfo *) realloc((char *)transInfo->
2860 transDebugEntries_val,
2862 sizeof(transDebugInfo));
2863 transInfo->transDebugEntries_val = pntr;
2865 transInfo->transDebugEntries_val +
2866 transInfo->transDebugEntries_len;
2867 /*set pntr to right position */
2878 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2879 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2880 afs_uint32 backupId)
2884 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2885 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2886 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2892 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2893 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2894 afs_uint32 backupId)
2898 struct volser_trans *tt;
2899 char caller[MAXKTCNAMELEN];
2901 if (strlen(name) > 31)
2902 return VOLSERBADNAME;
2903 if (!afsconf_SuperUser(tdir, acid, caller))
2904 return VOLSERBAD_ACCESS; /*not a super user */
2905 /* find the trans */
2906 tt = FindTrans(atid);
2909 if (tt->vflags & VTDeleted) {
2910 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2914 TSetRxCall(tt, acid, "SetIdsTypes");
2918 V_backupId(tv) = backupId;
2919 V_cloneId(tv) = cloneId;
2920 V_parentId(tv) = pId;
2921 strcpy((&V_disk(tv))->name, name);
2922 VUpdateVolume(&error, tv);
2924 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2929 if (TRELE(tt) && !error)
2930 return VOLSERTRELE_ERROR;
2935 if (TRELE(tt) && !error)
2936 return VOLSERTRELE_ERROR;
2941 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2945 code = VolSetDate(acid, atid, cdate);
2946 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2952 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2956 struct volser_trans *tt;
2957 char caller[MAXKTCNAMELEN];
2959 if (!afsconf_SuperUser(tdir, acid, caller))
2960 return VOLSERBAD_ACCESS; /*not a super user */
2961 /* find the trans */
2962 tt = FindTrans(atid);
2965 if (tt->vflags & VTDeleted) {
2966 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2970 TSetRxCall(tt, acid, "SetDate");
2973 V_creationDate(tv) = cdate;
2974 VUpdateVolume(&error, tv);
2976 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2981 if (TRELE(tt) && !error)
2982 return VOLSERTRELE_ERROR;
2987 if (TRELE(tt) && !error)
2988 return VOLSERTRELE_ERROR;
2993 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2994 afs_uint32 volumeId)
2999 char caller[MAXKTCNAMELEN];
3001 struct volser_trans *ttc;
3002 char pname[16], volname[20];
3003 struct DiskPartition64 *partP;
3004 afs_int32 ret = ENODEV;
3007 if (!afsconf_SuperUser(tdir, acid, caller))
3008 return VOLSERBAD_ACCESS; /*not a super user */
3009 if (GetPartName(partId, pname))
3010 return VOLSERILLEGAL_PARTITION;
3011 if (!(partP = VGetPartition(pname, 0)))
3012 return VOLSERILLEGAL_PARTITION;
3013 dirp = opendir(VPartitionPath(partP));
3015 return VOLSERILLEGAL_PARTITION;
3016 strcpy(volname, "");
3017 ttc = (struct volser_trans *)0;
3019 while (strcmp(volname, "EOD")) {
3020 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3021 GetNextVol(dirp, volname, &volid);
3022 continue; /*back to while loop */
3025 if (volid == volumeId) { /*copy other things too */
3026 #ifndef AFS_PTHREAD_ENV
3027 IOMGR_Poll(); /*make sure that the client doesnot time out */
3029 ttc = NewTrans(volumeId, partId);
3031 return VOLSERVOLBUSY;
3033 #ifdef AFS_NAMEI_ENV
3034 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3036 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3040 GetNextVol(dirp, volname, &volid);
3044 DeleteTrans(ttc, 1);
3045 ttc = (struct volser_trans *)0;
3054 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3055 struct volintSize *size)
3058 struct volser_trans *tt;
3059 char caller[MAXKTCNAMELEN];
3061 if (!afsconf_SuperUser(tdir, acid, caller))
3062 return VOLSERBAD_ACCESS; /*not a super user */
3063 tt = FindTrans(fromTrans);
3066 if (tt->vflags & VTDeleted) {
3070 TSetRxCall(tt, acid, "GetSize");
3071 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3074 return VOLSERTRELE_ERROR;
3076 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3081 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3082 afs_uint32 where, afs_int32 verbose)
3084 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3086 Volume *vol=0, *newvol=0;
3087 struct volser_trans *tt = 0, *tt2 = 0;
3088 char caller[MAXKTCNAMELEN];
3091 if (!afsconf_SuperUser(tdir, acall, caller))
3094 vol = VAttachVolume(&code, vid, V_VOLUPD);
3100 newvol = VAttachVolume(&code, new, V_VOLUPD);
3102 VDetachVolume(&code2, vol);
3107 if (V_device(vol) != V_device(newvol)
3108 || V_uniquifier(newvol) != 2) {
3109 if (V_device(vol) != V_device(newvol)) {
3110 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3112 rx_Write(acall, line, strlen(line));
3114 if (V_uniquifier(newvol) != 2) {
3115 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3116 rx_Write(acall, line, strlen(line));
3119 rx_Write(acall, line, 1);
3120 VDetachVolume(&code2, vol);
3121 VDetachVolume(&code2, newvol);
3124 tt = NewTrans(vid, V_device(vol));
3126 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3127 rx_Write(acall, line, strlen(line));
3129 rx_Write(acall, line, 1);
3130 VDetachVolume(&code2, vol);
3131 VDetachVolume(&code2, newvol);
3132 return VOLSERVOLBUSY;
3134 VTRANS_OBJ_LOCK(tt);
3135 tt->iflags = ITBusy;
3137 TSetRxCall_r(tt, NULL, "SplitVolume");
3138 VTRANS_OBJ_UNLOCK(tt);
3140 tt2 = NewTrans(new, V_device(newvol));
3142 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3143 rx_Write(acall, line, strlen(line));
3145 rx_Write(acall, line, 1);
3147 VDetachVolume(&code2, vol);
3148 VDetachVolume(&code2, newvol);
3149 return VOLSERVOLBUSY;
3151 VTRANS_OBJ_LOCK(tt2);
3152 tt2->iflags = ITBusy;
3154 TSetRxCall_r(tt2, NULL, "SplitVolume");
3155 VTRANS_OBJ_UNLOCK(tt2);
3157 code = split_volume(acall, vol, newvol, where, verbose);
3159 VDetachVolume(&code2, vol);
3161 VDetachVolume(&code2, newvol);
3162 DeleteTrans(tt2, 1);
3169 /* GetPartName - map partid (a decimal number) into pname (a string)
3170 * Since for NT we actually want to return the drive name, we map through the
3174 GetPartName(afs_int32 partid, char *pname)
3179 strcpy(pname, "/vicep");
3180 pname[6] = 'a' + partid;
3183 } else if (partid < VOLMAXPARTS) {
3184 strcpy(pname, "/vicep");
3186 pname[6] = 'a' + (partid / 26);
3187 pname[7] = 'a' + (partid % 26);