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 dp = VGetPartition(pname, 0);
454 strncpy(partition->name, dp->name, 32);
455 strncpy(partition->devName, dp->devName, 32);
456 partition->lock_fd = (int)dp->lock_fd;
457 partition->free = dp->free;
458 partition->minFree = dp->totalUsable;
461 return VOLSERILLEGAL_PARTITION;
464 /* obliterate a volume completely, and slowly. */
466 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, VolumeId avolID)
470 code = VolNukeVolume(acid, apartID, avolID);
471 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
476 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
483 char caller[MAXKTCNAMELEN];
485 /* check for access */
486 if (!afsconf_SuperUser(tdir, acid, caller))
487 return VOLSERBAD_ACCESS;
490 Log("%s on %s is executing VolNukeVolume %u\n", caller,
491 callerAddress(acid, buffer), avolID);
494 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
496 /* we first try to attach the volume in update mode, so that the file
497 * server doesn't try to use it (and abort) while (or after) we delete it.
498 * If we don't get the volume, that's fine, too. We just won't put it back.
500 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
501 code = nuke(partName, avolID);
503 VDetachVolume(&verror, tvp);
507 /* create a new volume, with name aname, on the specified partition (1..n)
508 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
509 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
510 * for the volume id (useful for things like volume restore).
511 * Return the new volume id in *avolid.
514 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
515 afs_int32 atype, VolumeId aparent, VolumeId *avolid,
521 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
522 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
523 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
529 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
530 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
535 Error junk; /* discardable error code */
537 afs_int32 doCreateRoot = 1;
538 struct volser_trans *tt;
540 char caller[MAXKTCNAMELEN];
542 if (strlen(aname) > 31)
543 return VOLSERBADNAME;
544 if (!afsconf_SuperUser(tdir, acid, caller))
545 return VOLSERBAD_ACCESS;
548 Log("%s on %s is executing CreateVolume '%s'\n", caller,
549 callerAddress(acid, buffer), aname);
551 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
552 return error; /*a standard unix error */
553 if (atype != readwriteVolume && atype != readonlyVolume
554 && atype != backupVolume)
556 if ((volumeID = *avolid) == 0) {
558 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
562 if ((aparent == volumeID) && (atype == readwriteVolume)) {
567 tt = NewTrans(volumeID, apart);
569 Log("1 createvolume: failed to create trans\n");
570 return VOLSERVOLBUSY; /* volume already busy! */
572 vp = VCreateVolume(&error, ppath, volumeID, aparent);
574 #ifdef AFS_DEMAND_ATTACH_FS
575 if (error != VVOLEXISTS && error != EXDEV) {
576 SalvageUnknownVolume(volumeID, ppath);
579 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
584 V_uniquifier(vp) = 1;
585 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
586 V_inService(vp) = V_blessed(vp) = 1;
588 AssignVolumeName(&V_disk(vp), aname, 0);
590 error = ViceCreateRoot(vp);
592 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
593 "error code %u\n", (unsigned)error);
595 V_needsSalvaged(vp) = 1;
596 VDetachVolume(&junk, vp);
600 V_destroyMe(vp) = DESTROY_ME;
602 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
603 VUpdateVolume(&error, vp);
605 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
608 VDetachVolume(&junk, vp); /* rather return the real error code */
614 TSetRxCall_r(tt, acid, "CreateVolume");
615 VTRANS_OBJ_UNLOCK(tt);
616 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
619 return VOLSERTRELE_ERROR;
623 /* delete the volume associated with this transaction */
625 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
629 code = VolDeleteVolume(acid, atrans);
630 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
635 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
637 struct volser_trans *tt;
639 char caller[MAXKTCNAMELEN];
641 if (!afsconf_SuperUser(tdir, acid, caller))
642 return VOLSERBAD_ACCESS;
643 tt = FindTrans(atrans);
646 if (tt->vflags & VTDeleted) {
647 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " already deleted \n",
648 afs_printable_VolumeId_lu(tt->volid));
654 Log("%s on %s is executing Delete Volume %" AFS_VOLID_FMT "\n", caller,
655 callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
657 TSetRxCall(tt, acid, "DeleteVolume");
658 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
659 V_destroyMe(tt->volume) = DESTROY_ME;
660 if (tt->volume->needsPutBack) {
661 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
664 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
666 VTRANS_OBJ_UNLOCK(tt);
668 return VOLSERTRELE_ERROR;
670 Log("1 Volser: Delete: volume %" AFS_VOLID_FMT " deleted \n",
671 afs_printable_VolumeId_lu(tt->volid));
672 return 0; /* vpurgevolume doesn't set an error code */
675 /* make a clone of the volume associated with atrans, possibly giving it a new
676 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
677 * for the clone's id). The new clone is given the name newName. Finally,
678 * due to efficiency considerations, if purgeId is non-zero, we purge that
679 * volume when doing the clone operation. This may be useful when making
680 * new backup volumes, for instance since the net result of a clone and a
681 * purge generally leaves many inode ref counts the same, while doing them
682 * separately would result in far more iincs and idecs being peformed
683 * (and they are slow operations).
685 /* for efficiency reasons, sometimes faster to piggyback a purge here */
687 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
688 afs_int32 newType, char *newName, VolumeId *newNumber)
691 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
692 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
693 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
699 VolClone(struct rx_call *acid, afs_int32 atrans, VolumeId purgeId,
700 afs_int32 newType, char *newName, VolumeId *newNumber)
703 struct Volume *originalvp, *purgevp, *newvp;
705 struct volser_trans *tt, *ttc;
706 char caller[MAXKTCNAMELEN];
707 #ifdef AFS_DEMAND_ATTACH_FS
708 struct Volume *salv_vp = NULL;
711 if (strlen(newName) > 31)
712 return VOLSERBADNAME;
713 if (!afsconf_SuperUser(tdir, acid, caller))
714 return VOLSERBAD_ACCESS; /*not a super user */
717 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
718 callerAddress(acid, buffer), newName);
721 purgevp = (Volume *) 0;
722 newvp = (Volume *) 0;
723 tt = ttc = (struct volser_trans *)0;
725 if (!newNumber || !*newNumber) {
726 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
731 tt = FindTrans(atrans);
734 if (tt->vflags & VTDeleted) {
735 Log("1 Volser: Clone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
739 ttc = NewTrans(newId, tt->partition);
740 if (!ttc) { /* someone is messing with the clone already */
742 return VOLSERVOLBUSY;
744 TSetRxCall(tt, acid, "Clone");
748 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
750 Log("1 Volser: Clone: Could not attach 'purge' volume %" AFS_VOLID_FMT "; clone aborted\n", afs_printable_VolumeId_lu(purgeId));
756 originalvp = tt->volume;
757 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
758 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
759 afs_printable_VolumeId_lu(V_id(originalvp)));
764 if (originalvp->device != purgevp->device) {
765 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));
769 if (V_type(purgevp) != readonlyVolume) {
770 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
774 if (V_parentId(originalvp) != V_parentId(purgevp)) {
775 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));
782 #ifdef AFS_DEMAND_ATTACH_FS
783 salv_vp = originalvp;
786 if (purgeId == newId) {
790 VCreateVolume(&error, originalvp->partition->name, newId,
791 V_parentId(originalvp));
793 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
794 newvp = (Volume *) 0;
798 if (newType == readonlyVolume)
799 V_cloneId(originalvp) = newId;
800 Log("1 Volser: Clone: Cloning volume %" AFS_VOLID_FMT " to new volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
801 afs_printable_VolumeId_lu(newId));
803 Log("1 Volser: Clone: Purging old read only volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(purgeId));
804 CloneVolume(&error, originalvp, newvp, purgevp);
805 purgevp = NULL; /* clone releases it, maybe even if error */
807 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
811 if (newType == readonlyVolume) {
812 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
813 V_type(newvp) = readonlyVolume;
814 } else if (newType == backupVolume) {
815 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
816 V_type(newvp) = backupVolume;
817 V_backupId(originalvp) = newId;
819 strcpy(V_name(newvp), newName);
820 V_creationDate(newvp) = V_copyDate(newvp);
821 ClearVolumeStats(&V_disk(newvp));
822 V_destroyMe(newvp) = DESTROY_ME;
823 V_inService(newvp) = 0;
824 if (newType == backupVolume) {
825 V_backupDate(originalvp) = V_copyDate(newvp);
826 V_backupDate(newvp) = V_copyDate(newvp);
829 VUpdateVolume(&error, newvp);
831 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
835 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
837 VUpdateVolume(&error, originalvp);
839 Log("1 Volser: Clone: original update %u\n", error);
844 #ifdef AFS_DEMAND_ATTACH_FS
848 tt = (struct volser_trans *)0;
849 error = VOLSERTRELE_ERROR;
857 VDetachVolume(&code, purgevp);
859 VDetachVolume(&code, newvp);
866 #ifdef AFS_DEMAND_ATTACH_FS
867 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
868 V_needsSalvaged(salv_vp) = 1;
870 #endif /* AFS_DEMAND_ATTACH_FS */
874 /* reclone this volume into the specified id */
876 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
880 code = VolReClone(acid, atrans, cloneId);
881 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
887 VolReClone(struct rx_call *acid, afs_int32 atrans, VolumeId cloneId)
889 struct Volume *originalvp, *clonevp;
892 struct volser_trans *tt, *ttc;
893 char caller[MAXKTCNAMELEN];
894 VolumeDiskData saved_header;
896 /*not a super user */
897 if (!afsconf_SuperUser(tdir, acid, caller))
898 return VOLSERBAD_ACCESS;
901 Log("%s on %s is executing Reclone Volume %" AFS_VOLID_FMT "\n", caller,
902 callerAddress(acid, buffer), afs_printable_VolumeId_lu(cloneId));
905 clonevp = originalvp = (Volume *) 0;
907 tt = FindTrans(atrans);
910 if (tt->vflags & VTDeleted) {
911 Log("1 Volser: VolReClone: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
915 ttc = NewTrans(cloneId, tt->partition);
916 if (!ttc) { /* someone is messing with the clone already */
918 return VOLSERVOLBUSY;
920 TSetRxCall(tt, acid, "ReClone");
922 originalvp = tt->volume;
923 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
924 Log("1 Volser: Clone: Volume %" AFS_VOLID_FMT " is offline and cannot be cloned\n",
925 afs_printable_VolumeId_lu(V_id(originalvp)));
930 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
932 Log("1 Volser: can't attach clone %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(cloneId));
936 newType = V_type(clonevp); /* type of the new volume */
938 if (originalvp->device != clonevp->device) {
939 Log("1 Volser: Clone: Volumes %" AFS_VOLID_FMT " and %" AFS_VOLID_FMT " are on different devices\n",
940 afs_printable_VolumeId_lu(tt->volid), afs_printable_VolumeId_lu(cloneId));
944 if (V_parentId(originalvp) != V_parentId(clonevp)) {
945 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));
950 if (DoPreserveVolumeStats) {
951 CopyVolumeStats(&V_disk(clonevp), &saved_header);
955 Log("1 Volser: Clone: Recloning volume %" AFS_VOLID_FMT " to volume %" AFS_VOLID_FMT "\n", afs_printable_VolumeId_lu(tt->volid),
956 afs_printable_VolumeId_lu(cloneId));
957 CloneVolume(&error, originalvp, clonevp, clonevp);
959 Log("1 Volser: Clone: reclone operation failed with code %d\n",
965 /* fix up volume name and type, CloneVolume just propagated RW's */
966 if (newType == readonlyVolume) {
967 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
968 V_type(clonevp) = readonlyVolume;
969 } else if (newType == backupVolume) {
970 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
971 V_type(clonevp) = backupVolume;
972 V_backupId(originalvp) = cloneId;
974 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
976 /* update the creationDate, since this represents the last cloning date
977 * for ROs. But do not update copyDate; let it stay so we can identify
978 * when the clone was first created. */
979 V_creationDate(clonevp) = time(0);
980 if (DoPreserveVolumeStats) {
981 CopyVolumeStats(&saved_header, &V_disk(clonevp));
983 ClearVolumeStats(&V_disk(clonevp));
985 V_destroyMe(clonevp) = 0;
986 V_inService(clonevp) = 0;
987 if (newType == backupVolume) {
988 V_backupDate(originalvp) = V_creationDate(clonevp);
989 V_backupDate(clonevp) = V_creationDate(clonevp);
991 V_inUse(clonevp) = 0;
992 VUpdateVolume(&error, clonevp);
994 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
998 /* VUpdateVolume succeeded. Mark it in service so there's no window
999 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
1000 * specialStatus; this is a reclone and this volume started online
1002 V_inService(clonevp) = 1;
1003 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
1005 VUpdateVolume(&error, originalvp);
1007 Log("1 Volser: Clone: original update %u\n", error);
1013 tt = (struct volser_trans *)0;
1014 error = VOLSERTRELE_ERROR;
1018 DeleteTrans(ttc, 1);
1021 struct DiskPartition64 *tpartp = originalvp->partition;
1022 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1028 VDetachVolume(&code, clonevp);
1034 DeleteTrans(ttc, 1);
1038 /* create a new transaction, associated with volume and partition. Type of
1039 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1040 * See volser.h for definition of iflags (the constants are named IT*).
1043 SAFSVolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1044 afs_int32 iflags, afs_int32 *ttid)
1048 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1049 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1055 VolTransCreate(struct rx_call *acid, VolumeId volume, afs_int32 partition,
1056 afs_int32 iflags, afs_int32 *ttid)
1058 struct volser_trans *tt;
1063 char caller[MAXKTCNAMELEN];
1065 if (!afsconf_SuperUser(tdir, acid, caller))
1066 return VOLSERBAD_ACCESS; /*not a super user */
1067 if (iflags & ITCreate)
1069 else if (iflags & ITBusy)
1071 else if (iflags & ITReadOnly)
1073 else if (iflags & ITOffline)
1076 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1081 tt = NewTrans(volume, partition);
1083 /* can't create a transaction? put the volume back */
1084 Log("1 transcreate: can't create transaction\n");
1085 return VOLSERVOLBUSY;
1087 tv = XAttachVolume(&error, volume, partition, mode);
1091 VDetachVolume(&code, tv);
1095 VTRANS_OBJ_LOCK(tt);
1098 tt->iflags = iflags;
1100 TSetRxCall_r(tt, NULL, "TransCreate");
1101 VTRANS_OBJ_UNLOCK(tt);
1103 return VOLSERTRELE_ERROR;
1108 /* using aindex as a 0-based index, return the aindex'th volume on this server
1109 * Both the volume number and partition number (one-based) are returned.
1112 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, VolumeId *avolume,
1117 code = VolGetNthVolume(acid, aindex, avolume, apart);
1118 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1123 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1126 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1130 /* return the volume flags (VT* constants in volser.h) associated with this
1134 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1138 code = VolGetFlags(acid, atid, aflags);
1139 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1144 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1146 struct volser_trans *tt;
1148 tt = FindTrans(atid);
1151 if (tt->vflags & VTDeleted) {
1152 Log("1 Volser: VolGetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1153 afs_printable_VolumeId_lu(tt->volid));
1157 TSetRxCall(tt, acid, "GetFlags");
1158 *aflags = tt->vflags;
1161 return VOLSERTRELE_ERROR;
1166 /* Change the volume flags (VT* constants in volser.h) associated with this
1167 * transaction. Effects take place immediately on volume, although volume
1168 * remains attached as usual by the transaction.
1171 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1175 code = VolSetFlags(acid, atid, aflags);
1176 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1182 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1184 struct volser_trans *tt;
1187 char caller[MAXKTCNAMELEN];
1189 if (!afsconf_SuperUser(tdir, acid, caller))
1190 return VOLSERBAD_ACCESS; /*not a super user */
1191 /* find the trans */
1192 tt = FindTrans(atid);
1195 if (tt->vflags & VTDeleted) {
1196 Log("1 Volser: VolSetFlags: volume %" AFS_VOLID_FMT " has been deleted \n",
1197 afs_printable_VolumeId_lu(tt->volid));
1201 TSetRxCall(tt, acid, "SetFlags");
1202 vp = tt->volume; /* pull volume out of transaction */
1204 /* check if we're allowed to make any updates */
1205 if (tt->iflags & ITReadOnly) {
1210 /* handle delete-on-salvage flag */
1211 if (aflags & VTDeleteOnSalvage) {
1212 V_destroyMe(tt->volume) = DESTROY_ME;
1214 V_destroyMe(tt->volume) = 0;
1217 if (aflags & VTOutOfService) {
1218 V_inService(vp) = 0;
1220 V_inService(vp) = 1;
1222 VUpdateVolume(&error, vp);
1223 VTRANS_OBJ_LOCK(tt);
1224 tt->vflags = aflags;
1226 VTRANS_OBJ_UNLOCK(tt);
1227 if (TRELE(tt) && !error)
1228 return VOLSERTRELE_ERROR;
1233 /* dumpS the volume associated with a particular transaction from a particular
1234 * date. Send the dump to a different transaction (destTrans) on the server
1235 * specified by the destServer structure.
1238 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1239 struct destServer *destination, afs_int32 destTrans,
1240 struct restoreCookie *cookie)
1245 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1246 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1247 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1252 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1253 struct destServer *destination, afs_int32 destTrans,
1254 struct restoreCookie *cookie)
1256 struct volser_trans *tt;
1258 struct rx_connection *tcon;
1259 struct rx_call *tcall;
1261 struct rx_securityClass *securityObject;
1262 afs_int32 securityIndex;
1263 char caller[MAXKTCNAMELEN];
1265 if (!afsconf_SuperUser(tdir, acid, caller))
1266 return VOLSERBAD_ACCESS; /*not a super user */
1268 /* find the local transaction */
1269 tt = FindTrans(fromTrans);
1272 if (tt->vflags & VTDeleted) {
1273 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1278 TSetRxCall(tt, NULL, "Forward");
1280 /* get auth info for the this connection (uses afs from ticket file) */
1281 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1287 /* make an rpc connection to the other server */
1289 rx_NewConnection(htonl(destination->destHost),
1290 htons(destination->destPort), VOLSERVICE_ID,
1291 securityObject, securityIndex);
1297 tcall = rx_NewCall(tcon);
1298 TSetRxCall(tt, tcall, "Forward");
1299 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1300 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1305 /* these next calls implictly call rx_Write when writing out data */
1306 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1309 EndAFSVolRestore(tcall); /* probably doesn't do much */
1311 code = rx_EndCall(tcall, 0);
1312 rx_DestroyConnection(tcon); /* done with the connection */
1317 return VOLSERTRELE_ERROR;
1323 (void)rx_EndCall(tcall, 0);
1324 rx_DestroyConnection(tcon);
1333 /* Start a dump and send it to multiple places simultaneously.
1334 * If this returns an error (eg, return ENOENT), it means that
1335 * none of the releases worked. If this returns 0, that means
1336 * that one or more of the releases worked, and the caller has
1337 * to examine the results array to see which one(s).
1338 * This will only do EITHER incremental or full, not both, so it's
1339 * the caller's responsibility to be sure that all the destinations
1340 * need just an incremental (and from the same time), if that's
1344 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1345 fromDate, manyDests *destinations, afs_int32 spare,
1346 struct restoreCookie *cookie, manyResults *results)
1348 afs_int32 securityIndex;
1349 struct rx_securityClass *securityObject;
1350 char caller[MAXKTCNAMELEN];
1351 struct volser_trans *tt;
1352 afs_int32 ec, code, *codes;
1353 struct rx_connection **tcons;
1354 struct rx_call **tcalls;
1356 int i, is_incremental;
1359 memset(results, 0, sizeof(manyResults));
1360 i = results->manyResults_len = destinations->manyDests_len;
1361 results->manyResults_val = codes = malloc(i * sizeof(afs_int32));
1363 if (!results || !results->manyResults_val)
1366 if (!afsconf_SuperUser(tdir, acid, caller))
1367 return VOLSERBAD_ACCESS; /*not a super user */
1368 tt = FindTrans(fromTrans);
1371 if (tt->vflags & VTDeleted) {
1372 Log("1 Volser: VolForward: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1377 TSetRxCall(tt, NULL, "ForwardMulti");
1379 /* (fromDate == 0) ==> full dump */
1380 is_incremental = (fromDate ? 1 : 0);
1382 tcons = malloc(i * sizeof(struct rx_connection *));
1386 tcalls = malloc(i * sizeof(struct rx_call *));
1392 /* get auth info for this connection (uses afs from ticket file) */
1393 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1395 goto fail; /* in order to audit each failure */
1398 /* make connections to all the other servers */
1399 for (i = 0; i < destinations->manyDests_len; i++) {
1400 struct replica *dest = &(destinations->manyDests_val[i]);
1402 rx_NewConnection(htonl(dest->server.destHost),
1403 htons(dest->server.destPort), VOLSERVICE_ID,
1404 securityObject, securityIndex);
1406 codes[i] = ENOTCONN;
1408 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1409 codes[i] = ENOTCONN;
1412 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1415 (void)rx_EndCall(tcalls[i], 0);
1417 rx_DestroyConnection(tcons[i]);
1424 /* these next calls implictly call rx_Write when writing out data */
1425 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1429 for (i--; i >= 0; i--) {
1430 struct replica *dest = &(destinations->manyDests_val[i]);
1432 if (!code && tcalls[i] && !codes[i]) {
1433 EndAFSVolRestore(tcalls[i]);
1436 ec = rx_EndCall(tcalls[i], 0);
1441 rx_DestroyConnection(tcons[i]); /* done with the connection */
1444 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1445 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1446 dest->trans, AUD_END);
1453 if (TRELE(tt) && !code) /* return the first code if it's set */
1454 return VOLSERTRELE_ERROR;
1461 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1465 code = VolDump(acid, fromTrans, fromDate, 0);
1466 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1471 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1476 code = VolDump(acid, fromTrans, fromDate, flags);
1477 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1482 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1486 struct volser_trans *tt;
1487 char caller[MAXKTCNAMELEN];
1489 if (!afsconf_SuperUser(tdir, acid, caller))
1490 return VOLSERBAD_ACCESS; /*not a super user */
1491 tt = FindTrans(fromTrans);
1494 if (tt->vflags & VTDeleted) {
1495 Log("1 Volser: VolDump: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1499 TSetRxCall(tt, acid, "Dump");
1500 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1501 ? 0 : 1); /* squirt out the volume's data, too */
1510 return VOLSERTRELE_ERROR;
1516 * Ha! No more helper process!
1519 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1520 struct restoreCookie *cookie)
1524 code = VolRestore(acid, atrans, aflags, cookie);
1525 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1530 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1531 struct restoreCookie *cookie)
1533 struct volser_trans *tt;
1534 afs_int32 code, tcode;
1535 char caller[MAXKTCNAMELEN];
1537 if (!afsconf_SuperUser(tdir, acid, caller))
1538 return VOLSERBAD_ACCESS; /*not a super user */
1539 tt = FindTrans(atrans);
1542 if (tt->vflags & VTDeleted) {
1543 Log("1 Volser: VolRestore: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1549 Log("%s on %s is executing Restore %" AFS_VOLID_FMT "\n", caller,
1550 callerAddress(acid, buffer), afs_printable_VolumeId_lu(tt->volid));
1552 TSetRxCall(tt, acid, "Restore");
1554 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1556 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1557 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1561 return (code ? code : tcode);
1564 /* end a transaction, returning the transaction's final error code in rcode */
1566 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1570 code = VolEndTrans(acid, destTrans, rcode);
1571 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1576 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1578 struct volser_trans *tt;
1579 char caller[MAXKTCNAMELEN];
1581 if (!afsconf_SuperUser(tdir, acid, caller))
1582 return VOLSERBAD_ACCESS; /*not a super user */
1583 tt = FindTrans(destTrans);
1587 *rcode = tt->returnCode;
1588 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1594 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1598 code = VolSetForwarding(acid, atid, anewsite);
1599 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1600 htonl(anewsite), AUD_END);
1605 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1607 struct volser_trans *tt;
1608 char caller[MAXKTCNAMELEN];
1611 if (!afsconf_SuperUser(tdir, acid, caller))
1612 return VOLSERBAD_ACCESS; /*not a super user */
1613 tt = FindTrans(atid);
1616 if (tt->vflags & VTDeleted) {
1617 Log("1 Volser: VolSetForwarding: volume %" AFS_VOLID_FMT " has been deleted \n",
1618 afs_printable_VolumeId_lu(tt->volid));
1622 TSetRxCall(tt, acid, "SetForwarding");
1623 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1626 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1629 return VOLSERTRELE_ERROR;
1635 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1636 struct volser_status *astatus)
1640 code = VolGetStatus(acid, atrans, astatus);
1641 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1646 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1647 struct volser_status *astatus)
1650 struct VolumeDiskData *td;
1651 struct volser_trans *tt;
1654 tt = FindTrans(atrans);
1657 if (tt->vflags & VTDeleted) {
1658 Log("1 Volser: VolGetStatus: volume %" AFS_VOLID_FMT " has been deleted \n",
1659 afs_printable_VolumeId_lu(tt->volid));
1663 TSetRxCall(tt, acid, "GetStatus");
1672 astatus->volID = td->id;
1673 astatus->nextUnique = td->uniquifier;
1674 astatus->type = td->type;
1675 astatus->parentID = td->parentId;
1676 astatus->cloneID = td->cloneId;
1677 astatus->backupID = td->backupId;
1678 astatus->restoredFromID = td->restoredFromId;
1679 astatus->maxQuota = td->maxquota;
1680 astatus->minQuota = td->minquota;
1681 astatus->owner = td->owner;
1682 astatus->creationDate = td->creationDate;
1683 astatus->accessDate = td->accessDate;
1684 astatus->updateDate = td->updateDate;
1685 astatus->expirationDate = td->expirationDate;
1686 astatus->backupDate = td->backupDate;
1687 astatus->copyDate = td->copyDate;
1690 return VOLSERTRELE_ERROR;
1696 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1697 struct volintInfo *astatus)
1701 code = VolSetInfo(acid, atrans, astatus);
1702 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1707 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1708 struct volintInfo *astatus)
1711 struct VolumeDiskData *td;
1712 struct volser_trans *tt;
1713 char caller[MAXKTCNAMELEN];
1716 if (!afsconf_SuperUser(tdir, acid, caller))
1717 return VOLSERBAD_ACCESS; /*not a super user */
1718 tt = FindTrans(atrans);
1721 if (tt->vflags & VTDeleted) {
1722 Log("1 Volser: VolSetInfo: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1726 TSetRxCall(tt, acid, "SetStatus");
1736 * Add more fields as necessary
1738 if (astatus->maxquota != -1)
1739 td->maxquota = astatus->maxquota;
1740 if (astatus->dayUse != -1)
1741 td->dayUse = astatus->dayUse;
1742 if (astatus->creationDate != -1)
1743 td->creationDate = astatus->creationDate;
1744 if (astatus->updateDate != -1)
1745 td->updateDate = astatus->updateDate;
1746 if (astatus->spare2 != -1)
1747 td->volUpdateCounter = (unsigned int)astatus->spare2;
1748 VUpdateVolume(&error, tv);
1751 return VOLSERTRELE_ERROR;
1757 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1761 code = VolGetName(acid, atrans, aname);
1762 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1767 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1770 struct VolumeDiskData *td;
1771 struct volser_trans *tt;
1774 /* We need to at least fill it in */
1778 tt = FindTrans(atrans);
1781 if (tt->vflags & VTDeleted) {
1782 Log("1 Volser: VolGetName: volume %" AFS_VOLID_FMT " has been deleted \n", afs_printable_VolumeId_lu(tt->volid));
1786 TSetRxCall(tt, acid, "GetName");
1795 len = strlen(td->name) + 1; /* don't forget the null */
1801 *aname = realloc(*aname, len);
1802 strcpy(*aname, td->name);
1805 return VOLSERTRELE_ERROR;
1810 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1813 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1814 VolumeId parentId, VolumeId cloneId)
1820 /*return a list of all partitions on the server. The non mounted
1821 *partitions are returned as -1 in the corresponding slot in partIds*/
1823 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1827 code = VolListPartitions(acid, partIds);
1828 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1833 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1838 strcpy(namehead, "/vicep"); /*7 including null terminator */
1840 /* Just return attached partitions. */
1842 for (i = 0; i < 26; i++) {
1843 namehead[6] = i + 'a';
1844 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1850 /*return a list of all partitions on the server. The non mounted
1851 *partitions are returned as -1 in the corresponding slot in partIds*/
1853 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1857 code = XVolListPartitions(acid, pEntries);
1858 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1863 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1866 struct partList partList;
1867 struct DiskPartition64 *dp;
1870 strcpy(namehead, "/vicep"); /*7 including null terminator */
1872 /* Only report attached partitions */
1873 for (i = 0; i < VOLMAXPARTS; i++) {
1874 #ifdef AFS_DEMAND_ATTACH_FS
1875 dp = VGetPartitionById(i, 0);
1878 namehead[6] = i + 'a';
1884 namehead[6] = 'a' + (k / 26);
1885 namehead[7] = 'a' + (k % 26);
1888 dp = VGetPartition(namehead, 0);
1891 partList.partId[j++] = i;
1894 pEntries->partEntries_val = malloc(j * sizeof(int));
1895 if (!pEntries->partEntries_val)
1897 memcpy(pEntries->partEntries_val, partList.partId,
1899 pEntries->partEntries_len = j;
1901 pEntries->partEntries_val = NULL;
1902 pEntries->partEntries_len = 0;
1909 * Scan a directory for possible volume headers.
1910 * in: DIR *dirp -- a directory handle from opendir()
1911 * out: char *volname -- set to name of directory entry
1912 * afs_uint32 *volid -- set to volume ID parsed from name
1914 * true if volname and volid have been set to valid values
1915 * false if we got to the end of the directory
1918 GetNextVol(DIR *dirp, char *volname, VolumeId *volid)
1922 while ((dp = readdir(dirp)) != NULL) {
1923 /* could be optimized on platforms with dp->d_namlen */
1924 if (dp->d_name[0] == 'V' && strlen(dp->d_name) == VHDRNAMELEN
1925 && strcmp(&(dp->d_name[VFORMATDIGITS + 1]), VHDREXT) == 0) {
1926 *volid = VolumeNumber(dp->d_name);
1927 strcpy(volname, dp->d_name);
1935 * volint vol info structure type.
1938 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1939 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1940 } volint_info_type_t;
1943 * handle to various on-wire vol info types.
1946 volint_info_type_t volinfo_type;
1952 } volint_info_handle_t;
1955 * store value to a field at the appropriate location in on-wire structure.
1957 #define VOLINT_INFO_STORE(handle, name, val) \
1959 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1960 (handle)->volinfo_ptr.base->name = (val); \
1962 (handle)->volinfo_ptr.ext->name = (val); \
1967 * get pointer to appropriate offset of field in on-wire structure.
1969 #define VOLINT_INFO_PTR(handle, name) \
1970 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1971 &((handle)->volinfo_ptr.base->name) : \
1972 &((handle)->volinfo_ptr.ext->name))
1975 * fill in appropriate type of on-wire volume metadata structure.
1977 * @param vp pointer to volume object
1978 * @param handle pointer to wire format handle object
1980 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1981 * @pre handle object must have a valid pointer and enumeration value
1983 * @note passing a NULL value for vp means that the fileserver doesn't
1984 * know about this particular volume, thus implying it is offline.
1986 * @return operation status
1991 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1993 unsigned int numStatBytes, now;
1994 struct VolumeDiskData *hdr = &(V_disk(vp));
1996 /*read in the relevant info */
1997 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1998 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1999 VOLINT_INFO_STORE(handle, volid, hdr->id);
2000 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2001 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2002 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2003 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2004 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2005 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2006 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2007 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2008 now = FT_ApproxTime();
2009 if ((now - hdr->dayUseDate) > OneDay) {
2010 VOLINT_INFO_STORE(handle, dayUse, 0);
2012 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2014 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2015 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2016 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2017 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2019 #ifdef AFS_DEMAND_ATTACH_FS
2021 * for DAFS, we "lie" about volume state --
2022 * instead of returning the raw state from the disk header,
2023 * we compute state based upon the fileserver's internal
2024 * in-core state enumeration value reported to us via fssync,
2025 * along with the blessed and inService flags from the header.
2026 * -- tkeiser 11/27/2007
2029 /* Conditions that offline status is based on:
2030 volume is unattached state
2031 volume state is in (one of several error states)
2032 volume not in service
2033 volume is not marked as blessed (not on hold)
2034 volume in salvage req. state
2035 volume needsSalvaged
2036 next op would set volume offline
2037 next op would not leave volume online (based on several conditions)
2040 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2041 VIsErrorState(V_attachState(vp)) ||
2044 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2045 hdr->needsSalvaged ||
2046 (vp->pending_vol_op &&
2047 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2048 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2051 VOLINT_INFO_STORE(handle, inUse, 0);
2053 VOLINT_INFO_STORE(handle, inUse, 1);
2056 /* offline status based on program type, where != fileServer enum (1) is offline */
2057 if (hdr->inUse == fileServer) {
2058 VOLINT_INFO_STORE(handle, inUse, 1);
2060 VOLINT_INFO_STORE(handle, inUse, 0);
2065 switch(handle->volinfo_type) {
2066 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2067 case VOLINT_INFO_TYPE_BASE:
2069 #ifdef AFS_DEMAND_ATTACH_FS
2070 /* see comment above where we set inUse bit */
2071 if (hdr->needsSalvaged ||
2072 (vp && VIsErrorState(V_attachState(vp)))) {
2073 handle->volinfo_ptr.base->needsSalvaged = 1;
2075 handle->volinfo_ptr.base->needsSalvaged = 0;
2078 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2080 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2081 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2082 handle->volinfo_ptr.base->spare1 =
2083 (long)hdr->weekUse[0] +
2084 (long)hdr->weekUse[1] +
2085 (long)hdr->weekUse[2] +
2086 (long)hdr->weekUse[3] +
2087 (long)hdr->weekUse[4] +
2088 (long)hdr->weekUse[5] +
2089 (long)hdr->weekUse[6];
2090 handle->volinfo_ptr.base->flags = 0;
2091 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2092 handle->volinfo_ptr.base->spare3 = 0;
2096 case VOLINT_INFO_TYPE_EXT:
2098 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2099 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2102 * Copy out the stat fields in a single operation.
2104 if ((now - hdr->dayUseDate) > OneDay) {
2105 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2108 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2109 (char *)&(hdr->stat_reads[0]),
2118 #ifdef AFS_DEMAND_ATTACH_FS
2121 * get struct Volume out of the fileserver.
2123 * @param[in] volumeId volumeId for which we want state information
2124 * @param[in] pname partition name string
2125 * @param[inout] vp pointer to pointer to Volume object which
2126 * will be populated (see note)
2128 * @return operation status
2130 * @retval non-zero failure
2132 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2137 GetVolObject(VolumeId volumeId, char * pname, Volume ** vp)
2142 res.hdr.response_len = sizeof(res.hdr);
2143 res.payload.buf = *vp;
2144 res.payload.len = sizeof(Volume);
2146 code = FSYNC_VolOp(volumeId,
2152 if (code != SYNC_OK) {
2153 switch (res.hdr.reason) {
2154 case FSYNC_WRONG_PART:
2155 case FSYNC_UNKNOWN_VOLID:
2168 * mode of volume list operation.
2171 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2172 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2173 } vol_info_list_mode_t;
2176 * abstract interface to populate wire-format volume metadata structures.
2178 * @param[in] partId partition id
2179 * @param[in] volumeId volume id
2180 * @param[in] pname partition name
2181 * @param[in] volname volume file name
2182 * @param[in] handle handle to on-wire volume metadata object
2183 * @param[in] mode listing mode
2185 * @return operation status
2187 * @retval -2 DESTROY_ME flag is set
2188 * @retval -1 general failure; some data filled in
2189 * @retval -3 couldn't create vtrans; some data filled in
2192 GetVolInfo(afs_uint32 partId,
2196 volint_info_handle_t * handle,
2197 vol_info_list_mode_t mode)
2201 struct volser_trans *ttc = NULL;
2202 struct Volume *fill_tv, *tv = NULL;
2203 #ifdef AFS_DEMAND_ATTACH_FS
2204 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2205 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2206 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2207 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2209 /* Set up response handle for pending_vol_op */
2210 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2211 fs_res.payload.buf = fs_res_buf;
2212 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2215 ttc = NewTrans(volumeId, partId);
2218 VOLINT_INFO_STORE(handle, status, VBUSY);
2219 VOLINT_INFO_STORE(handle, volid, volumeId);
2223 /* Get volume from volserver */
2224 if (mode == VOL_INFO_LIST_MULTIPLE)
2225 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2227 #ifdef AFS_DEMAND_ATTACH_FS
2230 int mode = V_READONLY; /* informs the fileserver to update the volume headers. */
2232 tv = VAttachVolumeByName_retry(&error, pname, volname, mode);
2236 Log("1 Volser: GetVolInfo: Could not attach volume %" AFS_VOLID_FMT " (%s:%s) error=%d\n",
2237 afs_printable_VolumeId_lu(volumeId), pname, volname, error);
2242 * please note that destroyMe and needsSalvaged checks used to be ordered
2243 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2244 * more correct to check destroyMe before needsSalvaged.
2245 * -- tkeiser 11/28/2007
2248 if (V_destroyMe(tv) == DESTROY_ME) {
2250 case VOL_INFO_LIST_MULTIPLE:
2254 case VOL_INFO_LIST_SINGLE:
2255 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) will be destroyed on next salvage\n",
2256 afs_printable_VolumeId_lu(volumeId), pname, volname);
2263 if (V_needsSalvaged(tv)) {
2264 /*this volume will be salvaged */
2265 Log("1 Volser: GetVolInfo: Volume %" AFS_VOLID_FMT " (%s:%s) needs to be salvaged\n",
2266 afs_printable_VolumeId_lu(volumeId), pname, volname);
2269 #ifdef AFS_DEMAND_ATTACH_FS
2270 /* If using DAFS, get volume from fsserver */
2271 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2276 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2277 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2278 /* If we if the pending vol op */
2279 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2280 fs_tv->pending_vol_op=&pending_vol_op_res;
2282 fs_tv->pending_vol_op=NULL;
2285 /* populate the header from the volserver copy */
2286 fs_tv->header=tv->header;
2288 /* When using DAFS, use the fs volume info, populated with required structures */
2291 /* When not using DAFS, just use the local volume info */
2295 /* ok, we have all the data we need; fill in the on-wire struct */
2296 code = FillVolInfo(fill_tv, handle);
2300 VOLINT_INFO_STORE(handle, status, 0);
2301 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2302 VOLINT_INFO_STORE(handle, volid, volumeId);
2305 VDetachVolume(&error, tv);
2308 VOLINT_INFO_STORE(handle, status, 0);
2309 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2310 Log("1 Volser: GetVolInfo: Could not detach volume %" AFS_VOLID_FMT " (%s:%s)\n",
2311 afs_printable_VolumeId_lu(volumeId), pname, volname);
2315 DeleteTrans(ttc, 1);
2322 /*return the header information about the <volid> */
2324 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2325 VolumeId volumeId, volEntries *volumeInfo)
2329 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2330 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2335 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2336 VolumeId volumeId, volEntries *volumeInfo)
2338 struct DiskPartition64 *partP;
2339 char pname[9], volname[20];
2343 volint_info_handle_t handle;
2345 volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2346 if (!volumeInfo->volEntries_val)
2349 volumeInfo->volEntries_len = 1;
2350 if (GetPartName(partid, pname))
2351 return VOLSERILLEGAL_PARTITION;
2352 if (!(partP = VGetPartition(pname, 0)))
2353 return VOLSERILLEGAL_PARTITION;
2354 dirp = opendir(VPartitionPath(partP));
2356 return VOLSERILLEGAL_PARTITION;
2358 while (GetNextVol(dirp, volname, &volid)) {
2359 if (volid == volumeId) { /*copy other things too */
2366 #ifndef AFS_PTHREAD_ENV
2367 IOMGR_Poll(); /*make sure that the client does not time out */
2370 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2371 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2373 /* The return code from GetVolInfo is ignored; there is no error from
2374 * it that results in the whole call being aborted. Any volume
2375 * attachment failures are reported in 'status' field in the
2376 * volumeInfo payload. */
2382 VOL_INFO_LIST_SINGLE);
2386 return (found) ? 0 : ENODEV;
2389 /*------------------------------------------------------------------------
2390 * EXPORTED SAFSVolXListOneVolume
2393 * Returns extended info on volume a_volID on partition a_partID.
2396 * a_rxCidP : Pointer to the Rx call we're performing.
2397 * a_partID : Partition for which we want the extended list.
2398 * a_volID : Volume ID we wish to know about.
2399 * a_volumeXInfoP : Ptr to the extended info blob.
2402 * 0 Successful operation
2403 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2406 * Nothing interesting.
2410 *------------------------------------------------------------------------*/
2413 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2414 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2418 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2419 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2424 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2425 VolumeId a_volID, volXEntries *a_volumeXInfoP)
2426 { /*SAFSVolXListOneVolume */
2428 struct DiskPartition64 *partP; /*Ptr to partition */
2429 char pname[9], volname[20]; /*Partition, volume names */
2430 DIR *dirp; /*Partition directory ptr */
2431 VolumeId currVolID; /*Current volume ID */
2432 int found = 0; /*Did we find the volume we need? */
2433 volint_info_handle_t handle;
2436 * Set up our pointers for action, marking our structure to hold exactly
2437 * one entry. Also, assume we'll fail in our quest.
2439 a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2440 if (!a_volumeXInfoP->volXEntries_val)
2443 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 */
2480 #ifndef AFS_PTHREAD_ENV
2484 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2485 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2487 /* The return code from GetVolInfo is ignored; there is no error from
2488 * it that results in the whole call being aborted. Any volume
2489 * attachment failures are reported in 'status' field in the
2490 * volumeInfo payload. */
2491 GetVolInfo(a_partID,
2496 VOL_INFO_LIST_SINGLE);
2500 * Clean up before going to dinner: close the partition directory,
2501 * return the proper value.
2504 return (found) ? 0 : ENODEV;
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);