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;
64 extern void LogError(afs_int32 errcode);
66 /* Forward declarations */
67 static int GetPartName(afs_int32 partid, char *pname);
69 #define OneDay (24*60*60)
75 afs_int32 localTid = 1;
77 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
78 struct diskPartition64 *);
79 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
80 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
81 afs_int32, afs_uint32, afs_uint32 *,
83 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
84 static afs_int32 VolClone(struct rx_call *, afs_int32, VolumeId,
85 afs_int32, char *, VolumeId *);
86 static afs_int32 VolReClone(struct rx_call *, afs_int32, VolumeId);
87 static afs_int32 VolTransCreate(struct rx_call *, VolumeId, afs_int32,
88 afs_int32, afs_int32 *);
89 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
91 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
92 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
93 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
94 struct destServer *destination, afs_int32,
95 struct restoreCookie *cookie);
96 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
97 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
98 struct restoreCookie *);
99 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
100 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
101 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
102 struct volser_status *);
103 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
104 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
105 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
106 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
107 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, VolumeId,
109 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, VolumeId,
111 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
113 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
115 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
116 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
117 afs_int32, VolumeId, VolumeId,
119 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
122 * Return the host address of the caller as a string.
124 * @param[in] acid incoming rx call
125 * @param[out] buffer buffer to be filled with the addess string
127 * @return address as formatted by inet_ntoa
130 callerAddress(struct rx_call *acid, char *buffer)
132 afs_uint32 ip = rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid)));
133 return afs_inet_ntoa_r(ip, buffer);
136 /* this call unlocks all of the partition locks we've set */
140 struct DiskPartition64 *tp;
141 for (tp = DiskPartitionList; tp; tp = tp->next) {
142 if (tp->lock_fd != INVALID_FD) {
143 OS_CLOSE(tp->lock_fd);
144 tp->lock_fd = INVALID_FD;
155 code = VPFullUnlock_r();
160 /* get partition id from a name */
162 PartitionID(char *aname)
170 return -1; /* unknown */
172 /* otherwise check for vicepa or /vicepa, or just plain "a" */
174 if (!strncmp(aname, "/vicep", 6)) {
175 strncpy(ascii, aname + 6, 2);
177 return -1; /* bad partition name */
178 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
179 * from 0. Do the appropriate conversion */
181 /* one char name, 0..25 */
182 if (ascii[0] < 'a' || ascii[0] > 'z')
183 return -1; /* wrongo */
184 return ascii[0] - 'a';
186 /* two char name, 26 .. <whatever> */
187 if (ascii[0] < 'a' || ascii[0] > 'z')
188 return -1; /* wrongo */
189 if (ascii[1] < 'a' || ascii[1] > 'z')
190 return -1; /* just as bad */
191 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
192 if (code > VOLMAXPARTS)
199 ConvertVolume(VolumeId avol, char *aname, afs_int32 asize)
203 /* 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 */
204 snprintf(aname, asize, VFORMAT, afs_printable_VolumeId_lu(avol));
209 ConvertPartition(int apartno, char *aname, int asize)
215 strcpy(aname, "/vicep");
217 aname[6] = 'a' + apartno;
221 aname[6] = 'a' + (apartno / 26);
222 aname[7] = 'a' + (apartno % 26);
228 #ifdef AFS_DEMAND_ATTACH_FS
229 /* normally we should use the regular salvaging functions from the volume
230 * package, but this is a special case where we have a volume ID, but no
231 * volume structure to give the volume package */
233 SalvageUnknownVolume(VolumeId volid, char *part)
237 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
238 afs_printable_uint32_lu(volid), part);
240 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
241 FSYNC_SALVAGE, NULL);
243 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
244 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
248 #endif /* AFS_DEMAND_ATTACH_FS */
250 static struct Volume *
251 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
256 vp = VAttachVolumeByName(ec, partition, name, mode);
258 #ifdef AFS_DEMAND_ATTACH_FS
262 * The fileserver will take care of keeping track of how many
263 * demand-salvages have been performed, and will force the volume to
264 * ERROR if we've done too many. The limit on This loop is just a
265 * failsafe to prevent trying to salvage forever. We want to attempt
266 * attachment at least SALVAGE_COUNT_MAX times, since we want to
267 * avoid prematurely exiting this loop, if we can.
269 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
270 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
271 vp = VAttachVolumeByName(ec, partition, name, mode);
274 if (*ec == VSALVAGING) {
278 #endif /* AFS_DEMAND_ATTACH_FS */
283 static struct Volume *
284 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
289 vp = VAttachVolume(ec, avolid, amode);
291 #ifdef AFS_DEMAND_ATTACH_FS
294 /* see comment above in VAttachVolumeByName_retry */
295 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
296 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
297 vp = VAttachVolume(ec, avolid, amode);
300 if (*ec == VSALVAGING) {
304 #endif /* AFS_DEMAND_ATTACH_FS */
309 /* the only attach function that takes a partition is "...ByName", so we use it */
310 static struct Volume *
311 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
313 char pbuf[30], vbuf[20];
315 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
319 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
324 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
327 /* Adapted from the file server; create a root directory for this volume */
329 ViceCreateRoot(Volume *vp)
332 struct acl_accessList *ACL;
334 Inode inodeNumber, AFS_UNUSED nearInode;
335 struct VnodeDiskObject *vnode;
336 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
342 vnode = calloc(1, SIZEOF_LARGEDISKVNODE);
346 V_pref(vp, nearInode);
348 IH_CREATE(V_linkHandle(vp), V_device(vp),
349 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
351 if (!VALID_INO(inodeNumber)) {
352 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
357 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
358 did.Volume = V_id(vp);
359 did.Vnode = (VnodeId) 1;
362 opr_Verify(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
363 DFlush(); /* flush all modified dir buffers out */
364 DZap(&dir); /* Remove all buffers for this dir */
365 length = afs_dir_Length(&dir); /* Remember size of this directory */
367 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
369 /* build a single entry ACL that gives all rights to system:administrators */
370 /* this section of code assumes that access list format is not going to
373 ACL = VVnodeDiskACL(vnode);
374 ACL->size = sizeof(struct acl_accessList);
375 ACL->version = ACL_ACLVERSION;
379 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
380 ACL->entries[0].rights =
381 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
382 | PRSFS_LOCK | PRSFS_ADMINISTER;
384 vnode->type = vDirectory;
386 vnode->modeBits = 0777;
387 vnode->linkCount = 2;
388 VNDISK_SET_LEN(vnode, length);
389 vnode->uniquifier = 1;
390 V_uniquifier(vp) = vnode->uniquifier + 1;
391 vnode->dataVersion = 1;
392 VNDISK_SET_INO(vnode, inodeNumber);
393 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
397 vnode->vnodeMagic = vcp->magic;
399 IH_INIT(h, vp->device, V_parentId(vp),
400 vp->vnodeIndex[vLarge].handle->ih_ino);
402 opr_Assert(fdP != NULL);
403 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
404 opr_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
405 FDH_REALLYCLOSE(fdP);
407 VNDISK_GET_LEN(length, vnode);
408 V_diskused(vp) = nBlocks(length);
415 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
419 struct diskPartition64 *dp = malloc(sizeof(struct diskPartition64));
421 code = VolPartitionInfo(acid, pname, dp);
423 strncpy(partition->name, dp->name, 32);
424 strncpy(partition->devName, dp->devName, 32);
425 partition->lock_fd = dp->lock_fd;
426 partition->free=RoundInt64ToInt32(dp->free);
427 partition->minFree=RoundInt64ToInt32(dp->minFree);
430 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
435 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
440 code = VolPartitionInfo(acid, pname, partition);
441 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
446 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
449 struct DiskPartition64 *dp;
452 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
455 dp = VGetPartition(pname, 0);
457 strncpy(partition->name, dp->name, 32);
458 strncpy(partition->devName, dp->devName, 32);
459 partition->lock_fd = (int)dp->lock_fd;
460 partition->free = dp->free;
461 partition->minFree = dp->totalUsable;
464 return VOLSERILLEGAL_PARTITION;
467 /* obliterate a volume completely, and slowly. */
469 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, VolumeId avolID)
473 code = VolNukeVolume(acid, apartID, avolID);
474 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
479 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
486 char caller[MAXKTCNAMELEN];
488 /* check for access */
489 if (!afsconf_SuperUser(tdir, acid, caller))
490 return VOLSERBAD_ACCESS;
493 Log("%s on %s is executing VolNukeVolume %u\n", caller,
494 callerAddress(acid, buffer), avolID);
497 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
499 /* we first try to attach the volume in update mode, so that the file
500 * server doesn't try to use it (and abort) while (or after) we delete it.
501 * If we don't get the volume, that's fine, too. We just won't put it back.
503 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
504 code = nuke(partName, avolID);
506 VDetachVolume(&verror, tvp);
510 /* create a new volume, with name aname, on the specified partition (1..n)
511 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
512 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
513 * for the volume id (useful for things like volume restore).
514 * Return the new volume id in *avolid.
517 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
518 afs_int32 atype, VolumeId aparent, VolumeId *avolid,
524 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
525 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
526 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
532 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
533 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
538 Error junk; /* discardable error code */
540 afs_int32 doCreateRoot = 1;
541 struct volser_trans *tt;
543 char caller[MAXKTCNAMELEN];
545 if (strlen(aname) > 31)
546 return VOLSERBADNAME;
547 if (!afsconf_SuperUser(tdir, acid, caller))
548 return VOLSERBAD_ACCESS;
551 Log("%s on %s is executing CreateVolume '%s'\n", caller,
552 callerAddress(acid, buffer), aname);
554 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
555 return error; /*a standard unix error */
556 if (atype != readwriteVolume && atype != readonlyVolume
557 && atype != backupVolume)
559 if ((volumeID = *avolid) == 0) {
561 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
565 if ((aparent == volumeID) && (atype == readwriteVolume)) {
570 tt = NewTrans(volumeID, apart);
572 Log("1 createvolume: failed to create trans\n");
573 return VOLSERVOLBUSY; /* volume already busy! */
575 vp = VCreateVolume(&error, ppath, volumeID, aparent);
577 #ifdef AFS_DEMAND_ATTACH_FS
578 if (error != VVOLEXISTS && error != EXDEV) {
579 SalvageUnknownVolume(volumeID, ppath);
582 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
587 V_uniquifier(vp) = 1;
588 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
589 V_inService(vp) = V_blessed(vp) = 1;
591 AssignVolumeName(&V_disk(vp), aname, 0);
593 error = ViceCreateRoot(vp);
595 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
596 "error code %u\n", (unsigned)error);
598 V_needsSalvaged(vp) = 1;
599 VDetachVolume(&junk, vp);
603 V_destroyMe(vp) = DESTROY_ME;
605 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
606 VUpdateVolume(&error, vp);
608 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
611 VDetachVolume(&junk, vp); /* rather return the real error code */
617 TSetRxCall_r(tt, acid, "CreateVolume");
618 VTRANS_OBJ_UNLOCK(tt);
619 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
622 return VOLSERTRELE_ERROR;
626 /* delete the volume associated with this transaction */
628 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
632 code = VolDeleteVolume(acid, atrans);
633 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
638 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
640 struct volser_trans *tt;
642 char caller[MAXKTCNAMELEN];
644 if (!afsconf_SuperUser(tdir, acid, caller))
645 return VOLSERBAD_ACCESS;
646 tt = FindTrans(atrans);
649 if (tt->vflags & VTDeleted) {
650 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " already deleted \n",
651 afs_printable_VolumeId_lu(tt->volid));
657 Log("%s on %s is executing Delete Volume %" AFS_VOLID_FMT "\n", caller,
658 callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
660 TSetRxCall(tt, acid, "DeleteVolume");
661 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
662 V_destroyMe(tt->volume) = DESTROY_ME;
663 if (tt->volume->needsPutBack) {
664 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
667 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
669 VTRANS_OBJ_UNLOCK(tt);
671 return VOLSERTRELE_ERROR;
673 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " deleted \n",
674 afs_printable_VolumeId_lu(tt->volid));
675 return 0; /* vpurgevolume doesn't set an error code */
678 /* make a clone of the volume associated with atrans, possibly giving it a new
679 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
680 * for the clone's id). The new clone is given the name newName. Finally,
681 * due to efficiency considerations, if purgeId is non-zero, we purge that
682 * volume when doing the clone operation. This may be useful when making
683 * new backup volumes, for instance since the net result of a clone and a
684 * purge generally leaves many inode ref counts the same, while doing them
685 * separately would result in far more iincs and idecs being peformed
686 * (and they are slow operations).
688 /* for efficiency reasons, sometimes faster to piggyback a purge here */
690 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
691 afs_int32 newType, char *newName, VolumeId *newNumber)
694 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
695 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
696 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
702 VolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
703 afs_int32 newType, char *newName, VolumeId *newNumber)
706 struct Volume *originalvp, *purgevp, *newvp;
708 struct volser_trans *tt, *ttc;
709 char caller[MAXKTCNAMELEN];
710 #ifdef AFS_DEMAND_ATTACH_FS
711 struct Volume *salv_vp = NULL;
714 if (strlen(newName) > 31)
715 return VOLSERBADNAME;
716 if (!afsconf_SuperUser(tdir, acid, caller))
717 return VOLSERBAD_ACCESS; /*not a super user */
720 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
721 callerAddress(acid, buffer), newName);
724 purgevp = (Volume *) 0;
725 newvp = (Volume *) 0;
726 tt = ttc = (struct volser_trans *)0;
728 if (!newNumber || !*newNumber) {
729 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
734 tt = FindTrans(atrans);
737 if (tt->vflags & VTDeleted) {
738 Log("1 Volser: Clone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
742 ttc = NewTrans(newId, tt->partition);
743 if (!ttc) { /* someone is messing with the clone already */
745 return VOLSERVOLBUSY;
747 TSetRxCall(tt, acid, "Clone");
751 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
753 Log("1 Volser: Clone: Could not attach 'purge' volume %" AFS_VOLID_FMT "; clone aborted\n", afs_printable_VolumeId_lu(purgeId));
759 originalvp = tt->volume;
760 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
761 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
762 afs_printable_VolumeId_lu(V_id(originalvp)));
767 if (originalvp->device != purgevp->device) {
768 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));
772 if (V_type(purgevp) != readonlyVolume) {
773 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
777 if (V_parentId(originalvp) != V_parentId(purgevp)) {
778 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));
785 #ifdef AFS_DEMAND_ATTACH_FS
786 salv_vp = originalvp;
789 if (purgeId == newId) {
793 VCreateVolume(&error, originalvp->partition->name, newId,
794 V_parentId(originalvp));
796 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
797 newvp = (Volume *) 0;
801 if (newType == readonlyVolume)
802 V_cloneId(originalvp) = newId;
803 Log("1 Volser: Clone: Cloning volume %" AFS_VOLID_FMT " to new volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
804 afs_printable_VolumeId_lu(newId));
806 Log("1 Volser: Clone: Purging old read only volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(purgeId));
807 CloneVolume(&error, originalvp, newvp, purgevp);
808 purgevp = NULL; /* clone releases it, maybe even if error */
810 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
814 if (newType == readonlyVolume) {
815 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
816 V_type(newvp) = readonlyVolume;
817 } else if (newType == backupVolume) {
818 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
819 V_type(newvp) = backupVolume;
820 V_backupId(originalvp) = newId;
822 strcpy(V_name(newvp), newName);
823 V_creationDate(newvp) = V_copyDate(newvp);
824 ClearVolumeStats(&V_disk(newvp));
825 V_destroyMe(newvp) = DESTROY_ME;
826 V_inService(newvp) = 0;
827 if (newType == backupVolume) {
828 V_backupDate(originalvp) = V_copyDate(newvp);
829 V_backupDate(newvp) = V_copyDate(newvp);
832 VUpdateVolume(&error, newvp);
834 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
838 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
840 VUpdateVolume(&error, originalvp);
842 Log("1 Volser: Clone: original update %u\n", error);
847 #ifdef AFS_DEMAND_ATTACH_FS
851 tt = (struct volser_trans *)0;
852 error = VOLSERTRELE_ERROR;
860 VDetachVolume(&code, purgevp);
862 VDetachVolume(&code, newvp);
869 #ifdef AFS_DEMAND_ATTACH_FS
870 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
871 V_needsSalvaged(salv_vp) = 1;
873 #endif /* AFS_DEMAND_ATTACH_FS */
877 /* reclone this volume into the specified id */
879 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
883 code = VolReClone(acid, atrans, cloneId);
884 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
890 VolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
892 struct Volume *originalvp, *clonevp;
895 struct volser_trans *tt, *ttc;
896 char caller[MAXKTCNAMELEN];
897 VolumeDiskData saved_header;
899 /*not a super user */
900 if (!afsconf_SuperUser(tdir, acid, caller))
901 return VOLSERBAD_ACCESS;
904 Log("%s on %s is executing Reclone Volume %" AFS_VOLID_FMT "\n", caller,
905 callerAddress(acid, buffer), afs_printable_VolumeId_lu(cloneId));
908 clonevp = originalvp = (Volume *) 0;
910 tt = FindTrans(atrans);
913 if (tt->vflags & VTDeleted) {
914 Log("1 Volser: VolReClone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
918 ttc = NewTrans(cloneId, tt->partition);
919 if (!ttc) { /* someone is messing with the clone already */
921 return VOLSERVOLBUSY;
923 TSetRxCall(tt, acid, "ReClone");
925 originalvp = tt->volume;
926 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
927 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
928 afs_printable_VolumeId_lu(V_id(originalvp)));
933 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
935 Log("1 Volser: can't attach clone %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(cloneId));
939 newType = V_type(clonevp); /* type of the new volume */
941 if (originalvp->device != clonevp->device) {
942 Log("1 Volser: Clone: Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are on different devices\n",
943 afs_printable_VolumeId_lu(tt->volid), afs_printable_VolumeId_lu(cloneId));
947 if (V_parentId(originalvp) != V_parentId(clonevp)) {
948 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));
953 if (DoPreserveVolumeStats) {
954 CopyVolumeStats(&V_disk(clonevp), &saved_header);
958 Log("1 Volser: Clone: Recloning volume %" AFS_VOLID_FMT " to volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
959 afs_printable_VolumeId_lu(cloneId));
960 CloneVolume(&error, originalvp, clonevp, clonevp);
962 Log("1 Volser: Clone: reclone operation failed with code %d\n",
968 /* fix up volume name and type, CloneVolume just propagated RW's */
969 if (newType == readonlyVolume) {
970 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
971 V_type(clonevp) = readonlyVolume;
972 } else if (newType == backupVolume) {
973 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
974 V_type(clonevp) = backupVolume;
975 V_backupId(originalvp) = cloneId;
977 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
979 /* update the creationDate, since this represents the last cloning date
980 * for ROs. But do not update copyDate; let it stay so we can identify
981 * when the clone was first created. */
982 V_creationDate(clonevp) = time(0);
983 if (DoPreserveVolumeStats) {
984 CopyVolumeStats(&saved_header, &V_disk(clonevp));
986 ClearVolumeStats(&V_disk(clonevp));
988 V_destroyMe(clonevp) = 0;
989 V_inService(clonevp) = 0;
990 if (newType == backupVolume) {
991 V_backupDate(originalvp) = V_creationDate(clonevp);
992 V_backupDate(clonevp) = V_creationDate(clonevp);
994 V_inUse(clonevp) = 0;
995 VUpdateVolume(&error, clonevp);
997 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
1001 /* VUpdateVolume succeeded. Mark it in service so there's no window
1002 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
1003 * specialStatus; this is a reclone and this volume started online
1005 V_inService(clonevp) = 1;
1006 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
1008 VUpdateVolume(&error, originalvp);
1010 Log("1 Volser: Clone: original update %u\n", error);
1016 tt = (struct volser_trans *)0;
1017 error = VOLSERTRELE_ERROR;
1021 DeleteTrans(ttc, 1);
1024 struct DiskPartition64 *tpartp = originalvp->partition;
1025 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1031 VDetachVolume(&code, clonevp);
1037 DeleteTrans(ttc, 1);
1041 /* create a new transaction, associated with volume and partition. Type of
1042 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1043 * See volser.h for definition of iflags (the constants are named IT*).
1046 SAFSVolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1047 afs_int32 iflags, afs_int32 *ttid)
1051 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1052 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1058 VolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1059 afs_int32 iflags, afs_int32 *ttid)
1061 struct volser_trans *tt;
1066 char caller[MAXKTCNAMELEN];
1068 if (!afsconf_SuperUser(tdir, acid, caller))
1069 return VOLSERBAD_ACCESS; /*not a super user */
1070 if (iflags & ITCreate)
1072 else if (iflags & ITBusy)
1074 else if (iflags & ITReadOnly)
1076 else if (iflags & ITOffline)
1079 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1084 tt = NewTrans(volume, partition);
1086 /* can't create a transaction? put the volume back */
1087 Log("1 transcreate: can't create transaction\n");
1088 return VOLSERVOLBUSY;
1090 tv = XAttachVolume(&error, volume, partition, mode);
1094 VDetachVolume(&code, tv);
1098 VTRANS_OBJ_LOCK(tt);
1101 tt->iflags = iflags;
1103 TSetRxCall_r(tt, NULL, "TransCreate");
1104 VTRANS_OBJ_UNLOCK(tt);
1106 return VOLSERTRELE_ERROR;
1111 /* using aindex as a 0-based index, return the aindex'th volume on this server
1112 * Both the volume number and partition number (one-based) are returned.
1115 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, VolumeId *avolume,
1120 code = VolGetNthVolume(acid, aindex, avolume, apart);
1121 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1126 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1129 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1133 /* return the volume flags (VT* constants in volser.h) associated with this
1137 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1141 code = VolGetFlags(acid, atid, aflags);
1142 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1147 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1149 struct volser_trans *tt;
1151 tt = FindTrans(atid);
1154 if (tt->vflags & VTDeleted) {
1155 Log("1 Volser: VolGetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1156 afs_printable_VolumeId_lu(tt->volid));
1160 TSetRxCall(tt, acid, "GetFlags");
1161 *aflags = tt->vflags;
1164 return VOLSERTRELE_ERROR;
1169 /* Change the volume flags (VT* constants in volser.h) associated with this
1170 * transaction. Effects take place immediately on volume, although volume
1171 * remains attached as usual by the transaction.
1174 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1178 code = VolSetFlags(acid, atid, aflags);
1179 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1185 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1187 struct volser_trans *tt;
1190 char caller[MAXKTCNAMELEN];
1192 if (!afsconf_SuperUser(tdir, acid, caller))
1193 return VOLSERBAD_ACCESS; /*not a super user */
1194 /* find the trans */
1195 tt = FindTrans(atid);
1198 if (tt->vflags & VTDeleted) {
1199 Log("1 Volser: VolSetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1200 afs_printable_VolumeId_lu(tt->volid));
1204 TSetRxCall(tt, acid, "SetFlags");
1205 vp = tt->volume; /* pull volume out of transaction */
1207 /* check if we're allowed to make any updates */
1208 if (tt->iflags & ITReadOnly) {
1213 /* handle delete-on-salvage flag */
1214 if (aflags & VTDeleteOnSalvage) {
1215 V_destroyMe(tt->volume) = DESTROY_ME;
1217 V_destroyMe(tt->volume) = 0;
1220 if (aflags & VTOutOfService) {
1221 V_inService(vp) = 0;
1223 V_inService(vp) = 1;
1225 VUpdateVolume(&error, vp);
1226 VTRANS_OBJ_LOCK(tt);
1227 tt->vflags = aflags;
1229 VTRANS_OBJ_UNLOCK(tt);
1230 if (TRELE(tt) && !error)
1231 return VOLSERTRELE_ERROR;
1236 /* dumpS the volume associated with a particular transaction from a particular
1237 * date. Send the dump to a different transaction (destTrans) on the server
1238 * specified by the destServer structure.
1241 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1242 struct destServer *destination, afs_int32 destTrans,
1243 struct restoreCookie *cookie)
1248 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1249 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1250 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1255 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1256 struct destServer *destination, afs_int32 destTrans,
1257 struct restoreCookie *cookie)
1259 struct volser_trans *tt;
1261 struct rx_connection *tcon;
1262 struct rx_call *tcall;
1264 struct rx_securityClass *securityObject;
1265 afs_int32 securityIndex;
1266 char caller[MAXKTCNAMELEN];
1268 if (!afsconf_SuperUser(tdir, acid, caller))
1269 return VOLSERBAD_ACCESS; /*not a super user */
1271 /* find the local transaction */
1272 tt = FindTrans(fromTrans);
1275 if (tt->vflags & VTDeleted) {
1276 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1281 TSetRxCall(tt, NULL, "Forward");
1283 /* get auth info for the this connection (uses afs from ticket file) */
1284 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1290 /* make an rpc connection to the other server */
1292 rx_NewConnection(htonl(destination->destHost),
1293 htons(destination->destPort), VOLSERVICE_ID,
1294 securityObject, securityIndex);
1300 tcall = rx_NewCall(tcon);
1301 TSetRxCall(tt, tcall, "Forward");
1302 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1303 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1308 /* these next calls implictly call rx_Write when writing out data */
1309 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1312 EndAFSVolRestore(tcall); /* probably doesn't do much */
1314 code = rx_EndCall(tcall, 0);
1315 rx_DestroyConnection(tcon); /* done with the connection */
1320 return VOLSERTRELE_ERROR;
1326 (void)rx_EndCall(tcall, 0);
1327 rx_DestroyConnection(tcon);
1336 /* Start a dump and send it to multiple places simultaneously.
1337 * If this returns an error (eg, return ENOENT), it means that
1338 * none of the releases worked. If this returns 0, that means
1339 * that one or more of the releases worked, and the caller has
1340 * to examine the results array to see which one(s).
1341 * This will only do EITHER incremental or full, not both, so it's
1342 * the caller's responsibility to be sure that all the destinations
1343 * need just an incremental (and from the same time), if that's
1347 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1348 fromDate, manyDests *destinations, afs_int32 spare,
1349 struct restoreCookie *cookie, manyResults *results)
1351 afs_int32 securityIndex;
1352 struct rx_securityClass *securityObject;
1353 char caller[MAXKTCNAMELEN];
1354 struct volser_trans *tt;
1355 afs_int32 ec, code, *codes;
1356 struct rx_connection **tcons;
1357 struct rx_call **tcalls;
1359 int i, is_incremental;
1362 memset(results, 0, sizeof(manyResults));
1363 i = results->manyResults_len = destinations->manyDests_len;
1364 results->manyResults_val = codes = malloc(i * sizeof(afs_int32));
1366 if (!results || !results->manyResults_val)
1369 if (!afsconf_SuperUser(tdir, acid, caller))
1370 return VOLSERBAD_ACCESS; /*not a super user */
1371 tt = FindTrans(fromTrans);
1374 if (tt->vflags & VTDeleted) {
1375 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1380 TSetRxCall(tt, NULL, "ForwardMulti");
1382 /* (fromDate == 0) ==> full dump */
1383 is_incremental = (fromDate ? 1 : 0);
1385 tcons = malloc(i * sizeof(struct rx_connection *));
1389 tcalls = malloc(i * sizeof(struct rx_call *));
1395 /* get auth info for this connection (uses afs from ticket file) */
1396 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1398 goto fail; /* in order to audit each failure */
1401 /* make connections to all the other servers */
1402 for (i = 0; i < destinations->manyDests_len; i++) {
1403 struct replica *dest = &(destinations->manyDests_val[i]);
1405 rx_NewConnection(htonl(dest->server.destHost),
1406 htons(dest->server.destPort), VOLSERVICE_ID,
1407 securityObject, securityIndex);
1409 codes[i] = ENOTCONN;
1411 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1412 codes[i] = ENOTCONN;
1415 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1418 (void)rx_EndCall(tcalls[i], 0);
1420 rx_DestroyConnection(tcons[i]);
1427 /* these next calls implictly call rx_Write when writing out data */
1428 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1432 for (i--; i >= 0; i--) {
1433 struct replica *dest = &(destinations->manyDests_val[i]);
1435 if (!code && tcalls[i] && !codes[i]) {
1436 EndAFSVolRestore(tcalls[i]);
1439 ec = rx_EndCall(tcalls[i], 0);
1444 rx_DestroyConnection(tcons[i]); /* done with the connection */
1447 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1448 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1449 dest->trans, AUD_END);
1456 if (TRELE(tt) && !code) /* return the first code if it's set */
1457 return VOLSERTRELE_ERROR;
1464 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1468 code = VolDump(acid, fromTrans, fromDate, 0);
1469 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1474 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1479 code = VolDump(acid, fromTrans, fromDate, flags);
1480 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1485 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1489 struct volser_trans *tt;
1490 char caller[MAXKTCNAMELEN];
1492 if (!afsconf_SuperUser(tdir, acid, caller))
1493 return VOLSERBAD_ACCESS; /*not a super user */
1494 tt = FindTrans(fromTrans);
1497 if (tt->vflags & VTDeleted) {
1498 Log("1 Volser: VolDump: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1502 TSetRxCall(tt, acid, "Dump");
1503 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1504 ? 0 : 1); /* squirt out the volume's data, too */
1513 return VOLSERTRELE_ERROR;
1519 * Ha! No more helper process!
1522 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1523 struct restoreCookie *cookie)
1527 code = VolRestore(acid, atrans, aflags, cookie);
1528 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1533 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1534 struct restoreCookie *cookie)
1536 struct volser_trans *tt;
1537 afs_int32 code, tcode;
1538 char caller[MAXKTCNAMELEN];
1540 if (!afsconf_SuperUser(tdir, acid, caller))
1541 return VOLSERBAD_ACCESS; /*not a super user */
1542 tt = FindTrans(atrans);
1545 if (tt->vflags & VTDeleted) {
1546 Log("1 Volser: VolRestore: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1552 Log("%s on %s is executing Restore %" AFS_VOLID_FMT "\n", caller,
1553 callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
1555 TSetRxCall(tt, acid, "Restore");
1557 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1559 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1560 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1564 return (code ? code : tcode);
1567 /* end a transaction, returning the transaction's final error code in rcode */
1569 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1573 code = VolEndTrans(acid, destTrans, rcode);
1574 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1579 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1581 struct volser_trans *tt;
1582 char caller[MAXKTCNAMELEN];
1584 if (!afsconf_SuperUser(tdir, acid, caller))
1585 return VOLSERBAD_ACCESS; /*not a super user */
1586 tt = FindTrans(destTrans);
1590 *rcode = tt->returnCode;
1591 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1597 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1601 code = VolSetForwarding(acid, atid, anewsite);
1602 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1603 htonl(anewsite), AUD_END);
1608 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1610 struct volser_trans *tt;
1611 char caller[MAXKTCNAMELEN];
1614 if (!afsconf_SuperUser(tdir, acid, caller))
1615 return VOLSERBAD_ACCESS; /*not a super user */
1616 tt = FindTrans(atid);
1619 if (tt->vflags & VTDeleted) {
1620 Log("1 Volser: VolSetForwarding: volume %" AFS_VOLID_FMT " has been deleted \n",
1621 afs_printable_VolumeId_lu(tt->volid));
1625 TSetRxCall(tt, acid, "SetForwarding");
1626 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1629 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1632 return VOLSERTRELE_ERROR;
1638 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1639 struct volser_status *astatus)
1643 code = VolGetStatus(acid, atrans, astatus);
1644 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1649 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1650 struct volser_status *astatus)
1653 struct VolumeDiskData *td;
1654 struct volser_trans *tt;
1657 tt = FindTrans(atrans);
1660 if (tt->vflags & VTDeleted) {
1661 Log("1 Volser: VolGetStatus: volume %" AFS_VOLID_FMT " has been deleted \n",
1662 afs_printable_VolumeId_lu(tt->volid));
1666 TSetRxCall(tt, acid, "GetStatus");
1675 astatus->volID = td->id;
1676 astatus->nextUnique = td->uniquifier;
1677 astatus->type = td->type;
1678 astatus->parentID = td->parentId;
1679 astatus->cloneID = td->cloneId;
1680 astatus->backupID = td->backupId;
1681 astatus->restoredFromID = td->restoredFromId;
1682 astatus->maxQuota = td->maxquota;
1683 astatus->minQuota = td->minquota;
1684 astatus->owner = td->owner;
1685 astatus->creationDate = td->creationDate;
1686 astatus->accessDate = td->accessDate;
1687 astatus->updateDate = td->updateDate;
1688 astatus->expirationDate = td->expirationDate;
1689 astatus->backupDate = td->backupDate;
1690 astatus->copyDate = td->copyDate;
1693 return VOLSERTRELE_ERROR;
1699 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1700 struct volintInfo *astatus)
1704 code = VolSetInfo(acid, atrans, astatus);
1705 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1710 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1711 struct volintInfo *astatus)
1714 struct VolumeDiskData *td;
1715 struct volser_trans *tt;
1716 char caller[MAXKTCNAMELEN];
1719 if (!afsconf_SuperUser(tdir, acid, caller))
1720 return VOLSERBAD_ACCESS; /*not a super user */
1721 tt = FindTrans(atrans);
1724 if (tt->vflags & VTDeleted) {
1725 Log("1 Volser: VolSetInfo: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1729 TSetRxCall(tt, acid, "SetStatus");
1739 * Add more fields as necessary
1741 if (astatus->maxquota != -1)
1742 td->maxquota = astatus->maxquota;
1743 if (astatus->dayUse != -1)
1744 td->dayUse = astatus->dayUse;
1745 if (astatus->creationDate != -1)
1746 td->creationDate = astatus->creationDate;
1747 if (astatus->updateDate != -1)
1748 td->updateDate = astatus->updateDate;
1749 if (astatus->spare2 != -1)
1750 td->volUpdateCounter = (unsigned int)astatus->spare2;
1751 VUpdateVolume(&error, tv);
1754 return VOLSERTRELE_ERROR;
1760 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1764 code = VolGetName(acid, atrans, aname);
1765 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1770 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1773 struct VolumeDiskData *td;
1774 struct volser_trans *tt;
1777 /* We need to at least fill it in */
1781 tt = FindTrans(atrans);
1784 if (tt->vflags & VTDeleted) {
1785 Log("1 Volser: VolGetName: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1789 TSetRxCall(tt, acid, "GetName");
1798 len = strlen(td->name) + 1; /* don't forget the null */
1804 *aname = realloc(*aname, len);
1805 strcpy(*aname, td->name);
1808 return VOLSERTRELE_ERROR;
1813 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1816 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1817 VolumeId parentId, VolumeId cloneId)
1823 /*return a list of all partitions on the server. The non mounted
1824 *partitions are returned as -1 in the corresponding slot in partIds*/
1826 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1830 code = VolListPartitions(acid, partIds);
1831 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1836 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1841 strcpy(namehead, "/vicep"); /*7 including null terminator */
1843 /* Just return attached partitions. */
1845 for (i = 0; i < 26; i++) {
1846 namehead[6] = i + 'a';
1847 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1853 /*return a list of all partitions on the server. The non mounted
1854 *partitions are returned as -1 in the corresponding slot in partIds*/
1856 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1860 code = XVolListPartitions(acid, pEntries);
1861 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1866 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1869 struct partList partList;
1870 struct DiskPartition64 *dp;
1873 strcpy(namehead, "/vicep"); /*7 including null terminator */
1875 /* Only report attached partitions */
1876 for (i = 0; i < VOLMAXPARTS; i++) {
1877 #ifdef AFS_DEMAND_ATTACH_FS
1878 dp = VGetPartitionById(i, 0);
1881 namehead[6] = i + 'a';
1887 namehead[6] = 'a' + (k / 26);
1888 namehead[7] = 'a' + (k % 26);
1891 dp = VGetPartition(namehead, 0);
1894 partList.partId[j++] = i;
1897 pEntries->partEntries_val = malloc(j * sizeof(int));
1898 if (!pEntries->partEntries_val)
1900 memcpy(pEntries->partEntries_val, partList.partId,
1902 pEntries->partEntries_len = j;
1904 pEntries->partEntries_val = NULL;
1905 pEntries->partEntries_len = 0;
1912 * Scan a directory for possible volume headers.
1913 * in: DIR *dirp -- a directory handle from opendir()
1914 * out: char *volname -- set to name of directory entry
1915 * afs_uint32 *volid -- set to volume ID parsed from name
1917 * true if volname and volid have been set to valid values
1918 * false if we got to the end of the directory
1921 GetNextVol(DIR *dirp, char *volname, VolumeId *volid)
1925 while ((dp = readdir(dirp)) != NULL) {
1926 /* could be optimized on platforms with dp->d_namlen */
1927 if (dp->d_name[0] == 'V' && strlen(dp->d_name) == VHDRNAMELEN
1928 && strcmp(&(dp->d_name[VFORMATDIGITS + 1]), VHDREXT) == 0) {
1929 *volid = VolumeNumber(dp->d_name);
1930 strcpy(volname, dp->d_name);
1938 * volint vol info structure type.
1941 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1942 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1943 } volint_info_type_t;
1946 * handle to various on-wire vol info types.
1949 volint_info_type_t volinfo_type;
1955 } volint_info_handle_t;
1958 * store value to a field at the appropriate location in on-wire structure.
1960 #define VOLINT_INFO_STORE(handle, name, val) \
1962 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1963 (handle)->volinfo_ptr.base->name = (val); \
1965 (handle)->volinfo_ptr.ext->name = (val); \
1970 * get pointer to appropriate offset of field in on-wire structure.
1972 #define VOLINT_INFO_PTR(handle, name) \
1973 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1974 &((handle)->volinfo_ptr.base->name) : \
1975 &((handle)->volinfo_ptr.ext->name))
1978 * fill in appropriate type of on-wire volume metadata structure.
1980 * @param vp pointer to volume object
1981 * @param handle pointer to wire format handle object
1983 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1984 * @pre handle object must have a valid pointer and enumeration value
1986 * @note passing a NULL value for vp means that the fileserver doesn't
1987 * know about this particular volume, thus implying it is offline.
1989 * @return operation status
1994 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1996 unsigned int numStatBytes, now;
1997 struct VolumeDiskData *hdr = &(V_disk(vp));
1999 /*read in the relevant info */
2000 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2001 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
2002 VOLINT_INFO_STORE(handle, volid, hdr->id);
2003 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2004 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2005 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2006 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2007 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2008 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2009 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2010 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2011 now = FT_ApproxTime();
2012 if ((now - hdr->dayUseDate) > OneDay) {
2013 VOLINT_INFO_STORE(handle, dayUse, 0);
2015 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2017 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2018 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2019 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2020 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2022 #ifdef AFS_DEMAND_ATTACH_FS
2024 * for DAFS, we "lie" about volume state --
2025 * instead of returning the raw state from the disk header,
2026 * we compute state based upon the fileserver's internal
2027 * in-core state enumeration value reported to us via fssync,
2028 * along with the blessed and inService flags from the header.
2029 * -- tkeiser 11/27/2007
2032 /* Conditions that offline status is based on:
2033 volume is unattached state
2034 volume state is in (one of several error states)
2035 volume not in service
2036 volume is not marked as blessed (not on hold)
2037 volume in salvage req. state
2038 volume needsSalvaged
2039 next op would set volume offline
2040 next op would not leave volume online (based on several conditions)
2043 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2044 VIsErrorState(V_attachState(vp)) ||
2047 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2048 hdr->needsSalvaged ||
2049 (vp->pending_vol_op &&
2050 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2051 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2054 VOLINT_INFO_STORE(handle, inUse, 0);
2056 VOLINT_INFO_STORE(handle, inUse, 1);
2059 /* offline status based on program type, where != fileServer enum (1) is offline */
2060 if (hdr->inUse == fileServer) {
2061 VOLINT_INFO_STORE(handle, inUse, 1);
2063 VOLINT_INFO_STORE(handle, inUse, 0);
2068 switch(handle->volinfo_type) {
2069 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2070 case VOLINT_INFO_TYPE_BASE:
2072 #ifdef AFS_DEMAND_ATTACH_FS
2073 /* see comment above where we set inUse bit */
2074 if (hdr->needsSalvaged ||
2075 (vp && VIsErrorState(V_attachState(vp)))) {
2076 handle->volinfo_ptr.base->needsSalvaged = 1;
2078 handle->volinfo_ptr.base->needsSalvaged = 0;
2081 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2083 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2084 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2085 handle->volinfo_ptr.base->spare1 =
2086 (long)hdr->weekUse[0] +
2087 (long)hdr->weekUse[1] +
2088 (long)hdr->weekUse[2] +
2089 (long)hdr->weekUse[3] +
2090 (long)hdr->weekUse[4] +
2091 (long)hdr->weekUse[5] +
2092 (long)hdr->weekUse[6];
2093 handle->volinfo_ptr.base->flags = 0;
2094 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2095 handle->volinfo_ptr.base->spare3 = 0;
2099 case VOLINT_INFO_TYPE_EXT:
2101 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2102 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2105 * Copy out the stat fields in a single operation.
2107 if ((now - hdr->dayUseDate) > OneDay) {
2108 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2111 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2112 (char *)&(hdr->stat_reads[0]),
2121 #ifdef AFS_DEMAND_ATTACH_FS
2124 * get struct Volume out of the fileserver.
2126 * @param[in] volumeId volumeId for which we want state information
2127 * @param[in] pname partition name string
2128 * @param[inout] vp pointer to pointer to Volume object which
2129 * will be populated (see note)
2131 * @return operation status
2133 * @retval non-zero failure
2135 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2140 GetVolObject(VolumeId volumeId, char * pname, Volume ** vp)
2145 res.hdr.response_len = sizeof(res.hdr);
2146 res.payload.buf = *vp;
2147 res.payload.len = sizeof(Volume);
2149 code = FSYNC_VolOp(volumeId,
2155 if (code != SYNC_OK) {
2156 switch (res.hdr.reason) {
2157 case FSYNC_WRONG_PART:
2158 case FSYNC_UNKNOWN_VOLID:
2171 * mode of volume list operation.
2174 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2175 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2176 } vol_info_list_mode_t;
2179 * abstract interface to populate wire-format volume metadata structures.
2181 * @param[in] partId partition id
2182 * @param[in] volumeId volume id
2183 * @param[in] pname partition name
2184 * @param[in] volname volume file name
2185 * @param[in] handle handle to on-wire volume metadata object
2186 * @param[in] mode listing mode
2188 * @return operation status
2190 * @retval -2 DESTROY_ME flag is set
2191 * @retval -1 general failure; some data filled in
2192 * @retval -3 couldn't create vtrans; some data filled in
2195 GetVolInfo(afs_uint32 partId,
2199 volint_info_handle_t * handle,
2200 vol_info_list_mode_t mode)
2204 struct volser_trans *ttc = NULL;
2205 struct Volume *fill_tv, *tv = NULL;
2206 #ifdef AFS_DEMAND_ATTACH_FS
2207 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2208 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2209 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2210 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2212 /* Set up response handle for pending_vol_op */
2213 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2214 fs_res.payload.buf = fs_res_buf;
2215 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2218 ttc = NewTrans(volumeId, partId);
2221 VOLINT_INFO_STORE(handle, status, VBUSY);
2222 VOLINT_INFO_STORE(handle, volid, volumeId);
2226 /* Get volume from volserver */
2227 if (mode == VOL_INFO_LIST_MULTIPLE)
2228 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2230 #ifdef AFS_DEMAND_ATTACH_FS
2233 int mode = V_READONLY; /* informs the fileserver to update the volume headers. */
2235 tv = VAttachVolumeByName_retry(&error, pname, volname, mode);
2239 Log("1 Volser: GetVolInfo: Could not attach volume %" AFS_VOLID_FMT " (%s:%s) error=%d\n",
2240 afs_printable_VolumeId_lu(volumeId), pname, volname, error);
2245 * please note that destroyMe and needsSalvaged checks used to be ordered
2246 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2247 * more correct to check destroyMe before needsSalvaged.
2248 * -- tkeiser 11/28/2007
2251 if (V_destroyMe(tv) == DESTROY_ME) {
2253 case VOL_INFO_LIST_MULTIPLE:
2257 case VOL_INFO_LIST_SINGLE:
2258 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) will be destroyed on next salvage\n",
2259 afs_printable_VolumeId_lu(volumeId), pname, volname);
2266 if (V_needsSalvaged(tv)) {
2267 /*this volume will be salvaged */
2268 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) needs to be salvaged\n",
2269 afs_printable_VolumeId_lu(volumeId), pname, volname);
2272 #ifdef AFS_DEMAND_ATTACH_FS
2273 /* If using DAFS, get volume from fsserver */
2274 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2279 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2280 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2281 /* If we if the pending vol op */
2282 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2283 fs_tv->pending_vol_op=&pending_vol_op_res;
2285 fs_tv->pending_vol_op=NULL;
2288 /* populate the header from the volserver copy */
2289 fs_tv->header=tv->header;
2291 /* When using DAFS, use the fs volume info, populated with required structures */
2294 /* When not using DAFS, just use the local volume info */
2298 /* ok, we have all the data we need; fill in the on-wire struct */
2299 code = FillVolInfo(fill_tv, handle);
2303 VOLINT_INFO_STORE(handle, status, 0);
2304 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2305 VOLINT_INFO_STORE(handle, volid, volumeId);
2308 VDetachVolume(&error, tv);
2311 VOLINT_INFO_STORE(handle, status, 0);
2312 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2313 Log("1 Volser: GetVolInfo: Could not detach volume %" AFS_VOLID_FMT " (%s:%s)\n",
2314 afs_printable_VolumeId_lu(volumeId), pname, volname);
2318 DeleteTrans(ttc, 1);
2325 /*return the header information about the <volid> */
2327 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2328 VolumeId volumeId, volEntries *volumeInfo)
2332 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2333 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2338 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2339 VolumeId volumeId, volEntries *volumeInfo)
2341 struct DiskPartition64 *partP;
2342 char pname[9], volname[20];
2346 volint_info_handle_t handle;
2348 volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2349 if (!volumeInfo->volEntries_val)
2352 volumeInfo->volEntries_len = 1;
2353 if (GetPartName(partid, pname))
2354 return VOLSERILLEGAL_PARTITION;
2355 if (!(partP = VGetPartition(pname, 0)))
2356 return VOLSERILLEGAL_PARTITION;
2357 dirp = opendir(VPartitionPath(partP));
2359 return VOLSERILLEGAL_PARTITION;
2361 while (GetNextVol(dirp, volname, &volid)) {
2362 if (volid == volumeId) { /*copy other things too */
2369 #ifndef AFS_PTHREAD_ENV
2370 IOMGR_Poll(); /*make sure that the client does not time out */
2373 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2374 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2376 /* The return code from GetVolInfo is ignored; there is no error from
2377 * it that results in the whole call being aborted. Any volume
2378 * attachment failures are reported in 'status' field in the
2379 * volumeInfo payload. */
2385 VOL_INFO_LIST_SINGLE);
2389 return (found) ? 0 : ENODEV;
2392 /*------------------------------------------------------------------------
2393 * EXPORTED SAFSVolXListOneVolume
2396 * Returns extended info on volume a_volID on partition a_partID.
2399 * a_rxCidP : Pointer to the Rx call we're performing.
2400 * a_partID : Partition for which we want the extended list.
2401 * a_volID : Volume ID we wish to know about.
2402 * a_volumeXInfoP : Ptr to the extended info blob.
2405 * 0 Successful operation
2406 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2409 * Nothing interesting.
2413 *------------------------------------------------------------------------*/
2416 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2417 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2421 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2422 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2427 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2428 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2429 { /*SAFSVolXListOneVolume */
2431 struct DiskPartition64 *partP; /*Ptr to partition */
2432 char pname[9], volname[20]; /*Partition, volume names */
2433 DIR *dirp; /*Partition directory ptr */
2434 VolumeId currVolID; /*Current volume ID */
2435 int found = 0; /*Did we find the volume we need? */
2436 volint_info_handle_t handle;
2439 * Set up our pointers for action, marking our structure to hold exactly
2440 * one entry. Also, assume we'll fail in our quest.
2442 a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2443 if (!a_volumeXInfoP->volXEntries_val)
2446 a_volumeXInfoP->volXEntries_len = 1;
2449 * If the partition name we've been given is bad, bogue out.
2451 if (GetPartName(a_partID, pname))
2452 return (VOLSERILLEGAL_PARTITION);
2455 * Open the directory representing the given AFS parttion. If we can't
2458 if (!(partP = VGetPartition(pname, 0)))
2459 return VOLSERILLEGAL_PARTITION;
2460 dirp = opendir(VPartitionPath(partP));
2462 return (VOLSERILLEGAL_PARTITION);
2466 * Sweep through the partition directory, looking for the desired entry.
2467 * First, of course, figure out how many stat bytes to copy out of each
2470 while (GetNextVol(dirp, volname, &currVolID)) {
2471 if (currVolID == a_volID) {
2473 * We found the volume entry we're interested. Pull out the
2474 * extended information, remembering to poll (so that the client
2475 * doesn't time out) and to set up a transaction on the volume.
2479 } /*Found desired volume */
2483 #ifndef AFS_PTHREAD_ENV
2487 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2488 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2490 /* The return code from GetVolInfo is ignored; there is no error from
2491 * it that results in the whole call being aborted. Any volume
2492 * attachment failures are reported in 'status' field in the
2493 * volumeInfo payload. */
2494 GetVolInfo(a_partID,
2499 VOL_INFO_LIST_SINGLE);
2503 * Clean up before going to dinner: close the partition directory,
2504 * return the proper value.
2507 return (found) ? 0 : ENODEV;
2508 } /*SAFSVolXListOneVolume */
2510 /*returns all the volumes on partition partid. If flags = 1 then all the
2511 * relevant info about the volumes is also returned */
2513 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2514 volEntries *volumeInfo)
2518 code = VolListVolumes(acid, partid, flags, volumeInfo);
2519 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2524 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2525 volEntries *volumeInfo)
2528 struct DiskPartition64 *partP;
2529 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2530 char pname[9], volname[20];
2534 volint_info_handle_t handle;
2536 volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2537 if (!volumeInfo->volEntries_val)
2540 pntr = volumeInfo->volEntries_val;
2541 volumeInfo->volEntries_len = 0;
2542 if (GetPartName(partid, pname))
2543 return VOLSERILLEGAL_PARTITION;
2544 if (!(partP = VGetPartition(pname, 0)))
2545 return VOLSERILLEGAL_PARTITION;
2546 dirp = opendir(VPartitionPath(partP));
2548 return VOLSERILLEGAL_PARTITION;
2550 while (GetNextVol(dirp, volname, &volid)) {
2551 if (flags) { /*copy other things too */
2552 #ifndef AFS_PTHREAD_ENV
2553 IOMGR_Poll(); /*make sure that the client does not time out */
2556 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2557 handle.volinfo_ptr.base = pntr;
2560 code = GetVolInfo(partid,
2565 VOL_INFO_LIST_MULTIPLE);
2566 if (code == -2) /* DESTROY_ME flag set */
2569 pntr->volid = volid;
2570 /*just volids are needed */
2574 volumeInfo->volEntries_len += 1;
2575 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2576 /*running out of space, allocate more space */
2577 allocSize = (allocSize * 3) / 2;
2578 pntr = realloc(volumeInfo->volEntries_val,
2579 allocSize * sizeof(volintInfo));
2582 return VOLSERNO_MEMORY;
2584 volumeInfo->volEntries_val = pntr; /* point to new block */
2585 /* set pntr to the right position */
2586 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2594 /*------------------------------------------------------------------------
2595 * EXPORTED SAFSVolXListVolumes
2598 * Returns all the volumes on partition a_partID. If a_flags
2599 * is set to 1, then all the relevant extended volume information
2603 * a_rxCidP : Pointer to the Rx call we're performing.
2604 * a_partID : Partition for which we want the extended list.
2605 * a_flags : Various flags.
2606 * a_volumeXInfoP : Ptr to the extended info blob.
2609 * 0 Successful operation
2610 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2611 * VOLSERNO_MEMORY if we ran out of memory allocating
2615 * Nothing interesting.
2619 *------------------------------------------------------------------------*/
2622 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2623 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2627 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2628 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2633 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2634 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2635 { /*SAFSVolXListVolumes */
2637 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2638 struct DiskPartition64 *partP; /*Ptr to partition */
2639 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2640 char pname[9], volname[20]; /*Partition, volume names */
2641 DIR *dirp; /*Partition directory ptr */
2642 VolumeId volid; /*Current volume ID */
2644 volint_info_handle_t handle;
2647 * Allocate a large array of extended volume info structures, then
2648 * set it up for action.
2650 a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2651 if (!a_volumeXInfoP->volXEntries_val)
2654 xInfoP = a_volumeXInfoP->volXEntries_val;
2655 a_volumeXInfoP->volXEntries_len = 0;
2658 * If the partition name we've been given is bad, bogue out.
2660 if (GetPartName(a_partID, pname))
2661 return (VOLSERILLEGAL_PARTITION);
2664 * Open the directory representing the given AFS parttion. If we can't
2667 if (!(partP = VGetPartition(pname, 0)))
2668 return VOLSERILLEGAL_PARTITION;
2669 dirp = opendir(VPartitionPath(partP));
2671 return (VOLSERILLEGAL_PARTITION);
2672 while (GetNextVol(dirp, volname, &volid)) {
2675 * Full info about the volume desired. Poll to make sure the
2676 * client doesn't time out, then start up a new transaction.
2678 #ifndef AFS_PTHREAD_ENV
2682 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2683 handle.volinfo_ptr.ext = xInfoP;
2685 code = GetVolInfo(a_partID,
2690 VOL_INFO_LIST_MULTIPLE);
2691 if (code == -2) /* DESTROY_ME flag set */
2695 * Just volume IDs are needed.
2697 xInfoP->volid = volid;
2701 * Bump the pointer in the data area we're building, along with
2702 * the count of the number of entries it contains.
2705 (a_volumeXInfoP->volXEntries_len)++;
2706 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2708 * We're running out of space in the area we've built. Grow it.
2710 allocSize = (allocSize * 3) / 2;
2711 xInfoP = (volintXInfo *)
2712 realloc((char *)a_volumeXInfoP->volXEntries_val,
2713 (allocSize * sizeof(volintXInfo)));
2714 if (xInfoP == NULL) {
2716 * Bummer, no memory. Bag it, tell our caller what went wrong.
2719 return (VOLSERNO_MEMORY);
2723 * Memory reallocation worked. Correct our pointers so they
2724 * now point to the new block and the current open position within
2727 a_volumeXInfoP->volXEntries_val = xInfoP;
2729 a_volumeXInfoP->volXEntries_val +
2730 a_volumeXInfoP->volXEntries_len;
2735 * We've examined all entries in the partition directory. Close it,
2736 * delete our transaction (if any), and go home happy.
2741 } /*SAFSVolXListVolumes */
2743 /*this call is used to monitor the status of volser for debugging purposes.
2744 *information about all the active transactions is returned in transInfo*/
2746 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2750 code = VolMonitor(acid, transInfo);
2751 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2756 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2758 transDebugInfo *pntr;
2759 afs_int32 allocSize = 50;
2760 struct volser_trans *tt, *nt, *allTrans;
2762 transInfo->transDebugEntries_val =
2763 malloc(allocSize * sizeof(transDebugInfo));
2764 if (!transInfo->transDebugEntries_val)
2766 pntr = transInfo->transDebugEntries_val;
2767 transInfo->transDebugEntries_len = 0;
2770 allTrans = TransList();
2771 if (allTrans == (struct volser_trans *)0)
2772 goto done; /*no active transactions */
2773 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2775 VTRANS_OBJ_LOCK(tt);
2776 pntr->tid = tt->tid;
2777 pntr->time = tt->time;
2778 pntr->creationTime = tt->creationTime;
2779 pntr->returnCode = tt->returnCode;
2780 pntr->volid = tt->volid;
2781 pntr->partition = tt->partition;
2782 pntr->iflags = tt->iflags;
2783 pntr->vflags = tt->vflags;
2784 pntr->tflags = tt->tflags;
2785 strcpy(pntr->lastProcName, tt->lastProcName);
2786 pntr->callValid = 0;
2787 if (tt->rxCallPtr) { /*record call related info */
2788 pntr->callValid = 1;
2790 pntr->readNext = tt->rxCallPtr->rnext;
2791 pntr->transmitNext = tt->rxCallPtr->tnext;
2792 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2793 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2796 VTRANS_OBJ_UNLOCK(tt);
2798 transInfo->transDebugEntries_len += 1;
2799 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2800 allocSize = (allocSize * 3) / 2;
2801 pntr = realloc(transInfo->transDebugEntries_val,
2802 allocSize * sizeof(transDebugInfo));
2803 transInfo->transDebugEntries_val = pntr;
2805 transInfo->transDebugEntries_val +
2806 transInfo->transDebugEntries_len;
2807 /*set pntr to right position */
2818 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2819 afs_int32 type, afs_uint32 pId, VolumeId cloneId,
2824 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2825 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2826 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2832 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2833 afs_int32 type, VolumeId pId, VolumeId cloneId,
2838 struct volser_trans *tt;
2839 char caller[MAXKTCNAMELEN];
2841 if (strlen(name) > 31)
2842 return VOLSERBADNAME;
2843 if (!afsconf_SuperUser(tdir, acid, caller))
2844 return VOLSERBAD_ACCESS; /*not a super user */
2845 /* find the trans */
2846 tt = FindTrans(atid);
2849 if (tt->vflags & VTDeleted) {
2850 Log("1 Volser: VolSetIds: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2854 TSetRxCall(tt, acid, "SetIdsTypes");
2858 V_backupId(tv) = backupId;
2859 V_cloneId(tv) = cloneId;
2860 V_parentId(tv) = pId;
2861 strcpy((&V_disk(tv))->name, name);
2862 VUpdateVolume(&error, tv);
2864 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2869 if (TRELE(tt) && !error)
2870 return VOLSERTRELE_ERROR;
2875 if (TRELE(tt) && !error)
2876 return VOLSERTRELE_ERROR;
2881 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2885 code = VolSetDate(acid, atid, cdate);
2886 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2892 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2896 struct volser_trans *tt;
2897 char caller[MAXKTCNAMELEN];
2899 if (!afsconf_SuperUser(tdir, acid, caller))
2900 return VOLSERBAD_ACCESS; /*not a super user */
2901 /* find the trans */
2902 tt = FindTrans(atid);
2905 if (tt->vflags & VTDeleted) {
2906 Log("1 Volser: VolSetDate: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2910 TSetRxCall(tt, acid, "SetDate");
2913 V_creationDate(tv) = cdate;
2914 VUpdateVolume(&error, tv);
2916 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2921 if (TRELE(tt) && !error)
2922 return VOLSERTRELE_ERROR;
2927 if (TRELE(tt) && !error)
2928 return VOLSERTRELE_ERROR;
2933 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2939 char caller[MAXKTCNAMELEN];
2941 struct volser_trans *ttc;
2942 char pname[16], volname[20];
2943 struct DiskPartition64 *partP;
2944 afs_int32 ret = ENODEV;
2947 if (!afsconf_SuperUser(tdir, acid, caller))
2948 return VOLSERBAD_ACCESS; /*not a super user */
2949 if (GetPartName(partId, pname))
2950 return VOLSERILLEGAL_PARTITION;
2951 if (!(partP = VGetPartition(pname, 0)))
2952 return VOLSERILLEGAL_PARTITION;
2953 dirp = opendir(VPartitionPath(partP));
2955 return VOLSERILLEGAL_PARTITION;
2956 ttc = (struct volser_trans *)0;
2958 while (GetNextVol(dirp, volname, &volid)) {
2959 if (volid == volumeId) { /*copy other things too */
2960 #ifndef AFS_PTHREAD_ENV
2961 IOMGR_Poll(); /*make sure that the client doesnot time out */
2963 ttc = NewTrans(volumeId, partId);
2965 return VOLSERVOLBUSY;
2967 #ifdef AFS_NAMEI_ENV
2968 ret = namei_ConvertROtoRWvolume(pname, volumeId);
2970 ret = inode_ConvertROtoRWvolume(pname, volumeId);
2977 DeleteTrans(ttc, 1);
2985 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
2986 struct volintSize *size)
2989 struct volser_trans *tt;
2990 char caller[MAXKTCNAMELEN];
2992 if (!afsconf_SuperUser(tdir, acid, caller))
2993 return VOLSERBAD_ACCESS; /*not a super user */
2994 tt = FindTrans(fromTrans);
2997 if (tt->vflags & VTDeleted) {
3001 TSetRxCall(tt, acid, "GetSize");
3002 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3005 return VOLSERTRELE_ERROR;
3007 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3012 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3013 afs_uint32 where, afs_int32 verbose)
3015 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3017 Volume *vol=0, *newvol=0;
3018 struct volser_trans *tt = 0, *tt2 = 0;
3019 char caller[MAXKTCNAMELEN];
3022 if (!afsconf_SuperUser(tdir, acall, caller))
3025 vol = VAttachVolume(&code, vid, V_VOLUPD);
3031 newvol = VAttachVolume(&code, new, V_VOLUPD);
3033 VDetachVolume(&code2, vol);
3038 if (V_device(vol) != V_device(newvol)
3039 || V_uniquifier(newvol) != 2) {
3040 if (V_device(vol) != V_device(newvol)) {
3041 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3043 rx_Write(acall, line, strlen(line));
3045 if (V_uniquifier(newvol) != 2) {
3046 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3047 rx_Write(acall, line, strlen(line));
3050 rx_Write(acall, line, 1);
3051 VDetachVolume(&code2, vol);
3052 VDetachVolume(&code2, newvol);
3055 tt = NewTrans(vid, V_device(vol));
3057 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3058 rx_Write(acall, line, strlen(line));
3060 rx_Write(acall, line, 1);
3061 VDetachVolume(&code2, vol);
3062 VDetachVolume(&code2, newvol);
3063 return VOLSERVOLBUSY;
3065 VTRANS_OBJ_LOCK(tt);
3066 tt->iflags = ITBusy;
3068 TSetRxCall_r(tt, NULL, "SplitVolume");
3069 VTRANS_OBJ_UNLOCK(tt);
3071 tt2 = NewTrans(new, V_device(newvol));
3073 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3074 rx_Write(acall, line, strlen(line));
3076 rx_Write(acall, line, 1);
3078 VDetachVolume(&code2, vol);
3079 VDetachVolume(&code2, newvol);
3080 return VOLSERVOLBUSY;
3082 VTRANS_OBJ_LOCK(tt2);
3083 tt2->iflags = ITBusy;
3085 TSetRxCall_r(tt2, NULL, "SplitVolume");
3086 VTRANS_OBJ_UNLOCK(tt2);
3088 code = split_volume(acall, vol, newvol, where, verbose);
3090 VDetachVolume(&code2, vol);
3092 VDetachVolume(&code2, newvol);
3093 DeleteTrans(tt2, 1);
3100 /* GetPartName - map partid (a decimal number) into pname (a string)
3101 * Since for NT we actually want to return the drive name, we map through the
3105 GetPartName(afs_int32 partid, char *pname)
3110 strcpy(pname, "/vicep");
3111 pname[6] = 'a' + partid;
3114 } else if (partid < VOLMAXPARTS) {
3115 strcpy(pname, "/vicep");
3117 pname[6] = 'a' + (partid / 26);
3118 pname[7] = 'a' + (partid % 26);