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>
20 #include <afs/afsint.h>
21 #include <afs/prs_fs.h>
25 #include <afs/cellconfig.h>
28 #include <afs/ihandle.h>
30 #include <afs/ntops.h>
32 #include <afs/vnode.h>
33 #include <afs/volume.h>
34 #include <afs/volume_inline.h>
35 #include <afs/partition.h>
37 #include <afs/daemon_com.h>
38 #include <afs/fssync.h>
40 #include "afs/audit.h"
42 #include <afs/afsutil.h>
43 #include <afs/com_err.h>
44 #include <afs/vol_prototypes.h>
45 #include <afs/errors.h>
48 #include "voltrans_inline.h"
51 #include "volser_internal.h"
53 #include "dumpstuff.h"
56 extern struct afsconf_dir *tdir;
58 extern void LogError(afs_int32 errcode);
60 /* Forward declarations */
61 static int GetPartName(afs_int32 partid, char *pname);
63 #define OneDay (24*60*60)
69 afs_int32 localTid = 1;
71 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
72 struct diskPartition64 *);
73 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
74 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
75 afs_int32, afs_uint32, afs_uint32 *,
77 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
78 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
79 afs_int32, char *, afs_uint32 *);
80 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
81 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
82 afs_int32, afs_int32 *);
83 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
85 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
86 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
87 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
88 struct destServer *destination, afs_int32,
89 struct restoreCookie *cookie);
90 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
91 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
92 struct restoreCookie *);
93 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
94 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
95 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
96 struct volser_status *);
97 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
98 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
99 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
100 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
101 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
103 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
105 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
107 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
109 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
110 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
111 afs_int32, afs_uint32, afs_uint32,
113 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
116 * Return the host address of the caller as a string.
118 * @param[in] acid incoming rx call
119 * @param[out] buffer buffer to be filled with the addess string
121 * @return address as formatted by inet_ntoa
124 callerAddress(struct rx_call *acid, char *buffer)
126 afs_uint32 ip = rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid)));
127 return afs_inet_ntoa_r(ip, buffer);
130 /* this call unlocks all of the partition locks we've set */
134 struct DiskPartition64 *tp;
135 for (tp = DiskPartitionList; tp; tp = tp->next) {
136 if (tp->lock_fd != INVALID_FD) {
137 OS_CLOSE(tp->lock_fd);
138 tp->lock_fd = INVALID_FD;
149 code = VPFullUnlock_r();
154 /* get partition id from a name */
156 PartitionID(char *aname)
164 return -1; /* unknown */
166 /* otherwise check for vicepa or /vicepa, or just plain "a" */
168 if (!strncmp(aname, "/vicep", 6)) {
169 strncpy(ascii, aname + 6, 2);
171 return -1; /* bad partition name */
172 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
173 * from 0. Do the appropriate conversion */
175 /* one char name, 0..25 */
176 if (ascii[0] < 'a' || ascii[0] > 'z')
177 return -1; /* wrongo */
178 return ascii[0] - 'a';
180 /* two char name, 26 .. <whatever> */
181 if (ascii[0] < 'a' || ascii[0] > 'z')
182 return -1; /* wrongo */
183 if (ascii[1] < 'a' || ascii[1] > 'z')
184 return -1; /* just as bad */
185 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
186 if (code > VOLMAXPARTS)
193 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
197 /* 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 */
198 snprintf(aname, asize, VFORMAT, (unsigned long)avol);
203 ConvertPartition(int apartno, char *aname, int asize)
209 strcpy(aname, "/vicep");
211 aname[6] = 'a' + apartno;
215 aname[6] = 'a' + (apartno / 26);
216 aname[7] = 'a' + (apartno % 26);
222 #ifdef AFS_DEMAND_ATTACH_FS
223 /* normally we should use the regular salvaging functions from the volume
224 * package, but this is a special case where we have a volume ID, but no
225 * volume structure to give the volume package */
227 SalvageUnknownVolume(VolumeId volid, char *part)
231 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
232 afs_printable_uint32_lu(volid), part);
234 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
235 FSYNC_SALVAGE, NULL);
237 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
238 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
242 #endif /* AFS_DEMAND_ATTACH_FS */
244 static struct Volume *
245 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
250 vp = VAttachVolumeByName(ec, partition, name, mode);
252 #ifdef AFS_DEMAND_ATTACH_FS
256 * The fileserver will take care of keeping track of how many
257 * demand-salvages have been performed, and will force the volume to
258 * ERROR if we've done too many. The limit on This loop is just a
259 * failsafe to prevent trying to salvage forever. We want to attempt
260 * attachment at least SALVAGE_COUNT_MAX times, since we want to
261 * avoid prematurely exiting this loop, if we can.
263 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
264 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
265 vp = VAttachVolumeByName(ec, partition, name, mode);
268 if (*ec == VSALVAGING) {
272 #endif /* AFS_DEMAND_ATTACH_FS */
277 static struct Volume *
278 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
283 vp = VAttachVolume(ec, avolid, amode);
285 #ifdef AFS_DEMAND_ATTACH_FS
288 /* see comment above in VAttachVolumeByName_retry */
289 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
290 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
291 vp = VAttachVolume(ec, avolid, amode);
294 if (*ec == VSALVAGING) {
298 #endif /* AFS_DEMAND_ATTACH_FS */
303 /* the only attach function that takes a partition is "...ByName", so we use it */
304 static struct Volume *
305 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
307 char pbuf[30], vbuf[20];
309 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
313 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
318 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
321 /* Adapted from the file server; create a root directory for this volume */
323 ViceCreateRoot(Volume *vp)
326 struct acl_accessList *ACL;
328 Inode inodeNumber, AFS_UNUSED nearInode;
329 struct VnodeDiskObject *vnode;
330 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
336 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
339 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
341 V_pref(vp, nearInode);
343 IH_CREATE(V_linkHandle(vp), V_device(vp),
344 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
346 if (!VALID_INO(inodeNumber)) {
347 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
352 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
353 did.Volume = V_id(vp);
354 did.Vnode = (VnodeId) 1;
357 osi_Assert(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
358 DFlush(); /* flush all modified dir buffers out */
359 DZap(&dir); /* Remove all buffers for this dir */
360 length = afs_dir_Length(&dir); /* Remember size of this directory */
362 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
364 /* build a single entry ACL that gives all rights to system:administrators */
365 /* this section of code assumes that access list format is not going to
368 ACL = VVnodeDiskACL(vnode);
369 ACL->size = sizeof(struct acl_accessList);
370 ACL->version = ACL_ACLVERSION;
374 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
375 ACL->entries[0].rights =
376 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
377 | PRSFS_LOCK | PRSFS_ADMINISTER;
379 vnode->type = vDirectory;
381 vnode->modeBits = 0777;
382 vnode->linkCount = 2;
383 VNDISK_SET_LEN(vnode, length);
384 vnode->uniquifier = 1;
385 V_uniquifier(vp) = vnode->uniquifier + 1;
386 vnode->dataVersion = 1;
387 VNDISK_SET_INO(vnode, inodeNumber);
388 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
392 vnode->vnodeMagic = vcp->magic;
394 IH_INIT(h, vp->device, V_parentId(vp),
395 vp->vnodeIndex[vLarge].handle->ih_ino);
397 osi_Assert(fdP != NULL);
398 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
399 osi_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
400 FDH_REALLYCLOSE(fdP);
402 VNDISK_GET_LEN(length, vnode);
403 V_diskused(vp) = nBlocks(length);
410 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
414 struct diskPartition64 *dp = (struct diskPartition64 *)
415 malloc(sizeof(struct diskPartition64));
417 code = VolPartitionInfo(acid, pname, dp);
419 strncpy(partition->name, dp->name, 32);
420 strncpy(partition->devName, dp->devName, 32);
421 partition->lock_fd = dp->lock_fd;
422 partition->free=RoundInt64ToInt32(dp->free);
423 partition->minFree=RoundInt64ToInt32(dp->minFree);
426 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
431 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
436 code = VolPartitionInfo(acid, pname, partition);
437 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
442 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
445 struct DiskPartition64 *dp;
448 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
451 dp = VGetPartition(pname, 0);
453 strncpy(partition->name, dp->name, 32);
454 strncpy(partition->devName, dp->devName, 32);
455 partition->lock_fd = (int)dp->lock_fd;
456 partition->free = dp->free;
457 partition->minFree = dp->totalUsable;
460 return VOLSERILLEGAL_PARTITION;
463 /* obliterate a volume completely, and slowly. */
465 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
469 code = VolNukeVolume(acid, apartID, avolID);
470 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
475 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
482 char caller[MAXKTCNAMELEN];
484 /* check for access */
485 if (!afsconf_SuperUser(tdir, acid, caller))
486 return VOLSERBAD_ACCESS;
489 Log("%s on %s is executing VolNukeVolume %u\n", caller,
490 callerAddress(acid, buffer), avolID);
493 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
495 /* we first try to attach the volume in update mode, so that the file
496 * server doesn't try to use it (and abort) while (or after) we delete it.
497 * If we don't get the volume, that's fine, too. We just won't put it back.
499 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
500 code = nuke(partName, avolID);
502 VDetachVolume(&verror, tvp);
506 /* create a new volume, with name aname, on the specified partition (1..n)
507 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
508 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
509 * for the volume id (useful for things like volume restore).
510 * Return the new volume id in *avolid.
513 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
514 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
520 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
521 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
522 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
528 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
529 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
534 Error junk; /* discardable error code */
536 afs_int32 doCreateRoot = 1;
537 struct volser_trans *tt;
539 char caller[MAXKTCNAMELEN];
541 if (strlen(aname) > 31)
542 return VOLSERBADNAME;
543 if (!afsconf_SuperUser(tdir, acid, caller))
544 return VOLSERBAD_ACCESS;
547 Log("%s on %s is executing CreateVolume '%s'\n", caller,
548 callerAddress(acid, buffer), aname);
550 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
551 return error; /*a standard unix error */
552 if (atype != readwriteVolume && atype != readonlyVolume
553 && atype != backupVolume)
555 if ((volumeID = *avolid) == 0) {
557 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
561 if ((aparent == volumeID) && (atype == readwriteVolume)) {
566 tt = NewTrans(volumeID, apart);
568 Log("1 createvolume: failed to create trans\n");
569 return VOLSERVOLBUSY; /* volume already busy! */
571 vp = VCreateVolume(&error, ppath, volumeID, aparent);
573 #ifdef AFS_DEMAND_ATTACH_FS
574 if (error != VVOLEXISTS && error != EXDEV) {
575 SalvageUnknownVolume(volumeID, ppath);
578 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
583 V_uniquifier(vp) = 1;
584 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
585 V_inService(vp) = V_blessed(vp) = 1;
587 AssignVolumeName(&V_disk(vp), aname, 0);
589 error = ViceCreateRoot(vp);
591 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
592 "error code %u\n", (unsigned)error);
594 V_needsSalvaged(vp) = 1;
595 VDetachVolume(&junk, vp);
599 V_destroyMe(vp) = DESTROY_ME;
601 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
602 VUpdateVolume(&error, vp);
604 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
607 VDetachVolume(&junk, vp); /* rather return the real error code */
613 TSetRxCall_r(tt, acid, "CreateVolume");
614 VTRANS_OBJ_UNLOCK(tt);
615 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
618 return VOLSERTRELE_ERROR;
622 /* delete the volume associated with this transaction */
624 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
628 code = VolDeleteVolume(acid, atrans);
629 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
634 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
636 struct volser_trans *tt;
638 char caller[MAXKTCNAMELEN];
640 if (!afsconf_SuperUser(tdir, acid, caller))
641 return VOLSERBAD_ACCESS;
642 tt = FindTrans(atrans);
645 if (tt->vflags & VTDeleted) {
646 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
652 Log("%s on %s is executing Delete Volume %u\n", caller,
653 callerAddress(acid, buffer), tt->volid);
655 TSetRxCall(tt, acid, "DeleteVolume");
656 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
657 V_destroyMe(tt->volume) = DESTROY_ME;
658 if (tt->volume->needsPutBack) {
659 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
662 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
664 VTRANS_OBJ_UNLOCK(tt);
666 return VOLSERTRELE_ERROR;
668 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
669 return 0; /* vpurgevolume doesn't set an error code */
672 /* make a clone of the volume associated with atrans, possibly giving it a new
673 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
674 * for the clone's id). The new clone is given the name newName. Finally,
675 * due to efficiency considerations, if purgeId is non-zero, we purge that
676 * volume when doing the clone operation. This may be useful when making
677 * new backup volumes, for instance since the net result of a clone and a
678 * purge generally leaves many inode ref counts the same, while doing them
679 * separately would result in far more iincs and idecs being peformed
680 * (and they are slow operations).
682 /* for efficiency reasons, sometimes faster to piggyback a purge here */
684 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
685 afs_int32 newType, char *newName, afs_uint32 *newNumber)
689 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
690 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
691 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
697 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
698 afs_int32 newType, char *newName, afs_uint32 *newNumber)
701 struct Volume *originalvp, *purgevp, *newvp;
703 struct volser_trans *tt, *ttc;
704 char caller[MAXKTCNAMELEN];
705 #ifdef AFS_DEMAND_ATTACH_FS
706 struct Volume *salv_vp = NULL;
709 if (strlen(newName) > 31)
710 return VOLSERBADNAME;
711 if (!afsconf_SuperUser(tdir, acid, caller))
712 return VOLSERBAD_ACCESS; /*not a super user */
715 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
716 callerAddress(acid, buffer), newName);
719 originalvp = (Volume *) 0;
720 purgevp = (Volume *) 0;
721 newvp = (Volume *) 0;
722 tt = ttc = (struct volser_trans *)0;
724 if (!newNumber || !*newNumber) {
725 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
730 tt = FindTrans(atrans);
733 if (tt->vflags & VTDeleted) {
734 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
738 ttc = NewTrans(newId, tt->partition);
739 if (!ttc) { /* someone is messing with the clone already */
741 return VOLSERVOLBUSY;
743 TSetRxCall(tt, acid, "Clone");
747 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
749 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
755 originalvp = tt->volume;
756 if ((V_type(originalvp) == backupVolume)
757 || (V_type(originalvp) == readonlyVolume)) {
758 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
762 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
763 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
769 if (originalvp->device != purgevp->device) {
770 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
774 if (V_type(purgevp) != readonlyVolume) {
775 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
779 if (V_parentId(originalvp) != V_parentId(purgevp)) {
780 Log("1 Volser: Clone: Volume %u and volume %u were not originally cloned from the same parent; aborted\n", purgeId, tt->volid);
787 #ifdef AFS_DEMAND_ATTACH_FS
788 salv_vp = originalvp;
792 VCreateVolume(&error, originalvp->partition->name, newId,
793 V_parentId(originalvp));
795 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
796 newvp = (Volume *) 0;
799 if (newType == readonlyVolume)
800 V_cloneId(originalvp) = newId;
801 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
804 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
805 CloneVolume(&error, originalvp, newvp, purgevp);
806 purgevp = NULL; /* clone releases it, maybe even if error */
808 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
812 if (newType == readonlyVolume) {
813 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
814 V_type(newvp) = readonlyVolume;
815 } else if (newType == backupVolume) {
816 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
817 V_type(newvp) = backupVolume;
818 V_backupId(originalvp) = newId;
820 strcpy(newvp->header->diskstuff.name, newName);
821 V_creationDate(newvp) = V_copyDate(newvp);
822 ClearVolumeStats(&V_disk(newvp));
823 V_destroyMe(newvp) = DESTROY_ME;
824 V_inService(newvp) = 0;
825 if (newType == backupVolume) {
826 V_backupDate(originalvp) = V_copyDate(newvp);
827 V_backupDate(newvp) = V_copyDate(newvp);
830 VUpdateVolume(&error, newvp);
832 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
836 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
838 VUpdateVolume(&error, originalvp);
840 Log("1 Volser: Clone: original update %u\n", error);
845 #ifdef AFS_DEMAND_ATTACH_FS
849 tt = (struct volser_trans *)0;
850 error = VOLSERTRELE_ERROR;
858 VDetachVolume(&code, purgevp);
860 VDetachVolume(&code, newvp);
867 #ifdef AFS_DEMAND_ATTACH_FS
868 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
869 V_needsSalvaged(salv_vp) = 1;
871 #endif /* AFS_DEMAND_ATTACH_FS */
875 /* reclone this volume into the specified id */
877 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
881 code = VolReClone(acid, atrans, cloneId);
882 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
888 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
890 struct Volume *originalvp, *clonevp;
893 struct volser_trans *tt, *ttc;
894 char caller[MAXKTCNAMELEN];
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 %u\n", caller,
902 callerAddress(acid, buffer), cloneId);
905 clonevp = originalvp = (Volume *) 0;
906 tt = (struct volser_trans *)0;
908 tt = FindTrans(atrans);
911 if (tt->vflags & VTDeleted) {
912 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
916 ttc = NewTrans(cloneId, tt->partition);
917 if (!ttc) { /* someone is messing with the clone already */
919 return VOLSERVOLBUSY;
921 TSetRxCall(tt, acid, "ReClone");
923 originalvp = tt->volume;
924 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
925 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
931 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
933 Log("1 Volser: can't attach clone %d\n", cloneId);
937 newType = V_type(clonevp); /* type of the new volume */
939 if (originalvp->device != clonevp->device) {
940 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
945 if (V_parentId(originalvp) != V_parentId(clonevp)) {
946 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
952 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
954 CloneVolume(&error, originalvp, clonevp, clonevp);
956 Log("1 Volser: Clone: reclone operation failed with code %d\n",
962 /* fix up volume name and type, CloneVolume just propagated RW's */
963 if (newType == readonlyVolume) {
964 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
965 V_type(clonevp) = readonlyVolume;
966 } else if (newType == backupVolume) {
967 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
968 V_type(clonevp) = backupVolume;
969 V_backupId(originalvp) = cloneId;
971 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
973 /* pretend recloned volume is a totally new instance */
974 V_copyDate(clonevp) = time(0);
975 V_creationDate(clonevp) = V_copyDate(clonevp);
976 ClearVolumeStats(&V_disk(clonevp));
977 V_destroyMe(clonevp) = 0;
978 V_inService(clonevp) = 0;
979 if (newType == backupVolume) {
980 V_backupDate(originalvp) = V_copyDate(clonevp);
981 V_backupDate(clonevp) = V_copyDate(clonevp);
983 V_inUse(clonevp) = 0;
984 VUpdateVolume(&error, clonevp);
986 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
990 /* VUpdateVolume succeeded. Mark it in service so there's no window
991 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
992 * specialStatus; this is a reclone and this volume started online
994 V_inService(clonevp) = 1;
995 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
997 VUpdateVolume(&error, originalvp);
999 Log("1 Volser: Clone: original update %u\n", error);
1005 tt = (struct volser_trans *)0;
1006 error = VOLSERTRELE_ERROR;
1010 DeleteTrans(ttc, 1);
1013 struct DiskPartition64 *tpartp = originalvp->partition;
1014 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1020 VDetachVolume(&code, clonevp);
1026 DeleteTrans(ttc, 1);
1030 /* create a new transaction, associated with volume and partition. Type of
1031 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1032 * See volser.h for definition of iflags (the constants are named IT*).
1035 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1036 afs_int32 iflags, afs_int32 *ttid)
1040 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1041 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1047 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1048 afs_int32 iflags, afs_int32 *ttid)
1050 struct volser_trans *tt;
1055 char caller[MAXKTCNAMELEN];
1057 if (!afsconf_SuperUser(tdir, acid, caller))
1058 return VOLSERBAD_ACCESS; /*not a super user */
1059 if (iflags & ITCreate)
1061 else if (iflags & ITBusy)
1063 else if (iflags & ITReadOnly)
1065 else if (iflags & ITOffline)
1068 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1073 tt = NewTrans(volume, partition);
1075 /* can't create a transaction? put the volume back */
1076 Log("1 transcreate: can't create transaction\n");
1077 return VOLSERVOLBUSY;
1079 tv = XAttachVolume(&error, volume, partition, mode);
1083 VDetachVolume(&code, tv);
1087 VTRANS_OBJ_LOCK(tt);
1090 tt->iflags = iflags;
1092 TSetRxCall_r(tt, NULL, "TransCreate");
1093 VTRANS_OBJ_UNLOCK(tt);
1095 return VOLSERTRELE_ERROR;
1100 /* using aindex as a 0-based index, return the aindex'th volume on this server
1101 * Both the volume number and partition number (one-based) are returned.
1104 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1109 code = VolGetNthVolume(acid, aindex, avolume, apart);
1110 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1115 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1118 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1122 /* return the volume flags (VT* constants in volser.h) associated with this
1126 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1130 code = VolGetFlags(acid, atid, aflags);
1131 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1136 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1138 struct volser_trans *tt;
1140 tt = FindTrans(atid);
1143 if (tt->vflags & VTDeleted) {
1144 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1149 TSetRxCall(tt, acid, "GetFlags");
1150 *aflags = tt->vflags;
1153 return VOLSERTRELE_ERROR;
1158 /* Change the volume flags (VT* constants in volser.h) associated with this
1159 * transaction. Effects take place immediately on volume, although volume
1160 * remains attached as usual by the transaction.
1163 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1167 code = VolSetFlags(acid, atid, aflags);
1168 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1174 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1176 struct volser_trans *tt;
1179 char caller[MAXKTCNAMELEN];
1181 if (!afsconf_SuperUser(tdir, acid, caller))
1182 return VOLSERBAD_ACCESS; /*not a super user */
1183 /* find the trans */
1184 tt = FindTrans(atid);
1187 if (tt->vflags & VTDeleted) {
1188 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1193 TSetRxCall(tt, acid, "SetFlags");
1194 vp = tt->volume; /* pull volume out of transaction */
1196 /* check if we're allowed to make any updates */
1197 if (tt->iflags & ITReadOnly) {
1202 /* handle delete-on-salvage flag */
1203 if (aflags & VTDeleteOnSalvage) {
1204 V_destroyMe(tt->volume) = DESTROY_ME;
1206 V_destroyMe(tt->volume) = 0;
1209 if (aflags & VTOutOfService) {
1210 V_inService(vp) = 0;
1212 V_inService(vp) = 1;
1214 VUpdateVolume(&error, vp);
1215 VTRANS_OBJ_LOCK(tt);
1216 tt->vflags = aflags;
1218 VTRANS_OBJ_UNLOCK(tt);
1219 if (TRELE(tt) && !error)
1220 return VOLSERTRELE_ERROR;
1225 /* dumpS the volume associated with a particular transaction from a particular
1226 * date. Send the dump to a different transaction (destTrans) on the server
1227 * specified by the destServer structure.
1230 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1231 struct destServer *destination, afs_int32 destTrans,
1232 struct restoreCookie *cookie)
1237 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1238 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1239 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1244 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1245 struct destServer *destination, afs_int32 destTrans,
1246 struct restoreCookie *cookie)
1248 struct volser_trans *tt;
1250 struct rx_connection *tcon;
1251 struct rx_call *tcall;
1253 struct rx_securityClass *securityObject;
1254 afs_int32 securityIndex;
1255 char caller[MAXKTCNAMELEN];
1257 if (!afsconf_SuperUser(tdir, acid, caller))
1258 return VOLSERBAD_ACCESS; /*not a super user */
1259 /* initialize things */
1260 tcon = (struct rx_connection *)0;
1261 tt = (struct volser_trans *)0;
1263 /* find the local transaction */
1264 tt = FindTrans(fromTrans);
1267 if (tt->vflags & VTDeleted) {
1268 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1273 TSetRxCall(tt, NULL, "Forward");
1275 /* get auth info for the this connection (uses afs from ticket file) */
1276 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1282 /* make an rpc connection to the other server */
1284 rx_NewConnection(htonl(destination->destHost),
1285 htons(destination->destPort), VOLSERVICE_ID,
1286 securityObject, securityIndex);
1292 tcall = rx_NewCall(tcon);
1293 TSetRxCall(tt, tcall, "Forward");
1294 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1295 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1300 /* these next calls implictly call rx_Write when writing out data */
1301 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1304 EndAFSVolRestore(tcall); /* probably doesn't do much */
1306 code = rx_EndCall(tcall, 0);
1307 rx_DestroyConnection(tcon); /* done with the connection */
1312 return VOLSERTRELE_ERROR;
1318 (void)rx_EndCall(tcall, 0);
1319 rx_DestroyConnection(tcon);
1328 /* Start a dump and send it to multiple places simultaneously.
1329 * If this returns an error (eg, return ENOENT), it means that
1330 * none of the releases worked. If this returns 0, that means
1331 * that one or more of the releases worked, and the caller has
1332 * to examine the results array to see which one(s).
1333 * This will only do EITHER incremental or full, not both, so it's
1334 * the caller's responsibility to be sure that all the destinations
1335 * need just an incremental (and from the same time), if that's
1339 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1340 fromDate, manyDests *destinations, afs_int32 spare,
1341 struct restoreCookie *cookie, manyResults *results)
1343 afs_int32 securityIndex;
1344 struct rx_securityClass *securityObject;
1345 char caller[MAXKTCNAMELEN];
1346 struct volser_trans *tt;
1347 afs_int32 ec, code, *codes;
1348 struct rx_connection **tcons;
1349 struct rx_call **tcalls;
1351 int i, is_incremental;
1354 memset(results, 0, sizeof(manyResults));
1355 i = results->manyResults_len = destinations->manyDests_len;
1356 results->manyResults_val = codes =
1357 (afs_int32 *) malloc(i * sizeof(afs_int32));
1359 if (!results || !results->manyResults_val)
1362 if (!afsconf_SuperUser(tdir, acid, caller))
1363 return VOLSERBAD_ACCESS; /*not a super user */
1364 tt = FindTrans(fromTrans);
1367 if (tt->vflags & VTDeleted) {
1368 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1373 TSetRxCall(tt, NULL, "ForwardMulti");
1375 /* (fromDate == 0) ==> full dump */
1376 is_incremental = (fromDate ? 1 : 0);
1379 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1383 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1389 /* get auth info for this connection (uses afs from ticket file) */
1390 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1392 goto fail; /* in order to audit each failure */
1395 /* make connections to all the other servers */
1396 for (i = 0; i < destinations->manyDests_len; i++) {
1397 struct replica *dest = &(destinations->manyDests_val[i]);
1399 rx_NewConnection(htonl(dest->server.destHost),
1400 htons(dest->server.destPort), VOLSERVICE_ID,
1401 securityObject, securityIndex);
1403 codes[i] = ENOTCONN;
1405 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1406 codes[i] = ENOTCONN;
1409 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1412 (void)rx_EndCall(tcalls[i], 0);
1414 rx_DestroyConnection(tcons[i]);
1421 /* these next calls implictly call rx_Write when writing out data */
1422 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1426 for (i--; i >= 0; i--) {
1427 struct replica *dest = &(destinations->manyDests_val[i]);
1429 if (!code && tcalls[i] && !codes[i]) {
1430 EndAFSVolRestore(tcalls[i]);
1433 ec = rx_EndCall(tcalls[i], 0);
1438 rx_DestroyConnection(tcons[i]); /* done with the connection */
1441 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1442 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1443 dest->trans, AUD_END);
1450 if (TRELE(tt) && !code) /* return the first code if it's set */
1451 return VOLSERTRELE_ERROR;
1458 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1462 code = VolDump(acid, fromTrans, fromDate, 0);
1463 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1468 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1473 code = VolDump(acid, fromTrans, fromDate, flags);
1474 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1479 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1483 struct volser_trans *tt;
1484 char caller[MAXKTCNAMELEN];
1486 if (!afsconf_SuperUser(tdir, acid, caller))
1487 return VOLSERBAD_ACCESS; /*not a super user */
1488 tt = FindTrans(fromTrans);
1491 if (tt->vflags & VTDeleted) {
1492 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1496 TSetRxCall(tt, acid, "Dump");
1497 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1498 ? 0 : 1); /* squirt out the volume's data, too */
1507 return VOLSERTRELE_ERROR;
1513 * Ha! No more helper process!
1516 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1517 struct restoreCookie *cookie)
1521 code = VolRestore(acid, atrans, aflags, cookie);
1522 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1527 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1528 struct restoreCookie *cookie)
1530 struct volser_trans *tt;
1531 afs_int32 code, tcode;
1532 char caller[MAXKTCNAMELEN];
1534 if (!afsconf_SuperUser(tdir, acid, caller))
1535 return VOLSERBAD_ACCESS; /*not a super user */
1536 tt = FindTrans(atrans);
1539 if (tt->vflags & VTDeleted) {
1540 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1544 TSetRxCall(tt, acid, "Restore");
1546 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1548 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1549 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1553 return (code ? code : tcode);
1556 /* end a transaction, returning the transaction's final error code in rcode */
1558 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1562 code = VolEndTrans(acid, destTrans, rcode);
1563 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1568 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1570 struct volser_trans *tt;
1571 char caller[MAXKTCNAMELEN];
1573 if (!afsconf_SuperUser(tdir, acid, caller))
1574 return VOLSERBAD_ACCESS; /*not a super user */
1575 tt = FindTrans(destTrans);
1579 *rcode = tt->returnCode;
1580 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1586 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1590 code = VolSetForwarding(acid, atid, anewsite);
1591 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1592 htonl(anewsite), AUD_END);
1597 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1599 struct volser_trans *tt;
1600 char caller[MAXKTCNAMELEN];
1603 if (!afsconf_SuperUser(tdir, acid, caller))
1604 return VOLSERBAD_ACCESS; /*not a super user */
1605 tt = FindTrans(atid);
1608 if (tt->vflags & VTDeleted) {
1609 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1614 TSetRxCall(tt, acid, "SetForwarding");
1615 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1618 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1621 return VOLSERTRELE_ERROR;
1627 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1628 struct volser_status *astatus)
1632 code = VolGetStatus(acid, atrans, astatus);
1633 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1638 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1639 struct volser_status *astatus)
1642 struct VolumeDiskData *td;
1643 struct volser_trans *tt;
1646 tt = FindTrans(atrans);
1649 if (tt->vflags & VTDeleted) {
1650 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1655 TSetRxCall(tt, acid, "GetStatus");
1663 td = &tv->header->diskstuff;
1664 astatus->volID = td->id;
1665 astatus->nextUnique = td->uniquifier;
1666 astatus->type = td->type;
1667 astatus->parentID = td->parentId;
1668 astatus->cloneID = td->cloneId;
1669 astatus->backupID = td->backupId;
1670 astatus->restoredFromID = td->restoredFromId;
1671 astatus->maxQuota = td->maxquota;
1672 astatus->minQuota = td->minquota;
1673 astatus->owner = td->owner;
1674 astatus->creationDate = td->creationDate;
1675 astatus->accessDate = td->accessDate;
1676 astatus->updateDate = td->updateDate;
1677 astatus->expirationDate = td->expirationDate;
1678 astatus->backupDate = td->backupDate;
1679 astatus->copyDate = td->copyDate;
1682 return VOLSERTRELE_ERROR;
1688 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1689 struct volintInfo *astatus)
1693 code = VolSetInfo(acid, atrans, astatus);
1694 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1699 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1700 struct volintInfo *astatus)
1703 struct VolumeDiskData *td;
1704 struct volser_trans *tt;
1705 char caller[MAXKTCNAMELEN];
1708 if (!afsconf_SuperUser(tdir, acid, caller))
1709 return VOLSERBAD_ACCESS; /*not a super user */
1710 tt = FindTrans(atrans);
1713 if (tt->vflags & VTDeleted) {
1714 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1718 TSetRxCall(tt, acid, "SetStatus");
1726 td = &tv->header->diskstuff;
1728 * Add more fields as necessary
1730 if (astatus->maxquota != -1)
1731 td->maxquota = astatus->maxquota;
1732 if (astatus->dayUse != -1)
1733 td->dayUse = astatus->dayUse;
1734 if (astatus->creationDate != -1)
1735 td->creationDate = astatus->creationDate;
1736 if (astatus->updateDate != -1)
1737 td->updateDate = astatus->updateDate;
1738 if (astatus->spare2 != -1)
1739 td->volUpdateCounter = (unsigned int)astatus->spare2;
1740 VUpdateVolume(&error, tv);
1743 return VOLSERTRELE_ERROR;
1749 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1753 code = VolGetName(acid, atrans, aname);
1754 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1759 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1762 struct VolumeDiskData *td;
1763 struct volser_trans *tt;
1766 /* We need to at least fill it in */
1767 *aname = (char *)malloc(1);
1770 tt = FindTrans(atrans);
1773 if (tt->vflags & VTDeleted) {
1774 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1778 TSetRxCall(tt, acid, "GetName");
1786 td = &tv->header->diskstuff;
1787 len = strlen(td->name) + 1; /* don't forget the null */
1793 *aname = (char *)realloc(*aname, len);
1794 strcpy(*aname, td->name);
1797 return VOLSERTRELE_ERROR;
1802 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1805 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1806 afs_uint32 parentId, afs_uint32 cloneId)
1812 /*return a list of all partitions on the server. The non mounted
1813 *partitions are returned as -1 in the corresponding slot in partIds*/
1815 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1819 code = VolListPartitions(acid, partIds);
1820 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1825 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1830 strcpy(namehead, "/vicep"); /*7 including null terminator */
1832 /* Just return attached partitions. */
1834 for (i = 0; i < 26; i++) {
1835 namehead[6] = i + 'a';
1836 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1842 /*return a list of all partitions on the server. The non mounted
1843 *partitions are returned as -1 in the corresponding slot in partIds*/
1845 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1849 code = XVolListPartitions(acid, pEntries);
1850 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1855 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1858 struct partList partList;
1859 struct DiskPartition64 *dp;
1862 strcpy(namehead, "/vicep"); /*7 including null terminator */
1864 /* Only report attached partitions */
1865 for (i = 0; i < VOLMAXPARTS; i++) {
1866 #ifdef AFS_DEMAND_ATTACH_FS
1867 dp = VGetPartitionById(i, 0);
1870 namehead[6] = i + 'a';
1876 namehead[6] = 'a' + (k / 26);
1877 namehead[7] = 'a' + (k % 26);
1880 dp = VGetPartition(namehead, 0);
1883 partList.partId[j++] = i;
1886 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1887 if (!pEntries->partEntries_val)
1889 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1891 pEntries->partEntries_len = j;
1893 pEntries->partEntries_val = NULL;
1894 pEntries->partEntries_len = 0;
1900 /*return the name of the next volume header in the directory associated with dirp and dp.
1901 *the volume id is returned in volid, and volume header name is returned in volname*/
1903 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1907 dp = readdir(dirp); /*read next entry in the directory */
1909 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1910 *volid = VolumeNumber(dp->d_name);
1911 strcpy(volname, dp->d_name);
1912 return 0; /*return the name of the file representing a volume */
1914 strcpy(volname, "");
1915 return 0; /*volname doesnot represent a volume */
1918 strcpy(volname, "EOD");
1919 return 0; /*end of directory */
1925 * volint vol info structure type.
1928 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1929 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1930 } volint_info_type_t;
1933 * handle to various on-wire vol info types.
1936 volint_info_type_t volinfo_type;
1942 } volint_info_handle_t;
1945 * store value to a field at the appropriate location in on-wire structure.
1947 #define VOLINT_INFO_STORE(handle, name, val) \
1949 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1950 (handle)->volinfo_ptr.base->name = (val); \
1952 (handle)->volinfo_ptr.ext->name = (val); \
1957 * get pointer to appropriate offset of field in on-wire structure.
1959 #define VOLINT_INFO_PTR(handle, name) \
1960 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1961 &((handle)->volinfo_ptr.base->name) : \
1962 &((handle)->volinfo_ptr.ext->name))
1965 * fill in appropriate type of on-wire volume metadata structure.
1967 * @param vp pointer to volume object
1968 * @param handle pointer to wire format handle object
1970 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1971 * @pre handle object must have a valid pointer and enumeration value
1973 * @note passing a NULL value for vp means that the fileserver doesn't
1974 * know about this particular volume, thus implying it is offline.
1976 * @return operation status
1981 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1983 unsigned int numStatBytes, now;
1984 struct VolumeDiskData *hdr = &vp->header->diskstuff;
1986 /*read in the relevant info */
1987 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1988 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1989 VOLINT_INFO_STORE(handle, volid, hdr->id);
1990 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1991 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
1992 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
1993 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
1994 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
1995 VOLINT_INFO_STORE(handle, size, hdr->diskused);
1996 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
1997 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
1998 now = FT_ApproxTime();
1999 if ((now - hdr->dayUseDate) > OneDay) {
2000 VOLINT_INFO_STORE(handle, dayUse, 0);
2002 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2004 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2005 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2006 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2007 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2009 #ifdef AFS_DEMAND_ATTACH_FS
2011 * for DAFS, we "lie" about volume state --
2012 * instead of returning the raw state from the disk header,
2013 * we compute state based upon the fileserver's internal
2014 * in-core state enumeration value reported to us via fssync,
2015 * along with the blessed and inService flags from the header.
2016 * -- tkeiser 11/27/2007
2019 /* Conditions that offline status is based on:
2020 volume is unattached state
2021 volume state is in (one of several error states)
2022 volume not in service
2023 volume is not marked as blessed (not on hold)
2024 volume in salvage req. state
2025 volume needsSalvaged
2026 next op would set volume offline
2027 next op would not leave volume online (based on several conditions)
2030 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2031 VIsErrorState(V_attachState(vp)) ||
2034 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2035 hdr->needsSalvaged ||
2036 (vp->pending_vol_op &&
2037 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2038 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2041 VOLINT_INFO_STORE(handle, inUse, 0);
2043 VOLINT_INFO_STORE(handle, inUse, 1);
2046 /* offline status based on program type, where != fileServer enum (1) is offline */
2047 if (hdr->inUse == fileServer) {
2048 VOLINT_INFO_STORE(handle, inUse, 1);
2050 VOLINT_INFO_STORE(handle, inUse, 0);
2055 switch(handle->volinfo_type) {
2056 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2057 case VOLINT_INFO_TYPE_BASE:
2059 #ifdef AFS_DEMAND_ATTACH_FS
2060 /* see comment above where we set inUse bit */
2061 if (hdr->needsSalvaged ||
2062 (vp && VIsErrorState(V_attachState(vp)))) {
2063 handle->volinfo_ptr.base->needsSalvaged = 1;
2065 handle->volinfo_ptr.base->needsSalvaged = 0;
2068 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2070 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2071 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2072 handle->volinfo_ptr.base->spare1 =
2073 (long)hdr->weekUse[0] +
2074 (long)hdr->weekUse[1] +
2075 (long)hdr->weekUse[2] +
2076 (long)hdr->weekUse[3] +
2077 (long)hdr->weekUse[4] +
2078 (long)hdr->weekUse[5] +
2079 (long)hdr->weekUse[6];
2080 handle->volinfo_ptr.base->flags = 0;
2081 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2082 handle->volinfo_ptr.base->spare3 = 0;
2086 case VOLINT_INFO_TYPE_EXT:
2088 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2089 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2092 * Copy out the stat fields in a single operation.
2094 if ((now - hdr->dayUseDate) > OneDay) {
2095 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2098 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2099 (char *)&(hdr->stat_reads[0]),
2108 #ifdef AFS_DEMAND_ATTACH_FS
2111 * get struct Volume out of the fileserver.
2113 * @param[in] volumeId volumeId for which we want state information
2114 * @param[in] pname partition name string
2115 * @param[inout] vp pointer to pointer to Volume object which
2116 * will be populated (see note)
2118 * @return operation status
2120 * @retval non-zero failure
2122 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2127 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2132 res.hdr.response_len = sizeof(res.hdr);
2133 res.payload.buf = *vp;
2134 res.payload.len = sizeof(Volume);
2136 code = FSYNC_VolOp(volumeId,
2142 if (code != SYNC_OK) {
2143 switch (res.hdr.reason) {
2144 case FSYNC_WRONG_PART:
2145 case FSYNC_UNKNOWN_VOLID:
2158 * mode of volume list operation.
2161 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2162 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2163 } vol_info_list_mode_t;
2166 * abstract interface to populate wire-format volume metadata structures.
2168 * @param[in] partId partition id
2169 * @param[in] volumeId volume id
2170 * @param[in] pname partition name
2171 * @param[in] volname volume file name
2172 * @param[in] handle handle to on-wire volume metadata object
2173 * @param[in] mode listing mode
2175 * @return operation status
2177 * @retval -2 DESTROY_ME flag is set
2178 * @retval -1 general failure; some data filled in
2179 * @retval -3 couldn't create vtrans; some data filled in
2182 GetVolInfo(afs_uint32 partId,
2183 afs_uint32 volumeId,
2186 volint_info_handle_t * handle,
2187 vol_info_list_mode_t mode)
2191 struct volser_trans *ttc = NULL;
2192 struct Volume *fill_tv, *tv = NULL;
2193 #ifdef AFS_DEMAND_ATTACH_FS
2194 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2195 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2196 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2197 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2199 /* Set up response handle for pending_vol_op */
2200 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2201 fs_res.payload.buf = fs_res_buf;
2202 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2205 ttc = NewTrans(volumeId, partId);
2208 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2209 VOLINT_INFO_STORE(handle, volid, volumeId);
2213 /* Get volume from volserver */
2214 if (mode == VOL_INFO_LIST_MULTIPLE)
2215 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2217 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2219 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2220 volumeId, pname, volname, error);
2225 * please note that destroyMe and needsSalvaged checks used to be ordered
2226 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2227 * more correct to check destroyMe before needsSalvaged.
2228 * -- tkeiser 11/28/2007
2231 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2233 case VOL_INFO_LIST_MULTIPLE:
2237 case VOL_INFO_LIST_SINGLE:
2238 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2239 volumeId, pname, volname);
2246 if (tv->header->diskstuff.needsSalvaged) {
2247 /*this volume will be salvaged */
2248 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2249 volumeId, pname, volname);
2252 #ifdef AFS_DEMAND_ATTACH_FS
2253 /* If using DAFS, get volume from fsserver */
2254 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2259 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2260 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2261 /* If we if the pending vol op */
2262 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2263 fs_tv->pending_vol_op=&pending_vol_op_res;
2265 fs_tv->pending_vol_op=NULL;
2268 /* populate the header from the volserver copy */
2269 fs_tv->header=tv->header;
2271 /* When using DAFS, use the fs volume info, populated with required structures */
2274 /* When not using DAFS, just use the local volume info */
2278 /* ok, we have all the data we need; fill in the on-wire struct */
2279 code = FillVolInfo(fill_tv, handle);
2283 VOLINT_INFO_STORE(handle, status, 0);
2284 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2285 VOLINT_INFO_STORE(handle, volid, volumeId);
2288 VDetachVolume(&error, tv);
2291 VOLINT_INFO_STORE(handle, status, 0);
2292 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2293 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2294 volumeId, pname, volname);
2298 DeleteTrans(ttc, 1);
2305 /*return the header information about the <volid> */
2307 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2308 afs_uint32 volumeId, volEntries *volumeInfo)
2312 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2313 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2318 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2319 afs_uint32 volumeId, volEntries *volumeInfo)
2321 struct DiskPartition64 *partP;
2322 char pname[9], volname[20];
2327 volint_info_handle_t handle;
2329 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2330 if (!volumeInfo->volEntries_val)
2332 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2334 volumeInfo->volEntries_len = 1;
2335 if (GetPartName(partid, pname))
2336 return VOLSERILLEGAL_PARTITION;
2337 if (!(partP = VGetPartition(pname, 0)))
2338 return VOLSERILLEGAL_PARTITION;
2339 dirp = opendir(VPartitionPath(partP));
2341 return VOLSERILLEGAL_PARTITION;
2343 strcpy(volname, "");
2345 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2347 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2348 GetNextVol(dirp, volname, &volid);
2349 continue; /*back to while loop */
2352 if (volid == volumeId) { /*copy other things too */
2357 GetNextVol(dirp, volname, &volid);
2361 #ifndef AFS_PTHREAD_ENV
2362 IOMGR_Poll(); /*make sure that the client does not time out */
2365 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2366 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2368 code = GetVolInfo(partid,
2373 VOL_INFO_LIST_SINGLE);
2378 return code ? ENODEV: 0;
2383 /*------------------------------------------------------------------------
2384 * EXPORTED SAFSVolXListOneVolume
2387 * Returns extended info on volume a_volID on partition a_partID.
2390 * a_rxCidP : Pointer to the Rx call we're performing.
2391 * a_partID : Partition for which we want the extended list.
2392 * a_volID : Volume ID we wish to know about.
2393 * a_volumeXInfoP : Ptr to the extended info blob.
2396 * 0 Successful operation
2397 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2400 * Nothing interesting.
2404 *------------------------------------------------------------------------*/
2407 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2408 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2412 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2413 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2418 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2419 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2420 { /*SAFSVolXListOneVolume */
2422 struct DiskPartition64 *partP; /*Ptr to partition */
2423 char pname[9], volname[20]; /*Partition, volume names */
2424 DIR *dirp; /*Partition directory ptr */
2425 afs_uint32 currVolID; /*Current volume ID */
2426 int found = 0; /*Did we find the volume we need? */
2428 volint_info_handle_t handle;
2431 * Set up our pointers for action, marking our structure to hold exactly
2432 * one entry. Also, assume we'll fail in our quest.
2434 a_volumeXInfoP->volXEntries_val =
2435 (volintXInfo *) malloc(sizeof(volintXInfo));
2436 if (!a_volumeXInfoP->volXEntries_val)
2438 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2440 a_volumeXInfoP->volXEntries_len = 1;
2444 * If the partition name we've been given is bad, bogue out.
2446 if (GetPartName(a_partID, pname))
2447 return (VOLSERILLEGAL_PARTITION);
2450 * Open the directory representing the given AFS parttion. If we can't
2453 if (!(partP = VGetPartition(pname, 0)))
2454 return VOLSERILLEGAL_PARTITION;
2455 dirp = opendir(VPartitionPath(partP));
2457 return (VOLSERILLEGAL_PARTITION);
2459 strcpy(volname, "");
2462 * Sweep through the partition directory, looking for the desired entry.
2463 * First, of course, figure out how many stat bytes to copy out of each
2466 while (strcmp(volname, "EOD") && !found) {
2468 * If this is not a volume, move on to the next entry in the
2469 * partition's directory.
2471 if (!strcmp(volname, "")) {
2472 GetNextVol(dirp, volname, &currVolID);
2476 if (currVolID == a_volID) {
2478 * We found the volume entry we're interested. Pull out the
2479 * extended information, remembering to poll (so that the client
2480 * doesn't time out) and to set up a transaction on the volume.
2484 } /*Found desired volume */
2486 GetNextVol(dirp, volname, &currVolID);
2490 #ifndef AFS_PTHREAD_ENV
2494 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2495 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2497 code = GetVolInfo(a_partID,
2502 VOL_INFO_LIST_SINGLE);
2507 * Clean up before going to dinner: close the partition directory,
2508 * return the proper value.
2512 return code ? ENODEV: 0;
2515 } /*SAFSVolXListOneVolume */
2517 /*returns all the volumes on partition partid. If flags = 1 then all the
2518 * relevant info about the volumes is also returned */
2520 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2521 volEntries *volumeInfo)
2525 code = VolListVolumes(acid, partid, flags, volumeInfo);
2526 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2531 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2532 volEntries *volumeInfo)
2535 struct DiskPartition64 *partP;
2536 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2537 char pname[9], volname[20];
2541 volint_info_handle_t handle;
2543 volumeInfo->volEntries_val =
2544 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2545 if (!volumeInfo->volEntries_val)
2547 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2549 pntr = volumeInfo->volEntries_val;
2550 volumeInfo->volEntries_len = 0;
2551 if (GetPartName(partid, pname))
2552 return VOLSERILLEGAL_PARTITION;
2553 if (!(partP = VGetPartition(pname, 0)))
2554 return VOLSERILLEGAL_PARTITION;
2555 dirp = opendir(VPartitionPath(partP));
2557 return VOLSERILLEGAL_PARTITION;
2558 strcpy(volname, "");
2560 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2562 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2563 GetNextVol(dirp, volname, &volid);
2564 continue; /*back to while loop */
2567 if (flags) { /*copy other things too */
2568 #ifndef AFS_PTHREAD_ENV
2569 IOMGR_Poll(); /*make sure that the client does not time out */
2572 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2573 handle.volinfo_ptr.base = pntr;
2576 code = GetVolInfo(partid,
2581 VOL_INFO_LIST_MULTIPLE);
2582 if (code == -2) { /* DESTROY_ME flag set */
2586 pntr->volid = volid;
2587 /*just volids are needed */
2591 volumeInfo->volEntries_len += 1;
2592 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2593 /*running out of space, allocate more space */
2594 allocSize = (allocSize * 3) / 2;
2596 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2597 allocSize * sizeof(volintInfo));
2600 return VOLSERNO_MEMORY;
2602 volumeInfo->volEntries_val = pntr; /* point to new block */
2603 /* set pntr to the right position */
2604 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2609 GetNextVol(dirp, volname, &volid);
2617 /*------------------------------------------------------------------------
2618 * EXPORTED SAFSVolXListVolumes
2621 * Returns all the volumes on partition a_partID. If a_flags
2622 * is set to 1, then all the relevant extended volume information
2626 * a_rxCidP : Pointer to the Rx call we're performing.
2627 * a_partID : Partition for which we want the extended list.
2628 * a_flags : Various flags.
2629 * a_volumeXInfoP : Ptr to the extended info blob.
2632 * 0 Successful operation
2633 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2634 * VOLSERNO_MEMORY if we ran out of memory allocating
2638 * Nothing interesting.
2642 *------------------------------------------------------------------------*/
2645 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2646 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2650 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2651 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2656 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2657 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2658 { /*SAFSVolXListVolumes */
2660 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2661 struct DiskPartition64 *partP; /*Ptr to partition */
2662 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2663 char pname[9], volname[20]; /*Partition, volume names */
2664 DIR *dirp; /*Partition directory ptr */
2665 afs_uint32 volid; /*Current volume ID */
2667 volint_info_handle_t handle;
2670 * Allocate a large array of extended volume info structures, then
2671 * set it up for action.
2673 a_volumeXInfoP->volXEntries_val =
2674 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2675 if (!a_volumeXInfoP->volXEntries_val)
2677 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2679 xInfoP = a_volumeXInfoP->volXEntries_val;
2680 a_volumeXInfoP->volXEntries_len = 0;
2683 * If the partition name we've been given is bad, bogue out.
2685 if (GetPartName(a_partID, pname))
2686 return (VOLSERILLEGAL_PARTITION);
2689 * Open the directory representing the given AFS parttion. If we can't
2692 if (!(partP = VGetPartition(pname, 0)))
2693 return VOLSERILLEGAL_PARTITION;
2694 dirp = opendir(VPartitionPath(partP));
2696 return (VOLSERILLEGAL_PARTITION);
2697 strcpy(volname, "");
2700 * Sweep through the partition directory, acting on each entry. First,
2701 * of course, figure out how many stat bytes to copy out of each volume.
2703 while (strcmp(volname, "EOD")) {
2706 * If this is not a volume, move on to the next entry in the
2707 * partition's directory.
2709 if (!strcmp(volname, "")) {
2710 GetNextVol(dirp, volname, &volid);
2716 * Full info about the volume desired. Poll to make sure the
2717 * client doesn't time out, then start up a new transaction.
2719 #ifndef AFS_PTHREAD_ENV
2723 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2724 handle.volinfo_ptr.ext = xInfoP;
2726 code = GetVolInfo(a_partID,
2731 VOL_INFO_LIST_MULTIPLE);
2732 if (code == -2) { /* DESTROY_ME flag set */
2737 * Just volume IDs are needed.
2739 xInfoP->volid = volid;
2743 * Bump the pointer in the data area we're building, along with
2744 * the count of the number of entries it contains.
2747 (a_volumeXInfoP->volXEntries_len)++;
2748 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2750 * We're running out of space in the area we've built. Grow it.
2752 allocSize = (allocSize * 3) / 2;
2753 xInfoP = (volintXInfo *)
2754 realloc((char *)a_volumeXInfoP->volXEntries_val,
2755 (allocSize * sizeof(volintXInfo)));
2756 if (xInfoP == NULL) {
2758 * Bummer, no memory. Bag it, tell our caller what went wrong.
2761 return (VOLSERNO_MEMORY);
2765 * Memory reallocation worked. Correct our pointers so they
2766 * now point to the new block and the current open position within
2769 a_volumeXInfoP->volXEntries_val = xInfoP;
2771 a_volumeXInfoP->volXEntries_val +
2772 a_volumeXInfoP->volXEntries_len;
2776 GetNextVol(dirp, volname, &volid);
2777 } /*Sweep through the partition directory */
2780 * We've examined all entries in the partition directory. Close it,
2781 * delete our transaction (if any), and go home happy.
2786 } /*SAFSVolXListVolumes */
2788 /*this call is used to monitor the status of volser for debugging purposes.
2789 *information about all the active transactions is returned in transInfo*/
2791 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2795 code = VolMonitor(acid, transInfo);
2796 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2801 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2803 transDebugInfo *pntr;
2804 afs_int32 allocSize = 50;
2805 struct volser_trans *tt, *nt, *allTrans;
2807 transInfo->transDebugEntries_val =
2808 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2809 if (!transInfo->transDebugEntries_val)
2811 pntr = transInfo->transDebugEntries_val;
2812 transInfo->transDebugEntries_len = 0;
2815 allTrans = TransList();
2816 if (allTrans == (struct volser_trans *)0)
2817 goto done; /*no active transactions */
2818 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2820 VTRANS_OBJ_LOCK(tt);
2821 pntr->tid = tt->tid;
2822 pntr->time = tt->time;
2823 pntr->creationTime = tt->creationTime;
2824 pntr->returnCode = tt->returnCode;
2825 pntr->volid = tt->volid;
2826 pntr->partition = tt->partition;
2827 pntr->iflags = tt->iflags;
2828 pntr->vflags = tt->vflags;
2829 pntr->tflags = tt->tflags;
2830 strcpy(pntr->lastProcName, tt->lastProcName);
2831 pntr->callValid = 0;
2832 if (tt->rxCallPtr) { /*record call related info */
2833 pntr->callValid = 1;
2834 pntr->readNext = tt->rxCallPtr->rnext;
2835 pntr->transmitNext = tt->rxCallPtr->tnext;
2836 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2837 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2839 VTRANS_OBJ_UNLOCK(tt);
2841 transInfo->transDebugEntries_len += 1;
2842 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2843 allocSize = (allocSize * 3) / 2;
2845 (transDebugInfo *) realloc((char *)transInfo->
2846 transDebugEntries_val,
2848 sizeof(transDebugInfo));
2849 transInfo->transDebugEntries_val = pntr;
2851 transInfo->transDebugEntries_val +
2852 transInfo->transDebugEntries_len;
2853 /*set pntr to right position */
2864 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2865 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2866 afs_uint32 backupId)
2870 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2871 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2872 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2878 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2879 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2880 afs_uint32 backupId)
2884 struct volser_trans *tt;
2885 char caller[MAXKTCNAMELEN];
2887 if (strlen(name) > 31)
2888 return VOLSERBADNAME;
2889 if (!afsconf_SuperUser(tdir, acid, caller))
2890 return VOLSERBAD_ACCESS; /*not a super user */
2891 /* find the trans */
2892 tt = FindTrans(atid);
2895 if (tt->vflags & VTDeleted) {
2896 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2900 TSetRxCall(tt, acid, "SetIdsTypes");
2904 V_backupId(tv) = backupId;
2905 V_cloneId(tv) = cloneId;
2906 V_parentId(tv) = pId;
2907 strcpy((&V_disk(tv))->name, name);
2908 VUpdateVolume(&error, tv);
2910 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2915 if (TRELE(tt) && !error)
2916 return VOLSERTRELE_ERROR;
2921 if (TRELE(tt) && !error)
2922 return VOLSERTRELE_ERROR;
2927 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2931 code = VolSetDate(acid, atid, cdate);
2932 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2938 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2942 struct volser_trans *tt;
2943 char caller[MAXKTCNAMELEN];
2945 if (!afsconf_SuperUser(tdir, acid, caller))
2946 return VOLSERBAD_ACCESS; /*not a super user */
2947 /* find the trans */
2948 tt = FindTrans(atid);
2951 if (tt->vflags & VTDeleted) {
2952 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2956 TSetRxCall(tt, acid, "SetDate");
2959 V_creationDate(tv) = cdate;
2960 VUpdateVolume(&error, tv);
2962 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2967 if (TRELE(tt) && !error)
2968 return VOLSERTRELE_ERROR;
2973 if (TRELE(tt) && !error)
2974 return VOLSERTRELE_ERROR;
2979 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2980 afs_uint32 volumeId)
2985 char caller[MAXKTCNAMELEN];
2987 struct volser_trans *ttc;
2988 char pname[16], volname[20];
2989 struct DiskPartition64 *partP;
2990 afs_int32 ret = ENODEV;
2993 if (!afsconf_SuperUser(tdir, acid, caller))
2994 return VOLSERBAD_ACCESS; /*not a super user */
2995 if (GetPartName(partId, pname))
2996 return VOLSERILLEGAL_PARTITION;
2997 if (!(partP = VGetPartition(pname, 0)))
2998 return VOLSERILLEGAL_PARTITION;
2999 dirp = opendir(VPartitionPath(partP));
3001 return VOLSERILLEGAL_PARTITION;
3002 strcpy(volname, "");
3003 ttc = (struct volser_trans *)0;
3005 while (strcmp(volname, "EOD")) {
3006 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3007 GetNextVol(dirp, volname, &volid);
3008 continue; /*back to while loop */
3011 if (volid == volumeId) { /*copy other things too */
3012 #ifndef AFS_PTHREAD_ENV
3013 IOMGR_Poll(); /*make sure that the client doesnot time out */
3015 ttc = NewTrans(volumeId, partId);
3017 return VOLSERVOLBUSY;
3019 #ifdef AFS_NAMEI_ENV
3020 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3022 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3026 GetNextVol(dirp, volname, &volid);
3030 DeleteTrans(ttc, 1);
3031 ttc = (struct volser_trans *)0;
3040 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3041 struct volintSize *size)
3044 struct volser_trans *tt;
3045 char caller[MAXKTCNAMELEN];
3047 if (!afsconf_SuperUser(tdir, acid, caller))
3048 return VOLSERBAD_ACCESS; /*not a super user */
3049 tt = FindTrans(fromTrans);
3052 if (tt->vflags & VTDeleted) {
3056 TSetRxCall(tt, acid, "GetSize");
3057 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3060 return VOLSERTRELE_ERROR;
3062 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3067 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3068 afs_uint32 where, afs_int32 verbose)
3070 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3072 Volume *vol=0, *newvol=0;
3073 struct volser_trans *tt = 0, *tt2 = 0;
3074 char caller[MAXKTCNAMELEN];
3077 if (!afsconf_SuperUser(tdir, acall, caller))
3080 vol = VAttachVolume(&code, vid, V_VOLUPD);
3086 newvol = VAttachVolume(&code, new, V_VOLUPD);
3088 VDetachVolume(&code2, vol);
3093 if (V_device(vol) != V_device(newvol)
3094 || V_uniquifier(newvol) != 2) {
3095 if (V_device(vol) != V_device(newvol)) {
3096 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3098 rx_Write(acall, line, strlen(line));
3100 if (V_uniquifier(newvol) != 2) {
3101 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3102 rx_Write(acall, line, strlen(line));
3105 rx_Write(acall, line, 1);
3106 VDetachVolume(&code2, vol);
3107 VDetachVolume(&code2, newvol);
3110 tt = NewTrans(vid, V_device(vol));
3112 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3113 rx_Write(acall, line, strlen(line));
3115 rx_Write(acall, line, 1);
3116 VDetachVolume(&code2, vol);
3117 VDetachVolume(&code2, newvol);
3118 return VOLSERVOLBUSY;
3120 VTRANS_OBJ_LOCK(tt);
3121 tt->iflags = ITBusy;
3123 TSetRxCall_r(tt, NULL, "SplitVolume");
3124 VTRANS_OBJ_UNLOCK(tt);
3126 tt2 = NewTrans(new, V_device(newvol));
3128 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3129 rx_Write(acall, line, strlen(line));
3131 rx_Write(acall, line, 1);
3133 VDetachVolume(&code2, vol);
3134 VDetachVolume(&code2, newvol);
3135 return VOLSERVOLBUSY;
3137 VTRANS_OBJ_LOCK(tt2);
3138 tt2->iflags = ITBusy;
3140 TSetRxCall_r(tt2, NULL, "SplitVolume");
3141 VTRANS_OBJ_UNLOCK(tt2);
3143 code = split_volume(acall, vol, newvol, where, verbose);
3145 VDetachVolume(&code2, vol);
3147 VDetachVolume(&code2, newvol);
3148 DeleteTrans(tt2, 1);
3155 /* GetPartName - map partid (a decimal number) into pname (a string)
3156 * Since for NT we actually want to return the drive name, we map through the
3160 GetPartName(afs_int32 partid, char *pname)
3165 strcpy(pname, "/vicep");
3166 pname[6] = 'a' + partid;
3169 } else if (partid < VOLMAXPARTS) {
3170 strcpy(pname, "/vicep");
3172 pname[6] = 'a' + (partid / 26);
3173 pname[7] = 'a' + (partid % 26);