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, struct restoreCookie *);
100 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
101 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
102 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
103 struct volser_status *);
104 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
105 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
106 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
107 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
108 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, VolumeId,
110 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, VolumeId,
112 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
114 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
116 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
117 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
118 afs_int32, VolumeId, VolumeId,
120 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
123 * Return the host address of the caller as a string.
125 * @param[in] acid incoming rx call
126 * @param[out] buffer buffer to be filled with the addess string
128 * @return address as formatted by inet_ntoa
131 callerAddress(struct rx_call *acid, char *buffer)
133 afs_uint32 ip = rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid)));
134 return afs_inet_ntoa_r(ip, buffer);
137 /* this call unlocks all of the partition locks we've set */
141 struct DiskPartition64 *tp;
142 for (tp = DiskPartitionList; tp; tp = tp->next) {
143 if (tp->lock_fd != INVALID_FD) {
144 OS_CLOSE(tp->lock_fd);
145 tp->lock_fd = INVALID_FD;
156 code = VPFullUnlock_r();
162 ConvertVolume(VolumeId avol, char *aname, afs_int32 asize)
166 /* 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 */
167 snprintf(aname, asize, VFORMAT, afs_printable_VolumeId_lu(avol));
172 ConvertPartition(int apartno, char *aname, int asize)
178 strcpy(aname, "/vicep");
180 aname[6] = 'a' + apartno;
184 aname[6] = 'a' + (apartno / 26);
185 aname[7] = 'a' + (apartno % 26);
191 #ifdef AFS_DEMAND_ATTACH_FS
192 /* normally we should use the regular salvaging functions from the volume
193 * package, but this is a special case where we have a volume ID, but no
194 * volume structure to give the volume package */
196 SalvageUnknownVolume(VolumeId volid, char *part)
200 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
201 afs_printable_uint32_lu(volid), part);
203 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
204 FSYNC_SALVAGE, NULL);
206 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
207 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
211 #endif /* AFS_DEMAND_ATTACH_FS */
213 static struct Volume *
214 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
219 vp = VAttachVolumeByName(ec, partition, name, mode);
221 #ifdef AFS_DEMAND_ATTACH_FS
225 * The fileserver will take care of keeping track of how many
226 * demand-salvages have been performed, and will force the volume to
227 * ERROR if we've done too many. The limit on This loop is just a
228 * failsafe to prevent trying to salvage forever. We want to attempt
229 * attachment at least SALVAGE_COUNT_MAX times, since we want to
230 * avoid prematurely exiting this loop, if we can.
232 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
233 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
234 vp = VAttachVolumeByName(ec, partition, name, mode);
237 if (*ec == VSALVAGING) {
241 #endif /* AFS_DEMAND_ATTACH_FS */
246 static struct Volume *
247 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
252 vp = VAttachVolume(ec, avolid, amode);
254 #ifdef AFS_DEMAND_ATTACH_FS
257 /* see comment above in VAttachVolumeByName_retry */
258 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
259 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
260 vp = VAttachVolume(ec, avolid, amode);
263 if (*ec == VSALVAGING) {
267 #endif /* AFS_DEMAND_ATTACH_FS */
272 /* the only attach function that takes a partition is "...ByName", so we use it */
273 static struct Volume *
274 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
276 char pbuf[30], vbuf[20];
278 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
282 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
287 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
290 /* Adapted from the file server; create a root directory for this volume */
292 ViceCreateRoot(Volume *vp)
295 struct acl_accessList *ACL;
297 Inode inodeNumber, AFS_UNUSED nearInode;
298 struct VnodeDiskObject *vnode;
299 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
305 vnode = calloc(1, SIZEOF_LARGEDISKVNODE);
309 V_pref(vp, nearInode);
311 IH_CREATE(V_linkHandle(vp), V_device(vp),
312 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
314 if (!VALID_INO(inodeNumber)) {
315 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
320 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
321 did.Volume = V_id(vp);
322 did.Vnode = (VnodeId) 1;
325 opr_Verify(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
326 DFlush(); /* flush all modified dir buffers out */
327 DZap(&dir); /* Remove all buffers for this dir */
328 length = afs_dir_Length(&dir); /* Remember size of this directory */
330 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
332 /* build a single entry ACL that gives all rights to system:administrators */
333 /* this section of code assumes that access list format is not going to
336 ACL = VVnodeDiskACL(vnode);
337 ACL->size = sizeof(struct acl_accessList);
338 ACL->version = ACL_ACLVERSION;
342 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
343 ACL->entries[0].rights =
344 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
345 | PRSFS_LOCK | PRSFS_ADMINISTER;
347 vnode->type = vDirectory;
349 vnode->modeBits = 0777;
350 vnode->linkCount = 2;
351 VNDISK_SET_LEN(vnode, length);
352 vnode->uniquifier = 1;
353 V_uniquifier(vp) = vnode->uniquifier + 1;
354 vnode->dataVersion = 1;
355 VNDISK_SET_INO(vnode, inodeNumber);
356 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
360 vnode->vnodeMagic = vcp->magic;
362 IH_INIT(h, vp->device, V_parentId(vp),
363 vp->vnodeIndex[vLarge].handle->ih_ino);
365 opr_Assert(fdP != NULL);
366 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
367 opr_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
368 FDH_REALLYCLOSE(fdP);
370 VNDISK_GET_LEN(length, vnode);
371 V_diskused(vp) = nBlocks(length);
378 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
382 struct diskPartition64 *dp = malloc(sizeof(struct diskPartition64));
384 memset(partition, 0, sizeof(*partition));
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 memset(partition, 0, sizeof(*partition));
405 code = VolPartitionInfo(acid, pname, partition);
406 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
411 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
414 struct DiskPartition64 *dp;
416 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
417 return VOLSERBAD_ACCESS;
420 dp = VGetPartition(pname, 0);
422 strncpy(partition->name, dp->name, 32);
423 strncpy(partition->devName, dp->devName, 32);
424 partition->lock_fd = (int)dp->lock_fd;
425 partition->free = dp->free;
426 partition->minFree = dp->totalUsable;
429 return VOLSERILLEGAL_PARTITION;
432 /* obliterate a volume completely, and slowly. */
434 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, VolumeId avolID)
438 code = VolNukeVolume(acid, apartID, avolID);
439 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
444 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
451 char caller[MAXKTCNAMELEN];
453 /* check for access */
454 if (!afsconf_SuperUser(tdir, acid, caller))
455 return VOLSERBAD_ACCESS;
458 Log("%s on %s is executing VolNukeVolume %u\n", caller,
459 callerAddress(acid, buffer), avolID);
462 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
464 /* we first try to attach the volume in update mode, so that the file
465 * server doesn't try to use it (and abort) while (or after) we delete it.
466 * If we don't get the volume, that's fine, too. We just won't put it back.
468 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
469 code = nuke(partName, avolID);
471 VDetachVolume(&verror, tvp);
475 /* create a new volume, with name aname, on the specified partition (1..n)
476 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
477 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
478 * for the volume id (useful for things like volume restore).
479 * Return the new volume id in *avolid.
482 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
483 afs_int32 atype, VolumeId aparent, VolumeId *avolid,
489 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
490 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
491 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
497 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
498 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
503 Error junk; /* discardable error code */
505 afs_int32 doCreateRoot = 1;
506 struct volser_trans *tt;
508 char caller[MAXKTCNAMELEN];
510 if (strlen(aname) > 31)
511 return VOLSERBADNAME;
512 if (!afsconf_SuperUser(tdir, acid, caller))
513 return VOLSERBAD_ACCESS;
516 Log("%s on %s is executing CreateVolume '%s'\n", caller,
517 callerAddress(acid, buffer), aname);
519 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
520 return error; /*a standard unix error */
521 if (atype != readwriteVolume && atype != readonlyVolume
522 && atype != backupVolume)
524 if ((volumeID = *avolid) == 0) {
526 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
530 if ((aparent == volumeID) && (atype == readwriteVolume)) {
535 tt = NewTrans(volumeID, apart);
537 Log("1 createvolume: failed to create trans\n");
538 return VOLSERVOLBUSY; /* volume already busy! */
540 vp = VCreateVolume(&error, ppath, volumeID, aparent);
542 #ifdef AFS_DEMAND_ATTACH_FS
543 if (error != VVOLEXISTS && error != EXDEV) {
544 SalvageUnknownVolume(volumeID, ppath);
547 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
552 V_uniquifier(vp) = 1;
553 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
554 V_inService(vp) = V_blessed(vp) = 1;
556 AssignVolumeName(&V_disk(vp), aname, 0);
558 error = ViceCreateRoot(vp);
560 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
561 "error code %u\n", (unsigned)error);
563 V_needsSalvaged(vp) = 1;
564 VDetachVolume(&junk, vp);
568 V_destroyMe(vp) = DESTROY_ME;
570 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
571 VUpdateVolume(&error, vp);
573 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
576 VDetachVolume(&junk, vp); /* rather return the real error code */
582 TSetRxCall_r(tt, acid, "CreateVolume");
583 VTRANS_OBJ_UNLOCK(tt);
584 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
587 return VOLSERTRELE_ERROR;
591 /* delete the volume associated with this transaction */
593 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
597 code = VolDeleteVolume(acid, atrans);
598 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
603 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
605 struct volser_trans *tt;
607 char caller[MAXKTCNAMELEN];
609 if (!afsconf_SuperUser(tdir, acid, caller))
610 return VOLSERBAD_ACCESS;
611 tt = FindTrans(atrans);
614 if (tt->vflags & VTDeleted) {
615 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " already deleted \n",
616 afs_printable_VolumeId_lu(tt->volid));
622 Log("%s on %s is executing Delete Volume %" AFS_VOLID_FMT "\n", caller,
623 callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
625 TSetRxCall(tt, acid, "DeleteVolume");
626 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
627 V_destroyMe(tt->volume) = DESTROY_ME;
628 if (tt->volume->needsPutBack) {
629 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
632 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
634 VTRANS_OBJ_UNLOCK(tt);
636 return VOLSERTRELE_ERROR;
638 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " deleted \n",
639 afs_printable_VolumeId_lu(tt->volid));
640 return 0; /* vpurgevolume doesn't set an error code */
643 /* make a clone of the volume associated with atrans, possibly giving it a new
644 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
645 * for the clone's id). The new clone is given the name newName. Finally,
646 * due to efficiency considerations, if purgeId is non-zero, we purge that
647 * volume when doing the clone operation. This may be useful when making
648 * new backup volumes, for instance since the net result of a clone and a
649 * purge generally leaves many inode ref counts the same, while doing them
650 * separately would result in far more iincs and idecs being peformed
651 * (and they are slow operations).
653 /* for efficiency reasons, sometimes faster to piggyback a purge here */
655 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
656 afs_int32 newType, char *newName, VolumeId *newNumber)
659 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
660 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
661 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
667 VolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
668 afs_int32 newType, char *newName, VolumeId *newNumber)
671 struct Volume *originalvp, *purgevp, *newvp;
673 struct volser_trans *tt, *ttc;
674 char caller[MAXKTCNAMELEN];
675 #ifdef AFS_DEMAND_ATTACH_FS
676 struct Volume *salv_vp = NULL;
679 if (strlen(newName) > 31)
680 return VOLSERBADNAME;
681 if (!afsconf_SuperUser(tdir, acid, caller))
682 return VOLSERBAD_ACCESS; /*not a super user */
685 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
686 callerAddress(acid, buffer), newName);
689 purgevp = (Volume *) 0;
690 newvp = (Volume *) 0;
691 tt = ttc = (struct volser_trans *)0;
693 if (!newNumber || !*newNumber) {
694 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
699 tt = FindTrans(atrans);
702 if (tt->vflags & VTDeleted) {
703 Log("1 Volser: Clone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
707 ttc = NewTrans(newId, tt->partition);
708 if (!ttc) { /* someone is messing with the clone already */
710 return VOLSERVOLBUSY;
712 TSetRxCall(tt, acid, "Clone");
716 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
718 Log("1 Volser: Clone: Could not attach 'purge' volume %" AFS_VOLID_FMT "; clone aborted\n", afs_printable_VolumeId_lu(purgeId));
724 originalvp = tt->volume;
725 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
726 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
727 afs_printable_VolumeId_lu(V_id(originalvp)));
732 if (originalvp->device != purgevp->device) {
733 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));
737 if (V_type(purgevp) != readonlyVolume) {
738 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
742 if (V_parentId(originalvp) != V_parentId(purgevp)) {
743 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));
750 #ifdef AFS_DEMAND_ATTACH_FS
751 salv_vp = originalvp;
754 if (purgeId == newId) {
758 VCreateVolume(&error, originalvp->partition->name, newId,
759 V_parentId(originalvp));
761 Log("1 Volser: Clone: Couldn't create new volume %" AFS_VOLID_FMT " for parent %" AFS_VOLID_FMT "; clone aborted\n",
762 afs_printable_VolumeId_lu(newId), afs_printable_VolumeId_lu(V_parentId(originalvp)));
763 newvp = (Volume *) 0;
767 if (newType == readonlyVolume)
768 V_cloneId(originalvp) = newId;
769 Log("1 Volser: Clone: Cloning volume %" AFS_VOLID_FMT " to new volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
770 afs_printable_VolumeId_lu(newId));
772 Log("1 Volser: Clone: Purging old read only volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(purgeId));
773 CloneVolume(&error, originalvp, newvp, purgevp);
774 purgevp = NULL; /* clone releases it, maybe even if error */
776 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
780 if (newType == readonlyVolume) {
781 V_type(newvp) = readonlyVolume;
782 } else if (newType == backupVolume) {
783 V_type(newvp) = backupVolume;
784 V_backupId(originalvp) = newId;
786 strcpy(V_name(newvp), newName);
787 V_creationDate(newvp) = V_copyDate(newvp);
788 ClearVolumeStats(&V_disk(newvp));
789 V_destroyMe(newvp) = DESTROY_ME;
790 V_inService(newvp) = 0;
791 if (newType == backupVolume) {
792 V_backupDate(originalvp) = V_copyDate(newvp);
793 V_backupDate(newvp) = V_copyDate(newvp);
796 VUpdateVolume(&error, newvp);
798 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
802 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
804 VUpdateVolume(&error, originalvp);
806 Log("1 Volser: Clone: original update %u\n", error);
811 #ifdef AFS_DEMAND_ATTACH_FS
815 /* Clients could have callbacks to the clone ID */
816 FSYNC_VolOp(newId, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
819 tt = (struct volser_trans *)0;
820 error = VOLSERTRELE_ERROR;
828 VDetachVolume(&code, purgevp);
830 VDetachVolume(&code, newvp);
837 #ifdef AFS_DEMAND_ATTACH_FS
838 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
839 V_needsSalvaged(salv_vp) = 1;
841 #endif /* AFS_DEMAND_ATTACH_FS */
845 /* reclone this volume into the specified id */
847 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
851 code = VolReClone(acid, atrans, cloneId);
852 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
858 VolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
860 struct Volume *originalvp, *clonevp;
863 struct volser_trans *tt, *ttc;
864 char caller[MAXKTCNAMELEN];
865 VolumeDiskData saved_header;
867 /*not a super user */
868 if (!afsconf_SuperUser(tdir, acid, caller))
869 return VOLSERBAD_ACCESS;
872 Log("%s on %s is executing Reclone Volume %" AFS_VOLID_FMT "\n", caller,
873 callerAddress(acid, buffer), afs_printable_VolumeId_lu(cloneId));
876 clonevp = originalvp = (Volume *) 0;
878 tt = FindTrans(atrans);
881 if (tt->vflags & VTDeleted) {
882 Log("1 Volser: VolReClone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
886 ttc = NewTrans(cloneId, tt->partition);
887 if (!ttc) { /* someone is messing with the clone already */
889 return VOLSERVOLBUSY;
891 TSetRxCall(tt, acid, "ReClone");
893 originalvp = tt->volume;
894 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
895 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
896 afs_printable_VolumeId_lu(V_id(originalvp)));
901 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
903 Log("1 Volser: can't attach clone %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(cloneId));
907 newType = V_type(clonevp); /* type of the new volume */
909 if (originalvp->device != clonevp->device) {
910 Log("1 Volser: Clone: Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are on different devices\n",
911 afs_printable_VolumeId_lu(tt->volid), afs_printable_VolumeId_lu(cloneId));
915 if (V_parentId(originalvp) != V_parentId(clonevp)) {
916 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));
921 if (DoPreserveVolumeStats) {
922 CopyVolumeStats(&V_disk(clonevp), &saved_header);
926 Log("1 Volser: Clone: Recloning volume %" AFS_VOLID_FMT " to volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
927 afs_printable_VolumeId_lu(cloneId));
928 CloneVolume(&error, originalvp, clonevp, clonevp);
930 Log("1 Volser: Clone: reclone operation failed with code %d\n",
936 /* fix up volume name and type, CloneVolume just propagated RW's */
937 if (newType == readonlyVolume) {
938 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
939 V_type(clonevp) = readonlyVolume;
940 } else if (newType == backupVolume) {
941 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
942 V_type(clonevp) = backupVolume;
943 V_backupId(originalvp) = cloneId;
945 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
947 /* update the creationDate, since this represents the last cloning date
948 * for ROs. But do not update copyDate; let it stay so we can identify
949 * when the clone was first created. */
950 V_creationDate(clonevp) = time(0);
951 if (DoPreserveVolumeStats) {
952 CopyVolumeStats(&saved_header, &V_disk(clonevp));
954 ClearVolumeStats(&V_disk(clonevp));
956 V_destroyMe(clonevp) = 0;
957 V_inService(clonevp) = 0;
958 if (newType == backupVolume) {
959 V_backupDate(originalvp) = V_creationDate(clonevp);
960 V_backupDate(clonevp) = V_creationDate(clonevp);
962 V_inUse(clonevp) = 0;
963 VUpdateVolume(&error, clonevp);
965 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
969 /* VUpdateVolume succeeded. Mark it in service so there's no window
970 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
971 * specialStatus; this is a reclone and this volume started online
973 V_inService(clonevp) = 1;
974 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
976 VUpdateVolume(&error, originalvp);
978 Log("1 Volser: Clone: original update %u\n", error);
984 tt = (struct volser_trans *)0;
985 error = VOLSERTRELE_ERROR;
992 struct DiskPartition64 *tpartp = originalvp->partition;
993 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
999 VDetachVolume(&code, clonevp);
1005 DeleteTrans(ttc, 1);
1009 /* create a new transaction, associated with volume and partition. Type of
1010 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1011 * See volser.h for definition of iflags (the constants are named IT*).
1014 SAFSVolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1015 afs_int32 iflags, afs_int32 *ttid)
1019 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1020 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1026 VolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1027 afs_int32 iflags, afs_int32 *ttid)
1029 struct volser_trans *tt;
1034 char caller[MAXKTCNAMELEN];
1036 if (!afsconf_SuperUser(tdir, acid, caller))
1037 return VOLSERBAD_ACCESS; /*not a super user */
1038 if (iflags & ITCreate)
1040 else if (iflags & ITBusy)
1042 else if (iflags & ITReadOnly)
1044 else if (iflags & ITOffline)
1047 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1052 tt = NewTrans(volume, partition);
1054 /* can't create a transaction? put the volume back */
1055 Log("1 transcreate: can't create transaction\n");
1056 return VOLSERVOLBUSY;
1058 tv = XAttachVolume(&error, volume, partition, mode);
1062 VDetachVolume(&code, tv);
1066 VTRANS_OBJ_LOCK(tt);
1069 tt->iflags = iflags;
1071 TSetRxCall_r(tt, NULL, "TransCreate");
1072 VTRANS_OBJ_UNLOCK(tt);
1074 return VOLSERTRELE_ERROR;
1079 /* using aindex as a 0-based index, return the aindex'th volume on this server
1080 * Both the volume number and partition number (one-based) are returned.
1083 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, VolumeId *avolume,
1088 code = VolGetNthVolume(acid, aindex, avolume, apart);
1089 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1094 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1097 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1098 return VOLSERBAD_ACCESS;
1100 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1104 /* return the volume flags (VT* constants in volser.h) associated with this
1108 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1112 code = VolGetFlags(acid, atid, aflags);
1113 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1118 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1120 struct volser_trans *tt;
1122 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1123 return VOLSERBAD_ACCESS;
1125 tt = FindTrans(atid);
1128 if (tt->vflags & VTDeleted) {
1129 Log("1 Volser: VolGetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1130 afs_printable_VolumeId_lu(tt->volid));
1134 TSetRxCall(tt, acid, "GetFlags");
1135 *aflags = tt->vflags;
1138 return VOLSERTRELE_ERROR;
1143 /* Change the volume flags (VT* constants in volser.h) associated with this
1144 * transaction. Effects take place immediately on volume, although volume
1145 * remains attached as usual by the transaction.
1148 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1152 code = VolSetFlags(acid, atid, aflags);
1153 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1159 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1161 struct volser_trans *tt;
1164 char caller[MAXKTCNAMELEN];
1166 if (!afsconf_SuperUser(tdir, acid, caller))
1167 return VOLSERBAD_ACCESS; /*not a super user */
1168 /* find the trans */
1169 tt = FindTrans(atid);
1172 if (tt->vflags & VTDeleted) {
1173 Log("1 Volser: VolSetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1174 afs_printable_VolumeId_lu(tt->volid));
1178 TSetRxCall(tt, acid, "SetFlags");
1179 vp = tt->volume; /* pull volume out of transaction */
1181 /* check if we're allowed to make any updates */
1182 if (tt->iflags & ITReadOnly) {
1187 /* handle delete-on-salvage flag */
1188 if (aflags & VTDeleteOnSalvage) {
1189 V_destroyMe(tt->volume) = DESTROY_ME;
1191 V_destroyMe(tt->volume) = 0;
1194 if (aflags & VTOutOfService) {
1195 V_inService(vp) = 0;
1197 V_inService(vp) = 1;
1199 VUpdateVolume(&error, vp);
1200 VTRANS_OBJ_LOCK(tt);
1201 tt->vflags = aflags;
1203 VTRANS_OBJ_UNLOCK(tt);
1204 if (TRELE(tt) && !error)
1205 return VOLSERTRELE_ERROR;
1210 /* dumpS the volume associated with a particular transaction from a particular
1211 * date. Send the dump to a different transaction (destTrans) on the server
1212 * specified by the destServer structure.
1215 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1216 struct destServer *destination, afs_int32 destTrans,
1217 struct restoreCookie *cookie)
1222 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1223 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1224 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1228 static_inline afs_int32
1229 MakeClient(struct rx_call *acid, struct rx_securityClass **securityObject,
1230 afs_int32 *securityIndex)
1232 rxkad_level enc_level = rxkad_clear;
1241 rxkad_GetServerInfo(rx_ConnectionOf(acid), &enc_level, 0, 0, 0, 0, 0);
1242 docrypt = (enc_level == rxkad_crypt ? 1 : 0);
1248 opr_Assert(0 && "doCrypt corrupt?");
1251 code = afsconf_ClientAuthSecure(tdir, securityObject, securityIndex);
1253 code = afsconf_ClientAuth(tdir, securityObject, securityIndex);
1258 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1259 struct destServer *destination, afs_int32 destTrans,
1260 struct restoreCookie *cookie)
1262 struct volser_trans *tt;
1264 struct rx_connection *tcon;
1265 struct rx_call *tcall;
1267 struct rx_securityClass *securityObject;
1268 afs_int32 securityIndex;
1269 char caller[MAXKTCNAMELEN];
1271 if (!afsconf_SuperUser(tdir, acid, caller))
1272 return VOLSERBAD_ACCESS; /*not a super user */
1274 /* find the local transaction */
1275 tt = FindTrans(fromTrans);
1278 if (tt->vflags & VTDeleted) {
1279 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1284 TSetRxCall(tt, NULL, "Forward");
1286 /* get auth info for the this connection (uses afs from ticket file) */
1287 code = MakeClient(acid, &securityObject, &securityIndex);
1293 /* make an rpc connection to the other server */
1295 rx_NewConnection(htonl(destination->destHost),
1296 htons(destination->destPort), VOLSERVICE_ID,
1297 securityObject, securityIndex);
1299 RXS_Close(securityObject); /* will be freed after connection destroyed */
1306 tcall = rx_NewCall(tcon);
1307 TSetRxCall(tt, tcall, "Forward");
1308 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1309 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1314 /* these next calls implictly call rx_Write when writing out data */
1315 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1318 EndAFSVolRestore(tcall); /* probably doesn't do much */
1320 code = rx_EndCall(tcall, 0);
1321 rx_DestroyConnection(tcon); /* done with the connection */
1326 return VOLSERTRELE_ERROR;
1332 (void)rx_EndCall(tcall, 0);
1333 rx_DestroyConnection(tcon);
1342 /* Start a dump and send it to multiple places simultaneously.
1343 * If this returns an error (eg, return ENOENT), it means that
1344 * none of the releases worked. If this returns 0, that means
1345 * that one or more of the releases worked, and the caller has
1346 * to examine the results array to see which one(s).
1347 * This will only do EITHER incremental or full, not both, so it's
1348 * the caller's responsibility to be sure that all the destinations
1349 * need just an incremental (and from the same time), if that's
1353 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1354 fromDate, manyDests *destinations, afs_int32 spare,
1355 struct restoreCookie *cookie, manyResults *results)
1357 afs_int32 securityIndex;
1358 struct rx_securityClass *securityObject;
1359 char caller[MAXKTCNAMELEN];
1360 struct volser_trans *tt;
1361 afs_int32 ec, code, *codes;
1362 struct rx_connection **tcons;
1363 struct rx_call **tcalls;
1365 int i, is_incremental;
1368 memset(results, 0, sizeof(manyResults));
1369 i = results->manyResults_len = destinations->manyDests_len;
1370 results->manyResults_val = codes = malloc(i * sizeof(afs_int32));
1372 if (!results || !results->manyResults_val)
1375 if (!afsconf_SuperUser(tdir, acid, caller))
1376 return VOLSERBAD_ACCESS; /*not a super user */
1377 tt = FindTrans(fromTrans);
1380 if (tt->vflags & VTDeleted) {
1381 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1386 TSetRxCall(tt, NULL, "ForwardMulti");
1388 /* (fromDate == 0) ==> full dump */
1389 is_incremental = (fromDate ? 1 : 0);
1391 tcons = malloc(i * sizeof(struct rx_connection *));
1395 tcalls = malloc(i * sizeof(struct rx_call *));
1401 /* get auth info for this connection (uses afs from ticket file) */
1402 code = MakeClient(acid, &securityObject, &securityIndex);
1404 goto fail; /* in order to audit each failure */
1407 /* make connections to all the other servers */
1408 for (i = 0; i < destinations->manyDests_len; i++) {
1409 struct replica *dest = &(destinations->manyDests_val[i]);
1411 rx_NewConnection(htonl(dest->server.destHost),
1412 htons(dest->server.destPort), VOLSERVICE_ID,
1413 securityObject, securityIndex);
1415 codes[i] = ENOTCONN;
1417 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1418 codes[i] = ENOTCONN;
1421 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1424 (void)rx_EndCall(tcalls[i], 0);
1426 rx_DestroyConnection(tcons[i]);
1433 /* Security object will be freed when all connections destroyed */
1434 RXS_Close(securityObject);
1436 /* these next calls implictly call rx_Write when writing out data */
1437 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1441 for (i--; i >= 0; i--) {
1442 struct replica *dest = &(destinations->manyDests_val[i]);
1444 if (!code && tcalls[i] && !codes[i]) {
1445 EndAFSVolRestore(tcalls[i]);
1448 ec = rx_EndCall(tcalls[i], 0);
1453 rx_DestroyConnection(tcons[i]); /* done with the connection */
1456 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1457 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1458 dest->trans, AUD_END);
1465 if (TRELE(tt) && !code) /* return the first code if it's set */
1466 return VOLSERTRELE_ERROR;
1473 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1477 code = VolDump(acid, fromTrans, fromDate, 0);
1478 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1483 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1488 code = VolDump(acid, fromTrans, fromDate, flags);
1489 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1494 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1498 struct volser_trans *tt;
1499 char caller[MAXKTCNAMELEN];
1501 if (!afsconf_SuperUser(tdir, acid, caller))
1502 return VOLSERBAD_ACCESS; /*not a super user */
1503 tt = FindTrans(fromTrans);
1506 if (tt->vflags & VTDeleted) {
1507 Log("1 Volser: VolDump: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1511 TSetRxCall(tt, acid, "Dump");
1512 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1513 ? 0 : 1); /* squirt out the volume's data, too */
1522 return VOLSERTRELE_ERROR;
1528 * Ha! No more helper process!
1531 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1532 struct restoreCookie *cookie)
1536 code = VolRestore(acid, atrans, cookie);
1537 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1542 VolRestore(struct rx_call *acid, afs_int32 atrans, 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, cookie);
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);
2286 if (V_needsSalvaged(tv)) {
2287 /*this volume will be salvaged */
2288 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) needs to be salvaged\n",
2289 afs_printable_VolumeId_lu(volumeId), pname, volname);
2292 #ifdef AFS_DEMAND_ATTACH_FS
2293 /* If using DAFS, get volume from fsserver */
2294 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2299 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2300 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2301 /* If we if the pending vol op */
2302 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2303 fs_tv->pending_vol_op=&pending_vol_op_res;
2305 fs_tv->pending_vol_op=NULL;
2308 /* populate the header from the volserver copy */
2309 fs_tv->header=tv->header;
2311 /* When using DAFS, use the fs volume info, populated with required structures */
2314 /* When not using DAFS, just use the local volume info */
2318 /* ok, we have all the data we need; fill in the on-wire struct */
2319 code = FillVolInfo(fill_tv, handle);
2323 VOLINT_INFO_STORE(handle, status, 0);
2324 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2325 VOLINT_INFO_STORE(handle, volid, volumeId);
2328 VDetachVolume(&error, tv);
2331 VOLINT_INFO_STORE(handle, status, 0);
2332 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2333 Log("1 Volser: GetVolInfo: Could not detach volume %" AFS_VOLID_FMT " (%s:%s)\n",
2334 afs_printable_VolumeId_lu(volumeId), pname, volname);
2338 DeleteTrans(ttc, 1);
2345 /*return the header information about the <volid> */
2347 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2348 VolumeId volumeId, volEntries *volumeInfo)
2352 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2353 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2358 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2359 VolumeId volumeId, volEntries *volumeInfo)
2361 struct DiskPartition64 *partP;
2362 char pname[9], volname[20];
2366 volint_info_handle_t handle;
2368 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2369 return VOLSERBAD_ACCESS;
2371 volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2372 if (!volumeInfo->volEntries_val)
2375 volumeInfo->volEntries_len = 1;
2376 if (GetPartName(partid, pname))
2377 return VOLSERILLEGAL_PARTITION;
2378 if (!(partP = VGetPartition(pname, 0)))
2379 return VOLSERILLEGAL_PARTITION;
2380 dirp = opendir(VPartitionPath(partP));
2382 return VOLSERILLEGAL_PARTITION;
2384 while (GetNextVol(dirp, volname, &volid)) {
2385 if (volid == volumeId) { /*copy other things too */
2392 #ifndef AFS_PTHREAD_ENV
2393 IOMGR_Poll(); /*make sure that the client does not time out */
2396 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2397 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2399 /* The return code from GetVolInfo is ignored; there is no error from
2400 * it that results in the whole call being aborted. Any volume
2401 * attachment failures are reported in 'status' field in the
2402 * volumeInfo payload. */
2408 VOL_INFO_LIST_SINGLE);
2412 return (found) ? 0 : ENODEV;
2415 /*------------------------------------------------------------------------
2416 * EXPORTED SAFSVolXListOneVolume
2419 * Returns extended info on volume a_volID on partition a_partID.
2422 * a_rxCidP : Pointer to the Rx call we're performing.
2423 * a_partID : Partition for which we want the extended list.
2424 * a_volID : Volume ID we wish to know about.
2425 * a_volumeXInfoP : Ptr to the extended info blob.
2428 * 0 Successful operation
2429 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2432 * Nothing interesting.
2436 *------------------------------------------------------------------------*/
2439 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2440 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2444 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2445 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2450 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2451 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2452 { /*SAFSVolXListOneVolume */
2454 struct DiskPartition64 *partP; /*Ptr to partition */
2455 char pname[9], volname[20]; /*Partition, volume names */
2456 DIR *dirp; /*Partition directory ptr */
2457 VolumeId currVolID; /*Current volume ID */
2458 int found = 0; /*Did we find the volume we need? */
2459 volint_info_handle_t handle;
2461 if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
2462 return VOLSERBAD_ACCESS;
2465 * Set up our pointers for action, marking our structure to hold exactly
2466 * one entry. Also, assume we'll fail in our quest.
2468 a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2469 if (!a_volumeXInfoP->volXEntries_val)
2472 a_volumeXInfoP->volXEntries_len = 1;
2475 * If the partition name we've been given is bad, bogue out.
2477 if (GetPartName(a_partID, pname))
2478 return (VOLSERILLEGAL_PARTITION);
2481 * Open the directory representing the given AFS parttion. If we can't
2484 if (!(partP = VGetPartition(pname, 0)))
2485 return VOLSERILLEGAL_PARTITION;
2486 dirp = opendir(VPartitionPath(partP));
2488 return (VOLSERILLEGAL_PARTITION);
2492 * Sweep through the partition directory, looking for the desired entry.
2493 * First, of course, figure out how many stat bytes to copy out of each
2496 while (GetNextVol(dirp, volname, &currVolID)) {
2497 if (currVolID == a_volID) {
2499 * We found the volume entry we're interested. Pull out the
2500 * extended information, remembering to poll (so that the client
2501 * doesn't time out) and to set up a transaction on the volume.
2505 } /*Found desired volume */
2509 #ifndef AFS_PTHREAD_ENV
2513 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2514 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2516 /* The return code from GetVolInfo is ignored; there is no error from
2517 * it that results in the whole call being aborted. Any volume
2518 * attachment failures are reported in 'status' field in the
2519 * volumeInfo payload. */
2520 GetVolInfo(a_partID,
2525 VOL_INFO_LIST_SINGLE);
2529 * Clean up before going to dinner: close the partition directory,
2530 * return the proper value.
2533 return (found) ? 0 : ENODEV;
2534 } /*SAFSVolXListOneVolume */
2536 /*returns all the volumes on partition partid. If flags = 1 then all the
2537 * relevant info about the volumes is also returned */
2539 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2540 volEntries *volumeInfo)
2544 code = VolListVolumes(acid, partid, flags, volumeInfo);
2545 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2550 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2551 volEntries *volumeInfo)
2554 struct DiskPartition64 *partP;
2555 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2556 char pname[9], volname[20];
2560 volint_info_handle_t handle;
2562 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2563 return VOLSERBAD_ACCESS;
2565 volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2566 if (!volumeInfo->volEntries_val)
2569 pntr = volumeInfo->volEntries_val;
2570 volumeInfo->volEntries_len = 0;
2571 if (GetPartName(partid, pname))
2572 return VOLSERILLEGAL_PARTITION;
2573 if (!(partP = VGetPartition(pname, 0)))
2574 return VOLSERILLEGAL_PARTITION;
2575 dirp = opendir(VPartitionPath(partP));
2577 return VOLSERILLEGAL_PARTITION;
2579 while (GetNextVol(dirp, volname, &volid)) {
2580 if (flags) { /*copy other things too */
2581 #ifndef AFS_PTHREAD_ENV
2582 IOMGR_Poll(); /*make sure that the client does not time out */
2585 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2586 handle.volinfo_ptr.base = pntr;
2589 code = GetVolInfo(partid,
2594 VOL_INFO_LIST_MULTIPLE);
2595 if (code == -2) /* DESTROY_ME flag set */
2598 pntr->volid = volid;
2599 /*just volids are needed */
2603 volumeInfo->volEntries_len += 1;
2604 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2605 /*running out of space, allocate more space */
2606 allocSize = (allocSize * 3) / 2;
2607 pntr = realloc(volumeInfo->volEntries_val,
2608 allocSize * sizeof(volintInfo));
2611 return VOLSERNO_MEMORY;
2613 volumeInfo->volEntries_val = pntr; /* point to new block */
2614 /* set pntr to the right position */
2615 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2623 /*------------------------------------------------------------------------
2624 * EXPORTED SAFSVolXListVolumes
2627 * Returns all the volumes on partition a_partID. If a_flags
2628 * is set to 1, then all the relevant extended volume information
2632 * a_rxCidP : Pointer to the Rx call we're performing.
2633 * a_partID : Partition for which we want the extended list.
2634 * a_flags : Various flags.
2635 * a_volumeXInfoP : Ptr to the extended info blob.
2638 * 0 Successful operation
2639 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2640 * VOLSERNO_MEMORY if we ran out of memory allocating
2644 * Nothing interesting.
2648 *------------------------------------------------------------------------*/
2651 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2652 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2656 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2657 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2662 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2663 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2664 { /*SAFSVolXListVolumes */
2666 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2667 struct DiskPartition64 *partP; /*Ptr to partition */
2668 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2669 char pname[9], volname[20]; /*Partition, volume names */
2670 DIR *dirp; /*Partition directory ptr */
2671 VolumeId volid; /*Current volume ID */
2673 volint_info_handle_t handle;
2675 if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
2676 return VOLSERBAD_ACCESS;
2679 * Allocate a large array of extended volume info structures, then
2680 * set it up for action.
2682 a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2683 if (!a_volumeXInfoP->volXEntries_val)
2686 xInfoP = a_volumeXInfoP->volXEntries_val;
2687 a_volumeXInfoP->volXEntries_len = 0;
2690 * If the partition name we've been given is bad, bogue out.
2692 if (GetPartName(a_partID, pname))
2693 return (VOLSERILLEGAL_PARTITION);
2696 * Open the directory representing the given AFS parttion. If we can't
2699 if (!(partP = VGetPartition(pname, 0)))
2700 return VOLSERILLEGAL_PARTITION;
2701 dirp = opendir(VPartitionPath(partP));
2703 return (VOLSERILLEGAL_PARTITION);
2704 while (GetNextVol(dirp, volname, &volid)) {
2707 * Full info about the volume desired. Poll to make sure the
2708 * client doesn't time out, then start up a new transaction.
2710 #ifndef AFS_PTHREAD_ENV
2714 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2715 handle.volinfo_ptr.ext = xInfoP;
2717 code = GetVolInfo(a_partID,
2722 VOL_INFO_LIST_MULTIPLE);
2723 if (code == -2) /* DESTROY_ME flag set */
2727 * Just volume IDs are needed.
2729 xInfoP->volid = volid;
2733 * Bump the pointer in the data area we're building, along with
2734 * the count of the number of entries it contains.
2737 (a_volumeXInfoP->volXEntries_len)++;
2738 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2740 * We're running out of space in the area we've built. Grow it.
2742 allocSize = (allocSize * 3) / 2;
2743 xInfoP = (volintXInfo *)
2744 realloc((char *)a_volumeXInfoP->volXEntries_val,
2745 (allocSize * sizeof(volintXInfo)));
2746 if (xInfoP == NULL) {
2748 * Bummer, no memory. Bag it, tell our caller what went wrong.
2751 return (VOLSERNO_MEMORY);
2755 * Memory reallocation worked. Correct our pointers so they
2756 * now point to the new block and the current open position within
2759 a_volumeXInfoP->volXEntries_val = xInfoP;
2761 a_volumeXInfoP->volXEntries_val +
2762 a_volumeXInfoP->volXEntries_len;
2767 * We've examined all entries in the partition directory. Close it,
2768 * delete our transaction (if any), and go home happy.
2773 } /*SAFSVolXListVolumes */
2775 /*this call is used to monitor the status of volser for debugging purposes.
2776 *information about all the active transactions is returned in transInfo*/
2778 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2782 code = VolMonitor(acid, transInfo);
2783 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2788 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2790 transDebugInfo *pntr;
2791 afs_int32 allocSize = 50;
2793 struct volser_trans *tt, *nt, *allTrans;
2795 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2796 return VOLSERBAD_ACCESS;
2798 transInfo->transDebugEntries_val =
2799 malloc(allocSize * sizeof(transDebugInfo));
2800 if (!transInfo->transDebugEntries_val)
2802 pntr = transInfo->transDebugEntries_val;
2803 transInfo->transDebugEntries_len = 0;
2806 allTrans = TransList();
2807 if (allTrans == (struct volser_trans *)0)
2808 goto done; /*no active transactions */
2809 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2811 memset(pntr, 0, sizeof(*pntr));
2812 VTRANS_OBJ_LOCK(tt);
2813 pntr->tid = tt->tid;
2814 pntr->time = tt->time;
2815 pntr->creationTime = tt->creationTime;
2816 pntr->returnCode = tt->returnCode;
2817 pntr->volid = tt->volid;
2818 pntr->partition = tt->partition;
2819 pntr->iflags = tt->iflags;
2820 pntr->vflags = tt->vflags;
2821 pntr->tflags = tt->tflags;
2822 strcpy(pntr->lastProcName, tt->lastProcName);
2823 pntr->callValid = 0;
2824 if (tt->rxCallPtr) { /*record call related info */
2825 pntr->callValid = 1;
2826 rx_GetCallStatus(tt->rxCallPtr, &(pntr->readNext), &(pntr->transmitNext),
2827 &(pntr->lastSendTime), &(pntr->lastReceiveTime));
2829 VTRANS_OBJ_UNLOCK(tt);
2831 transInfo->transDebugEntries_len += 1;
2832 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2833 allocSize = (allocSize * 3) / 2;
2834 pntr = realloc(transInfo->transDebugEntries_val,
2835 allocSize * sizeof(transDebugInfo));
2840 transInfo->transDebugEntries_val = pntr;
2842 transInfo->transDebugEntries_val +
2843 transInfo->transDebugEntries_len;
2844 /*set pntr to right position */
2855 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2856 afs_int32 type, afs_uint32 pId, VolumeId cloneId,
2861 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2862 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2863 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2869 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2870 afs_int32 type, VolumeId pId, VolumeId cloneId,
2875 struct volser_trans *tt;
2876 char caller[MAXKTCNAMELEN];
2878 if (strlen(name) > 31)
2879 return VOLSERBADNAME;
2880 if (!afsconf_SuperUser(tdir, acid, caller))
2881 return VOLSERBAD_ACCESS; /*not a super user */
2882 /* find the trans */
2883 tt = FindTrans(atid);
2886 if (tt->vflags & VTDeleted) {
2887 Log("1 Volser: VolSetIds: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2891 TSetRxCall(tt, acid, "SetIdsTypes");
2895 V_backupId(tv) = backupId;
2896 V_cloneId(tv) = cloneId;
2897 V_parentId(tv) = pId;
2898 strcpy((&V_disk(tv))->name, name);
2899 VUpdateVolume(&error, tv);
2901 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2906 if (TRELE(tt) && !error)
2907 return VOLSERTRELE_ERROR;
2912 if (TRELE(tt) && !error)
2913 return VOLSERTRELE_ERROR;
2918 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2922 code = VolSetDate(acid, atid, cdate);
2923 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2929 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2933 struct volser_trans *tt;
2934 char caller[MAXKTCNAMELEN];
2936 if (!afsconf_SuperUser(tdir, acid, caller))
2937 return VOLSERBAD_ACCESS; /*not a super user */
2938 /* find the trans */
2939 tt = FindTrans(atid);
2942 if (tt->vflags & VTDeleted) {
2943 Log("1 Volser: VolSetDate: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2947 TSetRxCall(tt, acid, "SetDate");
2950 V_creationDate(tv) = cdate;
2951 VUpdateVolume(&error, tv);
2953 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2958 if (TRELE(tt) && !error)
2959 return VOLSERTRELE_ERROR;
2964 if (TRELE(tt) && !error)
2965 return VOLSERTRELE_ERROR;
2970 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2976 char caller[MAXKTCNAMELEN];
2978 struct volser_trans *ttc;
2979 char pname[16], volname[20];
2980 struct DiskPartition64 *partP;
2981 afs_int32 ret = ENODEV;
2984 if (!afsconf_SuperUser(tdir, acid, caller))
2985 return VOLSERBAD_ACCESS; /*not a super user */
2986 if (GetPartName(partId, pname))
2987 return VOLSERILLEGAL_PARTITION;
2988 if (!(partP = VGetPartition(pname, 0)))
2989 return VOLSERILLEGAL_PARTITION;
2990 dirp = opendir(VPartitionPath(partP));
2992 return VOLSERILLEGAL_PARTITION;
2993 ttc = (struct volser_trans *)0;
2995 while (GetNextVol(dirp, volname, &volid)) {
2996 if (volid == volumeId) { /*copy other things too */
2997 #ifndef AFS_PTHREAD_ENV
2998 IOMGR_Poll(); /*make sure that the client doesnot time out */
3000 ttc = NewTrans(volumeId, partId);
3002 ret = VOLSERVOLBUSY;
3005 ret = FSYNC_VolOp(volumeId, pname, FSYNC_VOL_NEEDVOLUME, V_VOLUPD,
3007 if (ret != SYNC_OK) {
3008 Log("SAFSVolConvertROtoRWvolume: Error %ld trying to check out "
3009 "vol %lu part %s.\n", afs_printable_int32_ld(ret),
3010 afs_printable_uint32_lu(volumeId), pname);
3011 ret = VOLSERFAILEDOP;
3014 #ifdef AFS_NAMEI_ENV
3015 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3017 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3020 Log("SAFSVolConvertROtoRWvolume: Error %ld trying to convert "
3021 "RO vol %lu to RW. The volume may be in an inconsistent or "
3022 "partially converted state; if the volume seems unusable, "
3023 "you can try salvaging it or restoring from another RO "
3024 "copy.\n", afs_printable_int32_ld(ret),
3025 afs_printable_uint32_lu(volumeId));
3027 * the volume may or may not be usable at this point; let the
3028 * fileserver try to attach and decide.
3030 FSYNC_VolOp(volumeId, pname, FSYNC_VOL_ON, 0, NULL);
3037 DeleteTrans(ttc, 1);
3045 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3046 struct volintSize *size)
3049 struct volser_trans *tt;
3050 char caller[MAXKTCNAMELEN];
3052 if (!afsconf_SuperUser(tdir, acid, caller))
3053 return VOLSERBAD_ACCESS; /*not a super user */
3054 tt = FindTrans(fromTrans);
3057 if (tt->vflags & VTDeleted) {
3061 TSetRxCall(tt, acid, "GetSize");
3062 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3065 return VOLSERTRELE_ERROR;
3067 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3072 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 ovid, afs_uint32 onew,
3073 afs_uint32 where, afs_int32 verbose)
3075 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3077 Volume *vol=0, *newvol=0;
3078 struct volser_trans *tt = 0, *tt2 = 0;
3079 char caller[MAXKTCNAMELEN];
3081 VolumeId new = onew;
3082 VolumeId vid = ovid;
3084 if (!afsconf_SuperUser(tdir, acall, caller))
3087 vol = VAttachVolume(&code, vid, V_VOLUPD);
3093 newvol = VAttachVolume(&code, new, V_VOLUPD);
3095 VDetachVolume(&code2, vol);
3100 if (V_device(vol) != V_device(newvol)
3101 || V_uniquifier(newvol) != 2) {
3102 if (V_device(vol) != V_device(newvol)) {
3103 sprintf(line, "Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are not in the same partition, aborted.\n",
3104 afs_printable_VolumeId_lu(vid),
3105 afs_printable_VolumeId_lu(new));
3106 rx_Write(acall, line, strlen(line));
3108 if (V_uniquifier(newvol) != 2) {
3109 sprintf(line, "Volume %" AFS_VOLID_FMT " is not freshly created, aborted.\n",
3110 afs_printable_VolumeId_lu(new));
3111 rx_Write(acall, line, strlen(line));
3114 rx_Write(acall, line, 1);
3115 VDetachVolume(&code2, vol);
3116 VDetachVolume(&code2, newvol);
3119 tt = NewTrans(vid, V_device(vol));
3121 sprintf(line, "Couldn't create transaction for %" AFS_VOLID_FMT ", aborted.\n",
3122 afs_printable_VolumeId_lu(vid));
3123 rx_Write(acall, line, strlen(line));
3125 rx_Write(acall, line, 1);
3126 VDetachVolume(&code2, vol);
3127 VDetachVolume(&code2, newvol);
3128 return VOLSERVOLBUSY;
3130 VTRANS_OBJ_LOCK(tt);
3131 tt->iflags = ITBusy;
3133 TSetRxCall_r(tt, NULL, "SplitVolume");
3134 VTRANS_OBJ_UNLOCK(tt);
3136 tt2 = NewTrans(new, V_device(newvol));
3138 sprintf(line, "Couldn't create transaction for %" AFS_VOLID_FMT ", aborted.\n",
3139 afs_printable_VolumeId_lu(new));
3140 rx_Write(acall, line, strlen(line));
3142 rx_Write(acall, line, 1);
3144 VDetachVolume(&code2, vol);
3145 VDetachVolume(&code2, newvol);
3146 return VOLSERVOLBUSY;
3148 VTRANS_OBJ_LOCK(tt2);
3149 tt2->iflags = ITBusy;
3151 TSetRxCall_r(tt2, NULL, "SplitVolume");
3152 VTRANS_OBJ_UNLOCK(tt2);
3154 code = split_volume(acall, vol, newvol, where, verbose);
3156 VDetachVolume(&code2, vol);
3158 VDetachVolume(&code2, newvol);
3159 DeleteTrans(tt2, 1);
3166 /* GetPartName - map partid (a decimal number) into pname (a string)
3167 * Since for NT we actually want to return the drive name, we map through the
3171 GetPartName(afs_int32 partid, char *pname)
3176 strcpy(pname, "/vicep");
3177 pname[6] = 'a' + partid;
3180 } else if (partid < VOLMAXPARTS) {
3181 strcpy(pname, "/vicep");
3183 pname[6] = 'a' + (partid / 26);
3184 pname[7] = 'a' + (partid % 26);