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>
18 #ifdef AFS_PTHREAD_ENV
19 # include <opr/lock.h>
24 #include <rx/rx_queue.h>
25 #include <afs/afsint.h>
26 #include <afs/prs_fs.h>
30 #include <afs/cellconfig.h>
33 #include <afs/ihandle.h>
35 #include <afs/ntops.h>
37 #include <afs/vnode.h>
38 #include <afs/volume.h>
39 #include <afs/volume_inline.h>
40 #include <afs/partition.h>
42 #include <afs/daemon_com.h>
43 #include <afs/fssync.h>
45 #include "afs/audit.h"
47 #include <afs/afsutil.h>
48 #include <afs/com_err.h>
49 #include <afs/vol_prototypes.h>
50 #include <afs/errors.h>
53 #include "voltrans_inline.h"
56 #include "volser_internal.h"
58 #include "dumpstuff.h"
61 extern struct afsconf_dir *tdir;
62 extern int DoPreserveVolumeStats;
63 extern int restrictedQueryLevel;
64 extern enum vol_s2s_crypt doCrypt;
66 extern void LogError(afs_int32 errcode);
68 /* Forward declarations */
69 static int GetPartName(afs_int32 partid, char *pname);
71 #define OneDay (24*60*60)
77 afs_int32 localTid = 1;
79 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
80 struct diskPartition64 *);
81 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
82 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
83 afs_int32, afs_uint32, afs_uint32 *,
85 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
86 static afs_int32 VolClone(struct rx_call *, afs_int32, VolumeId,
87 afs_int32, char *, VolumeId *);
88 static afs_int32 VolReClone(struct rx_call *, afs_int32, VolumeId);
89 static afs_int32 VolTransCreate(struct rx_call *, VolumeId, afs_int32,
90 afs_int32, afs_int32 *);
91 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
93 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
94 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
95 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
96 struct destServer *destination, afs_int32,
97 struct restoreCookie *cookie);
98 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
99 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
100 struct restoreCookie *);
101 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
102 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
103 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
104 struct volser_status *);
105 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
106 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
107 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
108 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
109 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, VolumeId,
111 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, VolumeId,
113 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
115 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
117 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
118 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
119 afs_int32, VolumeId, VolumeId,
121 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
124 * Return the host address of the caller as a string.
126 * @param[in] acid incoming rx call
127 * @param[out] buffer buffer to be filled with the addess string
129 * @return address as formatted by inet_ntoa
132 callerAddress(struct rx_call *acid, char *buffer)
134 afs_uint32 ip = rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid)));
135 return afs_inet_ntoa_r(ip, buffer);
138 /* this call unlocks all of the partition locks we've set */
142 struct DiskPartition64 *tp;
143 for (tp = DiskPartitionList; tp; tp = tp->next) {
144 if (tp->lock_fd != INVALID_FD) {
145 OS_CLOSE(tp->lock_fd);
146 tp->lock_fd = INVALID_FD;
157 code = VPFullUnlock_r();
163 ConvertVolume(VolumeId avol, char *aname, afs_int32 asize)
167 /* 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 */
168 snprintf(aname, asize, VFORMAT, afs_printable_VolumeId_lu(avol));
173 ConvertPartition(int apartno, char *aname, int asize)
179 strcpy(aname, "/vicep");
181 aname[6] = 'a' + apartno;
185 aname[6] = 'a' + (apartno / 26);
186 aname[7] = 'a' + (apartno % 26);
192 #ifdef AFS_DEMAND_ATTACH_FS
193 /* normally we should use the regular salvaging functions from the volume
194 * package, but this is a special case where we have a volume ID, but no
195 * volume structure to give the volume package */
197 SalvageUnknownVolume(VolumeId volid, char *part)
201 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
202 afs_printable_uint32_lu(volid), part);
204 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
205 FSYNC_SALVAGE, NULL);
207 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
208 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
212 #endif /* AFS_DEMAND_ATTACH_FS */
214 static struct Volume *
215 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
220 vp = VAttachVolumeByName(ec, partition, name, mode);
222 #ifdef AFS_DEMAND_ATTACH_FS
226 * The fileserver will take care of keeping track of how many
227 * demand-salvages have been performed, and will force the volume to
228 * ERROR if we've done too many. The limit on This loop is just a
229 * failsafe to prevent trying to salvage forever. We want to attempt
230 * attachment at least SALVAGE_COUNT_MAX times, since we want to
231 * avoid prematurely exiting this loop, if we can.
233 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
234 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
235 vp = VAttachVolumeByName(ec, partition, name, mode);
238 if (*ec == VSALVAGING) {
242 #endif /* AFS_DEMAND_ATTACH_FS */
247 static struct Volume *
248 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
253 vp = VAttachVolume(ec, avolid, amode);
255 #ifdef AFS_DEMAND_ATTACH_FS
258 /* see comment above in VAttachVolumeByName_retry */
259 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
260 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
261 vp = VAttachVolume(ec, avolid, amode);
264 if (*ec == VSALVAGING) {
268 #endif /* AFS_DEMAND_ATTACH_FS */
273 /* the only attach function that takes a partition is "...ByName", so we use it */
274 static struct Volume *
275 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
277 char pbuf[30], vbuf[20];
279 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
283 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
288 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
291 /* Adapted from the file server; create a root directory for this volume */
293 ViceCreateRoot(Volume *vp)
296 struct acl_accessList *ACL;
298 Inode inodeNumber, AFS_UNUSED nearInode;
299 struct VnodeDiskObject *vnode;
300 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
306 vnode = calloc(1, SIZEOF_LARGEDISKVNODE);
310 V_pref(vp, nearInode);
312 IH_CREATE(V_linkHandle(vp), V_device(vp),
313 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
315 if (!VALID_INO(inodeNumber)) {
316 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
321 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
322 did.Volume = V_id(vp);
323 did.Vnode = (VnodeId) 1;
326 opr_Verify(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
327 DFlush(); /* flush all modified dir buffers out */
328 DZap(&dir); /* Remove all buffers for this dir */
329 length = afs_dir_Length(&dir); /* Remember size of this directory */
331 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
333 /* build a single entry ACL that gives all rights to system:administrators */
334 /* this section of code assumes that access list format is not going to
337 ACL = VVnodeDiskACL(vnode);
338 ACL->size = sizeof(struct acl_accessList);
339 ACL->version = ACL_ACLVERSION;
343 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
344 ACL->entries[0].rights =
345 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
346 | PRSFS_LOCK | PRSFS_ADMINISTER;
348 vnode->type = vDirectory;
350 vnode->modeBits = 0777;
351 vnode->linkCount = 2;
352 VNDISK_SET_LEN(vnode, length);
353 vnode->uniquifier = 1;
354 V_uniquifier(vp) = vnode->uniquifier + 1;
355 vnode->dataVersion = 1;
356 VNDISK_SET_INO(vnode, inodeNumber);
357 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
361 vnode->vnodeMagic = vcp->magic;
363 IH_INIT(h, vp->device, V_parentId(vp),
364 vp->vnodeIndex[vLarge].handle->ih_ino);
366 opr_Assert(fdP != NULL);
367 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
368 opr_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
369 FDH_REALLYCLOSE(fdP);
371 VNDISK_GET_LEN(length, vnode);
372 V_diskused(vp) = nBlocks(length);
379 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
383 struct diskPartition64 *dp = malloc(sizeof(struct diskPartition64));
385 code = VolPartitionInfo(acid, pname, dp);
387 strncpy(partition->name, dp->name, 32);
388 strncpy(partition->devName, dp->devName, 32);
389 partition->lock_fd = dp->lock_fd;
390 partition->free=RoundInt64ToInt32(dp->free);
391 partition->minFree=RoundInt64ToInt32(dp->minFree);
394 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
399 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
404 code = VolPartitionInfo(acid, pname, partition);
405 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
410 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
413 struct DiskPartition64 *dp;
415 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
416 return VOLSERBAD_ACCESS;
419 dp = VGetPartition(pname, 0);
421 strncpy(partition->name, dp->name, 32);
422 strncpy(partition->devName, dp->devName, 32);
423 partition->lock_fd = (int)dp->lock_fd;
424 partition->free = dp->free;
425 partition->minFree = dp->totalUsable;
428 return VOLSERILLEGAL_PARTITION;
431 /* obliterate a volume completely, and slowly. */
433 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, VolumeId avolID)
437 code = VolNukeVolume(acid, apartID, avolID);
438 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
443 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
450 char caller[MAXKTCNAMELEN];
452 /* check for access */
453 if (!afsconf_SuperUser(tdir, acid, caller))
454 return VOLSERBAD_ACCESS;
457 Log("%s on %s is executing VolNukeVolume %u\n", caller,
458 callerAddress(acid, buffer), avolID);
461 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
463 /* we first try to attach the volume in update mode, so that the file
464 * server doesn't try to use it (and abort) while (or after) we delete it.
465 * If we don't get the volume, that's fine, too. We just won't put it back.
467 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
468 code = nuke(partName, avolID);
470 VDetachVolume(&verror, tvp);
474 /* create a new volume, with name aname, on the specified partition (1..n)
475 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
476 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
477 * for the volume id (useful for things like volume restore).
478 * Return the new volume id in *avolid.
481 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
482 afs_int32 atype, VolumeId aparent, VolumeId *avolid,
488 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
489 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
490 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
496 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
497 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
502 Error junk; /* discardable error code */
504 afs_int32 doCreateRoot = 1;
505 struct volser_trans *tt;
507 char caller[MAXKTCNAMELEN];
509 if (strlen(aname) > 31)
510 return VOLSERBADNAME;
511 if (!afsconf_SuperUser(tdir, acid, caller))
512 return VOLSERBAD_ACCESS;
515 Log("%s on %s is executing CreateVolume '%s'\n", caller,
516 callerAddress(acid, buffer), aname);
518 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
519 return error; /*a standard unix error */
520 if (atype != readwriteVolume && atype != readonlyVolume
521 && atype != backupVolume)
523 if ((volumeID = *avolid) == 0) {
525 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
529 if ((aparent == volumeID) && (atype == readwriteVolume)) {
534 tt = NewTrans(volumeID, apart);
536 Log("1 createvolume: failed to create trans\n");
537 return VOLSERVOLBUSY; /* volume already busy! */
539 vp = VCreateVolume(&error, ppath, volumeID, aparent);
541 #ifdef AFS_DEMAND_ATTACH_FS
542 if (error != VVOLEXISTS && error != EXDEV) {
543 SalvageUnknownVolume(volumeID, ppath);
546 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
551 V_uniquifier(vp) = 1;
552 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
553 V_inService(vp) = V_blessed(vp) = 1;
555 AssignVolumeName(&V_disk(vp), aname, 0);
557 error = ViceCreateRoot(vp);
559 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
560 "error code %u\n", (unsigned)error);
562 V_needsSalvaged(vp) = 1;
563 VDetachVolume(&junk, vp);
567 V_destroyMe(vp) = DESTROY_ME;
569 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
570 VUpdateVolume(&error, vp);
572 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
575 VDetachVolume(&junk, vp); /* rather return the real error code */
581 TSetRxCall_r(tt, acid, "CreateVolume");
582 VTRANS_OBJ_UNLOCK(tt);
583 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
586 return VOLSERTRELE_ERROR;
590 /* delete the volume associated with this transaction */
592 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
596 code = VolDeleteVolume(acid, atrans);
597 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
602 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
604 struct volser_trans *tt;
606 char caller[MAXKTCNAMELEN];
608 if (!afsconf_SuperUser(tdir, acid, caller))
609 return VOLSERBAD_ACCESS;
610 tt = FindTrans(atrans);
613 if (tt->vflags & VTDeleted) {
614 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " already deleted \n",
615 afs_printable_VolumeId_lu(tt->volid));
621 Log("%s on %s is executing Delete Volume %" AFS_VOLID_FMT "\n", caller,
622 callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
624 TSetRxCall(tt, acid, "DeleteVolume");
625 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
626 V_destroyMe(tt->volume) = DESTROY_ME;
627 if (tt->volume->needsPutBack) {
628 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
631 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
633 VTRANS_OBJ_UNLOCK(tt);
635 return VOLSERTRELE_ERROR;
637 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " deleted \n",
638 afs_printable_VolumeId_lu(tt->volid));
639 return 0; /* vpurgevolume doesn't set an error code */
642 /* make a clone of the volume associated with atrans, possibly giving it a new
643 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
644 * for the clone's id). The new clone is given the name newName. Finally,
645 * due to efficiency considerations, if purgeId is non-zero, we purge that
646 * volume when doing the clone operation. This may be useful when making
647 * new backup volumes, for instance since the net result of a clone and a
648 * purge generally leaves many inode ref counts the same, while doing them
649 * separately would result in far more iincs and idecs being peformed
650 * (and they are slow operations).
652 /* for efficiency reasons, sometimes faster to piggyback a purge here */
654 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
655 afs_int32 newType, char *newName, VolumeId *newNumber)
658 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
659 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
660 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
666 VolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
667 afs_int32 newType, char *newName, VolumeId *newNumber)
670 struct Volume *originalvp, *purgevp, *newvp;
672 struct volser_trans *tt, *ttc;
673 char caller[MAXKTCNAMELEN];
674 #ifdef AFS_DEMAND_ATTACH_FS
675 struct Volume *salv_vp = NULL;
678 if (strlen(newName) > 31)
679 return VOLSERBADNAME;
680 if (!afsconf_SuperUser(tdir, acid, caller))
681 return VOLSERBAD_ACCESS; /*not a super user */
684 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
685 callerAddress(acid, buffer), newName);
688 purgevp = (Volume *) 0;
689 newvp = (Volume *) 0;
690 tt = ttc = (struct volser_trans *)0;
692 if (!newNumber || !*newNumber) {
693 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
698 tt = FindTrans(atrans);
701 if (tt->vflags & VTDeleted) {
702 Log("1 Volser: Clone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
706 ttc = NewTrans(newId, tt->partition);
707 if (!ttc) { /* someone is messing with the clone already */
709 return VOLSERVOLBUSY;
711 TSetRxCall(tt, acid, "Clone");
715 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
717 Log("1 Volser: Clone: Could not attach 'purge' volume %" AFS_VOLID_FMT "; clone aborted\n", afs_printable_VolumeId_lu(purgeId));
723 originalvp = tt->volume;
724 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
725 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
726 afs_printable_VolumeId_lu(V_id(originalvp)));
731 if (originalvp->device != purgevp->device) {
732 Log("1 Volser: Clone: Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are on different devices\n", afs_printable_VolumeId_lu(tt->volid), afs_printable_VolumeId_lu(purgeId));
736 if (V_type(purgevp) != readonlyVolume) {
737 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
741 if (V_parentId(originalvp) != V_parentId(purgevp)) {
742 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " and volume %" AFS_VOLID_FMT " were not originally cloned from the same parent; aborted\n", afs_printable_VolumeId_lu(purgeId), afs_printable_VolumeId_lu(tt->volid));
749 #ifdef AFS_DEMAND_ATTACH_FS
750 salv_vp = originalvp;
753 if (purgeId == newId) {
757 VCreateVolume(&error, originalvp->partition->name, newId,
758 V_parentId(originalvp));
760 Log("1 Volser: Clone: Couldn't create new volume %" AFS_VOLID_FMT " for parent %" AFS_VOLID_FMT "; clone aborted\n",
761 afs_printable_VolumeId_lu(newId), afs_printable_VolumeId_lu(V_parentId(originalvp)));
762 newvp = (Volume *) 0;
766 if (newType == readonlyVolume)
767 V_cloneId(originalvp) = newId;
768 Log("1 Volser: Clone: Cloning volume %" AFS_VOLID_FMT " to new volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
769 afs_printable_VolumeId_lu(newId));
771 Log("1 Volser: Clone: Purging old read only volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(purgeId));
772 CloneVolume(&error, originalvp, newvp, purgevp);
773 purgevp = NULL; /* clone releases it, maybe even if error */
775 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
779 if (newType == readonlyVolume) {
780 V_type(newvp) = readonlyVolume;
781 } else if (newType == backupVolume) {
782 V_type(newvp) = backupVolume;
783 V_backupId(originalvp) = newId;
785 strcpy(V_name(newvp), newName);
786 V_creationDate(newvp) = V_copyDate(newvp);
787 ClearVolumeStats(&V_disk(newvp));
788 V_destroyMe(newvp) = DESTROY_ME;
789 V_inService(newvp) = 0;
790 if (newType == backupVolume) {
791 V_backupDate(originalvp) = V_copyDate(newvp);
792 V_backupDate(newvp) = V_copyDate(newvp);
795 VUpdateVolume(&error, newvp);
797 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
801 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
803 VUpdateVolume(&error, originalvp);
805 Log("1 Volser: Clone: original update %u\n", error);
810 #ifdef AFS_DEMAND_ATTACH_FS
814 /* Clients could have callbacks to the clone ID */
815 FSYNC_VolOp(newId, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
818 tt = (struct volser_trans *)0;
819 error = VOLSERTRELE_ERROR;
827 VDetachVolume(&code, purgevp);
829 VDetachVolume(&code, newvp);
836 #ifdef AFS_DEMAND_ATTACH_FS
837 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
838 V_needsSalvaged(salv_vp) = 1;
840 #endif /* AFS_DEMAND_ATTACH_FS */
844 /* reclone this volume into the specified id */
846 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
850 code = VolReClone(acid, atrans, cloneId);
851 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
857 VolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
859 struct Volume *originalvp, *clonevp;
862 struct volser_trans *tt, *ttc;
863 char caller[MAXKTCNAMELEN];
864 VolumeDiskData saved_header;
866 /*not a super user */
867 if (!afsconf_SuperUser(tdir, acid, caller))
868 return VOLSERBAD_ACCESS;
871 Log("%s on %s is executing Reclone Volume %" AFS_VOLID_FMT "\n", caller,
872 callerAddress(acid, buffer), afs_printable_VolumeId_lu(cloneId));
875 clonevp = originalvp = (Volume *) 0;
877 tt = FindTrans(atrans);
880 if (tt->vflags & VTDeleted) {
881 Log("1 Volser: VolReClone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
885 ttc = NewTrans(cloneId, tt->partition);
886 if (!ttc) { /* someone is messing with the clone already */
888 return VOLSERVOLBUSY;
890 TSetRxCall(tt, acid, "ReClone");
892 originalvp = tt->volume;
893 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
894 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
895 afs_printable_VolumeId_lu(V_id(originalvp)));
900 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
902 Log("1 Volser: can't attach clone %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(cloneId));
906 newType = V_type(clonevp); /* type of the new volume */
908 if (originalvp->device != clonevp->device) {
909 Log("1 Volser: Clone: Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are on different devices\n",
910 afs_printable_VolumeId_lu(tt->volid), afs_printable_VolumeId_lu(cloneId));
914 if (V_parentId(originalvp) != V_parentId(clonevp)) {
915 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " was not originally cloned from volume %" AFS_VOLID_FMT "; aborted\n", afs_printable_VolumeId_lu(cloneId), afs_printable_VolumeId_lu(tt->volid));
920 if (DoPreserveVolumeStats) {
921 CopyVolumeStats(&V_disk(clonevp), &saved_header);
925 Log("1 Volser: Clone: Recloning volume %" AFS_VOLID_FMT " to volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
926 afs_printable_VolumeId_lu(cloneId));
927 CloneVolume(&error, originalvp, clonevp, clonevp);
929 Log("1 Volser: Clone: reclone operation failed with code %d\n",
935 /* fix up volume name and type, CloneVolume just propagated RW's */
936 if (newType == readonlyVolume) {
937 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
938 V_type(clonevp) = readonlyVolume;
939 } else if (newType == backupVolume) {
940 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
941 V_type(clonevp) = backupVolume;
942 V_backupId(originalvp) = cloneId;
944 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
946 /* update the creationDate, since this represents the last cloning date
947 * for ROs. But do not update copyDate; let it stay so we can identify
948 * when the clone was first created. */
949 V_creationDate(clonevp) = time(0);
950 if (DoPreserveVolumeStats) {
951 CopyVolumeStats(&saved_header, &V_disk(clonevp));
953 ClearVolumeStats(&V_disk(clonevp));
955 V_destroyMe(clonevp) = 0;
956 V_inService(clonevp) = 0;
957 if (newType == backupVolume) {
958 V_backupDate(originalvp) = V_creationDate(clonevp);
959 V_backupDate(clonevp) = V_creationDate(clonevp);
961 V_inUse(clonevp) = 0;
962 VUpdateVolume(&error, clonevp);
964 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
968 /* VUpdateVolume succeeded. Mark it in service so there's no window
969 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
970 * specialStatus; this is a reclone and this volume started online
972 V_inService(clonevp) = 1;
973 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
975 VUpdateVolume(&error, originalvp);
977 Log("1 Volser: Clone: original update %u\n", error);
983 tt = (struct volser_trans *)0;
984 error = VOLSERTRELE_ERROR;
991 struct DiskPartition64 *tpartp = originalvp->partition;
992 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
998 VDetachVolume(&code, clonevp);
1004 DeleteTrans(ttc, 1);
1008 /* create a new transaction, associated with volume and partition. Type of
1009 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1010 * See volser.h for definition of iflags (the constants are named IT*).
1013 SAFSVolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1014 afs_int32 iflags, afs_int32 *ttid)
1018 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1019 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1025 VolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1026 afs_int32 iflags, afs_int32 *ttid)
1028 struct volser_trans *tt;
1033 char caller[MAXKTCNAMELEN];
1035 if (!afsconf_SuperUser(tdir, acid, caller))
1036 return VOLSERBAD_ACCESS; /*not a super user */
1037 if (iflags & ITCreate)
1039 else if (iflags & ITBusy)
1041 else if (iflags & ITReadOnly)
1043 else if (iflags & ITOffline)
1046 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1051 tt = NewTrans(volume, partition);
1053 /* can't create a transaction? put the volume back */
1054 Log("1 transcreate: can't create transaction\n");
1055 return VOLSERVOLBUSY;
1057 tv = XAttachVolume(&error, volume, partition, mode);
1061 VDetachVolume(&code, tv);
1065 VTRANS_OBJ_LOCK(tt);
1068 tt->iflags = iflags;
1070 TSetRxCall_r(tt, NULL, "TransCreate");
1071 VTRANS_OBJ_UNLOCK(tt);
1073 return VOLSERTRELE_ERROR;
1078 /* using aindex as a 0-based index, return the aindex'th volume on this server
1079 * Both the volume number and partition number (one-based) are returned.
1082 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, VolumeId *avolume,
1087 code = VolGetNthVolume(acid, aindex, avolume, apart);
1088 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1093 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1096 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1097 return VOLSERBAD_ACCESS;
1099 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1103 /* return the volume flags (VT* constants in volser.h) associated with this
1107 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1111 code = VolGetFlags(acid, atid, aflags);
1112 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1117 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1119 struct volser_trans *tt;
1121 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1122 return VOLSERBAD_ACCESS;
1124 tt = FindTrans(atid);
1127 if (tt->vflags & VTDeleted) {
1128 Log("1 Volser: VolGetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1129 afs_printable_VolumeId_lu(tt->volid));
1133 TSetRxCall(tt, acid, "GetFlags");
1134 *aflags = tt->vflags;
1137 return VOLSERTRELE_ERROR;
1142 /* Change the volume flags (VT* constants in volser.h) associated with this
1143 * transaction. Effects take place immediately on volume, although volume
1144 * remains attached as usual by the transaction.
1147 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1151 code = VolSetFlags(acid, atid, aflags);
1152 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1158 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1160 struct volser_trans *tt;
1163 char caller[MAXKTCNAMELEN];
1165 if (!afsconf_SuperUser(tdir, acid, caller))
1166 return VOLSERBAD_ACCESS; /*not a super user */
1167 /* find the trans */
1168 tt = FindTrans(atid);
1171 if (tt->vflags & VTDeleted) {
1172 Log("1 Volser: VolSetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1173 afs_printable_VolumeId_lu(tt->volid));
1177 TSetRxCall(tt, acid, "SetFlags");
1178 vp = tt->volume; /* pull volume out of transaction */
1180 /* check if we're allowed to make any updates */
1181 if (tt->iflags & ITReadOnly) {
1186 /* handle delete-on-salvage flag */
1187 if (aflags & VTDeleteOnSalvage) {
1188 V_destroyMe(tt->volume) = DESTROY_ME;
1190 V_destroyMe(tt->volume) = 0;
1193 if (aflags & VTOutOfService) {
1194 V_inService(vp) = 0;
1196 V_inService(vp) = 1;
1198 VUpdateVolume(&error, vp);
1199 VTRANS_OBJ_LOCK(tt);
1200 tt->vflags = aflags;
1202 VTRANS_OBJ_UNLOCK(tt);
1203 if (TRELE(tt) && !error)
1204 return VOLSERTRELE_ERROR;
1209 /* dumpS the volume associated with a particular transaction from a particular
1210 * date. Send the dump to a different transaction (destTrans) on the server
1211 * specified by the destServer structure.
1214 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1215 struct destServer *destination, afs_int32 destTrans,
1216 struct restoreCookie *cookie)
1221 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1222 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1223 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1227 static_inline afs_int32
1228 MakeClient(struct rx_call *acid, struct rx_securityClass **securityObject,
1229 afs_int32 *securityIndex)
1231 rxkad_level enc_level = rxkad_clear;
1240 rxkad_GetServerInfo(rx_ConnectionOf(acid), &enc_level, 0, 0, 0, 0, 0);
1241 docrypt = (enc_level == rxkad_crypt ? 1 : 0);
1247 opr_Assert(0 && "doCrypt corrupt?");
1250 code = afsconf_ClientAuthSecure(tdir, securityObject, securityIndex);
1252 code = afsconf_ClientAuth(tdir, securityObject, securityIndex);
1257 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1258 struct destServer *destination, afs_int32 destTrans,
1259 struct restoreCookie *cookie)
1261 struct volser_trans *tt;
1263 struct rx_connection *tcon;
1264 struct rx_call *tcall;
1266 struct rx_securityClass *securityObject;
1267 afs_int32 securityIndex;
1268 char caller[MAXKTCNAMELEN];
1270 if (!afsconf_SuperUser(tdir, acid, caller))
1271 return VOLSERBAD_ACCESS; /*not a super user */
1273 /* find the local transaction */
1274 tt = FindTrans(fromTrans);
1277 if (tt->vflags & VTDeleted) {
1278 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1283 TSetRxCall(tt, NULL, "Forward");
1285 /* get auth info for the this connection (uses afs from ticket file) */
1286 code = MakeClient(acid, &securityObject, &securityIndex);
1292 /* make an rpc connection to the other server */
1294 rx_NewConnection(htonl(destination->destHost),
1295 htons(destination->destPort), VOLSERVICE_ID,
1296 securityObject, securityIndex);
1298 RXS_Close(securityObject); /* will be freed after connection destroyed */
1305 tcall = rx_NewCall(tcon);
1306 TSetRxCall(tt, tcall, "Forward");
1307 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1308 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1313 /* these next calls implictly call rx_Write when writing out data */
1314 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1317 EndAFSVolRestore(tcall); /* probably doesn't do much */
1319 code = rx_EndCall(tcall, 0);
1320 rx_DestroyConnection(tcon); /* done with the connection */
1325 return VOLSERTRELE_ERROR;
1331 (void)rx_EndCall(tcall, 0);
1332 rx_DestroyConnection(tcon);
1341 /* Start a dump and send it to multiple places simultaneously.
1342 * If this returns an error (eg, return ENOENT), it means that
1343 * none of the releases worked. If this returns 0, that means
1344 * that one or more of the releases worked, and the caller has
1345 * to examine the results array to see which one(s).
1346 * This will only do EITHER incremental or full, not both, so it's
1347 * the caller's responsibility to be sure that all the destinations
1348 * need just an incremental (and from the same time), if that's
1352 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1353 fromDate, manyDests *destinations, afs_int32 spare,
1354 struct restoreCookie *cookie, manyResults *results)
1356 afs_int32 securityIndex;
1357 struct rx_securityClass *securityObject;
1358 char caller[MAXKTCNAMELEN];
1359 struct volser_trans *tt;
1360 afs_int32 ec, code, *codes;
1361 struct rx_connection **tcons;
1362 struct rx_call **tcalls;
1364 int i, is_incremental;
1367 memset(results, 0, sizeof(manyResults));
1368 i = results->manyResults_len = destinations->manyDests_len;
1369 results->manyResults_val = codes = malloc(i * sizeof(afs_int32));
1371 if (!results || !results->manyResults_val)
1374 if (!afsconf_SuperUser(tdir, acid, caller))
1375 return VOLSERBAD_ACCESS; /*not a super user */
1376 tt = FindTrans(fromTrans);
1379 if (tt->vflags & VTDeleted) {
1380 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1385 TSetRxCall(tt, NULL, "ForwardMulti");
1387 /* (fromDate == 0) ==> full dump */
1388 is_incremental = (fromDate ? 1 : 0);
1390 tcons = malloc(i * sizeof(struct rx_connection *));
1394 tcalls = malloc(i * sizeof(struct rx_call *));
1400 /* get auth info for this connection (uses afs from ticket file) */
1401 code = MakeClient(acid, &securityObject, &securityIndex);
1403 goto fail; /* in order to audit each failure */
1406 /* make connections to all the other servers */
1407 for (i = 0; i < destinations->manyDests_len; i++) {
1408 struct replica *dest = &(destinations->manyDests_val[i]);
1410 rx_NewConnection(htonl(dest->server.destHost),
1411 htons(dest->server.destPort), VOLSERVICE_ID,
1412 securityObject, securityIndex);
1414 codes[i] = ENOTCONN;
1416 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1417 codes[i] = ENOTCONN;
1420 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1423 (void)rx_EndCall(tcalls[i], 0);
1425 rx_DestroyConnection(tcons[i]);
1432 /* Security object will be freed when all connections destroyed */
1433 RXS_Close(securityObject);
1435 /* these next calls implictly call rx_Write when writing out data */
1436 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1440 for (i--; i >= 0; i--) {
1441 struct replica *dest = &(destinations->manyDests_val[i]);
1443 if (!code && tcalls[i] && !codes[i]) {
1444 EndAFSVolRestore(tcalls[i]);
1447 ec = rx_EndCall(tcalls[i], 0);
1452 rx_DestroyConnection(tcons[i]); /* done with the connection */
1455 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1456 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1457 dest->trans, AUD_END);
1464 if (TRELE(tt) && !code) /* return the first code if it's set */
1465 return VOLSERTRELE_ERROR;
1472 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1476 code = VolDump(acid, fromTrans, fromDate, 0);
1477 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1482 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1487 code = VolDump(acid, fromTrans, fromDate, flags);
1488 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1493 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1497 struct volser_trans *tt;
1498 char caller[MAXKTCNAMELEN];
1500 if (!afsconf_SuperUser(tdir, acid, caller))
1501 return VOLSERBAD_ACCESS; /*not a super user */
1502 tt = FindTrans(fromTrans);
1505 if (tt->vflags & VTDeleted) {
1506 Log("1 Volser: VolDump: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1510 TSetRxCall(tt, acid, "Dump");
1511 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1512 ? 0 : 1); /* squirt out the volume's data, too */
1521 return VOLSERTRELE_ERROR;
1527 * Ha! No more helper process!
1530 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1531 struct restoreCookie *cookie)
1535 code = VolRestore(acid, atrans, aflags, cookie);
1536 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1541 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1542 struct restoreCookie *cookie)
1544 struct volser_trans *tt;
1545 afs_int32 code, tcode;
1546 char caller[MAXKTCNAMELEN];
1548 if (!afsconf_SuperUser(tdir, acid, caller))
1549 return VOLSERBAD_ACCESS; /*not a super user */
1550 tt = FindTrans(atrans);
1553 if (tt->vflags & VTDeleted) {
1554 Log("1 Volser: VolRestore: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1560 Log("%s on %s is executing Restore %" AFS_VOLID_FMT "\n", caller,
1561 callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
1563 TSetRxCall(tt, acid, "Restore");
1565 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1567 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1568 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1572 return (code ? code : tcode);
1575 /* end a transaction, returning the transaction's final error code in rcode */
1577 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1581 code = VolEndTrans(acid, destTrans, rcode);
1582 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1587 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1589 struct volser_trans *tt;
1590 char caller[MAXKTCNAMELEN];
1592 if (!afsconf_SuperUser(tdir, acid, caller))
1593 return VOLSERBAD_ACCESS; /*not a super user */
1594 tt = FindTrans(destTrans);
1598 *rcode = tt->returnCode;
1599 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1605 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1609 code = VolSetForwarding(acid, atid, anewsite);
1610 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1611 htonl(anewsite), AUD_END);
1616 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1618 struct volser_trans *tt;
1619 char caller[MAXKTCNAMELEN];
1622 if (!afsconf_SuperUser(tdir, acid, caller))
1623 return VOLSERBAD_ACCESS; /*not a super user */
1624 tt = FindTrans(atid);
1627 if (tt->vflags & VTDeleted) {
1628 Log("1 Volser: VolSetForwarding: volume %" AFS_VOLID_FMT " has been deleted \n",
1629 afs_printable_VolumeId_lu(tt->volid));
1633 TSetRxCall(tt, acid, "SetForwarding");
1634 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1637 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1640 return VOLSERTRELE_ERROR;
1646 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1647 struct volser_status *astatus)
1651 code = VolGetStatus(acid, atrans, astatus);
1652 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1657 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1658 struct volser_status *astatus)
1661 struct VolumeDiskData *td;
1662 struct volser_trans *tt;
1664 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1665 return VOLSERBAD_ACCESS;
1667 tt = FindTrans(atrans);
1670 if (tt->vflags & VTDeleted) {
1671 Log("1 Volser: VolGetStatus: volume %" AFS_VOLID_FMT " has been deleted \n",
1672 afs_printable_VolumeId_lu(tt->volid));
1676 TSetRxCall(tt, acid, "GetStatus");
1685 astatus->volID = td->id;
1686 astatus->nextUnique = td->uniquifier;
1687 astatus->type = td->type;
1688 astatus->parentID = td->parentId;
1689 astatus->cloneID = td->cloneId;
1690 astatus->backupID = td->backupId;
1691 astatus->restoredFromID = td->restoredFromId;
1692 astatus->maxQuota = td->maxquota;
1693 astatus->minQuota = td->minquota;
1694 astatus->owner = td->owner;
1695 astatus->creationDate = td->creationDate;
1696 astatus->accessDate = td->accessDate;
1697 astatus->updateDate = td->updateDate;
1698 astatus->expirationDate = td->expirationDate;
1699 astatus->backupDate = td->backupDate;
1700 astatus->copyDate = td->copyDate;
1703 return VOLSERTRELE_ERROR;
1709 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1710 struct volintInfo *astatus)
1714 code = VolSetInfo(acid, atrans, astatus);
1715 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1720 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1721 struct volintInfo *astatus)
1724 struct VolumeDiskData *td;
1725 struct volser_trans *tt;
1726 char caller[MAXKTCNAMELEN];
1729 if (!afsconf_SuperUser(tdir, acid, caller))
1730 return VOLSERBAD_ACCESS; /*not a super user */
1731 tt = FindTrans(atrans);
1734 if (tt->vflags & VTDeleted) {
1735 Log("1 Volser: VolSetInfo: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1739 TSetRxCall(tt, acid, "SetStatus");
1749 * Add more fields as necessary
1751 if (astatus->maxquota != -1)
1752 td->maxquota = astatus->maxquota;
1753 if (astatus->dayUse != -1)
1754 td->dayUse = astatus->dayUse;
1755 if (astatus->creationDate != -1)
1756 td->creationDate = astatus->creationDate;
1757 if (astatus->updateDate != -1)
1758 td->updateDate = astatus->updateDate;
1759 if (astatus->spare2 != -1)
1760 td->volUpdateCounter = (unsigned int)astatus->spare2;
1761 VUpdateVolume(&error, tv);
1764 return VOLSERTRELE_ERROR;
1770 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1774 code = VolGetName(acid, atrans, aname);
1775 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1780 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1783 struct VolumeDiskData *td;
1784 struct volser_trans *tt;
1787 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1788 return VOLSERBAD_ACCESS;
1790 /* We need to at least fill it in */
1794 tt = FindTrans(atrans);
1797 if (tt->vflags & VTDeleted) {
1798 Log("1 Volser: VolGetName: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1802 TSetRxCall(tt, acid, "GetName");
1811 len = strlen(td->name) + 1; /* don't forget the null */
1817 *aname = realloc(*aname, len);
1818 strcpy(*aname, td->name);
1821 return VOLSERTRELE_ERROR;
1826 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1829 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1830 VolumeId parentId, VolumeId cloneId)
1836 /*return a list of all partitions on the server. The non mounted
1837 *partitions are returned as -1 in the corresponding slot in partIds*/
1839 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1843 code = VolListPartitions(acid, partIds);
1844 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1849 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1854 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1855 return VOLSERBAD_ACCESS;
1857 strcpy(namehead, "/vicep"); /*7 including null terminator */
1859 /* Just return attached partitions. */
1861 for (i = 0; i < 26; i++) {
1862 namehead[6] = i + 'a';
1863 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1869 /*return a list of all partitions on the server. The non mounted
1870 *partitions are returned as -1 in the corresponding slot in partIds*/
1872 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1876 code = XVolListPartitions(acid, pEntries);
1877 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1882 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1885 struct partList partList;
1886 struct DiskPartition64 *dp;
1889 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1890 return VOLSERBAD_ACCESS;
1892 strcpy(namehead, "/vicep"); /*7 including null terminator */
1894 /* Only report attached partitions */
1895 for (i = 0; i < VOLMAXPARTS; i++) {
1896 #ifdef AFS_DEMAND_ATTACH_FS
1897 dp = VGetPartitionById(i, 0);
1900 namehead[6] = i + 'a';
1906 namehead[6] = 'a' + (k / 26);
1907 namehead[7] = 'a' + (k % 26);
1910 dp = VGetPartition(namehead, 0);
1913 partList.partId[j++] = i;
1916 pEntries->partEntries_val = malloc(j * sizeof(int));
1917 if (!pEntries->partEntries_val)
1919 memcpy(pEntries->partEntries_val, partList.partId,
1921 pEntries->partEntries_len = j;
1923 pEntries->partEntries_val = NULL;
1924 pEntries->partEntries_len = 0;
1931 * Scan a directory for possible volume headers.
1932 * in: DIR *dirp -- a directory handle from opendir()
1933 * out: char *volname -- set to name of directory entry
1934 * afs_uint32 *volid -- set to volume ID parsed from name
1936 * true if volname and volid have been set to valid values
1937 * false if we got to the end of the directory
1940 GetNextVol(DIR *dirp, char *volname, VolumeId *volid)
1944 while ((dp = readdir(dirp)) != NULL) {
1945 /* could be optimized on platforms with dp->d_namlen */
1946 if (dp->d_name[0] == 'V' && strlen(dp->d_name) == VHDRNAMELEN
1947 && strcmp(&(dp->d_name[VFORMATDIGITS + 1]), VHDREXT) == 0) {
1948 *volid = VolumeNumber(dp->d_name);
1949 strcpy(volname, dp->d_name);
1957 * volint vol info structure type.
1960 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1961 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1962 } volint_info_type_t;
1965 * handle to various on-wire vol info types.
1968 volint_info_type_t volinfo_type;
1974 } volint_info_handle_t;
1977 * store value to a field at the appropriate location in on-wire structure.
1979 #define VOLINT_INFO_STORE(handle, name, val) \
1981 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1982 (handle)->volinfo_ptr.base->name = (val); \
1984 (handle)->volinfo_ptr.ext->name = (val); \
1989 * get pointer to appropriate offset of field in on-wire structure.
1991 #define VOLINT_INFO_PTR(handle, name) \
1992 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1993 &((handle)->volinfo_ptr.base->name) : \
1994 &((handle)->volinfo_ptr.ext->name))
1997 * fill in appropriate type of on-wire volume metadata structure.
1999 * @param vp pointer to volume object
2000 * @param handle pointer to wire format handle object
2002 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
2003 * @pre handle object must have a valid pointer and enumeration value
2005 * @note passing a NULL value for vp means that the fileserver doesn't
2006 * know about this particular volume, thus implying it is offline.
2008 * @return operation status
2013 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
2015 unsigned int numStatBytes, now;
2016 struct VolumeDiskData *hdr = &(V_disk(vp));
2018 /*read in the relevant info */
2019 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2020 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
2021 VOLINT_INFO_STORE(handle, volid, hdr->id);
2022 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2023 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2024 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2025 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2026 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2027 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2028 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2029 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2030 now = FT_ApproxTime();
2031 if ((now - hdr->dayUseDate) > OneDay) {
2032 VOLINT_INFO_STORE(handle, dayUse, 0);
2034 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2036 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2037 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2038 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2039 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2041 #ifdef AFS_DEMAND_ATTACH_FS
2043 * for DAFS, we "lie" about volume state --
2044 * instead of returning the raw state from the disk header,
2045 * we compute state based upon the fileserver's internal
2046 * in-core state enumeration value reported to us via fssync,
2047 * along with the blessed and inService flags from the header.
2048 * -- tkeiser 11/27/2007
2051 /* Conditions that offline status is based on:
2052 volume is unattached state
2053 volume state is in (one of several error states)
2054 volume not in service
2055 volume is not marked as blessed (not on hold)
2056 volume in salvage req. state
2057 volume needsSalvaged
2058 next op would set volume offline
2059 next op would not leave volume online (based on several conditions)
2062 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2063 VIsErrorState(V_attachState(vp)) ||
2066 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2067 hdr->needsSalvaged ||
2068 (vp->pending_vol_op &&
2069 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2070 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2073 VOLINT_INFO_STORE(handle, inUse, 0);
2075 VOLINT_INFO_STORE(handle, inUse, 1);
2078 /* offline status based on program type, where != fileServer enum (1) is offline */
2079 if (hdr->inUse == fileServer) {
2080 VOLINT_INFO_STORE(handle, inUse, 1);
2082 VOLINT_INFO_STORE(handle, inUse, 0);
2087 switch(handle->volinfo_type) {
2088 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2089 case VOLINT_INFO_TYPE_BASE:
2091 #ifdef AFS_DEMAND_ATTACH_FS
2092 /* see comment above where we set inUse bit */
2093 if (hdr->needsSalvaged ||
2094 (vp && VIsErrorState(V_attachState(vp)))) {
2095 handle->volinfo_ptr.base->needsSalvaged = 1;
2097 handle->volinfo_ptr.base->needsSalvaged = 0;
2100 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2102 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2103 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2104 handle->volinfo_ptr.base->spare1 =
2105 (long)hdr->weekUse[0] +
2106 (long)hdr->weekUse[1] +
2107 (long)hdr->weekUse[2] +
2108 (long)hdr->weekUse[3] +
2109 (long)hdr->weekUse[4] +
2110 (long)hdr->weekUse[5] +
2111 (long)hdr->weekUse[6];
2112 handle->volinfo_ptr.base->flags = 0;
2113 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2114 handle->volinfo_ptr.base->spare3 = 0;
2118 case VOLINT_INFO_TYPE_EXT:
2120 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2121 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2124 * Copy out the stat fields in a single operation.
2126 if ((now - hdr->dayUseDate) > OneDay) {
2127 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2130 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2131 (char *)&(hdr->stat_reads[0]),
2140 #ifdef AFS_DEMAND_ATTACH_FS
2143 * get struct Volume out of the fileserver.
2145 * @param[in] volumeId volumeId for which we want state information
2146 * @param[in] pname partition name string
2147 * @param[inout] vp pointer to pointer to Volume object which
2148 * will be populated (see note)
2150 * @return operation status
2152 * @retval non-zero failure
2154 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2159 GetVolObject(VolumeId volumeId, char * pname, Volume ** vp)
2164 res.hdr.response_len = sizeof(res.hdr);
2165 res.payload.buf = *vp;
2166 res.payload.len = sizeof(Volume);
2168 code = FSYNC_VolOp(volumeId,
2174 if (code != SYNC_OK) {
2175 switch (res.hdr.reason) {
2176 case FSYNC_WRONG_PART:
2177 case FSYNC_UNKNOWN_VOLID:
2190 * mode of volume list operation.
2193 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2194 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2195 } vol_info_list_mode_t;
2198 * abstract interface to populate wire-format volume metadata structures.
2200 * @param[in] partId partition id
2201 * @param[in] volumeId volume id
2202 * @param[in] pname partition name
2203 * @param[in] volname volume file name
2204 * @param[in] handle handle to on-wire volume metadata object
2205 * @param[in] mode listing mode
2207 * @return operation status
2209 * @retval -2 DESTROY_ME flag is set
2210 * @retval -1 general failure; some data filled in
2211 * @retval -3 couldn't create vtrans; some data filled in
2214 GetVolInfo(afs_uint32 partId,
2218 volint_info_handle_t * handle,
2219 vol_info_list_mode_t mode)
2223 struct volser_trans *ttc = NULL;
2224 struct Volume *fill_tv, *tv = NULL;
2225 #ifdef AFS_DEMAND_ATTACH_FS
2226 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2227 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2228 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2229 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2231 /* Set up response handle for pending_vol_op */
2232 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2233 fs_res.payload.buf = fs_res_buf;
2234 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2237 ttc = NewTrans(volumeId, partId);
2240 VOLINT_INFO_STORE(handle, status, VBUSY);
2241 VOLINT_INFO_STORE(handle, volid, volumeId);
2245 /* Get volume from volserver */
2246 if (mode == VOL_INFO_LIST_MULTIPLE)
2247 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2249 #ifdef AFS_DEMAND_ATTACH_FS
2252 int mode = V_READONLY; /* informs the fileserver to update the volume headers. */
2254 tv = VAttachVolumeByName_retry(&error, pname, volname, mode);
2258 Log("1 Volser: GetVolInfo: Could not attach volume %" AFS_VOLID_FMT " (%s:%s) error=%d\n",
2259 afs_printable_VolumeId_lu(volumeId), pname, volname, error);
2264 * please note that destroyMe and needsSalvaged checks used to be ordered
2265 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2266 * more correct to check destroyMe before needsSalvaged.
2267 * -- tkeiser 11/28/2007
2270 if (V_destroyMe(tv) == DESTROY_ME) {
2272 case VOL_INFO_LIST_MULTIPLE:
2276 case VOL_INFO_LIST_SINGLE:
2277 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) will be destroyed on next salvage\n",
2278 afs_printable_VolumeId_lu(volumeId), pname, volname);
2285 if (V_needsSalvaged(tv)) {
2286 /*this volume will be salvaged */
2287 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) needs to be salvaged\n",
2288 afs_printable_VolumeId_lu(volumeId), pname, volname);
2291 #ifdef AFS_DEMAND_ATTACH_FS
2292 /* If using DAFS, get volume from fsserver */
2293 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2298 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2299 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2300 /* If we if the pending vol op */
2301 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2302 fs_tv->pending_vol_op=&pending_vol_op_res;
2304 fs_tv->pending_vol_op=NULL;
2307 /* populate the header from the volserver copy */
2308 fs_tv->header=tv->header;
2310 /* When using DAFS, use the fs volume info, populated with required structures */
2313 /* When not using DAFS, just use the local volume info */
2317 /* ok, we have all the data we need; fill in the on-wire struct */
2318 code = FillVolInfo(fill_tv, handle);
2322 VOLINT_INFO_STORE(handle, status, 0);
2323 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2324 VOLINT_INFO_STORE(handle, volid, volumeId);
2327 VDetachVolume(&error, tv);
2330 VOLINT_INFO_STORE(handle, status, 0);
2331 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2332 Log("1 Volser: GetVolInfo: Could not detach volume %" AFS_VOLID_FMT " (%s:%s)\n",
2333 afs_printable_VolumeId_lu(volumeId), pname, volname);
2337 DeleteTrans(ttc, 1);
2344 /*return the header information about the <volid> */
2346 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2347 VolumeId volumeId, volEntries *volumeInfo)
2351 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2352 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2357 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2358 VolumeId volumeId, volEntries *volumeInfo)
2360 struct DiskPartition64 *partP;
2361 char pname[9], volname[20];
2365 volint_info_handle_t handle;
2367 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2368 return VOLSERBAD_ACCESS;
2370 volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2371 if (!volumeInfo->volEntries_val)
2374 volumeInfo->volEntries_len = 1;
2375 if (GetPartName(partid, pname))
2376 return VOLSERILLEGAL_PARTITION;
2377 if (!(partP = VGetPartition(pname, 0)))
2378 return VOLSERILLEGAL_PARTITION;
2379 dirp = opendir(VPartitionPath(partP));
2381 return VOLSERILLEGAL_PARTITION;
2383 while (GetNextVol(dirp, volname, &volid)) {
2384 if (volid == volumeId) { /*copy other things too */
2391 #ifndef AFS_PTHREAD_ENV
2392 IOMGR_Poll(); /*make sure that the client does not time out */
2395 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2396 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2398 /* The return code from GetVolInfo is ignored; there is no error from
2399 * it that results in the whole call being aborted. Any volume
2400 * attachment failures are reported in 'status' field in the
2401 * volumeInfo payload. */
2407 VOL_INFO_LIST_SINGLE);
2411 return (found) ? 0 : ENODEV;
2414 /*------------------------------------------------------------------------
2415 * EXPORTED SAFSVolXListOneVolume
2418 * Returns extended info on volume a_volID on partition a_partID.
2421 * a_rxCidP : Pointer to the Rx call we're performing.
2422 * a_partID : Partition for which we want the extended list.
2423 * a_volID : Volume ID we wish to know about.
2424 * a_volumeXInfoP : Ptr to the extended info blob.
2427 * 0 Successful operation
2428 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2431 * Nothing interesting.
2435 *------------------------------------------------------------------------*/
2438 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2439 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2443 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2444 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2449 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2450 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2451 { /*SAFSVolXListOneVolume */
2453 struct DiskPartition64 *partP; /*Ptr to partition */
2454 char pname[9], volname[20]; /*Partition, volume names */
2455 DIR *dirp; /*Partition directory ptr */
2456 VolumeId currVolID; /*Current volume ID */
2457 int found = 0; /*Did we find the volume we need? */
2458 volint_info_handle_t handle;
2460 if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
2461 return VOLSERBAD_ACCESS;
2464 * Set up our pointers for action, marking our structure to hold exactly
2465 * one entry. Also, assume we'll fail in our quest.
2467 a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2468 if (!a_volumeXInfoP->volXEntries_val)
2471 a_volumeXInfoP->volXEntries_len = 1;
2474 * If the partition name we've been given is bad, bogue out.
2476 if (GetPartName(a_partID, pname))
2477 return (VOLSERILLEGAL_PARTITION);
2480 * Open the directory representing the given AFS parttion. If we can't
2483 if (!(partP = VGetPartition(pname, 0)))
2484 return VOLSERILLEGAL_PARTITION;
2485 dirp = opendir(VPartitionPath(partP));
2487 return (VOLSERILLEGAL_PARTITION);
2491 * Sweep through the partition directory, looking for the desired entry.
2492 * First, of course, figure out how many stat bytes to copy out of each
2495 while (GetNextVol(dirp, volname, &currVolID)) {
2496 if (currVolID == a_volID) {
2498 * We found the volume entry we're interested. Pull out the
2499 * extended information, remembering to poll (so that the client
2500 * doesn't time out) and to set up a transaction on the volume.
2504 } /*Found desired volume */
2508 #ifndef AFS_PTHREAD_ENV
2512 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2513 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2515 /* The return code from GetVolInfo is ignored; there is no error from
2516 * it that results in the whole call being aborted. Any volume
2517 * attachment failures are reported in 'status' field in the
2518 * volumeInfo payload. */
2519 GetVolInfo(a_partID,
2524 VOL_INFO_LIST_SINGLE);
2528 * Clean up before going to dinner: close the partition directory,
2529 * return the proper value.
2532 return (found) ? 0 : ENODEV;
2533 } /*SAFSVolXListOneVolume */
2535 /*returns all the volumes on partition partid. If flags = 1 then all the
2536 * relevant info about the volumes is also returned */
2538 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2539 volEntries *volumeInfo)
2543 code = VolListVolumes(acid, partid, flags, volumeInfo);
2544 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2549 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2550 volEntries *volumeInfo)
2553 struct DiskPartition64 *partP;
2554 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2555 char pname[9], volname[20];
2559 volint_info_handle_t handle;
2561 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2562 return VOLSERBAD_ACCESS;
2564 volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2565 if (!volumeInfo->volEntries_val)
2568 pntr = volumeInfo->volEntries_val;
2569 volumeInfo->volEntries_len = 0;
2570 if (GetPartName(partid, pname))
2571 return VOLSERILLEGAL_PARTITION;
2572 if (!(partP = VGetPartition(pname, 0)))
2573 return VOLSERILLEGAL_PARTITION;
2574 dirp = opendir(VPartitionPath(partP));
2576 return VOLSERILLEGAL_PARTITION;
2578 while (GetNextVol(dirp, volname, &volid)) {
2579 if (flags) { /*copy other things too */
2580 #ifndef AFS_PTHREAD_ENV
2581 IOMGR_Poll(); /*make sure that the client does not time out */
2584 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2585 handle.volinfo_ptr.base = pntr;
2588 code = GetVolInfo(partid,
2593 VOL_INFO_LIST_MULTIPLE);
2594 if (code == -2) /* DESTROY_ME flag set */
2597 pntr->volid = volid;
2598 /*just volids are needed */
2602 volumeInfo->volEntries_len += 1;
2603 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2604 /*running out of space, allocate more space */
2605 allocSize = (allocSize * 3) / 2;
2606 pntr = realloc(volumeInfo->volEntries_val,
2607 allocSize * sizeof(volintInfo));
2610 return VOLSERNO_MEMORY;
2612 volumeInfo->volEntries_val = pntr; /* point to new block */
2613 /* set pntr to the right position */
2614 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2622 /*------------------------------------------------------------------------
2623 * EXPORTED SAFSVolXListVolumes
2626 * Returns all the volumes on partition a_partID. If a_flags
2627 * is set to 1, then all the relevant extended volume information
2631 * a_rxCidP : Pointer to the Rx call we're performing.
2632 * a_partID : Partition for which we want the extended list.
2633 * a_flags : Various flags.
2634 * a_volumeXInfoP : Ptr to the extended info blob.
2637 * 0 Successful operation
2638 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2639 * VOLSERNO_MEMORY if we ran out of memory allocating
2643 * Nothing interesting.
2647 *------------------------------------------------------------------------*/
2650 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2651 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2655 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2656 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2661 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2662 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2663 { /*SAFSVolXListVolumes */
2665 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2666 struct DiskPartition64 *partP; /*Ptr to partition */
2667 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2668 char pname[9], volname[20]; /*Partition, volume names */
2669 DIR *dirp; /*Partition directory ptr */
2670 VolumeId volid; /*Current volume ID */
2672 volint_info_handle_t handle;
2674 if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
2675 return VOLSERBAD_ACCESS;
2678 * Allocate a large array of extended volume info structures, then
2679 * set it up for action.
2681 a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2682 if (!a_volumeXInfoP->volXEntries_val)
2685 xInfoP = a_volumeXInfoP->volXEntries_val;
2686 a_volumeXInfoP->volXEntries_len = 0;
2689 * If the partition name we've been given is bad, bogue out.
2691 if (GetPartName(a_partID, pname))
2692 return (VOLSERILLEGAL_PARTITION);
2695 * Open the directory representing the given AFS parttion. If we can't
2698 if (!(partP = VGetPartition(pname, 0)))
2699 return VOLSERILLEGAL_PARTITION;
2700 dirp = opendir(VPartitionPath(partP));
2702 return (VOLSERILLEGAL_PARTITION);
2703 while (GetNextVol(dirp, volname, &volid)) {
2706 * Full info about the volume desired. Poll to make sure the
2707 * client doesn't time out, then start up a new transaction.
2709 #ifndef AFS_PTHREAD_ENV
2713 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2714 handle.volinfo_ptr.ext = xInfoP;
2716 code = GetVolInfo(a_partID,
2721 VOL_INFO_LIST_MULTIPLE);
2722 if (code == -2) /* DESTROY_ME flag set */
2726 * Just volume IDs are needed.
2728 xInfoP->volid = volid;
2732 * Bump the pointer in the data area we're building, along with
2733 * the count of the number of entries it contains.
2736 (a_volumeXInfoP->volXEntries_len)++;
2737 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2739 * We're running out of space in the area we've built. Grow it.
2741 allocSize = (allocSize * 3) / 2;
2742 xInfoP = (volintXInfo *)
2743 realloc((char *)a_volumeXInfoP->volXEntries_val,
2744 (allocSize * sizeof(volintXInfo)));
2745 if (xInfoP == NULL) {
2747 * Bummer, no memory. Bag it, tell our caller what went wrong.
2750 return (VOLSERNO_MEMORY);
2754 * Memory reallocation worked. Correct our pointers so they
2755 * now point to the new block and the current open position within
2758 a_volumeXInfoP->volXEntries_val = xInfoP;
2760 a_volumeXInfoP->volXEntries_val +
2761 a_volumeXInfoP->volXEntries_len;
2766 * We've examined all entries in the partition directory. Close it,
2767 * delete our transaction (if any), and go home happy.
2772 } /*SAFSVolXListVolumes */
2774 /*this call is used to monitor the status of volser for debugging purposes.
2775 *information about all the active transactions is returned in transInfo*/
2777 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2781 code = VolMonitor(acid, transInfo);
2782 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2787 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2789 transDebugInfo *pntr;
2790 afs_int32 allocSize = 50;
2791 struct volser_trans *tt, *nt, *allTrans;
2793 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2794 return VOLSERBAD_ACCESS;
2796 transInfo->transDebugEntries_val =
2797 malloc(allocSize * sizeof(transDebugInfo));
2798 if (!transInfo->transDebugEntries_val)
2800 pntr = transInfo->transDebugEntries_val;
2801 transInfo->transDebugEntries_len = 0;
2804 allTrans = TransList();
2805 if (allTrans == (struct volser_trans *)0)
2806 goto done; /*no active transactions */
2807 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2809 VTRANS_OBJ_LOCK(tt);
2810 pntr->tid = tt->tid;
2811 pntr->time = tt->time;
2812 pntr->creationTime = tt->creationTime;
2813 pntr->returnCode = tt->returnCode;
2814 pntr->volid = tt->volid;
2815 pntr->partition = tt->partition;
2816 pntr->iflags = tt->iflags;
2817 pntr->vflags = tt->vflags;
2818 pntr->tflags = tt->tflags;
2819 strcpy(pntr->lastProcName, tt->lastProcName);
2820 pntr->callValid = 0;
2821 if (tt->rxCallPtr) { /*record call related info */
2822 pntr->callValid = 1;
2824 pntr->readNext = tt->rxCallPtr->rnext;
2825 pntr->transmitNext = tt->rxCallPtr->tnext;
2826 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2827 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2830 VTRANS_OBJ_UNLOCK(tt);
2832 transInfo->transDebugEntries_len += 1;
2833 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2834 allocSize = (allocSize * 3) / 2;
2835 pntr = realloc(transInfo->transDebugEntries_val,
2836 allocSize * sizeof(transDebugInfo));
2837 transInfo->transDebugEntries_val = pntr;
2839 transInfo->transDebugEntries_val +
2840 transInfo->transDebugEntries_len;
2841 /*set pntr to right position */
2852 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2853 afs_int32 type, afs_uint32 pId, VolumeId cloneId,
2858 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2859 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2860 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2866 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2867 afs_int32 type, VolumeId pId, VolumeId cloneId,
2872 struct volser_trans *tt;
2873 char caller[MAXKTCNAMELEN];
2875 if (strlen(name) > 31)
2876 return VOLSERBADNAME;
2877 if (!afsconf_SuperUser(tdir, acid, caller))
2878 return VOLSERBAD_ACCESS; /*not a super user */
2879 /* find the trans */
2880 tt = FindTrans(atid);
2883 if (tt->vflags & VTDeleted) {
2884 Log("1 Volser: VolSetIds: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2888 TSetRxCall(tt, acid, "SetIdsTypes");
2892 V_backupId(tv) = backupId;
2893 V_cloneId(tv) = cloneId;
2894 V_parentId(tv) = pId;
2895 strcpy((&V_disk(tv))->name, name);
2896 VUpdateVolume(&error, tv);
2898 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2903 if (TRELE(tt) && !error)
2904 return VOLSERTRELE_ERROR;
2909 if (TRELE(tt) && !error)
2910 return VOLSERTRELE_ERROR;
2915 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2919 code = VolSetDate(acid, atid, cdate);
2920 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2926 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2930 struct volser_trans *tt;
2931 char caller[MAXKTCNAMELEN];
2933 if (!afsconf_SuperUser(tdir, acid, caller))
2934 return VOLSERBAD_ACCESS; /*not a super user */
2935 /* find the trans */
2936 tt = FindTrans(atid);
2939 if (tt->vflags & VTDeleted) {
2940 Log("1 Volser: VolSetDate: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2944 TSetRxCall(tt, acid, "SetDate");
2947 V_creationDate(tv) = cdate;
2948 VUpdateVolume(&error, tv);
2950 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2955 if (TRELE(tt) && !error)
2956 return VOLSERTRELE_ERROR;
2961 if (TRELE(tt) && !error)
2962 return VOLSERTRELE_ERROR;
2967 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2973 char caller[MAXKTCNAMELEN];
2975 struct volser_trans *ttc;
2976 char pname[16], volname[20];
2977 struct DiskPartition64 *partP;
2978 afs_int32 ret = ENODEV;
2981 if (!afsconf_SuperUser(tdir, acid, caller))
2982 return VOLSERBAD_ACCESS; /*not a super user */
2983 if (GetPartName(partId, pname))
2984 return VOLSERILLEGAL_PARTITION;
2985 if (!(partP = VGetPartition(pname, 0)))
2986 return VOLSERILLEGAL_PARTITION;
2987 dirp = opendir(VPartitionPath(partP));
2989 return VOLSERILLEGAL_PARTITION;
2990 ttc = (struct volser_trans *)0;
2992 while (GetNextVol(dirp, volname, &volid)) {
2993 if (volid == volumeId) { /*copy other things too */
2994 #ifndef AFS_PTHREAD_ENV
2995 IOMGR_Poll(); /*make sure that the client doesnot time out */
2997 ttc = NewTrans(volumeId, partId);
2999 return VOLSERVOLBUSY;
3001 #ifdef AFS_NAMEI_ENV
3002 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3004 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3011 DeleteTrans(ttc, 1);
3019 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3020 struct volintSize *size)
3023 struct volser_trans *tt;
3024 char caller[MAXKTCNAMELEN];
3026 if (!afsconf_SuperUser(tdir, acid, caller))
3027 return VOLSERBAD_ACCESS; /*not a super user */
3028 tt = FindTrans(fromTrans);
3031 if (tt->vflags & VTDeleted) {
3035 TSetRxCall(tt, acid, "GetSize");
3036 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3039 return VOLSERTRELE_ERROR;
3041 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3046 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 ovid, afs_uint32 onew,
3047 afs_uint32 where, afs_int32 verbose)
3049 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3051 Volume *vol=0, *newvol=0;
3052 struct volser_trans *tt = 0, *tt2 = 0;
3053 char caller[MAXKTCNAMELEN];
3055 VolumeId new = onew;
3056 VolumeId vid = ovid;
3058 if (!afsconf_SuperUser(tdir, acall, caller))
3061 vol = VAttachVolume(&code, vid, V_VOLUPD);
3067 newvol = VAttachVolume(&code, new, V_VOLUPD);
3069 VDetachVolume(&code2, vol);
3074 if (V_device(vol) != V_device(newvol)
3075 || V_uniquifier(newvol) != 2) {
3076 if (V_device(vol) != V_device(newvol)) {
3077 sprintf(line, "Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are not in the same partition, aborted.\n",
3078 afs_printable_VolumeId_lu(vid),
3079 afs_printable_VolumeId_lu(new));
3080 rx_Write(acall, line, strlen(line));
3082 if (V_uniquifier(newvol) != 2) {
3083 sprintf(line, "Volume %" AFS_VOLID_FMT " is not freshly created, aborted.\n",
3084 afs_printable_VolumeId_lu(new));
3085 rx_Write(acall, line, strlen(line));
3088 rx_Write(acall, line, 1);
3089 VDetachVolume(&code2, vol);
3090 VDetachVolume(&code2, newvol);
3093 tt = NewTrans(vid, V_device(vol));
3095 sprintf(line, "Couldn't create transaction for %" AFS_VOLID_FMT ", aborted.\n",
3096 afs_printable_VolumeId_lu(vid));
3097 rx_Write(acall, line, strlen(line));
3099 rx_Write(acall, line, 1);
3100 VDetachVolume(&code2, vol);
3101 VDetachVolume(&code2, newvol);
3102 return VOLSERVOLBUSY;
3104 VTRANS_OBJ_LOCK(tt);
3105 tt->iflags = ITBusy;
3107 TSetRxCall_r(tt, NULL, "SplitVolume");
3108 VTRANS_OBJ_UNLOCK(tt);
3110 tt2 = NewTrans(new, V_device(newvol));
3112 sprintf(line, "Couldn't create transaction for %" AFS_VOLID_FMT ", aborted.\n",
3113 afs_printable_VolumeId_lu(new));
3114 rx_Write(acall, line, strlen(line));
3116 rx_Write(acall, line, 1);
3118 VDetachVolume(&code2, vol);
3119 VDetachVolume(&code2, newvol);
3120 return VOLSERVOLBUSY;
3122 VTRANS_OBJ_LOCK(tt2);
3123 tt2->iflags = ITBusy;
3125 TSetRxCall_r(tt2, NULL, "SplitVolume");
3126 VTRANS_OBJ_UNLOCK(tt2);
3128 code = split_volume(acall, vol, newvol, where, verbose);
3130 VDetachVolume(&code2, vol);
3132 VDetachVolume(&code2, newvol);
3133 DeleteTrans(tt2, 1);
3140 /* GetPartName - map partid (a decimal number) into pname (a string)
3141 * Since for NT we actually want to return the drive name, we map through the
3145 GetPartName(afs_int32 partid, char *pname)
3150 strcpy(pname, "/vicep");
3151 pname[6] = 'a' + partid;
3154 } else if (partid < VOLMAXPARTS) {
3155 strcpy(pname, "/vicep");
3157 pname[6] = 'a' + (partid / 26);
3158 pname[7] = 'a' + (partid % 26);