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;
65 extern void LogError(afs_int32 errcode);
67 /* Forward declarations */
68 static int GetPartName(afs_int32 partid, char *pname);
70 #define OneDay (24*60*60)
76 afs_int32 localTid = 1;
78 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
79 struct diskPartition64 *);
80 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
81 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
82 afs_int32, afs_uint32, afs_uint32 *,
84 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
85 static afs_int32 VolClone(struct rx_call *, afs_int32, VolumeId,
86 afs_int32, char *, VolumeId *);
87 static afs_int32 VolReClone(struct rx_call *, afs_int32, VolumeId);
88 static afs_int32 VolTransCreate(struct rx_call *, VolumeId, afs_int32,
89 afs_int32, afs_int32 *);
90 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
92 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
93 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
94 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
95 struct destServer *destination, afs_int32,
96 struct restoreCookie *cookie);
97 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
98 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
99 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();
161 /* get partition id from a name */
163 PartitionID(char *aname)
171 return -1; /* unknown */
173 /* otherwise check for vicepa or /vicepa, or just plain "a" */
175 if (!strncmp(aname, "/vicep", 6)) {
176 strncpy(ascii, aname + 6, 2);
178 return -1; /* bad partition name */
179 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
180 * from 0. Do the appropriate conversion */
182 /* one char name, 0..25 */
183 if (ascii[0] < 'a' || ascii[0] > 'z')
184 return -1; /* wrongo */
185 return ascii[0] - 'a';
187 /* two char name, 26 .. <whatever> */
188 if (ascii[0] < 'a' || ascii[0] > 'z')
189 return -1; /* wrongo */
190 if (ascii[1] < 'a' || ascii[1] > 'z')
191 return -1; /* just as bad */
192 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
193 if (code > VOLMAXPARTS)
200 ConvertVolume(VolumeId avol, char *aname, afs_int32 asize)
204 /* 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 */
205 snprintf(aname, asize, VFORMAT, afs_printable_VolumeId_lu(avol));
210 ConvertPartition(int apartno, char *aname, int asize)
216 strcpy(aname, "/vicep");
218 aname[6] = 'a' + apartno;
222 aname[6] = 'a' + (apartno / 26);
223 aname[7] = 'a' + (apartno % 26);
229 #ifdef AFS_DEMAND_ATTACH_FS
230 /* normally we should use the regular salvaging functions from the volume
231 * package, but this is a special case where we have a volume ID, but no
232 * volume structure to give the volume package */
234 SalvageUnknownVolume(VolumeId volid, char *part)
238 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
239 afs_printable_uint32_lu(volid), part);
241 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
242 FSYNC_SALVAGE, NULL);
244 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
245 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
249 #endif /* AFS_DEMAND_ATTACH_FS */
251 static struct Volume *
252 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
257 vp = VAttachVolumeByName(ec, partition, name, mode);
259 #ifdef AFS_DEMAND_ATTACH_FS
263 * The fileserver will take care of keeping track of how many
264 * demand-salvages have been performed, and will force the volume to
265 * ERROR if we've done too many. The limit on This loop is just a
266 * failsafe to prevent trying to salvage forever. We want to attempt
267 * attachment at least SALVAGE_COUNT_MAX times, since we want to
268 * avoid prematurely exiting this loop, if we can.
270 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
271 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
272 vp = VAttachVolumeByName(ec, partition, name, mode);
275 if (*ec == VSALVAGING) {
279 #endif /* AFS_DEMAND_ATTACH_FS */
284 static struct Volume *
285 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
290 vp = VAttachVolume(ec, avolid, amode);
292 #ifdef AFS_DEMAND_ATTACH_FS
295 /* see comment above in VAttachVolumeByName_retry */
296 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
297 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
298 vp = VAttachVolume(ec, avolid, amode);
301 if (*ec == VSALVAGING) {
305 #endif /* AFS_DEMAND_ATTACH_FS */
310 /* the only attach function that takes a partition is "...ByName", so we use it */
311 static struct Volume *
312 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
314 char pbuf[30], vbuf[20];
316 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
320 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
325 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
328 /* Adapted from the file server; create a root directory for this volume */
330 ViceCreateRoot(Volume *vp)
333 struct acl_accessList *ACL;
335 Inode inodeNumber, AFS_UNUSED nearInode;
336 struct VnodeDiskObject *vnode;
337 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
343 vnode = calloc(1, SIZEOF_LARGEDISKVNODE);
347 V_pref(vp, nearInode);
349 IH_CREATE(V_linkHandle(vp), V_device(vp),
350 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
352 if (!VALID_INO(inodeNumber)) {
353 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
358 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
359 did.Volume = V_id(vp);
360 did.Vnode = (VnodeId) 1;
363 opr_Verify(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
364 DFlush(); /* flush all modified dir buffers out */
365 DZap(&dir); /* Remove all buffers for this dir */
366 length = afs_dir_Length(&dir); /* Remember size of this directory */
368 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
370 /* build a single entry ACL that gives all rights to system:administrators */
371 /* this section of code assumes that access list format is not going to
374 ACL = VVnodeDiskACL(vnode);
375 ACL->size = sizeof(struct acl_accessList);
376 ACL->version = ACL_ACLVERSION;
380 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
381 ACL->entries[0].rights =
382 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
383 | PRSFS_LOCK | PRSFS_ADMINISTER;
385 vnode->type = vDirectory;
387 vnode->modeBits = 0777;
388 vnode->linkCount = 2;
389 VNDISK_SET_LEN(vnode, length);
390 vnode->uniquifier = 1;
391 V_uniquifier(vp) = vnode->uniquifier + 1;
392 vnode->dataVersion = 1;
393 VNDISK_SET_INO(vnode, inodeNumber);
394 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
398 vnode->vnodeMagic = vcp->magic;
400 IH_INIT(h, vp->device, V_parentId(vp),
401 vp->vnodeIndex[vLarge].handle->ih_ino);
403 opr_Assert(fdP != NULL);
404 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
405 opr_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
406 FDH_REALLYCLOSE(fdP);
408 VNDISK_GET_LEN(length, vnode);
409 V_diskused(vp) = nBlocks(length);
416 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
420 struct diskPartition64 *dp = malloc(sizeof(struct diskPartition64));
422 code = VolPartitionInfo(acid, pname, dp);
424 strncpy(partition->name, dp->name, 32);
425 strncpy(partition->devName, dp->devName, 32);
426 partition->lock_fd = dp->lock_fd;
427 partition->free=RoundInt64ToInt32(dp->free);
428 partition->minFree=RoundInt64ToInt32(dp->minFree);
431 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
436 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
441 code = VolPartitionInfo(acid, pname, partition);
442 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
447 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
450 struct DiskPartition64 *dp;
452 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
453 return VOLSERBAD_ACCESS;
456 dp = VGetPartition(pname, 0);
458 strncpy(partition->name, dp->name, 32);
459 strncpy(partition->devName, dp->devName, 32);
460 partition->lock_fd = (int)dp->lock_fd;
461 partition->free = dp->free;
462 partition->minFree = dp->totalUsable;
465 return VOLSERILLEGAL_PARTITION;
468 /* obliterate a volume completely, and slowly. */
470 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, VolumeId avolID)
474 code = VolNukeVolume(acid, apartID, avolID);
475 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
480 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
487 char caller[MAXKTCNAMELEN];
489 /* check for access */
490 if (!afsconf_SuperUser(tdir, acid, caller))
491 return VOLSERBAD_ACCESS;
494 Log("%s on %s is executing VolNukeVolume %u\n", caller,
495 callerAddress(acid, buffer), avolID);
498 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
500 /* we first try to attach the volume in update mode, so that the file
501 * server doesn't try to use it (and abort) while (or after) we delete it.
502 * If we don't get the volume, that's fine, too. We just won't put it back.
504 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
505 code = nuke(partName, avolID);
507 VDetachVolume(&verror, tvp);
511 /* create a new volume, with name aname, on the specified partition (1..n)
512 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
513 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
514 * for the volume id (useful for things like volume restore).
515 * Return the new volume id in *avolid.
518 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
519 afs_int32 atype, VolumeId aparent, VolumeId *avolid,
525 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
526 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
527 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
533 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
534 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
539 Error junk; /* discardable error code */
541 afs_int32 doCreateRoot = 1;
542 struct volser_trans *tt;
544 char caller[MAXKTCNAMELEN];
546 if (strlen(aname) > 31)
547 return VOLSERBADNAME;
548 if (!afsconf_SuperUser(tdir, acid, caller))
549 return VOLSERBAD_ACCESS;
552 Log("%s on %s is executing CreateVolume '%s'\n", caller,
553 callerAddress(acid, buffer), aname);
555 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
556 return error; /*a standard unix error */
557 if (atype != readwriteVolume && atype != readonlyVolume
558 && atype != backupVolume)
560 if ((volumeID = *avolid) == 0) {
562 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
566 if ((aparent == volumeID) && (atype == readwriteVolume)) {
571 tt = NewTrans(volumeID, apart);
573 Log("1 createvolume: failed to create trans\n");
574 return VOLSERVOLBUSY; /* volume already busy! */
576 vp = VCreateVolume(&error, ppath, volumeID, aparent);
578 #ifdef AFS_DEMAND_ATTACH_FS
579 if (error != VVOLEXISTS && error != EXDEV) {
580 SalvageUnknownVolume(volumeID, ppath);
583 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
588 V_uniquifier(vp) = 1;
589 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
590 V_inService(vp) = V_blessed(vp) = 1;
592 AssignVolumeName(&V_disk(vp), aname, 0);
594 error = ViceCreateRoot(vp);
596 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
597 "error code %u\n", (unsigned)error);
599 V_needsSalvaged(vp) = 1;
600 VDetachVolume(&junk, vp);
604 V_destroyMe(vp) = DESTROY_ME;
606 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
607 VUpdateVolume(&error, vp);
609 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
612 VDetachVolume(&junk, vp); /* rather return the real error code */
618 TSetRxCall_r(tt, acid, "CreateVolume");
619 VTRANS_OBJ_UNLOCK(tt);
620 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
623 return VOLSERTRELE_ERROR;
627 /* delete the volume associated with this transaction */
629 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
633 code = VolDeleteVolume(acid, atrans);
634 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
639 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
641 struct volser_trans *tt;
643 char caller[MAXKTCNAMELEN];
645 if (!afsconf_SuperUser(tdir, acid, caller))
646 return VOLSERBAD_ACCESS;
647 tt = FindTrans(atrans);
650 if (tt->vflags & VTDeleted) {
651 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " already deleted \n",
652 afs_printable_VolumeId_lu(tt->volid));
658 Log("%s on %s is executing Delete Volume %" AFS_VOLID_FMT "\n", caller,
659 callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
661 TSetRxCall(tt, acid, "DeleteVolume");
662 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
663 V_destroyMe(tt->volume) = DESTROY_ME;
664 if (tt->volume->needsPutBack) {
665 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
668 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
670 VTRANS_OBJ_UNLOCK(tt);
672 return VOLSERTRELE_ERROR;
674 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " deleted \n",
675 afs_printable_VolumeId_lu(tt->volid));
676 return 0; /* vpurgevolume doesn't set an error code */
679 /* make a clone of the volume associated with atrans, possibly giving it a new
680 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
681 * for the clone's id). The new clone is given the name newName. Finally,
682 * due to efficiency considerations, if purgeId is non-zero, we purge that
683 * volume when doing the clone operation. This may be useful when making
684 * new backup volumes, for instance since the net result of a clone and a
685 * purge generally leaves many inode ref counts the same, while doing them
686 * separately would result in far more iincs and idecs being peformed
687 * (and they are slow operations).
689 /* for efficiency reasons, sometimes faster to piggyback a purge here */
691 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
692 afs_int32 newType, char *newName, VolumeId *newNumber)
695 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
696 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
697 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
703 VolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
704 afs_int32 newType, char *newName, VolumeId *newNumber)
707 struct Volume *originalvp, *purgevp, *newvp;
709 struct volser_trans *tt, *ttc;
710 char caller[MAXKTCNAMELEN];
711 #ifdef AFS_DEMAND_ATTACH_FS
712 struct Volume *salv_vp = NULL;
715 if (strlen(newName) > 31)
716 return VOLSERBADNAME;
717 if (!afsconf_SuperUser(tdir, acid, caller))
718 return VOLSERBAD_ACCESS; /*not a super user */
721 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
722 callerAddress(acid, buffer), newName);
725 purgevp = (Volume *) 0;
726 newvp = (Volume *) 0;
727 tt = ttc = (struct volser_trans *)0;
729 if (!newNumber || !*newNumber) {
730 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
735 tt = FindTrans(atrans);
738 if (tt->vflags & VTDeleted) {
739 Log("1 Volser: Clone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
743 ttc = NewTrans(newId, tt->partition);
744 if (!ttc) { /* someone is messing with the clone already */
746 return VOLSERVOLBUSY;
748 TSetRxCall(tt, acid, "Clone");
752 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
754 Log("1 Volser: Clone: Could not attach 'purge' volume %" AFS_VOLID_FMT "; clone aborted\n", afs_printable_VolumeId_lu(purgeId));
760 originalvp = tt->volume;
761 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
762 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
763 afs_printable_VolumeId_lu(V_id(originalvp)));
768 if (originalvp->device != purgevp->device) {
769 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));
773 if (V_type(purgevp) != readonlyVolume) {
774 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
778 if (V_parentId(originalvp) != V_parentId(purgevp)) {
779 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));
786 #ifdef AFS_DEMAND_ATTACH_FS
787 salv_vp = originalvp;
790 if (purgeId == newId) {
794 VCreateVolume(&error, originalvp->partition->name, newId,
795 V_parentId(originalvp));
797 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
798 newvp = (Volume *) 0;
802 if (newType == readonlyVolume)
803 V_cloneId(originalvp) = newId;
804 Log("1 Volser: Clone: Cloning volume %" AFS_VOLID_FMT " to new volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
805 afs_printable_VolumeId_lu(newId));
807 Log("1 Volser: Clone: Purging old read only volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(purgeId));
808 CloneVolume(&error, originalvp, newvp, purgevp);
809 purgevp = NULL; /* clone releases it, maybe even if error */
811 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
815 if (newType == readonlyVolume) {
816 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
817 V_type(newvp) = readonlyVolume;
818 } else if (newType == backupVolume) {
819 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
820 V_type(newvp) = backupVolume;
821 V_backupId(originalvp) = newId;
823 strcpy(V_name(newvp), newName);
824 V_creationDate(newvp) = V_copyDate(newvp);
825 ClearVolumeStats(&V_disk(newvp));
826 V_destroyMe(newvp) = DESTROY_ME;
827 V_inService(newvp) = 0;
828 if (newType == backupVolume) {
829 V_backupDate(originalvp) = V_copyDate(newvp);
830 V_backupDate(newvp) = V_copyDate(newvp);
833 VUpdateVolume(&error, newvp);
835 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
839 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
841 VUpdateVolume(&error, originalvp);
843 Log("1 Volser: Clone: original update %u\n", error);
848 #ifdef AFS_DEMAND_ATTACH_FS
852 tt = (struct volser_trans *)0;
853 error = VOLSERTRELE_ERROR;
861 VDetachVolume(&code, purgevp);
863 VDetachVolume(&code, newvp);
870 #ifdef AFS_DEMAND_ATTACH_FS
871 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
872 V_needsSalvaged(salv_vp) = 1;
874 #endif /* AFS_DEMAND_ATTACH_FS */
878 /* reclone this volume into the specified id */
880 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
884 code = VolReClone(acid, atrans, cloneId);
885 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
891 VolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
893 struct Volume *originalvp, *clonevp;
896 struct volser_trans *tt, *ttc;
897 char caller[MAXKTCNAMELEN];
898 VolumeDiskData saved_header;
900 /*not a super user */
901 if (!afsconf_SuperUser(tdir, acid, caller))
902 return VOLSERBAD_ACCESS;
905 Log("%s on %s is executing Reclone Volume %" AFS_VOLID_FMT "\n", caller,
906 callerAddress(acid, buffer), afs_printable_VolumeId_lu(cloneId));
909 clonevp = originalvp = (Volume *) 0;
911 tt = FindTrans(atrans);
914 if (tt->vflags & VTDeleted) {
915 Log("1 Volser: VolReClone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
919 ttc = NewTrans(cloneId, tt->partition);
920 if (!ttc) { /* someone is messing with the clone already */
922 return VOLSERVOLBUSY;
924 TSetRxCall(tt, acid, "ReClone");
926 originalvp = tt->volume;
927 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
928 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
929 afs_printable_VolumeId_lu(V_id(originalvp)));
934 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
936 Log("1 Volser: can't attach clone %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(cloneId));
940 newType = V_type(clonevp); /* type of the new volume */
942 if (originalvp->device != clonevp->device) {
943 Log("1 Volser: Clone: Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are on different devices\n",
944 afs_printable_VolumeId_lu(tt->volid), afs_printable_VolumeId_lu(cloneId));
948 if (V_parentId(originalvp) != V_parentId(clonevp)) {
949 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));
954 if (DoPreserveVolumeStats) {
955 CopyVolumeStats(&V_disk(clonevp), &saved_header);
959 Log("1 Volser: Clone: Recloning volume %" AFS_VOLID_FMT " to volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
960 afs_printable_VolumeId_lu(cloneId));
961 CloneVolume(&error, originalvp, clonevp, clonevp);
963 Log("1 Volser: Clone: reclone operation failed with code %d\n",
969 /* fix up volume name and type, CloneVolume just propagated RW's */
970 if (newType == readonlyVolume) {
971 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
972 V_type(clonevp) = readonlyVolume;
973 } else if (newType == backupVolume) {
974 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
975 V_type(clonevp) = backupVolume;
976 V_backupId(originalvp) = cloneId;
978 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
980 /* update the creationDate, since this represents the last cloning date
981 * for ROs. But do not update copyDate; let it stay so we can identify
982 * when the clone was first created. */
983 V_creationDate(clonevp) = time(0);
984 if (DoPreserveVolumeStats) {
985 CopyVolumeStats(&saved_header, &V_disk(clonevp));
987 ClearVolumeStats(&V_disk(clonevp));
989 V_destroyMe(clonevp) = 0;
990 V_inService(clonevp) = 0;
991 if (newType == backupVolume) {
992 V_backupDate(originalvp) = V_creationDate(clonevp);
993 V_backupDate(clonevp) = V_creationDate(clonevp);
995 V_inUse(clonevp) = 0;
996 VUpdateVolume(&error, clonevp);
998 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
1002 /* VUpdateVolume succeeded. Mark it in service so there's no window
1003 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
1004 * specialStatus; this is a reclone and this volume started online
1006 V_inService(clonevp) = 1;
1007 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
1009 VUpdateVolume(&error, originalvp);
1011 Log("1 Volser: Clone: original update %u\n", error);
1017 tt = (struct volser_trans *)0;
1018 error = VOLSERTRELE_ERROR;
1022 DeleteTrans(ttc, 1);
1025 struct DiskPartition64 *tpartp = originalvp->partition;
1026 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1032 VDetachVolume(&code, clonevp);
1038 DeleteTrans(ttc, 1);
1042 /* create a new transaction, associated with volume and partition. Type of
1043 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1044 * See volser.h for definition of iflags (the constants are named IT*).
1047 SAFSVolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1048 afs_int32 iflags, afs_int32 *ttid)
1052 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1053 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1059 VolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1060 afs_int32 iflags, afs_int32 *ttid)
1062 struct volser_trans *tt;
1067 char caller[MAXKTCNAMELEN];
1069 if (!afsconf_SuperUser(tdir, acid, caller))
1070 return VOLSERBAD_ACCESS; /*not a super user */
1071 if (iflags & ITCreate)
1073 else if (iflags & ITBusy)
1075 else if (iflags & ITReadOnly)
1077 else if (iflags & ITOffline)
1080 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1085 tt = NewTrans(volume, partition);
1087 /* can't create a transaction? put the volume back */
1088 Log("1 transcreate: can't create transaction\n");
1089 return VOLSERVOLBUSY;
1091 tv = XAttachVolume(&error, volume, partition, mode);
1095 VDetachVolume(&code, tv);
1099 VTRANS_OBJ_LOCK(tt);
1102 tt->iflags = iflags;
1104 TSetRxCall_r(tt, NULL, "TransCreate");
1105 VTRANS_OBJ_UNLOCK(tt);
1107 return VOLSERTRELE_ERROR;
1112 /* using aindex as a 0-based index, return the aindex'th volume on this server
1113 * Both the volume number and partition number (one-based) are returned.
1116 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, VolumeId *avolume,
1121 code = VolGetNthVolume(acid, aindex, avolume, apart);
1122 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1127 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1130 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1131 return VOLSERBAD_ACCESS;
1133 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1137 /* return the volume flags (VT* constants in volser.h) associated with this
1141 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1145 code = VolGetFlags(acid, atid, aflags);
1146 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1151 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1153 struct volser_trans *tt;
1155 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1156 return VOLSERBAD_ACCESS;
1158 tt = FindTrans(atid);
1161 if (tt->vflags & VTDeleted) {
1162 Log("1 Volser: VolGetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1163 afs_printable_VolumeId_lu(tt->volid));
1167 TSetRxCall(tt, acid, "GetFlags");
1168 *aflags = tt->vflags;
1171 return VOLSERTRELE_ERROR;
1176 /* Change the volume flags (VT* constants in volser.h) associated with this
1177 * transaction. Effects take place immediately on volume, although volume
1178 * remains attached as usual by the transaction.
1181 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1185 code = VolSetFlags(acid, atid, aflags);
1186 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1192 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1194 struct volser_trans *tt;
1197 char caller[MAXKTCNAMELEN];
1199 if (!afsconf_SuperUser(tdir, acid, caller))
1200 return VOLSERBAD_ACCESS; /*not a super user */
1201 /* find the trans */
1202 tt = FindTrans(atid);
1205 if (tt->vflags & VTDeleted) {
1206 Log("1 Volser: VolSetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1207 afs_printable_VolumeId_lu(tt->volid));
1211 TSetRxCall(tt, acid, "SetFlags");
1212 vp = tt->volume; /* pull volume out of transaction */
1214 /* check if we're allowed to make any updates */
1215 if (tt->iflags & ITReadOnly) {
1220 /* handle delete-on-salvage flag */
1221 if (aflags & VTDeleteOnSalvage) {
1222 V_destroyMe(tt->volume) = DESTROY_ME;
1224 V_destroyMe(tt->volume) = 0;
1227 if (aflags & VTOutOfService) {
1228 V_inService(vp) = 0;
1230 V_inService(vp) = 1;
1232 VUpdateVolume(&error, vp);
1233 VTRANS_OBJ_LOCK(tt);
1234 tt->vflags = aflags;
1236 VTRANS_OBJ_UNLOCK(tt);
1237 if (TRELE(tt) && !error)
1238 return VOLSERTRELE_ERROR;
1243 /* dumpS the volume associated with a particular transaction from a particular
1244 * date. Send the dump to a different transaction (destTrans) on the server
1245 * specified by the destServer structure.
1248 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1249 struct destServer *destination, afs_int32 destTrans,
1250 struct restoreCookie *cookie)
1255 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1256 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1257 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1262 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1263 struct destServer *destination, afs_int32 destTrans,
1264 struct restoreCookie *cookie)
1266 struct volser_trans *tt;
1268 struct rx_connection *tcon;
1269 struct rx_call *tcall;
1271 struct rx_securityClass *securityObject;
1272 afs_int32 securityIndex;
1273 char caller[MAXKTCNAMELEN];
1275 if (!afsconf_SuperUser(tdir, acid, caller))
1276 return VOLSERBAD_ACCESS; /*not a super user */
1278 /* find the local transaction */
1279 tt = FindTrans(fromTrans);
1282 if (tt->vflags & VTDeleted) {
1283 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1288 TSetRxCall(tt, NULL, "Forward");
1290 /* get auth info for the this connection (uses afs from ticket file) */
1291 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1297 /* make an rpc connection to the other server */
1299 rx_NewConnection(htonl(destination->destHost),
1300 htons(destination->destPort), VOLSERVICE_ID,
1301 securityObject, securityIndex);
1307 tcall = rx_NewCall(tcon);
1308 TSetRxCall(tt, tcall, "Forward");
1309 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1310 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1315 /* these next calls implictly call rx_Write when writing out data */
1316 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1319 EndAFSVolRestore(tcall); /* probably doesn't do much */
1321 code = rx_EndCall(tcall, 0);
1322 rx_DestroyConnection(tcon); /* done with the connection */
1327 return VOLSERTRELE_ERROR;
1333 (void)rx_EndCall(tcall, 0);
1334 rx_DestroyConnection(tcon);
1343 /* Start a dump and send it to multiple places simultaneously.
1344 * If this returns an error (eg, return ENOENT), it means that
1345 * none of the releases worked. If this returns 0, that means
1346 * that one or more of the releases worked, and the caller has
1347 * to examine the results array to see which one(s).
1348 * This will only do EITHER incremental or full, not both, so it's
1349 * the caller's responsibility to be sure that all the destinations
1350 * need just an incremental (and from the same time), if that's
1354 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1355 fromDate, manyDests *destinations, afs_int32 spare,
1356 struct restoreCookie *cookie, manyResults *results)
1358 afs_int32 securityIndex;
1359 struct rx_securityClass *securityObject;
1360 char caller[MAXKTCNAMELEN];
1361 struct volser_trans *tt;
1362 afs_int32 ec, code, *codes;
1363 struct rx_connection **tcons;
1364 struct rx_call **tcalls;
1366 int i, is_incremental;
1369 memset(results, 0, sizeof(manyResults));
1370 i = results->manyResults_len = destinations->manyDests_len;
1371 results->manyResults_val = codes = malloc(i * sizeof(afs_int32));
1373 if (!results || !results->manyResults_val)
1376 if (!afsconf_SuperUser(tdir, acid, caller))
1377 return VOLSERBAD_ACCESS; /*not a super user */
1378 tt = FindTrans(fromTrans);
1381 if (tt->vflags & VTDeleted) {
1382 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1387 TSetRxCall(tt, NULL, "ForwardMulti");
1389 /* (fromDate == 0) ==> full dump */
1390 is_incremental = (fromDate ? 1 : 0);
1392 tcons = malloc(i * sizeof(struct rx_connection *));
1396 tcalls = malloc(i * sizeof(struct rx_call *));
1402 /* get auth info for this connection (uses afs from ticket file) */
1403 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1405 goto fail; /* in order to audit each failure */
1408 /* make connections to all the other servers */
1409 for (i = 0; i < destinations->manyDests_len; i++) {
1410 struct replica *dest = &(destinations->manyDests_val[i]);
1412 rx_NewConnection(htonl(dest->server.destHost),
1413 htons(dest->server.destPort), VOLSERVICE_ID,
1414 securityObject, securityIndex);
1416 codes[i] = ENOTCONN;
1418 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1419 codes[i] = ENOTCONN;
1422 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1425 (void)rx_EndCall(tcalls[i], 0);
1427 rx_DestroyConnection(tcons[i]);
1434 /* these next calls implictly call rx_Write when writing out data */
1435 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1439 for (i--; i >= 0; i--) {
1440 struct replica *dest = &(destinations->manyDests_val[i]);
1442 if (!code && tcalls[i] && !codes[i]) {
1443 EndAFSVolRestore(tcalls[i]);
1446 ec = rx_EndCall(tcalls[i], 0);
1451 rx_DestroyConnection(tcons[i]); /* done with the connection */
1454 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1455 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1456 dest->trans, AUD_END);
1463 if (TRELE(tt) && !code) /* return the first code if it's set */
1464 return VOLSERTRELE_ERROR;
1471 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1475 code = VolDump(acid, fromTrans, fromDate, 0);
1476 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1481 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1486 code = VolDump(acid, fromTrans, fromDate, flags);
1487 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1492 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1496 struct volser_trans *tt;
1497 char caller[MAXKTCNAMELEN];
1499 if (!afsconf_SuperUser(tdir, acid, caller))
1500 return VOLSERBAD_ACCESS; /*not a super user */
1501 tt = FindTrans(fromTrans);
1504 if (tt->vflags & VTDeleted) {
1505 Log("1 Volser: VolDump: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1509 TSetRxCall(tt, acid, "Dump");
1510 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1511 ? 0 : 1); /* squirt out the volume's data, too */
1520 return VOLSERTRELE_ERROR;
1526 * Ha! No more helper process!
1529 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1530 struct restoreCookie *cookie)
1534 code = VolRestore(acid, atrans, aflags, cookie);
1535 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1540 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1541 struct restoreCookie *cookie)
1543 struct volser_trans *tt;
1544 afs_int32 code, tcode;
1545 char caller[MAXKTCNAMELEN];
1547 if (!afsconf_SuperUser(tdir, acid, caller))
1548 return VOLSERBAD_ACCESS; /*not a super user */
1549 tt = FindTrans(atrans);
1552 if (tt->vflags & VTDeleted) {
1553 Log("1 Volser: VolRestore: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1559 Log("%s on %s is executing Restore %" AFS_VOLID_FMT "\n", caller,
1560 callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
1562 TSetRxCall(tt, acid, "Restore");
1564 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1566 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1567 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1571 return (code ? code : tcode);
1574 /* end a transaction, returning the transaction's final error code in rcode */
1576 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1580 code = VolEndTrans(acid, destTrans, rcode);
1581 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1586 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1588 struct volser_trans *tt;
1589 char caller[MAXKTCNAMELEN];
1591 if (!afsconf_SuperUser(tdir, acid, caller))
1592 return VOLSERBAD_ACCESS; /*not a super user */
1593 tt = FindTrans(destTrans);
1597 *rcode = tt->returnCode;
1598 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1604 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1608 code = VolSetForwarding(acid, atid, anewsite);
1609 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1610 htonl(anewsite), AUD_END);
1615 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1617 struct volser_trans *tt;
1618 char caller[MAXKTCNAMELEN];
1621 if (!afsconf_SuperUser(tdir, acid, caller))
1622 return VOLSERBAD_ACCESS; /*not a super user */
1623 tt = FindTrans(atid);
1626 if (tt->vflags & VTDeleted) {
1627 Log("1 Volser: VolSetForwarding: volume %" AFS_VOLID_FMT " has been deleted \n",
1628 afs_printable_VolumeId_lu(tt->volid));
1632 TSetRxCall(tt, acid, "SetForwarding");
1633 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1636 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1639 return VOLSERTRELE_ERROR;
1645 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1646 struct volser_status *astatus)
1650 code = VolGetStatus(acid, atrans, astatus);
1651 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1656 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1657 struct volser_status *astatus)
1660 struct VolumeDiskData *td;
1661 struct volser_trans *tt;
1663 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1664 return VOLSERBAD_ACCESS;
1666 tt = FindTrans(atrans);
1669 if (tt->vflags & VTDeleted) {
1670 Log("1 Volser: VolGetStatus: volume %" AFS_VOLID_FMT " has been deleted \n",
1671 afs_printable_VolumeId_lu(tt->volid));
1675 TSetRxCall(tt, acid, "GetStatus");
1684 astatus->volID = td->id;
1685 astatus->nextUnique = td->uniquifier;
1686 astatus->type = td->type;
1687 astatus->parentID = td->parentId;
1688 astatus->cloneID = td->cloneId;
1689 astatus->backupID = td->backupId;
1690 astatus->restoredFromID = td->restoredFromId;
1691 astatus->maxQuota = td->maxquota;
1692 astatus->minQuota = td->minquota;
1693 astatus->owner = td->owner;
1694 astatus->creationDate = td->creationDate;
1695 astatus->accessDate = td->accessDate;
1696 astatus->updateDate = td->updateDate;
1697 astatus->expirationDate = td->expirationDate;
1698 astatus->backupDate = td->backupDate;
1699 astatus->copyDate = td->copyDate;
1702 return VOLSERTRELE_ERROR;
1708 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1709 struct volintInfo *astatus)
1713 code = VolSetInfo(acid, atrans, astatus);
1714 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1719 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1720 struct volintInfo *astatus)
1723 struct VolumeDiskData *td;
1724 struct volser_trans *tt;
1725 char caller[MAXKTCNAMELEN];
1728 if (!afsconf_SuperUser(tdir, acid, caller))
1729 return VOLSERBAD_ACCESS; /*not a super user */
1730 tt = FindTrans(atrans);
1733 if (tt->vflags & VTDeleted) {
1734 Log("1 Volser: VolSetInfo: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1738 TSetRxCall(tt, acid, "SetStatus");
1748 * Add more fields as necessary
1750 if (astatus->maxquota != -1)
1751 td->maxquota = astatus->maxquota;
1752 if (astatus->dayUse != -1)
1753 td->dayUse = astatus->dayUse;
1754 if (astatus->creationDate != -1)
1755 td->creationDate = astatus->creationDate;
1756 if (astatus->updateDate != -1)
1757 td->updateDate = astatus->updateDate;
1758 if (astatus->spare2 != -1)
1759 td->volUpdateCounter = (unsigned int)astatus->spare2;
1760 VUpdateVolume(&error, tv);
1763 return VOLSERTRELE_ERROR;
1769 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1773 code = VolGetName(acid, atrans, aname);
1774 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1779 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1782 struct VolumeDiskData *td;
1783 struct volser_trans *tt;
1786 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1787 return VOLSERBAD_ACCESS;
1789 /* We need to at least fill it in */
1793 tt = FindTrans(atrans);
1796 if (tt->vflags & VTDeleted) {
1797 Log("1 Volser: VolGetName: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1801 TSetRxCall(tt, acid, "GetName");
1810 len = strlen(td->name) + 1; /* don't forget the null */
1816 *aname = realloc(*aname, len);
1817 strcpy(*aname, td->name);
1820 return VOLSERTRELE_ERROR;
1825 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1828 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1829 VolumeId parentId, VolumeId cloneId)
1835 /*return a list of all partitions on the server. The non mounted
1836 *partitions are returned as -1 in the corresponding slot in partIds*/
1838 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1842 code = VolListPartitions(acid, partIds);
1843 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1848 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1853 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1854 return VOLSERBAD_ACCESS;
1856 strcpy(namehead, "/vicep"); /*7 including null terminator */
1858 /* Just return attached partitions. */
1860 for (i = 0; i < 26; i++) {
1861 namehead[6] = i + 'a';
1862 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1868 /*return a list of all partitions on the server. The non mounted
1869 *partitions are returned as -1 in the corresponding slot in partIds*/
1871 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1875 code = XVolListPartitions(acid, pEntries);
1876 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1881 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1884 struct partList partList;
1885 struct DiskPartition64 *dp;
1888 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
1889 return VOLSERBAD_ACCESS;
1891 strcpy(namehead, "/vicep"); /*7 including null terminator */
1893 /* Only report attached partitions */
1894 for (i = 0; i < VOLMAXPARTS; i++) {
1895 #ifdef AFS_DEMAND_ATTACH_FS
1896 dp = VGetPartitionById(i, 0);
1899 namehead[6] = i + 'a';
1905 namehead[6] = 'a' + (k / 26);
1906 namehead[7] = 'a' + (k % 26);
1909 dp = VGetPartition(namehead, 0);
1912 partList.partId[j++] = i;
1915 pEntries->partEntries_val = malloc(j * sizeof(int));
1916 if (!pEntries->partEntries_val)
1918 memcpy(pEntries->partEntries_val, partList.partId,
1920 pEntries->partEntries_len = j;
1922 pEntries->partEntries_val = NULL;
1923 pEntries->partEntries_len = 0;
1930 * Scan a directory for possible volume headers.
1931 * in: DIR *dirp -- a directory handle from opendir()
1932 * out: char *volname -- set to name of directory entry
1933 * afs_uint32 *volid -- set to volume ID parsed from name
1935 * true if volname and volid have been set to valid values
1936 * false if we got to the end of the directory
1939 GetNextVol(DIR *dirp, char *volname, VolumeId *volid)
1943 while ((dp = readdir(dirp)) != NULL) {
1944 /* could be optimized on platforms with dp->d_namlen */
1945 if (dp->d_name[0] == 'V' && strlen(dp->d_name) == VHDRNAMELEN
1946 && strcmp(&(dp->d_name[VFORMATDIGITS + 1]), VHDREXT) == 0) {
1947 *volid = VolumeNumber(dp->d_name);
1948 strcpy(volname, dp->d_name);
1956 * volint vol info structure type.
1959 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1960 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1961 } volint_info_type_t;
1964 * handle to various on-wire vol info types.
1967 volint_info_type_t volinfo_type;
1973 } volint_info_handle_t;
1976 * store value to a field at the appropriate location in on-wire structure.
1978 #define VOLINT_INFO_STORE(handle, name, val) \
1980 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1981 (handle)->volinfo_ptr.base->name = (val); \
1983 (handle)->volinfo_ptr.ext->name = (val); \
1988 * get pointer to appropriate offset of field in on-wire structure.
1990 #define VOLINT_INFO_PTR(handle, name) \
1991 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1992 &((handle)->volinfo_ptr.base->name) : \
1993 &((handle)->volinfo_ptr.ext->name))
1996 * fill in appropriate type of on-wire volume metadata structure.
1998 * @param vp pointer to volume object
1999 * @param handle pointer to wire format handle object
2001 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
2002 * @pre handle object must have a valid pointer and enumeration value
2004 * @note passing a NULL value for vp means that the fileserver doesn't
2005 * know about this particular volume, thus implying it is offline.
2007 * @return operation status
2012 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
2014 unsigned int numStatBytes, now;
2015 struct VolumeDiskData *hdr = &(V_disk(vp));
2017 /*read in the relevant info */
2018 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2019 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
2020 VOLINT_INFO_STORE(handle, volid, hdr->id);
2021 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2022 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2023 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2024 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2025 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2026 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2027 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2028 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2029 now = FT_ApproxTime();
2030 if ((now - hdr->dayUseDate) > OneDay) {
2031 VOLINT_INFO_STORE(handle, dayUse, 0);
2033 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2035 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2036 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2037 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2038 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2040 #ifdef AFS_DEMAND_ATTACH_FS
2042 * for DAFS, we "lie" about volume state --
2043 * instead of returning the raw state from the disk header,
2044 * we compute state based upon the fileserver's internal
2045 * in-core state enumeration value reported to us via fssync,
2046 * along with the blessed and inService flags from the header.
2047 * -- tkeiser 11/27/2007
2050 /* Conditions that offline status is based on:
2051 volume is unattached state
2052 volume state is in (one of several error states)
2053 volume not in service
2054 volume is not marked as blessed (not on hold)
2055 volume in salvage req. state
2056 volume needsSalvaged
2057 next op would set volume offline
2058 next op would not leave volume online (based on several conditions)
2061 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2062 VIsErrorState(V_attachState(vp)) ||
2065 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2066 hdr->needsSalvaged ||
2067 (vp->pending_vol_op &&
2068 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2069 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2072 VOLINT_INFO_STORE(handle, inUse, 0);
2074 VOLINT_INFO_STORE(handle, inUse, 1);
2077 /* offline status based on program type, where != fileServer enum (1) is offline */
2078 if (hdr->inUse == fileServer) {
2079 VOLINT_INFO_STORE(handle, inUse, 1);
2081 VOLINT_INFO_STORE(handle, inUse, 0);
2086 switch(handle->volinfo_type) {
2087 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2088 case VOLINT_INFO_TYPE_BASE:
2090 #ifdef AFS_DEMAND_ATTACH_FS
2091 /* see comment above where we set inUse bit */
2092 if (hdr->needsSalvaged ||
2093 (vp && VIsErrorState(V_attachState(vp)))) {
2094 handle->volinfo_ptr.base->needsSalvaged = 1;
2096 handle->volinfo_ptr.base->needsSalvaged = 0;
2099 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2101 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2102 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2103 handle->volinfo_ptr.base->spare1 =
2104 (long)hdr->weekUse[0] +
2105 (long)hdr->weekUse[1] +
2106 (long)hdr->weekUse[2] +
2107 (long)hdr->weekUse[3] +
2108 (long)hdr->weekUse[4] +
2109 (long)hdr->weekUse[5] +
2110 (long)hdr->weekUse[6];
2111 handle->volinfo_ptr.base->flags = 0;
2112 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2113 handle->volinfo_ptr.base->spare3 = 0;
2117 case VOLINT_INFO_TYPE_EXT:
2119 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2120 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2123 * Copy out the stat fields in a single operation.
2125 if ((now - hdr->dayUseDate) > OneDay) {
2126 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2129 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2130 (char *)&(hdr->stat_reads[0]),
2139 #ifdef AFS_DEMAND_ATTACH_FS
2142 * get struct Volume out of the fileserver.
2144 * @param[in] volumeId volumeId for which we want state information
2145 * @param[in] pname partition name string
2146 * @param[inout] vp pointer to pointer to Volume object which
2147 * will be populated (see note)
2149 * @return operation status
2151 * @retval non-zero failure
2153 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2158 GetVolObject(VolumeId volumeId, char * pname, Volume ** vp)
2163 res.hdr.response_len = sizeof(res.hdr);
2164 res.payload.buf = *vp;
2165 res.payload.len = sizeof(Volume);
2167 code = FSYNC_VolOp(volumeId,
2173 if (code != SYNC_OK) {
2174 switch (res.hdr.reason) {
2175 case FSYNC_WRONG_PART:
2176 case FSYNC_UNKNOWN_VOLID:
2189 * mode of volume list operation.
2192 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2193 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2194 } vol_info_list_mode_t;
2197 * abstract interface to populate wire-format volume metadata structures.
2199 * @param[in] partId partition id
2200 * @param[in] volumeId volume id
2201 * @param[in] pname partition name
2202 * @param[in] volname volume file name
2203 * @param[in] handle handle to on-wire volume metadata object
2204 * @param[in] mode listing mode
2206 * @return operation status
2208 * @retval -2 DESTROY_ME flag is set
2209 * @retval -1 general failure; some data filled in
2210 * @retval -3 couldn't create vtrans; some data filled in
2213 GetVolInfo(afs_uint32 partId,
2217 volint_info_handle_t * handle,
2218 vol_info_list_mode_t mode)
2222 struct volser_trans *ttc = NULL;
2223 struct Volume *fill_tv, *tv = NULL;
2224 #ifdef AFS_DEMAND_ATTACH_FS
2225 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2226 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2227 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2228 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2230 /* Set up response handle for pending_vol_op */
2231 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2232 fs_res.payload.buf = fs_res_buf;
2233 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2236 ttc = NewTrans(volumeId, partId);
2239 VOLINT_INFO_STORE(handle, status, VBUSY);
2240 VOLINT_INFO_STORE(handle, volid, volumeId);
2244 /* Get volume from volserver */
2245 if (mode == VOL_INFO_LIST_MULTIPLE)
2246 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2248 #ifdef AFS_DEMAND_ATTACH_FS
2251 int mode = V_READONLY; /* informs the fileserver to update the volume headers. */
2253 tv = VAttachVolumeByName_retry(&error, pname, volname, mode);
2257 Log("1 Volser: GetVolInfo: Could not attach volume %" AFS_VOLID_FMT " (%s:%s) error=%d\n",
2258 afs_printable_VolumeId_lu(volumeId), pname, volname, error);
2263 * please note that destroyMe and needsSalvaged checks used to be ordered
2264 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2265 * more correct to check destroyMe before needsSalvaged.
2266 * -- tkeiser 11/28/2007
2269 if (V_destroyMe(tv) == DESTROY_ME) {
2271 case VOL_INFO_LIST_MULTIPLE:
2275 case VOL_INFO_LIST_SINGLE:
2276 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) will be destroyed on next salvage\n",
2277 afs_printable_VolumeId_lu(volumeId), pname, volname);
2284 if (V_needsSalvaged(tv)) {
2285 /*this volume will be salvaged */
2286 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) needs to be salvaged\n",
2287 afs_printable_VolumeId_lu(volumeId), pname, volname);
2290 #ifdef AFS_DEMAND_ATTACH_FS
2291 /* If using DAFS, get volume from fsserver */
2292 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2297 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2298 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2299 /* If we if the pending vol op */
2300 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2301 fs_tv->pending_vol_op=&pending_vol_op_res;
2303 fs_tv->pending_vol_op=NULL;
2306 /* populate the header from the volserver copy */
2307 fs_tv->header=tv->header;
2309 /* When using DAFS, use the fs volume info, populated with required structures */
2312 /* When not using DAFS, just use the local volume info */
2316 /* ok, we have all the data we need; fill in the on-wire struct */
2317 code = FillVolInfo(fill_tv, handle);
2321 VOLINT_INFO_STORE(handle, status, 0);
2322 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2323 VOLINT_INFO_STORE(handle, volid, volumeId);
2326 VDetachVolume(&error, tv);
2329 VOLINT_INFO_STORE(handle, status, 0);
2330 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2331 Log("1 Volser: GetVolInfo: Could not detach volume %" AFS_VOLID_FMT " (%s:%s)\n",
2332 afs_printable_VolumeId_lu(volumeId), pname, volname);
2336 DeleteTrans(ttc, 1);
2343 /*return the header information about the <volid> */
2345 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2346 VolumeId volumeId, volEntries *volumeInfo)
2350 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2351 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2356 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2357 VolumeId volumeId, volEntries *volumeInfo)
2359 struct DiskPartition64 *partP;
2360 char pname[9], volname[20];
2364 volint_info_handle_t handle;
2366 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2367 return VOLSERBAD_ACCESS;
2369 volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2370 if (!volumeInfo->volEntries_val)
2373 volumeInfo->volEntries_len = 1;
2374 if (GetPartName(partid, pname))
2375 return VOLSERILLEGAL_PARTITION;
2376 if (!(partP = VGetPartition(pname, 0)))
2377 return VOLSERILLEGAL_PARTITION;
2378 dirp = opendir(VPartitionPath(partP));
2380 return VOLSERILLEGAL_PARTITION;
2382 while (GetNextVol(dirp, volname, &volid)) {
2383 if (volid == volumeId) { /*copy other things too */
2390 #ifndef AFS_PTHREAD_ENV
2391 IOMGR_Poll(); /*make sure that the client does not time out */
2394 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2395 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2397 /* The return code from GetVolInfo is ignored; there is no error from
2398 * it that results in the whole call being aborted. Any volume
2399 * attachment failures are reported in 'status' field in the
2400 * volumeInfo payload. */
2406 VOL_INFO_LIST_SINGLE);
2410 return (found) ? 0 : ENODEV;
2413 /*------------------------------------------------------------------------
2414 * EXPORTED SAFSVolXListOneVolume
2417 * Returns extended info on volume a_volID on partition a_partID.
2420 * a_rxCidP : Pointer to the Rx call we're performing.
2421 * a_partID : Partition for which we want the extended list.
2422 * a_volID : Volume ID we wish to know about.
2423 * a_volumeXInfoP : Ptr to the extended info blob.
2426 * 0 Successful operation
2427 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2430 * Nothing interesting.
2434 *------------------------------------------------------------------------*/
2437 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2438 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2442 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2443 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2448 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2449 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2450 { /*SAFSVolXListOneVolume */
2452 struct DiskPartition64 *partP; /*Ptr to partition */
2453 char pname[9], volname[20]; /*Partition, volume names */
2454 DIR *dirp; /*Partition directory ptr */
2455 VolumeId currVolID; /*Current volume ID */
2456 int found = 0; /*Did we find the volume we need? */
2457 volint_info_handle_t handle;
2459 if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
2460 return VOLSERBAD_ACCESS;
2463 * Set up our pointers for action, marking our structure to hold exactly
2464 * one entry. Also, assume we'll fail in our quest.
2466 a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2467 if (!a_volumeXInfoP->volXEntries_val)
2470 a_volumeXInfoP->volXEntries_len = 1;
2473 * If the partition name we've been given is bad, bogue out.
2475 if (GetPartName(a_partID, pname))
2476 return (VOLSERILLEGAL_PARTITION);
2479 * Open the directory representing the given AFS parttion. If we can't
2482 if (!(partP = VGetPartition(pname, 0)))
2483 return VOLSERILLEGAL_PARTITION;
2484 dirp = opendir(VPartitionPath(partP));
2486 return (VOLSERILLEGAL_PARTITION);
2490 * Sweep through the partition directory, looking for the desired entry.
2491 * First, of course, figure out how many stat bytes to copy out of each
2494 while (GetNextVol(dirp, volname, &currVolID)) {
2495 if (currVolID == a_volID) {
2497 * We found the volume entry we're interested. Pull out the
2498 * extended information, remembering to poll (so that the client
2499 * doesn't time out) and to set up a transaction on the volume.
2503 } /*Found desired volume */
2507 #ifndef AFS_PTHREAD_ENV
2511 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2512 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2514 /* The return code from GetVolInfo is ignored; there is no error from
2515 * it that results in the whole call being aborted. Any volume
2516 * attachment failures are reported in 'status' field in the
2517 * volumeInfo payload. */
2518 GetVolInfo(a_partID,
2523 VOL_INFO_LIST_SINGLE);
2527 * Clean up before going to dinner: close the partition directory,
2528 * return the proper value.
2531 return (found) ? 0 : ENODEV;
2532 } /*SAFSVolXListOneVolume */
2534 /*returns all the volumes on partition partid. If flags = 1 then all the
2535 * relevant info about the volumes is also returned */
2537 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2538 volEntries *volumeInfo)
2542 code = VolListVolumes(acid, partid, flags, volumeInfo);
2543 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2548 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2549 volEntries *volumeInfo)
2552 struct DiskPartition64 *partP;
2553 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2554 char pname[9], volname[20];
2558 volint_info_handle_t handle;
2560 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2561 return VOLSERBAD_ACCESS;
2563 volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2564 if (!volumeInfo->volEntries_val)
2567 pntr = volumeInfo->volEntries_val;
2568 volumeInfo->volEntries_len = 0;
2569 if (GetPartName(partid, pname))
2570 return VOLSERILLEGAL_PARTITION;
2571 if (!(partP = VGetPartition(pname, 0)))
2572 return VOLSERILLEGAL_PARTITION;
2573 dirp = opendir(VPartitionPath(partP));
2575 return VOLSERILLEGAL_PARTITION;
2577 while (GetNextVol(dirp, volname, &volid)) {
2578 if (flags) { /*copy other things too */
2579 #ifndef AFS_PTHREAD_ENV
2580 IOMGR_Poll(); /*make sure that the client does not time out */
2583 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2584 handle.volinfo_ptr.base = pntr;
2587 code = GetVolInfo(partid,
2592 VOL_INFO_LIST_MULTIPLE);
2593 if (code == -2) /* DESTROY_ME flag set */
2596 pntr->volid = volid;
2597 /*just volids are needed */
2601 volumeInfo->volEntries_len += 1;
2602 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2603 /*running out of space, allocate more space */
2604 allocSize = (allocSize * 3) / 2;
2605 pntr = realloc(volumeInfo->volEntries_val,
2606 allocSize * sizeof(volintInfo));
2609 return VOLSERNO_MEMORY;
2611 volumeInfo->volEntries_val = pntr; /* point to new block */
2612 /* set pntr to the right position */
2613 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2621 /*------------------------------------------------------------------------
2622 * EXPORTED SAFSVolXListVolumes
2625 * Returns all the volumes on partition a_partID. If a_flags
2626 * is set to 1, then all the relevant extended volume information
2630 * a_rxCidP : Pointer to the Rx call we're performing.
2631 * a_partID : Partition for which we want the extended list.
2632 * a_flags : Various flags.
2633 * a_volumeXInfoP : Ptr to the extended info blob.
2636 * 0 Successful operation
2637 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2638 * VOLSERNO_MEMORY if we ran out of memory allocating
2642 * Nothing interesting.
2646 *------------------------------------------------------------------------*/
2649 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2650 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2654 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2655 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2660 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2661 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2662 { /*SAFSVolXListVolumes */
2664 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2665 struct DiskPartition64 *partP; /*Ptr to partition */
2666 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2667 char pname[9], volname[20]; /*Partition, volume names */
2668 DIR *dirp; /*Partition directory ptr */
2669 VolumeId volid; /*Current volume ID */
2671 volint_info_handle_t handle;
2673 if (!afsconf_CheckRestrictedQuery(tdir, a_rxCidP, restrictedQueryLevel))
2674 return VOLSERBAD_ACCESS;
2677 * Allocate a large array of extended volume info structures, then
2678 * set it up for action.
2680 a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2681 if (!a_volumeXInfoP->volXEntries_val)
2684 xInfoP = a_volumeXInfoP->volXEntries_val;
2685 a_volumeXInfoP->volXEntries_len = 0;
2688 * If the partition name we've been given is bad, bogue out.
2690 if (GetPartName(a_partID, pname))
2691 return (VOLSERILLEGAL_PARTITION);
2694 * Open the directory representing the given AFS parttion. If we can't
2697 if (!(partP = VGetPartition(pname, 0)))
2698 return VOLSERILLEGAL_PARTITION;
2699 dirp = opendir(VPartitionPath(partP));
2701 return (VOLSERILLEGAL_PARTITION);
2702 while (GetNextVol(dirp, volname, &volid)) {
2705 * Full info about the volume desired. Poll to make sure the
2706 * client doesn't time out, then start up a new transaction.
2708 #ifndef AFS_PTHREAD_ENV
2712 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2713 handle.volinfo_ptr.ext = xInfoP;
2715 code = GetVolInfo(a_partID,
2720 VOL_INFO_LIST_MULTIPLE);
2721 if (code == -2) /* DESTROY_ME flag set */
2725 * Just volume IDs are needed.
2727 xInfoP->volid = volid;
2731 * Bump the pointer in the data area we're building, along with
2732 * the count of the number of entries it contains.
2735 (a_volumeXInfoP->volXEntries_len)++;
2736 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2738 * We're running out of space in the area we've built. Grow it.
2740 allocSize = (allocSize * 3) / 2;
2741 xInfoP = (volintXInfo *)
2742 realloc((char *)a_volumeXInfoP->volXEntries_val,
2743 (allocSize * sizeof(volintXInfo)));
2744 if (xInfoP == NULL) {
2746 * Bummer, no memory. Bag it, tell our caller what went wrong.
2749 return (VOLSERNO_MEMORY);
2753 * Memory reallocation worked. Correct our pointers so they
2754 * now point to the new block and the current open position within
2757 a_volumeXInfoP->volXEntries_val = xInfoP;
2759 a_volumeXInfoP->volXEntries_val +
2760 a_volumeXInfoP->volXEntries_len;
2765 * We've examined all entries in the partition directory. Close it,
2766 * delete our transaction (if any), and go home happy.
2771 } /*SAFSVolXListVolumes */
2773 /*this call is used to monitor the status of volser for debugging purposes.
2774 *information about all the active transactions is returned in transInfo*/
2776 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2780 code = VolMonitor(acid, transInfo);
2781 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2786 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2788 transDebugInfo *pntr;
2789 afs_int32 allocSize = 50;
2790 struct volser_trans *tt, *nt, *allTrans;
2792 if (!afsconf_CheckRestrictedQuery(tdir, acid, restrictedQueryLevel))
2793 return VOLSERBAD_ACCESS;
2795 transInfo->transDebugEntries_val =
2796 malloc(allocSize * sizeof(transDebugInfo));
2797 if (!transInfo->transDebugEntries_val)
2799 pntr = transInfo->transDebugEntries_val;
2800 transInfo->transDebugEntries_len = 0;
2803 allTrans = TransList();
2804 if (allTrans == (struct volser_trans *)0)
2805 goto done; /*no active transactions */
2806 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2808 VTRANS_OBJ_LOCK(tt);
2809 pntr->tid = tt->tid;
2810 pntr->time = tt->time;
2811 pntr->creationTime = tt->creationTime;
2812 pntr->returnCode = tt->returnCode;
2813 pntr->volid = tt->volid;
2814 pntr->partition = tt->partition;
2815 pntr->iflags = tt->iflags;
2816 pntr->vflags = tt->vflags;
2817 pntr->tflags = tt->tflags;
2818 strcpy(pntr->lastProcName, tt->lastProcName);
2819 pntr->callValid = 0;
2820 if (tt->rxCallPtr) { /*record call related info */
2821 pntr->callValid = 1;
2823 pntr->readNext = tt->rxCallPtr->rnext;
2824 pntr->transmitNext = tt->rxCallPtr->tnext;
2825 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2826 pntr->lastReceiveTime = tt->rxCallPtr->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));
2836 transInfo->transDebugEntries_val = pntr;
2838 transInfo->transDebugEntries_val +
2839 transInfo->transDebugEntries_len;
2840 /*set pntr to right position */
2851 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2852 afs_int32 type, afs_uint32 pId, VolumeId cloneId,
2857 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2858 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2859 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2865 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2866 afs_int32 type, VolumeId pId, VolumeId cloneId,
2871 struct volser_trans *tt;
2872 char caller[MAXKTCNAMELEN];
2874 if (strlen(name) > 31)
2875 return VOLSERBADNAME;
2876 if (!afsconf_SuperUser(tdir, acid, caller))
2877 return VOLSERBAD_ACCESS; /*not a super user */
2878 /* find the trans */
2879 tt = FindTrans(atid);
2882 if (tt->vflags & VTDeleted) {
2883 Log("1 Volser: VolSetIds: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2887 TSetRxCall(tt, acid, "SetIdsTypes");
2891 V_backupId(tv) = backupId;
2892 V_cloneId(tv) = cloneId;
2893 V_parentId(tv) = pId;
2894 strcpy((&V_disk(tv))->name, name);
2895 VUpdateVolume(&error, tv);
2897 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2902 if (TRELE(tt) && !error)
2903 return VOLSERTRELE_ERROR;
2908 if (TRELE(tt) && !error)
2909 return VOLSERTRELE_ERROR;
2914 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2918 code = VolSetDate(acid, atid, cdate);
2919 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2925 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2929 struct volser_trans *tt;
2930 char caller[MAXKTCNAMELEN];
2932 if (!afsconf_SuperUser(tdir, acid, caller))
2933 return VOLSERBAD_ACCESS; /*not a super user */
2934 /* find the trans */
2935 tt = FindTrans(atid);
2938 if (tt->vflags & VTDeleted) {
2939 Log("1 Volser: VolSetDate: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2943 TSetRxCall(tt, acid, "SetDate");
2946 V_creationDate(tv) = cdate;
2947 VUpdateVolume(&error, tv);
2949 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2954 if (TRELE(tt) && !error)
2955 return VOLSERTRELE_ERROR;
2960 if (TRELE(tt) && !error)
2961 return VOLSERTRELE_ERROR;
2966 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2972 char caller[MAXKTCNAMELEN];
2974 struct volser_trans *ttc;
2975 char pname[16], volname[20];
2976 struct DiskPartition64 *partP;
2977 afs_int32 ret = ENODEV;
2980 if (!afsconf_SuperUser(tdir, acid, caller))
2981 return VOLSERBAD_ACCESS; /*not a super user */
2982 if (GetPartName(partId, pname))
2983 return VOLSERILLEGAL_PARTITION;
2984 if (!(partP = VGetPartition(pname, 0)))
2985 return VOLSERILLEGAL_PARTITION;
2986 dirp = opendir(VPartitionPath(partP));
2988 return VOLSERILLEGAL_PARTITION;
2989 ttc = (struct volser_trans *)0;
2991 while (GetNextVol(dirp, volname, &volid)) {
2992 if (volid == volumeId) { /*copy other things too */
2993 #ifndef AFS_PTHREAD_ENV
2994 IOMGR_Poll(); /*make sure that the client doesnot time out */
2996 ttc = NewTrans(volumeId, partId);
2998 return VOLSERVOLBUSY;
3000 #ifdef AFS_NAMEI_ENV
3001 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3003 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3010 DeleteTrans(ttc, 1);
3018 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3019 struct volintSize *size)
3022 struct volser_trans *tt;
3023 char caller[MAXKTCNAMELEN];
3025 if (!afsconf_SuperUser(tdir, acid, caller))
3026 return VOLSERBAD_ACCESS; /*not a super user */
3027 tt = FindTrans(fromTrans);
3030 if (tt->vflags & VTDeleted) {
3034 TSetRxCall(tt, acid, "GetSize");
3035 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3038 return VOLSERTRELE_ERROR;
3040 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3045 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3046 afs_uint32 where, afs_int32 verbose)
3048 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3050 Volume *vol=0, *newvol=0;
3051 struct volser_trans *tt = 0, *tt2 = 0;
3052 char caller[MAXKTCNAMELEN];
3055 if (!afsconf_SuperUser(tdir, acall, caller))
3058 vol = VAttachVolume(&code, vid, V_VOLUPD);
3064 newvol = VAttachVolume(&code, new, V_VOLUPD);
3066 VDetachVolume(&code2, vol);
3071 if (V_device(vol) != V_device(newvol)
3072 || V_uniquifier(newvol) != 2) {
3073 if (V_device(vol) != V_device(newvol)) {
3074 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3076 rx_Write(acall, line, strlen(line));
3078 if (V_uniquifier(newvol) != 2) {
3079 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3080 rx_Write(acall, line, strlen(line));
3083 rx_Write(acall, line, 1);
3084 VDetachVolume(&code2, vol);
3085 VDetachVolume(&code2, newvol);
3088 tt = NewTrans(vid, V_device(vol));
3090 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3091 rx_Write(acall, line, strlen(line));
3093 rx_Write(acall, line, 1);
3094 VDetachVolume(&code2, vol);
3095 VDetachVolume(&code2, newvol);
3096 return VOLSERVOLBUSY;
3098 VTRANS_OBJ_LOCK(tt);
3099 tt->iflags = ITBusy;
3101 TSetRxCall_r(tt, NULL, "SplitVolume");
3102 VTRANS_OBJ_UNLOCK(tt);
3104 tt2 = NewTrans(new, V_device(newvol));
3106 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3107 rx_Write(acall, line, strlen(line));
3109 rx_Write(acall, line, 1);
3111 VDetachVolume(&code2, vol);
3112 VDetachVolume(&code2, newvol);
3113 return VOLSERVOLBUSY;
3115 VTRANS_OBJ_LOCK(tt2);
3116 tt2->iflags = ITBusy;
3118 TSetRxCall_r(tt2, NULL, "SplitVolume");
3119 VTRANS_OBJ_UNLOCK(tt2);
3121 code = split_volume(acall, vol, newvol, where, verbose);
3123 VDetachVolume(&code2, vol);
3125 VDetachVolume(&code2, newvol);
3126 DeleteTrans(tt2, 1);
3133 /* GetPartName - map partid (a decimal number) into pname (a string)
3134 * Since for NT we actually want to return the drive name, we map through the
3138 GetPartName(afs_int32 partid, char *pname)
3143 strcpy(pname, "/vicep");
3144 pname[6] = 'a' + partid;
3147 } else if (partid < VOLMAXPARTS) {
3148 strcpy(pname, "/vicep");
3150 pname[6] = 'a' + (partid / 26);
3151 pname[7] = 'a' + (partid % 26);