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, 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);
2391 return (found) ? 0 : ENODEV;
2394 /*------------------------------------------------------------------------
2395 * EXPORTED SAFSVolXListOneVolume
2398 * Returns extended info on volume a_volID on partition a_partID.
2401 * a_rxCidP : Pointer to the Rx call we're performing.
2402 * a_partID : Partition for which we want the extended list.
2403 * a_volID : Volume ID we wish to know about.
2404 * a_volumeXInfoP : Ptr to the extended info blob.
2407 * 0 Successful operation
2408 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2411 * Nothing interesting.
2415 *------------------------------------------------------------------------*/
2418 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2419 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2423 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2424 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2429 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2430 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2431 { /*SAFSVolXListOneVolume */
2433 struct DiskPartition64 *partP; /*Ptr to partition */
2434 char pname[9], volname[20]; /*Partition, volume names */
2435 DIR *dirp; /*Partition directory ptr */
2436 afs_uint32 currVolID; /*Current volume ID */
2437 int found = 0; /*Did we find the volume we need? */
2439 volint_info_handle_t handle;
2442 * Set up our pointers for action, marking our structure to hold exactly
2443 * one entry. Also, assume we'll fail in our quest.
2445 a_volumeXInfoP->volXEntries_val =
2446 (volintXInfo *) malloc(sizeof(volintXInfo));
2447 if (!a_volumeXInfoP->volXEntries_val)
2449 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2451 a_volumeXInfoP->volXEntries_len = 1;
2455 * If the partition name we've been given is bad, bogue out.
2457 if (GetPartName(a_partID, pname))
2458 return (VOLSERILLEGAL_PARTITION);
2461 * Open the directory representing the given AFS parttion. If we can't
2464 if (!(partP = VGetPartition(pname, 0)))
2465 return VOLSERILLEGAL_PARTITION;
2466 dirp = opendir(VPartitionPath(partP));
2468 return (VOLSERILLEGAL_PARTITION);
2470 strcpy(volname, "");
2473 * Sweep through the partition directory, looking for the desired entry.
2474 * First, of course, figure out how many stat bytes to copy out of each
2477 while (strcmp(volname, "EOD") && !found) {
2479 * If this is not a volume, move on to the next entry in the
2480 * partition's directory.
2482 if (!strcmp(volname, "")) {
2483 GetNextVol(dirp, volname, &currVolID);
2487 if (currVolID == a_volID) {
2489 * We found the volume entry we're interested. Pull out the
2490 * extended information, remembering to poll (so that the client
2491 * doesn't time out) and to set up a transaction on the volume.
2495 } /*Found desired volume */
2497 GetNextVol(dirp, volname, &currVolID);
2501 #ifndef AFS_PTHREAD_ENV
2505 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2506 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2508 code = GetVolInfo(a_partID,
2513 VOL_INFO_LIST_SINGLE);
2518 * Clean up before going to dinner: close the partition directory,
2519 * return the proper value.
2522 return (found) ? 0 : ENODEV;
2523 } /*SAFSVolXListOneVolume */
2525 /*returns all the volumes on partition partid. If flags = 1 then all the
2526 * relevant info about the volumes is also returned */
2528 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2529 volEntries *volumeInfo)
2533 code = VolListVolumes(acid, partid, flags, volumeInfo);
2534 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2539 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2540 volEntries *volumeInfo)
2543 struct DiskPartition64 *partP;
2544 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2545 char pname[9], volname[20];
2549 volint_info_handle_t handle;
2551 volumeInfo->volEntries_val =
2552 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2553 if (!volumeInfo->volEntries_val)
2555 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2557 pntr = volumeInfo->volEntries_val;
2558 volumeInfo->volEntries_len = 0;
2559 if (GetPartName(partid, pname))
2560 return VOLSERILLEGAL_PARTITION;
2561 if (!(partP = VGetPartition(pname, 0)))
2562 return VOLSERILLEGAL_PARTITION;
2563 dirp = opendir(VPartitionPath(partP));
2565 return VOLSERILLEGAL_PARTITION;
2566 strcpy(volname, "");
2568 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2570 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2571 GetNextVol(dirp, volname, &volid);
2572 continue; /*back to while loop */
2575 if (flags) { /*copy other things too */
2576 #ifndef AFS_PTHREAD_ENV
2577 IOMGR_Poll(); /*make sure that the client does not time out */
2580 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2581 handle.volinfo_ptr.base = pntr;
2584 code = GetVolInfo(partid,
2589 VOL_INFO_LIST_MULTIPLE);
2590 if (code == -2) { /* DESTROY_ME flag set */
2594 pntr->volid = volid;
2595 /*just volids are needed */
2599 volumeInfo->volEntries_len += 1;
2600 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2601 /*running out of space, allocate more space */
2602 allocSize = (allocSize * 3) / 2;
2604 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2605 allocSize * sizeof(volintInfo));
2608 return VOLSERNO_MEMORY;
2610 volumeInfo->volEntries_val = pntr; /* point to new block */
2611 /* set pntr to the right position */
2612 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2617 GetNextVol(dirp, volname, &volid);
2625 /*------------------------------------------------------------------------
2626 * EXPORTED SAFSVolXListVolumes
2629 * Returns all the volumes on partition a_partID. If a_flags
2630 * is set to 1, then all the relevant extended volume information
2634 * a_rxCidP : Pointer to the Rx call we're performing.
2635 * a_partID : Partition for which we want the extended list.
2636 * a_flags : Various flags.
2637 * a_volumeXInfoP : Ptr to the extended info blob.
2640 * 0 Successful operation
2641 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2642 * VOLSERNO_MEMORY if we ran out of memory allocating
2646 * Nothing interesting.
2650 *------------------------------------------------------------------------*/
2653 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2654 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2658 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2659 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2664 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2665 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2666 { /*SAFSVolXListVolumes */
2668 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2669 struct DiskPartition64 *partP; /*Ptr to partition */
2670 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2671 char pname[9], volname[20]; /*Partition, volume names */
2672 DIR *dirp; /*Partition directory ptr */
2673 afs_uint32 volid; /*Current volume ID */
2675 volint_info_handle_t handle;
2678 * Allocate a large array of extended volume info structures, then
2679 * set it up for action.
2681 a_volumeXInfoP->volXEntries_val =
2682 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2683 if (!a_volumeXInfoP->volXEntries_val)
2685 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2687 xInfoP = a_volumeXInfoP->volXEntries_val;
2688 a_volumeXInfoP->volXEntries_len = 0;
2691 * If the partition name we've been given is bad, bogue out.
2693 if (GetPartName(a_partID, pname))
2694 return (VOLSERILLEGAL_PARTITION);
2697 * Open the directory representing the given AFS parttion. If we can't
2700 if (!(partP = VGetPartition(pname, 0)))
2701 return VOLSERILLEGAL_PARTITION;
2702 dirp = opendir(VPartitionPath(partP));
2704 return (VOLSERILLEGAL_PARTITION);
2705 strcpy(volname, "");
2708 * Sweep through the partition directory, acting on each entry. First,
2709 * of course, figure out how many stat bytes to copy out of each volume.
2711 while (strcmp(volname, "EOD")) {
2714 * If this is not a volume, move on to the next entry in the
2715 * partition's directory.
2717 if (!strcmp(volname, "")) {
2718 GetNextVol(dirp, volname, &volid);
2724 * Full info about the volume desired. Poll to make sure the
2725 * client doesn't time out, then start up a new transaction.
2727 #ifndef AFS_PTHREAD_ENV
2731 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2732 handle.volinfo_ptr.ext = xInfoP;
2734 code = GetVolInfo(a_partID,
2739 VOL_INFO_LIST_MULTIPLE);
2740 if (code == -2) { /* DESTROY_ME flag set */
2745 * Just volume IDs are needed.
2747 xInfoP->volid = volid;
2751 * Bump the pointer in the data area we're building, along with
2752 * the count of the number of entries it contains.
2755 (a_volumeXInfoP->volXEntries_len)++;
2756 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2758 * We're running out of space in the area we've built. Grow it.
2760 allocSize = (allocSize * 3) / 2;
2761 xInfoP = (volintXInfo *)
2762 realloc((char *)a_volumeXInfoP->volXEntries_val,
2763 (allocSize * sizeof(volintXInfo)));
2764 if (xInfoP == NULL) {
2766 * Bummer, no memory. Bag it, tell our caller what went wrong.
2769 return (VOLSERNO_MEMORY);
2773 * Memory reallocation worked. Correct our pointers so they
2774 * now point to the new block and the current open position within
2777 a_volumeXInfoP->volXEntries_val = xInfoP;
2779 a_volumeXInfoP->volXEntries_val +
2780 a_volumeXInfoP->volXEntries_len;
2784 GetNextVol(dirp, volname, &volid);
2785 } /*Sweep through the partition directory */
2788 * We've examined all entries in the partition directory. Close it,
2789 * delete our transaction (if any), and go home happy.
2794 } /*SAFSVolXListVolumes */
2796 /*this call is used to monitor the status of volser for debugging purposes.
2797 *information about all the active transactions is returned in transInfo*/
2799 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2803 code = VolMonitor(acid, transInfo);
2804 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2809 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2811 transDebugInfo *pntr;
2812 afs_int32 allocSize = 50;
2813 struct volser_trans *tt, *nt, *allTrans;
2815 transInfo->transDebugEntries_val =
2816 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2817 if (!transInfo->transDebugEntries_val)
2819 pntr = transInfo->transDebugEntries_val;
2820 transInfo->transDebugEntries_len = 0;
2823 allTrans = TransList();
2824 if (allTrans == (struct volser_trans *)0)
2825 goto done; /*no active transactions */
2826 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2828 VTRANS_OBJ_LOCK(tt);
2829 pntr->tid = tt->tid;
2830 pntr->time = tt->time;
2831 pntr->creationTime = tt->creationTime;
2832 pntr->returnCode = tt->returnCode;
2833 pntr->volid = tt->volid;
2834 pntr->partition = tt->partition;
2835 pntr->iflags = tt->iflags;
2836 pntr->vflags = tt->vflags;
2837 pntr->tflags = tt->tflags;
2838 strcpy(pntr->lastProcName, tt->lastProcName);
2839 pntr->callValid = 0;
2840 if (tt->rxCallPtr) { /*record call related info */
2841 pntr->callValid = 1;
2842 pntr->readNext = tt->rxCallPtr->rnext;
2843 pntr->transmitNext = tt->rxCallPtr->tnext;
2844 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2845 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2847 VTRANS_OBJ_UNLOCK(tt);
2849 transInfo->transDebugEntries_len += 1;
2850 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2851 allocSize = (allocSize * 3) / 2;
2853 (transDebugInfo *) realloc((char *)transInfo->
2854 transDebugEntries_val,
2856 sizeof(transDebugInfo));
2857 transInfo->transDebugEntries_val = pntr;
2859 transInfo->transDebugEntries_val +
2860 transInfo->transDebugEntries_len;
2861 /*set pntr to right position */
2872 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2873 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2874 afs_uint32 backupId)
2878 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2879 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2880 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2886 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2887 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2888 afs_uint32 backupId)
2892 struct volser_trans *tt;
2893 char caller[MAXKTCNAMELEN];
2895 if (strlen(name) > 31)
2896 return VOLSERBADNAME;
2897 if (!afsconf_SuperUser(tdir, acid, caller))
2898 return VOLSERBAD_ACCESS; /*not a super user */
2899 /* find the trans */
2900 tt = FindTrans(atid);
2903 if (tt->vflags & VTDeleted) {
2904 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2908 TSetRxCall(tt, acid, "SetIdsTypes");
2912 V_backupId(tv) = backupId;
2913 V_cloneId(tv) = cloneId;
2914 V_parentId(tv) = pId;
2915 strcpy((&V_disk(tv))->name, name);
2916 VUpdateVolume(&error, tv);
2918 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2923 if (TRELE(tt) && !error)
2924 return VOLSERTRELE_ERROR;
2929 if (TRELE(tt) && !error)
2930 return VOLSERTRELE_ERROR;
2935 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2939 code = VolSetDate(acid, atid, cdate);
2940 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2946 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2950 struct volser_trans *tt;
2951 char caller[MAXKTCNAMELEN];
2953 if (!afsconf_SuperUser(tdir, acid, caller))
2954 return VOLSERBAD_ACCESS; /*not a super user */
2955 /* find the trans */
2956 tt = FindTrans(atid);
2959 if (tt->vflags & VTDeleted) {
2960 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2964 TSetRxCall(tt, acid, "SetDate");
2967 V_creationDate(tv) = cdate;
2968 VUpdateVolume(&error, tv);
2970 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2975 if (TRELE(tt) && !error)
2976 return VOLSERTRELE_ERROR;
2981 if (TRELE(tt) && !error)
2982 return VOLSERTRELE_ERROR;
2987 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2988 afs_uint32 volumeId)
2993 char caller[MAXKTCNAMELEN];
2995 struct volser_trans *ttc;
2996 char pname[16], volname[20];
2997 struct DiskPartition64 *partP;
2998 afs_int32 ret = ENODEV;
3001 if (!afsconf_SuperUser(tdir, acid, caller))
3002 return VOLSERBAD_ACCESS; /*not a super user */
3003 if (GetPartName(partId, pname))
3004 return VOLSERILLEGAL_PARTITION;
3005 if (!(partP = VGetPartition(pname, 0)))
3006 return VOLSERILLEGAL_PARTITION;
3007 dirp = opendir(VPartitionPath(partP));
3009 return VOLSERILLEGAL_PARTITION;
3010 strcpy(volname, "");
3011 ttc = (struct volser_trans *)0;
3013 while (strcmp(volname, "EOD")) {
3014 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3015 GetNextVol(dirp, volname, &volid);
3016 continue; /*back to while loop */
3019 if (volid == volumeId) { /*copy other things too */
3020 #ifndef AFS_PTHREAD_ENV
3021 IOMGR_Poll(); /*make sure that the client doesnot time out */
3023 ttc = NewTrans(volumeId, partId);
3025 return VOLSERVOLBUSY;
3027 #ifdef AFS_NAMEI_ENV
3028 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3030 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3034 GetNextVol(dirp, volname, &volid);
3038 DeleteTrans(ttc, 1);
3039 ttc = (struct volser_trans *)0;
3048 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3049 struct volintSize *size)
3052 struct volser_trans *tt;
3053 char caller[MAXKTCNAMELEN];
3055 if (!afsconf_SuperUser(tdir, acid, caller))
3056 return VOLSERBAD_ACCESS; /*not a super user */
3057 tt = FindTrans(fromTrans);
3060 if (tt->vflags & VTDeleted) {
3064 TSetRxCall(tt, acid, "GetSize");
3065 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3068 return VOLSERTRELE_ERROR;
3070 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3075 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3076 afs_uint32 where, afs_int32 verbose)
3078 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3080 Volume *vol=0, *newvol=0;
3081 struct volser_trans *tt = 0, *tt2 = 0;
3082 char caller[MAXKTCNAMELEN];
3085 if (!afsconf_SuperUser(tdir, acall, caller))
3088 vol = VAttachVolume(&code, vid, V_VOLUPD);
3094 newvol = VAttachVolume(&code, new, V_VOLUPD);
3096 VDetachVolume(&code2, vol);
3101 if (V_device(vol) != V_device(newvol)
3102 || V_uniquifier(newvol) != 2) {
3103 if (V_device(vol) != V_device(newvol)) {
3104 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3106 rx_Write(acall, line, strlen(line));
3108 if (V_uniquifier(newvol) != 2) {
3109 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3110 rx_Write(acall, line, strlen(line));
3113 rx_Write(acall, line, 1);
3114 VDetachVolume(&code2, vol);
3115 VDetachVolume(&code2, newvol);
3118 tt = NewTrans(vid, V_device(vol));
3120 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3121 rx_Write(acall, line, strlen(line));
3123 rx_Write(acall, line, 1);
3124 VDetachVolume(&code2, vol);
3125 VDetachVolume(&code2, newvol);
3126 return VOLSERVOLBUSY;
3128 VTRANS_OBJ_LOCK(tt);
3129 tt->iflags = ITBusy;
3131 TSetRxCall_r(tt, NULL, "SplitVolume");
3132 VTRANS_OBJ_UNLOCK(tt);
3134 tt2 = NewTrans(new, V_device(newvol));
3136 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3137 rx_Write(acall, line, strlen(line));
3139 rx_Write(acall, line, 1);
3141 VDetachVolume(&code2, vol);
3142 VDetachVolume(&code2, newvol);
3143 return VOLSERVOLBUSY;
3145 VTRANS_OBJ_LOCK(tt2);
3146 tt2->iflags = ITBusy;
3148 TSetRxCall_r(tt2, NULL, "SplitVolume");
3149 VTRANS_OBJ_UNLOCK(tt2);
3151 code = split_volume(acall, vol, newvol, where, verbose);
3153 VDetachVolume(&code2, vol);
3155 VDetachVolume(&code2, newvol);
3156 DeleteTrans(tt2, 1);
3163 /* GetPartName - map partid (a decimal number) into pname (a string)
3164 * Since for NT we actually want to return the drive name, we map through the
3168 GetPartName(afs_int32 partid, char *pname)
3173 strcpy(pname, "/vicep");
3174 pname[6] = 'a' + partid;
3177 } else if (partid < VOLMAXPARTS) {
3178 strcpy(pname, "/vicep");
3180 pname[6] = 'a' + (partid / 26);
3181 pname[7] = 'a' + (partid % 26);