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));
1550 TSetRxCall(tt, acid, "Restore");
1552 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1554 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1555 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1559 return (code ? code : tcode);
1562 /* end a transaction, returning the transaction's final error code in rcode */
1564 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1568 code = VolEndTrans(acid, destTrans, rcode);
1569 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1574 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1576 struct volser_trans *tt;
1577 char caller[MAXKTCNAMELEN];
1579 if (!afsconf_SuperUser(tdir, acid, caller))
1580 return VOLSERBAD_ACCESS; /*not a super user */
1581 tt = FindTrans(destTrans);
1585 *rcode = tt->returnCode;
1586 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1592 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1596 code = VolSetForwarding(acid, atid, anewsite);
1597 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1598 htonl(anewsite), AUD_END);
1603 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1605 struct volser_trans *tt;
1606 char caller[MAXKTCNAMELEN];
1609 if (!afsconf_SuperUser(tdir, acid, caller))
1610 return VOLSERBAD_ACCESS; /*not a super user */
1611 tt = FindTrans(atid);
1614 if (tt->vflags & VTDeleted) {
1615 Log("1 Volser: VolSetForwarding: volume %" AFS_VOLID_FMT " has been deleted \n",
1616 afs_printable_VolumeId_lu(tt->volid));
1620 TSetRxCall(tt, acid, "SetForwarding");
1621 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1624 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1627 return VOLSERTRELE_ERROR;
1633 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1634 struct volser_status *astatus)
1638 code = VolGetStatus(acid, atrans, astatus);
1639 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1644 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1645 struct volser_status *astatus)
1648 struct VolumeDiskData *td;
1649 struct volser_trans *tt;
1652 tt = FindTrans(atrans);
1655 if (tt->vflags & VTDeleted) {
1656 Log("1 Volser: VolGetStatus: volume %" AFS_VOLID_FMT " has been deleted \n",
1657 afs_printable_VolumeId_lu(tt->volid));
1661 TSetRxCall(tt, acid, "GetStatus");
1670 astatus->volID = td->id;
1671 astatus->nextUnique = td->uniquifier;
1672 astatus->type = td->type;
1673 astatus->parentID = td->parentId;
1674 astatus->cloneID = td->cloneId;
1675 astatus->backupID = td->backupId;
1676 astatus->restoredFromID = td->restoredFromId;
1677 astatus->maxQuota = td->maxquota;
1678 astatus->minQuota = td->minquota;
1679 astatus->owner = td->owner;
1680 astatus->creationDate = td->creationDate;
1681 astatus->accessDate = td->accessDate;
1682 astatus->updateDate = td->updateDate;
1683 astatus->expirationDate = td->expirationDate;
1684 astatus->backupDate = td->backupDate;
1685 astatus->copyDate = td->copyDate;
1688 return VOLSERTRELE_ERROR;
1694 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1695 struct volintInfo *astatus)
1699 code = VolSetInfo(acid, atrans, astatus);
1700 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1705 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1706 struct volintInfo *astatus)
1709 struct VolumeDiskData *td;
1710 struct volser_trans *tt;
1711 char caller[MAXKTCNAMELEN];
1714 if (!afsconf_SuperUser(tdir, acid, caller))
1715 return VOLSERBAD_ACCESS; /*not a super user */
1716 tt = FindTrans(atrans);
1719 if (tt->vflags & VTDeleted) {
1720 Log("1 Volser: VolSetInfo: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1724 TSetRxCall(tt, acid, "SetStatus");
1734 * Add more fields as necessary
1736 if (astatus->maxquota != -1)
1737 td->maxquota = astatus->maxquota;
1738 if (astatus->dayUse != -1)
1739 td->dayUse = astatus->dayUse;
1740 if (astatus->creationDate != -1)
1741 td->creationDate = astatus->creationDate;
1742 if (astatus->updateDate != -1)
1743 td->updateDate = astatus->updateDate;
1744 if (astatus->spare2 != -1)
1745 td->volUpdateCounter = (unsigned int)astatus->spare2;
1746 VUpdateVolume(&error, tv);
1749 return VOLSERTRELE_ERROR;
1755 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1759 code = VolGetName(acid, atrans, aname);
1760 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1765 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1768 struct VolumeDiskData *td;
1769 struct volser_trans *tt;
1772 /* We need to at least fill it in */
1776 tt = FindTrans(atrans);
1779 if (tt->vflags & VTDeleted) {
1780 Log("1 Volser: VolGetName: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1784 TSetRxCall(tt, acid, "GetName");
1793 len = strlen(td->name) + 1; /* don't forget the null */
1799 *aname = realloc(*aname, len);
1800 strcpy(*aname, td->name);
1803 return VOLSERTRELE_ERROR;
1808 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1811 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1812 VolumeId parentId, VolumeId cloneId)
1818 /*return a list of all partitions on the server. The non mounted
1819 *partitions are returned as -1 in the corresponding slot in partIds*/
1821 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1825 code = VolListPartitions(acid, partIds);
1826 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1831 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1836 strcpy(namehead, "/vicep"); /*7 including null terminator */
1838 /* Just return attached partitions. */
1840 for (i = 0; i < 26; i++) {
1841 namehead[6] = i + 'a';
1842 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1848 /*return a list of all partitions on the server. The non mounted
1849 *partitions are returned as -1 in the corresponding slot in partIds*/
1851 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1855 code = XVolListPartitions(acid, pEntries);
1856 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1861 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1864 struct partList partList;
1865 struct DiskPartition64 *dp;
1868 strcpy(namehead, "/vicep"); /*7 including null terminator */
1870 /* Only report attached partitions */
1871 for (i = 0; i < VOLMAXPARTS; i++) {
1872 #ifdef AFS_DEMAND_ATTACH_FS
1873 dp = VGetPartitionById(i, 0);
1876 namehead[6] = i + 'a';
1882 namehead[6] = 'a' + (k / 26);
1883 namehead[7] = 'a' + (k % 26);
1886 dp = VGetPartition(namehead, 0);
1889 partList.partId[j++] = i;
1892 pEntries->partEntries_val = malloc(j * sizeof(int));
1893 if (!pEntries->partEntries_val)
1895 memcpy(pEntries->partEntries_val, partList.partId,
1897 pEntries->partEntries_len = j;
1899 pEntries->partEntries_val = NULL;
1900 pEntries->partEntries_len = 0;
1907 * Scan a directory for possible volume headers.
1908 * in: DIR *dirp -- a directory handle from opendir()
1909 * out: char *volname -- set to name of directory entry
1910 * afs_uint32 *volid -- set to volume ID parsed from name
1912 * true if volname and volid have been set to valid values
1913 * false if we got to the end of the directory
1916 GetNextVol(DIR *dirp, char *volname, VolumeId *volid)
1920 while ((dp = readdir(dirp)) != NULL) {
1921 /* could be optimized on platforms with dp->d_namlen */
1922 if (dp->d_name[0] == 'V' && strlen(dp->d_name) == VHDRNAMELEN
1923 && strcmp(&(dp->d_name[VFORMATDIGITS + 1]), VHDREXT) == 0) {
1924 *volid = VolumeNumber(dp->d_name);
1925 strcpy(volname, dp->d_name);
1933 * volint vol info structure type.
1936 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1937 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1938 } volint_info_type_t;
1941 * handle to various on-wire vol info types.
1944 volint_info_type_t volinfo_type;
1950 } volint_info_handle_t;
1953 * store value to a field at the appropriate location in on-wire structure.
1955 #define VOLINT_INFO_STORE(handle, name, val) \
1957 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1958 (handle)->volinfo_ptr.base->name = (val); \
1960 (handle)->volinfo_ptr.ext->name = (val); \
1965 * get pointer to appropriate offset of field in on-wire structure.
1967 #define VOLINT_INFO_PTR(handle, name) \
1968 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1969 &((handle)->volinfo_ptr.base->name) : \
1970 &((handle)->volinfo_ptr.ext->name))
1973 * fill in appropriate type of on-wire volume metadata structure.
1975 * @param vp pointer to volume object
1976 * @param handle pointer to wire format handle object
1978 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1979 * @pre handle object must have a valid pointer and enumeration value
1981 * @note passing a NULL value for vp means that the fileserver doesn't
1982 * know about this particular volume, thus implying it is offline.
1984 * @return operation status
1989 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1991 unsigned int numStatBytes, now;
1992 struct VolumeDiskData *hdr = &(V_disk(vp));
1994 /*read in the relevant info */
1995 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1996 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1997 VOLINT_INFO_STORE(handle, volid, hdr->id);
1998 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1999 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2000 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2001 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2002 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2003 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2004 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2005 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2006 now = FT_ApproxTime();
2007 if ((now - hdr->dayUseDate) > OneDay) {
2008 VOLINT_INFO_STORE(handle, dayUse, 0);
2010 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2012 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2013 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2014 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2015 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2017 #ifdef AFS_DEMAND_ATTACH_FS
2019 * for DAFS, we "lie" about volume state --
2020 * instead of returning the raw state from the disk header,
2021 * we compute state based upon the fileserver's internal
2022 * in-core state enumeration value reported to us via fssync,
2023 * along with the blessed and inService flags from the header.
2024 * -- tkeiser 11/27/2007
2027 /* Conditions that offline status is based on:
2028 volume is unattached state
2029 volume state is in (one of several error states)
2030 volume not in service
2031 volume is not marked as blessed (not on hold)
2032 volume in salvage req. state
2033 volume needsSalvaged
2034 next op would set volume offline
2035 next op would not leave volume online (based on several conditions)
2038 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2039 VIsErrorState(V_attachState(vp)) ||
2042 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2043 hdr->needsSalvaged ||
2044 (vp->pending_vol_op &&
2045 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2046 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2049 VOLINT_INFO_STORE(handle, inUse, 0);
2051 VOLINT_INFO_STORE(handle, inUse, 1);
2054 /* offline status based on program type, where != fileServer enum (1) is offline */
2055 if (hdr->inUse == fileServer) {
2056 VOLINT_INFO_STORE(handle, inUse, 1);
2058 VOLINT_INFO_STORE(handle, inUse, 0);
2063 switch(handle->volinfo_type) {
2064 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2065 case VOLINT_INFO_TYPE_BASE:
2067 #ifdef AFS_DEMAND_ATTACH_FS
2068 /* see comment above where we set inUse bit */
2069 if (hdr->needsSalvaged ||
2070 (vp && VIsErrorState(V_attachState(vp)))) {
2071 handle->volinfo_ptr.base->needsSalvaged = 1;
2073 handle->volinfo_ptr.base->needsSalvaged = 0;
2076 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2078 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2079 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2080 handle->volinfo_ptr.base->spare1 =
2081 (long)hdr->weekUse[0] +
2082 (long)hdr->weekUse[1] +
2083 (long)hdr->weekUse[2] +
2084 (long)hdr->weekUse[3] +
2085 (long)hdr->weekUse[4] +
2086 (long)hdr->weekUse[5] +
2087 (long)hdr->weekUse[6];
2088 handle->volinfo_ptr.base->flags = 0;
2089 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2090 handle->volinfo_ptr.base->spare3 = 0;
2094 case VOLINT_INFO_TYPE_EXT:
2096 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2097 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2100 * Copy out the stat fields in a single operation.
2102 if ((now - hdr->dayUseDate) > OneDay) {
2103 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2106 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2107 (char *)&(hdr->stat_reads[0]),
2116 #ifdef AFS_DEMAND_ATTACH_FS
2119 * get struct Volume out of the fileserver.
2121 * @param[in] volumeId volumeId for which we want state information
2122 * @param[in] pname partition name string
2123 * @param[inout] vp pointer to pointer to Volume object which
2124 * will be populated (see note)
2126 * @return operation status
2128 * @retval non-zero failure
2130 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2135 GetVolObject(VolumeId volumeId, char * pname, Volume ** vp)
2140 res.hdr.response_len = sizeof(res.hdr);
2141 res.payload.buf = *vp;
2142 res.payload.len = sizeof(Volume);
2144 code = FSYNC_VolOp(volumeId,
2150 if (code != SYNC_OK) {
2151 switch (res.hdr.reason) {
2152 case FSYNC_WRONG_PART:
2153 case FSYNC_UNKNOWN_VOLID:
2166 * mode of volume list operation.
2169 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2170 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2171 } vol_info_list_mode_t;
2174 * abstract interface to populate wire-format volume metadata structures.
2176 * @param[in] partId partition id
2177 * @param[in] volumeId volume id
2178 * @param[in] pname partition name
2179 * @param[in] volname volume file name
2180 * @param[in] handle handle to on-wire volume metadata object
2181 * @param[in] mode listing mode
2183 * @return operation status
2185 * @retval -2 DESTROY_ME flag is set
2186 * @retval -1 general failure; some data filled in
2187 * @retval -3 couldn't create vtrans; some data filled in
2190 GetVolInfo(afs_uint32 partId,
2194 volint_info_handle_t * handle,
2195 vol_info_list_mode_t mode)
2199 struct volser_trans *ttc = NULL;
2200 struct Volume *fill_tv, *tv = NULL;
2201 #ifdef AFS_DEMAND_ATTACH_FS
2202 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2203 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2204 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2205 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2207 /* Set up response handle for pending_vol_op */
2208 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2209 fs_res.payload.buf = fs_res_buf;
2210 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2213 ttc = NewTrans(volumeId, partId);
2216 VOLINT_INFO_STORE(handle, status, VBUSY);
2217 VOLINT_INFO_STORE(handle, volid, volumeId);
2221 /* Get volume from volserver */
2222 if (mode == VOL_INFO_LIST_MULTIPLE)
2223 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2225 #ifdef AFS_DEMAND_ATTACH_FS
2228 int mode = V_READONLY; /* informs the fileserver to update the volume headers. */
2230 tv = VAttachVolumeByName_retry(&error, pname, volname, mode);
2234 Log("1 Volser: GetVolInfo: Could not attach volume %" AFS_VOLID_FMT " (%s:%s) error=%d\n",
2235 afs_printable_VolumeId_lu(volumeId), pname, volname, error);
2240 * please note that destroyMe and needsSalvaged checks used to be ordered
2241 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2242 * more correct to check destroyMe before needsSalvaged.
2243 * -- tkeiser 11/28/2007
2246 if (V_destroyMe(tv) == DESTROY_ME) {
2248 case VOL_INFO_LIST_MULTIPLE:
2252 case VOL_INFO_LIST_SINGLE:
2253 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) will be destroyed on next salvage\n",
2254 afs_printable_VolumeId_lu(volumeId), pname, volname);
2261 if (V_needsSalvaged(tv)) {
2262 /*this volume will be salvaged */
2263 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) needs to be salvaged\n",
2264 afs_printable_VolumeId_lu(volumeId), pname, volname);
2267 #ifdef AFS_DEMAND_ATTACH_FS
2268 /* If using DAFS, get volume from fsserver */
2269 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2274 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2275 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2276 /* If we if the pending vol op */
2277 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2278 fs_tv->pending_vol_op=&pending_vol_op_res;
2280 fs_tv->pending_vol_op=NULL;
2283 /* populate the header from the volserver copy */
2284 fs_tv->header=tv->header;
2286 /* When using DAFS, use the fs volume info, populated with required structures */
2289 /* When not using DAFS, just use the local volume info */
2293 /* ok, we have all the data we need; fill in the on-wire struct */
2294 code = FillVolInfo(fill_tv, handle);
2298 VOLINT_INFO_STORE(handle, status, 0);
2299 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2300 VOLINT_INFO_STORE(handle, volid, volumeId);
2303 VDetachVolume(&error, tv);
2306 VOLINT_INFO_STORE(handle, status, 0);
2307 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2308 Log("1 Volser: GetVolInfo: Could not detach volume %" AFS_VOLID_FMT " (%s:%s)\n",
2309 afs_printable_VolumeId_lu(volumeId), pname, volname);
2313 DeleteTrans(ttc, 1);
2320 /*return the header information about the <volid> */
2322 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2323 VolumeId volumeId, volEntries *volumeInfo)
2327 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2328 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2333 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2334 VolumeId volumeId, volEntries *volumeInfo)
2336 struct DiskPartition64 *partP;
2337 char pname[9], volname[20];
2341 volint_info_handle_t handle;
2343 volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2344 if (!volumeInfo->volEntries_val)
2347 volumeInfo->volEntries_len = 1;
2348 if (GetPartName(partid, pname))
2349 return VOLSERILLEGAL_PARTITION;
2350 if (!(partP = VGetPartition(pname, 0)))
2351 return VOLSERILLEGAL_PARTITION;
2352 dirp = opendir(VPartitionPath(partP));
2354 return VOLSERILLEGAL_PARTITION;
2356 while (GetNextVol(dirp, volname, &volid)) {
2357 if (volid == volumeId) { /*copy other things too */
2364 #ifndef AFS_PTHREAD_ENV
2365 IOMGR_Poll(); /*make sure that the client does not time out */
2368 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2369 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2371 /* The return code from GetVolInfo is ignored; there is no error from
2372 * it that results in the whole call being aborted. Any volume
2373 * attachment failures are reported in 'status' field in the
2374 * volumeInfo payload. */
2380 VOL_INFO_LIST_SINGLE);
2384 return (found) ? 0 : ENODEV;
2387 /*------------------------------------------------------------------------
2388 * EXPORTED SAFSVolXListOneVolume
2391 * Returns extended info on volume a_volID on partition a_partID.
2394 * a_rxCidP : Pointer to the Rx call we're performing.
2395 * a_partID : Partition for which we want the extended list.
2396 * a_volID : Volume ID we wish to know about.
2397 * a_volumeXInfoP : Ptr to the extended info blob.
2400 * 0 Successful operation
2401 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2404 * Nothing interesting.
2408 *------------------------------------------------------------------------*/
2411 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2412 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2416 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2417 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2422 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2423 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2424 { /*SAFSVolXListOneVolume */
2426 struct DiskPartition64 *partP; /*Ptr to partition */
2427 char pname[9], volname[20]; /*Partition, volume names */
2428 DIR *dirp; /*Partition directory ptr */
2429 VolumeId currVolID; /*Current volume ID */
2430 int found = 0; /*Did we find the volume we need? */
2432 volint_info_handle_t handle;
2435 * Set up our pointers for action, marking our structure to hold exactly
2436 * one entry. Also, assume we'll fail in our quest.
2438 a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2439 if (!a_volumeXInfoP->volXEntries_val)
2442 a_volumeXInfoP->volXEntries_len = 1;
2446 * If the partition name we've been given is bad, bogue out.
2448 if (GetPartName(a_partID, pname))
2449 return (VOLSERILLEGAL_PARTITION);
2452 * Open the directory representing the given AFS parttion. If we can't
2455 if (!(partP = VGetPartition(pname, 0)))
2456 return VOLSERILLEGAL_PARTITION;
2457 dirp = opendir(VPartitionPath(partP));
2459 return (VOLSERILLEGAL_PARTITION);
2463 * Sweep through the partition directory, looking for the desired entry.
2464 * First, of course, figure out how many stat bytes to copy out of each
2467 while (GetNextVol(dirp, volname, &currVolID)) {
2468 if (currVolID == a_volID) {
2470 * We found the volume entry we're interested. Pull out the
2471 * extended information, remembering to poll (so that the client
2472 * doesn't time out) and to set up a transaction on the volume.
2476 } /*Found desired volume */
2481 #ifndef AFS_PTHREAD_ENV
2485 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2486 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2488 error = GetVolInfo(a_partID,
2493 VOL_INFO_LIST_SINGLE);
2500 * Clean up before going to dinner: close the partition directory,
2501 * return the proper value.
2505 } /*SAFSVolXListOneVolume */
2507 /*returns all the volumes on partition partid. If flags = 1 then all the
2508 * relevant info about the volumes is also returned */
2510 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2511 volEntries *volumeInfo)
2515 code = VolListVolumes(acid, partid, flags, volumeInfo);
2516 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2521 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2522 volEntries *volumeInfo)
2525 struct DiskPartition64 *partP;
2526 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2527 char pname[9], volname[20];
2531 volint_info_handle_t handle;
2533 volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2534 if (!volumeInfo->volEntries_val)
2537 pntr = volumeInfo->volEntries_val;
2538 volumeInfo->volEntries_len = 0;
2539 if (GetPartName(partid, pname))
2540 return VOLSERILLEGAL_PARTITION;
2541 if (!(partP = VGetPartition(pname, 0)))
2542 return VOLSERILLEGAL_PARTITION;
2543 dirp = opendir(VPartitionPath(partP));
2545 return VOLSERILLEGAL_PARTITION;
2547 while (GetNextVol(dirp, volname, &volid)) {
2548 if (flags) { /*copy other things too */
2549 #ifndef AFS_PTHREAD_ENV
2550 IOMGR_Poll(); /*make sure that the client does not time out */
2553 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2554 handle.volinfo_ptr.base = pntr;
2557 code = GetVolInfo(partid,
2562 VOL_INFO_LIST_MULTIPLE);
2563 if (code == -2) /* DESTROY_ME flag set */
2566 pntr->volid = volid;
2567 /*just volids are needed */
2571 volumeInfo->volEntries_len += 1;
2572 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2573 /*running out of space, allocate more space */
2574 allocSize = (allocSize * 3) / 2;
2575 pntr = realloc(volumeInfo->volEntries_val,
2576 allocSize * sizeof(volintInfo));
2579 return VOLSERNO_MEMORY;
2581 volumeInfo->volEntries_val = pntr; /* point to new block */
2582 /* set pntr to the right position */
2583 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2591 /*------------------------------------------------------------------------
2592 * EXPORTED SAFSVolXListVolumes
2595 * Returns all the volumes on partition a_partID. If a_flags
2596 * is set to 1, then all the relevant extended volume information
2600 * a_rxCidP : Pointer to the Rx call we're performing.
2601 * a_partID : Partition for which we want the extended list.
2602 * a_flags : Various flags.
2603 * a_volumeXInfoP : Ptr to the extended info blob.
2606 * 0 Successful operation
2607 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2608 * VOLSERNO_MEMORY if we ran out of memory allocating
2612 * Nothing interesting.
2616 *------------------------------------------------------------------------*/
2619 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2620 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2624 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2625 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2630 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2631 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2632 { /*SAFSVolXListVolumes */
2634 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2635 struct DiskPartition64 *partP; /*Ptr to partition */
2636 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2637 char pname[9], volname[20]; /*Partition, volume names */
2638 DIR *dirp; /*Partition directory ptr */
2639 VolumeId volid; /*Current volume ID */
2641 volint_info_handle_t handle;
2644 * Allocate a large array of extended volume info structures, then
2645 * set it up for action.
2647 a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2648 if (!a_volumeXInfoP->volXEntries_val)
2651 xInfoP = a_volumeXInfoP->volXEntries_val;
2652 a_volumeXInfoP->volXEntries_len = 0;
2655 * If the partition name we've been given is bad, bogue out.
2657 if (GetPartName(a_partID, pname))
2658 return (VOLSERILLEGAL_PARTITION);
2661 * Open the directory representing the given AFS parttion. If we can't
2664 if (!(partP = VGetPartition(pname, 0)))
2665 return VOLSERILLEGAL_PARTITION;
2666 dirp = opendir(VPartitionPath(partP));
2668 return (VOLSERILLEGAL_PARTITION);
2669 while (GetNextVol(dirp, volname, &volid)) {
2672 * Full info about the volume desired. Poll to make sure the
2673 * client doesn't time out, then start up a new transaction.
2675 #ifndef AFS_PTHREAD_ENV
2679 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2680 handle.volinfo_ptr.ext = xInfoP;
2682 code = GetVolInfo(a_partID,
2687 VOL_INFO_LIST_MULTIPLE);
2688 if (code == -2) /* DESTROY_ME flag set */
2692 * Just volume IDs are needed.
2694 xInfoP->volid = volid;
2698 * Bump the pointer in the data area we're building, along with
2699 * the count of the number of entries it contains.
2702 (a_volumeXInfoP->volXEntries_len)++;
2703 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2705 * We're running out of space in the area we've built. Grow it.
2707 allocSize = (allocSize * 3) / 2;
2708 xInfoP = (volintXInfo *)
2709 realloc((char *)a_volumeXInfoP->volXEntries_val,
2710 (allocSize * sizeof(volintXInfo)));
2711 if (xInfoP == NULL) {
2713 * Bummer, no memory. Bag it, tell our caller what went wrong.
2716 return (VOLSERNO_MEMORY);
2720 * Memory reallocation worked. Correct our pointers so they
2721 * now point to the new block and the current open position within
2724 a_volumeXInfoP->volXEntries_val = xInfoP;
2726 a_volumeXInfoP->volXEntries_val +
2727 a_volumeXInfoP->volXEntries_len;
2732 * We've examined all entries in the partition directory. Close it,
2733 * delete our transaction (if any), and go home happy.
2738 } /*SAFSVolXListVolumes */
2740 /*this call is used to monitor the status of volser for debugging purposes.
2741 *information about all the active transactions is returned in transInfo*/
2743 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2747 code = VolMonitor(acid, transInfo);
2748 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2753 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2755 transDebugInfo *pntr;
2756 afs_int32 allocSize = 50;
2757 struct volser_trans *tt, *nt, *allTrans;
2759 transInfo->transDebugEntries_val =
2760 malloc(allocSize * sizeof(transDebugInfo));
2761 if (!transInfo->transDebugEntries_val)
2763 pntr = transInfo->transDebugEntries_val;
2764 transInfo->transDebugEntries_len = 0;
2767 allTrans = TransList();
2768 if (allTrans == (struct volser_trans *)0)
2769 goto done; /*no active transactions */
2770 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2772 VTRANS_OBJ_LOCK(tt);
2773 pntr->tid = tt->tid;
2774 pntr->time = tt->time;
2775 pntr->creationTime = tt->creationTime;
2776 pntr->returnCode = tt->returnCode;
2777 pntr->volid = tt->volid;
2778 pntr->partition = tt->partition;
2779 pntr->iflags = tt->iflags;
2780 pntr->vflags = tt->vflags;
2781 pntr->tflags = tt->tflags;
2782 strcpy(pntr->lastProcName, tt->lastProcName);
2783 pntr->callValid = 0;
2784 if (tt->rxCallPtr) { /*record call related info */
2785 pntr->callValid = 1;
2787 pntr->readNext = tt->rxCallPtr->rnext;
2788 pntr->transmitNext = tt->rxCallPtr->tnext;
2789 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2790 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2793 VTRANS_OBJ_UNLOCK(tt);
2795 transInfo->transDebugEntries_len += 1;
2796 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2797 allocSize = (allocSize * 3) / 2;
2798 pntr = realloc(transInfo->transDebugEntries_val,
2799 allocSize * sizeof(transDebugInfo));
2800 transInfo->transDebugEntries_val = pntr;
2802 transInfo->transDebugEntries_val +
2803 transInfo->transDebugEntries_len;
2804 /*set pntr to right position */
2815 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2816 afs_int32 type, afs_uint32 pId, VolumeId cloneId,
2821 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2822 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2823 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2829 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2830 afs_int32 type, VolumeId pId, VolumeId cloneId,
2835 struct volser_trans *tt;
2836 char caller[MAXKTCNAMELEN];
2838 if (strlen(name) > 31)
2839 return VOLSERBADNAME;
2840 if (!afsconf_SuperUser(tdir, acid, caller))
2841 return VOLSERBAD_ACCESS; /*not a super user */
2842 /* find the trans */
2843 tt = FindTrans(atid);
2846 if (tt->vflags & VTDeleted) {
2847 Log("1 Volser: VolSetIds: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2851 TSetRxCall(tt, acid, "SetIdsTypes");
2855 V_backupId(tv) = backupId;
2856 V_cloneId(tv) = cloneId;
2857 V_parentId(tv) = pId;
2858 strcpy((&V_disk(tv))->name, name);
2859 VUpdateVolume(&error, tv);
2861 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2866 if (TRELE(tt) && !error)
2867 return VOLSERTRELE_ERROR;
2872 if (TRELE(tt) && !error)
2873 return VOLSERTRELE_ERROR;
2878 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2882 code = VolSetDate(acid, atid, cdate);
2883 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2889 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2893 struct volser_trans *tt;
2894 char caller[MAXKTCNAMELEN];
2896 if (!afsconf_SuperUser(tdir, acid, caller))
2897 return VOLSERBAD_ACCESS; /*not a super user */
2898 /* find the trans */
2899 tt = FindTrans(atid);
2902 if (tt->vflags & VTDeleted) {
2903 Log("1 Volser: VolSetDate: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
2907 TSetRxCall(tt, acid, "SetDate");
2910 V_creationDate(tv) = cdate;
2911 VUpdateVolume(&error, tv);
2913 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2918 if (TRELE(tt) && !error)
2919 return VOLSERTRELE_ERROR;
2924 if (TRELE(tt) && !error)
2925 return VOLSERTRELE_ERROR;
2930 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2936 char caller[MAXKTCNAMELEN];
2938 struct volser_trans *ttc;
2939 char pname[16], volname[20];
2940 struct DiskPartition64 *partP;
2941 afs_int32 ret = ENODEV;
2944 if (!afsconf_SuperUser(tdir, acid, caller))
2945 return VOLSERBAD_ACCESS; /*not a super user */
2946 if (GetPartName(partId, pname))
2947 return VOLSERILLEGAL_PARTITION;
2948 if (!(partP = VGetPartition(pname, 0)))
2949 return VOLSERILLEGAL_PARTITION;
2950 dirp = opendir(VPartitionPath(partP));
2952 return VOLSERILLEGAL_PARTITION;
2953 ttc = (struct volser_trans *)0;
2955 while (GetNextVol(dirp, volname, &volid)) {
2956 if (volid == volumeId) { /*copy other things too */
2957 #ifndef AFS_PTHREAD_ENV
2958 IOMGR_Poll(); /*make sure that the client doesnot time out */
2960 ttc = NewTrans(volumeId, partId);
2962 return VOLSERVOLBUSY;
2964 #ifdef AFS_NAMEI_ENV
2965 ret = namei_ConvertROtoRWvolume(pname, volumeId);
2967 ret = inode_ConvertROtoRWvolume(pname, volumeId);
2974 DeleteTrans(ttc, 1);
2982 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
2983 struct volintSize *size)
2986 struct volser_trans *tt;
2987 char caller[MAXKTCNAMELEN];
2989 if (!afsconf_SuperUser(tdir, acid, caller))
2990 return VOLSERBAD_ACCESS; /*not a super user */
2991 tt = FindTrans(fromTrans);
2994 if (tt->vflags & VTDeleted) {
2998 TSetRxCall(tt, acid, "GetSize");
2999 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3002 return VOLSERTRELE_ERROR;
3004 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3009 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3010 afs_uint32 where, afs_int32 verbose)
3012 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3014 Volume *vol=0, *newvol=0;
3015 struct volser_trans *tt = 0, *tt2 = 0;
3016 char caller[MAXKTCNAMELEN];
3019 if (!afsconf_SuperUser(tdir, acall, caller))
3022 vol = VAttachVolume(&code, vid, V_VOLUPD);
3028 newvol = VAttachVolume(&code, new, V_VOLUPD);
3030 VDetachVolume(&code2, vol);
3035 if (V_device(vol) != V_device(newvol)
3036 || V_uniquifier(newvol) != 2) {
3037 if (V_device(vol) != V_device(newvol)) {
3038 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3040 rx_Write(acall, line, strlen(line));
3042 if (V_uniquifier(newvol) != 2) {
3043 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3044 rx_Write(acall, line, strlen(line));
3047 rx_Write(acall, line, 1);
3048 VDetachVolume(&code2, vol);
3049 VDetachVolume(&code2, newvol);
3052 tt = NewTrans(vid, V_device(vol));
3054 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3055 rx_Write(acall, line, strlen(line));
3057 rx_Write(acall, line, 1);
3058 VDetachVolume(&code2, vol);
3059 VDetachVolume(&code2, newvol);
3060 return VOLSERVOLBUSY;
3062 VTRANS_OBJ_LOCK(tt);
3063 tt->iflags = ITBusy;
3065 TSetRxCall_r(tt, NULL, "SplitVolume");
3066 VTRANS_OBJ_UNLOCK(tt);
3068 tt2 = NewTrans(new, V_device(newvol));
3070 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3071 rx_Write(acall, line, strlen(line));
3073 rx_Write(acall, line, 1);
3075 VDetachVolume(&code2, vol);
3076 VDetachVolume(&code2, newvol);
3077 return VOLSERVOLBUSY;
3079 VTRANS_OBJ_LOCK(tt2);
3080 tt2->iflags = ITBusy;
3082 TSetRxCall_r(tt2, NULL, "SplitVolume");
3083 VTRANS_OBJ_UNLOCK(tt2);
3085 code = split_volume(acall, vol, newvol, where, verbose);
3087 VDetachVolume(&code2, vol);
3089 VDetachVolume(&code2, newvol);
3090 DeleteTrans(tt2, 1);
3097 /* GetPartName - map partid (a decimal number) into pname (a string)
3098 * Since for NT we actually want to return the drive name, we map through the
3102 GetPartName(afs_int32 partid, char *pname)
3107 strcpy(pname, "/vicep");
3108 pname[6] = 'a' + partid;
3111 } else if (partid < VOLMAXPARTS) {
3112 strcpy(pname, "/vicep");
3114 pname[6] = 'a' + (partid / 26);
3115 pname[7] = 'a' + (partid % 26);