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 /* update the creationDate, since this represents the last cloning date
974 * for ROs. But do not update copyDate; let it stay so we can identify
975 * when the clone was first created. */
976 V_creationDate(clonevp) = time(0);
977 ClearVolumeStats(&V_disk(clonevp));
978 V_destroyMe(clonevp) = 0;
979 V_inService(clonevp) = 0;
980 if (newType == backupVolume) {
981 V_backupDate(originalvp) = V_creationDate(clonevp);
982 V_backupDate(clonevp) = V_creationDate(clonevp);
984 V_inUse(clonevp) = 0;
985 VUpdateVolume(&error, clonevp);
987 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
991 /* VUpdateVolume succeeded. Mark it in service so there's no window
992 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
993 * specialStatus; this is a reclone and this volume started online
995 V_inService(clonevp) = 1;
996 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
998 VUpdateVolume(&error, originalvp);
1000 Log("1 Volser: Clone: original update %u\n", error);
1006 tt = (struct volser_trans *)0;
1007 error = VOLSERTRELE_ERROR;
1011 DeleteTrans(ttc, 1);
1014 struct DiskPartition64 *tpartp = originalvp->partition;
1015 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1021 VDetachVolume(&code, clonevp);
1027 DeleteTrans(ttc, 1);
1031 /* create a new transaction, associated with volume and partition. Type of
1032 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1033 * See volser.h for definition of iflags (the constants are named IT*).
1036 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1037 afs_int32 iflags, afs_int32 *ttid)
1041 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1042 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1048 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1049 afs_int32 iflags, afs_int32 *ttid)
1051 struct volser_trans *tt;
1056 char caller[MAXKTCNAMELEN];
1058 if (!afsconf_SuperUser(tdir, acid, caller))
1059 return VOLSERBAD_ACCESS; /*not a super user */
1060 if (iflags & ITCreate)
1062 else if (iflags & ITBusy)
1064 else if (iflags & ITReadOnly)
1066 else if (iflags & ITOffline)
1069 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1074 tt = NewTrans(volume, partition);
1076 /* can't create a transaction? put the volume back */
1077 Log("1 transcreate: can't create transaction\n");
1078 return VOLSERVOLBUSY;
1080 tv = XAttachVolume(&error, volume, partition, mode);
1084 VDetachVolume(&code, tv);
1088 VTRANS_OBJ_LOCK(tt);
1091 tt->iflags = iflags;
1093 TSetRxCall_r(tt, NULL, "TransCreate");
1094 VTRANS_OBJ_UNLOCK(tt);
1096 return VOLSERTRELE_ERROR;
1101 /* using aindex as a 0-based index, return the aindex'th volume on this server
1102 * Both the volume number and partition number (one-based) are returned.
1105 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1110 code = VolGetNthVolume(acid, aindex, avolume, apart);
1111 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1116 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1119 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1123 /* return the volume flags (VT* constants in volser.h) associated with this
1127 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1131 code = VolGetFlags(acid, atid, aflags);
1132 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1137 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1139 struct volser_trans *tt;
1141 tt = FindTrans(atid);
1144 if (tt->vflags & VTDeleted) {
1145 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1150 TSetRxCall(tt, acid, "GetFlags");
1151 *aflags = tt->vflags;
1154 return VOLSERTRELE_ERROR;
1159 /* Change the volume flags (VT* constants in volser.h) associated with this
1160 * transaction. Effects take place immediately on volume, although volume
1161 * remains attached as usual by the transaction.
1164 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1168 code = VolSetFlags(acid, atid, aflags);
1169 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1175 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1177 struct volser_trans *tt;
1180 char caller[MAXKTCNAMELEN];
1182 if (!afsconf_SuperUser(tdir, acid, caller))
1183 return VOLSERBAD_ACCESS; /*not a super user */
1184 /* find the trans */
1185 tt = FindTrans(atid);
1188 if (tt->vflags & VTDeleted) {
1189 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1194 TSetRxCall(tt, acid, "SetFlags");
1195 vp = tt->volume; /* pull volume out of transaction */
1197 /* check if we're allowed to make any updates */
1198 if (tt->iflags & ITReadOnly) {
1203 /* handle delete-on-salvage flag */
1204 if (aflags & VTDeleteOnSalvage) {
1205 V_destroyMe(tt->volume) = DESTROY_ME;
1207 V_destroyMe(tt->volume) = 0;
1210 if (aflags & VTOutOfService) {
1211 V_inService(vp) = 0;
1213 V_inService(vp) = 1;
1215 VUpdateVolume(&error, vp);
1216 VTRANS_OBJ_LOCK(tt);
1217 tt->vflags = aflags;
1219 VTRANS_OBJ_UNLOCK(tt);
1220 if (TRELE(tt) && !error)
1221 return VOLSERTRELE_ERROR;
1226 /* dumpS the volume associated with a particular transaction from a particular
1227 * date. Send the dump to a different transaction (destTrans) on the server
1228 * specified by the destServer structure.
1231 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1232 struct destServer *destination, afs_int32 destTrans,
1233 struct restoreCookie *cookie)
1238 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1239 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1240 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1245 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1246 struct destServer *destination, afs_int32 destTrans,
1247 struct restoreCookie *cookie)
1249 struct volser_trans *tt;
1251 struct rx_connection *tcon;
1252 struct rx_call *tcall;
1254 struct rx_securityClass *securityObject;
1255 afs_int32 securityIndex;
1256 char caller[MAXKTCNAMELEN];
1258 if (!afsconf_SuperUser(tdir, acid, caller))
1259 return VOLSERBAD_ACCESS; /*not a super user */
1260 /* initialize things */
1261 tcon = (struct rx_connection *)0;
1262 tt = (struct volser_trans *)0;
1264 /* find the local transaction */
1265 tt = FindTrans(fromTrans);
1268 if (tt->vflags & VTDeleted) {
1269 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1274 TSetRxCall(tt, NULL, "Forward");
1276 /* get auth info for the this connection (uses afs from ticket file) */
1277 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1283 /* make an rpc connection to the other server */
1285 rx_NewConnection(htonl(destination->destHost),
1286 htons(destination->destPort), VOLSERVICE_ID,
1287 securityObject, securityIndex);
1293 tcall = rx_NewCall(tcon);
1294 TSetRxCall(tt, tcall, "Forward");
1295 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1296 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1301 /* these next calls implictly call rx_Write when writing out data */
1302 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1305 EndAFSVolRestore(tcall); /* probably doesn't do much */
1307 code = rx_EndCall(tcall, 0);
1308 rx_DestroyConnection(tcon); /* done with the connection */
1313 return VOLSERTRELE_ERROR;
1319 (void)rx_EndCall(tcall, 0);
1320 rx_DestroyConnection(tcon);
1329 /* Start a dump and send it to multiple places simultaneously.
1330 * If this returns an error (eg, return ENOENT), it means that
1331 * none of the releases worked. If this returns 0, that means
1332 * that one or more of the releases worked, and the caller has
1333 * to examine the results array to see which one(s).
1334 * This will only do EITHER incremental or full, not both, so it's
1335 * the caller's responsibility to be sure that all the destinations
1336 * need just an incremental (and from the same time), if that's
1340 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1341 fromDate, manyDests *destinations, afs_int32 spare,
1342 struct restoreCookie *cookie, manyResults *results)
1344 afs_int32 securityIndex;
1345 struct rx_securityClass *securityObject;
1346 char caller[MAXKTCNAMELEN];
1347 struct volser_trans *tt;
1348 afs_int32 ec, code, *codes;
1349 struct rx_connection **tcons;
1350 struct rx_call **tcalls;
1352 int i, is_incremental;
1355 memset(results, 0, sizeof(manyResults));
1356 i = results->manyResults_len = destinations->manyDests_len;
1357 results->manyResults_val = codes =
1358 (afs_int32 *) malloc(i * sizeof(afs_int32));
1360 if (!results || !results->manyResults_val)
1363 if (!afsconf_SuperUser(tdir, acid, caller))
1364 return VOLSERBAD_ACCESS; /*not a super user */
1365 tt = FindTrans(fromTrans);
1368 if (tt->vflags & VTDeleted) {
1369 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1374 TSetRxCall(tt, NULL, "ForwardMulti");
1376 /* (fromDate == 0) ==> full dump */
1377 is_incremental = (fromDate ? 1 : 0);
1380 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1384 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1390 /* get auth info for this connection (uses afs from ticket file) */
1391 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1393 goto fail; /* in order to audit each failure */
1396 /* make connections to all the other servers */
1397 for (i = 0; i < destinations->manyDests_len; i++) {
1398 struct replica *dest = &(destinations->manyDests_val[i]);
1400 rx_NewConnection(htonl(dest->server.destHost),
1401 htons(dest->server.destPort), VOLSERVICE_ID,
1402 securityObject, securityIndex);
1404 codes[i] = ENOTCONN;
1406 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1407 codes[i] = ENOTCONN;
1410 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1413 (void)rx_EndCall(tcalls[i], 0);
1415 rx_DestroyConnection(tcons[i]);
1422 /* these next calls implictly call rx_Write when writing out data */
1423 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1427 for (i--; i >= 0; i--) {
1428 struct replica *dest = &(destinations->manyDests_val[i]);
1430 if (!code && tcalls[i] && !codes[i]) {
1431 EndAFSVolRestore(tcalls[i]);
1434 ec = rx_EndCall(tcalls[i], 0);
1439 rx_DestroyConnection(tcons[i]); /* done with the connection */
1442 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1443 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1444 dest->trans, AUD_END);
1451 if (TRELE(tt) && !code) /* return the first code if it's set */
1452 return VOLSERTRELE_ERROR;
1459 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1463 code = VolDump(acid, fromTrans, fromDate, 0);
1464 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1469 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1474 code = VolDump(acid, fromTrans, fromDate, flags);
1475 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1480 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1484 struct volser_trans *tt;
1485 char caller[MAXKTCNAMELEN];
1487 if (!afsconf_SuperUser(tdir, acid, caller))
1488 return VOLSERBAD_ACCESS; /*not a super user */
1489 tt = FindTrans(fromTrans);
1492 if (tt->vflags & VTDeleted) {
1493 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1497 TSetRxCall(tt, acid, "Dump");
1498 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1499 ? 0 : 1); /* squirt out the volume's data, too */
1508 return VOLSERTRELE_ERROR;
1514 * Ha! No more helper process!
1517 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1518 struct restoreCookie *cookie)
1522 code = VolRestore(acid, atrans, aflags, cookie);
1523 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1528 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1529 struct restoreCookie *cookie)
1531 struct volser_trans *tt;
1532 afs_int32 code, tcode;
1533 char caller[MAXKTCNAMELEN];
1535 if (!afsconf_SuperUser(tdir, acid, caller))
1536 return VOLSERBAD_ACCESS; /*not a super user */
1537 tt = FindTrans(atrans);
1540 if (tt->vflags & VTDeleted) {
1541 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1545 TSetRxCall(tt, acid, "Restore");
1547 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1549 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1550 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1554 return (code ? code : tcode);
1557 /* end a transaction, returning the transaction's final error code in rcode */
1559 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1563 code = VolEndTrans(acid, destTrans, rcode);
1564 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1569 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1571 struct volser_trans *tt;
1572 char caller[MAXKTCNAMELEN];
1574 if (!afsconf_SuperUser(tdir, acid, caller))
1575 return VOLSERBAD_ACCESS; /*not a super user */
1576 tt = FindTrans(destTrans);
1580 *rcode = tt->returnCode;
1581 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1587 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1591 code = VolSetForwarding(acid, atid, anewsite);
1592 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1593 htonl(anewsite), AUD_END);
1598 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1600 struct volser_trans *tt;
1601 char caller[MAXKTCNAMELEN];
1604 if (!afsconf_SuperUser(tdir, acid, caller))
1605 return VOLSERBAD_ACCESS; /*not a super user */
1606 tt = FindTrans(atid);
1609 if (tt->vflags & VTDeleted) {
1610 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1615 TSetRxCall(tt, acid, "SetForwarding");
1616 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1619 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1622 return VOLSERTRELE_ERROR;
1628 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1629 struct volser_status *astatus)
1633 code = VolGetStatus(acid, atrans, astatus);
1634 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1639 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1640 struct volser_status *astatus)
1643 struct VolumeDiskData *td;
1644 struct volser_trans *tt;
1647 tt = FindTrans(atrans);
1650 if (tt->vflags & VTDeleted) {
1651 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1656 TSetRxCall(tt, acid, "GetStatus");
1664 td = &tv->header->diskstuff;
1665 astatus->volID = td->id;
1666 astatus->nextUnique = td->uniquifier;
1667 astatus->type = td->type;
1668 astatus->parentID = td->parentId;
1669 astatus->cloneID = td->cloneId;
1670 astatus->backupID = td->backupId;
1671 astatus->restoredFromID = td->restoredFromId;
1672 astatus->maxQuota = td->maxquota;
1673 astatus->minQuota = td->minquota;
1674 astatus->owner = td->owner;
1675 astatus->creationDate = td->creationDate;
1676 astatus->accessDate = td->accessDate;
1677 astatus->updateDate = td->updateDate;
1678 astatus->expirationDate = td->expirationDate;
1679 astatus->backupDate = td->backupDate;
1680 astatus->copyDate = td->copyDate;
1683 return VOLSERTRELE_ERROR;
1689 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1690 struct volintInfo *astatus)
1694 code = VolSetInfo(acid, atrans, astatus);
1695 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1700 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1701 struct volintInfo *astatus)
1704 struct VolumeDiskData *td;
1705 struct volser_trans *tt;
1706 char caller[MAXKTCNAMELEN];
1709 if (!afsconf_SuperUser(tdir, acid, caller))
1710 return VOLSERBAD_ACCESS; /*not a super user */
1711 tt = FindTrans(atrans);
1714 if (tt->vflags & VTDeleted) {
1715 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1719 TSetRxCall(tt, acid, "SetStatus");
1727 td = &tv->header->diskstuff;
1729 * Add more fields as necessary
1731 if (astatus->maxquota != -1)
1732 td->maxquota = astatus->maxquota;
1733 if (astatus->dayUse != -1)
1734 td->dayUse = astatus->dayUse;
1735 if (astatus->creationDate != -1)
1736 td->creationDate = astatus->creationDate;
1737 if (astatus->updateDate != -1)
1738 td->updateDate = astatus->updateDate;
1739 if (astatus->spare2 != -1)
1740 td->volUpdateCounter = (unsigned int)astatus->spare2;
1741 VUpdateVolume(&error, tv);
1744 return VOLSERTRELE_ERROR;
1750 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1754 code = VolGetName(acid, atrans, aname);
1755 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1760 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1763 struct VolumeDiskData *td;
1764 struct volser_trans *tt;
1767 /* We need to at least fill it in */
1768 *aname = (char *)malloc(1);
1771 tt = FindTrans(atrans);
1774 if (tt->vflags & VTDeleted) {
1775 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1779 TSetRxCall(tt, acid, "GetName");
1787 td = &tv->header->diskstuff;
1788 len = strlen(td->name) + 1; /* don't forget the null */
1794 *aname = (char *)realloc(*aname, len);
1795 strcpy(*aname, td->name);
1798 return VOLSERTRELE_ERROR;
1803 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1806 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1807 afs_uint32 parentId, afs_uint32 cloneId)
1813 /*return a list of all partitions on the server. The non mounted
1814 *partitions are returned as -1 in the corresponding slot in partIds*/
1816 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1820 code = VolListPartitions(acid, partIds);
1821 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1826 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1831 strcpy(namehead, "/vicep"); /*7 including null terminator */
1833 /* Just return attached partitions. */
1835 for (i = 0; i < 26; i++) {
1836 namehead[6] = i + 'a';
1837 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1843 /*return a list of all partitions on the server. The non mounted
1844 *partitions are returned as -1 in the corresponding slot in partIds*/
1846 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1850 code = XVolListPartitions(acid, pEntries);
1851 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1856 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1859 struct partList partList;
1860 struct DiskPartition64 *dp;
1863 strcpy(namehead, "/vicep"); /*7 including null terminator */
1865 /* Only report attached partitions */
1866 for (i = 0; i < VOLMAXPARTS; i++) {
1867 #ifdef AFS_DEMAND_ATTACH_FS
1868 dp = VGetPartitionById(i, 0);
1871 namehead[6] = i + 'a';
1877 namehead[6] = 'a' + (k / 26);
1878 namehead[7] = 'a' + (k % 26);
1881 dp = VGetPartition(namehead, 0);
1884 partList.partId[j++] = i;
1887 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1888 if (!pEntries->partEntries_val)
1890 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1892 pEntries->partEntries_len = j;
1894 pEntries->partEntries_val = NULL;
1895 pEntries->partEntries_len = 0;
1901 /*return the name of the next volume header in the directory associated with dirp and dp.
1902 *the volume id is returned in volid, and volume header name is returned in volname*/
1904 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1908 dp = readdir(dirp); /*read next entry in the directory */
1910 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1911 *volid = VolumeNumber(dp->d_name);
1912 strcpy(volname, dp->d_name);
1913 return 0; /*return the name of the file representing a volume */
1915 strcpy(volname, "");
1916 return 0; /*volname doesnot represent a volume */
1919 strcpy(volname, "EOD");
1920 return 0; /*end of directory */
1926 * volint vol info structure type.
1929 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1930 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1931 } volint_info_type_t;
1934 * handle to various on-wire vol info types.
1937 volint_info_type_t volinfo_type;
1943 } volint_info_handle_t;
1946 * store value to a field at the appropriate location in on-wire structure.
1948 #define VOLINT_INFO_STORE(handle, name, val) \
1950 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1951 (handle)->volinfo_ptr.base->name = (val); \
1953 (handle)->volinfo_ptr.ext->name = (val); \
1958 * get pointer to appropriate offset of field in on-wire structure.
1960 #define VOLINT_INFO_PTR(handle, name) \
1961 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1962 &((handle)->volinfo_ptr.base->name) : \
1963 &((handle)->volinfo_ptr.ext->name))
1966 * fill in appropriate type of on-wire volume metadata structure.
1968 * @param vp pointer to volume object
1969 * @param handle pointer to wire format handle object
1971 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1972 * @pre handle object must have a valid pointer and enumeration value
1974 * @note passing a NULL value for vp means that the fileserver doesn't
1975 * know about this particular volume, thus implying it is offline.
1977 * @return operation status
1982 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1984 unsigned int numStatBytes, now;
1985 struct VolumeDiskData *hdr = &vp->header->diskstuff;
1987 /*read in the relevant info */
1988 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1989 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1990 VOLINT_INFO_STORE(handle, volid, hdr->id);
1991 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1992 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
1993 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
1994 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
1995 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
1996 VOLINT_INFO_STORE(handle, size, hdr->diskused);
1997 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
1998 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
1999 now = FT_ApproxTime();
2000 if ((now - hdr->dayUseDate) > OneDay) {
2001 VOLINT_INFO_STORE(handle, dayUse, 0);
2003 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2005 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2006 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2007 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2008 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2010 #ifdef AFS_DEMAND_ATTACH_FS
2012 * for DAFS, we "lie" about volume state --
2013 * instead of returning the raw state from the disk header,
2014 * we compute state based upon the fileserver's internal
2015 * in-core state enumeration value reported to us via fssync,
2016 * along with the blessed and inService flags from the header.
2017 * -- tkeiser 11/27/2007
2020 /* Conditions that offline status is based on:
2021 volume is unattached state
2022 volume state is in (one of several error states)
2023 volume not in service
2024 volume is not marked as blessed (not on hold)
2025 volume in salvage req. state
2026 volume needsSalvaged
2027 next op would set volume offline
2028 next op would not leave volume online (based on several conditions)
2031 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2032 VIsErrorState(V_attachState(vp)) ||
2035 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2036 hdr->needsSalvaged ||
2037 (vp->pending_vol_op &&
2038 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2039 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2042 VOLINT_INFO_STORE(handle, inUse, 0);
2044 VOLINT_INFO_STORE(handle, inUse, 1);
2047 /* offline status based on program type, where != fileServer enum (1) is offline */
2048 if (hdr->inUse == fileServer) {
2049 VOLINT_INFO_STORE(handle, inUse, 1);
2051 VOLINT_INFO_STORE(handle, inUse, 0);
2056 switch(handle->volinfo_type) {
2057 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2058 case VOLINT_INFO_TYPE_BASE:
2060 #ifdef AFS_DEMAND_ATTACH_FS
2061 /* see comment above where we set inUse bit */
2062 if (hdr->needsSalvaged ||
2063 (vp && VIsErrorState(V_attachState(vp)))) {
2064 handle->volinfo_ptr.base->needsSalvaged = 1;
2066 handle->volinfo_ptr.base->needsSalvaged = 0;
2069 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2071 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2072 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2073 handle->volinfo_ptr.base->spare1 =
2074 (long)hdr->weekUse[0] +
2075 (long)hdr->weekUse[1] +
2076 (long)hdr->weekUse[2] +
2077 (long)hdr->weekUse[3] +
2078 (long)hdr->weekUse[4] +
2079 (long)hdr->weekUse[5] +
2080 (long)hdr->weekUse[6];
2081 handle->volinfo_ptr.base->flags = 0;
2082 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2083 handle->volinfo_ptr.base->spare3 = 0;
2087 case VOLINT_INFO_TYPE_EXT:
2089 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2090 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2093 * Copy out the stat fields in a single operation.
2095 if ((now - hdr->dayUseDate) > OneDay) {
2096 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2099 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2100 (char *)&(hdr->stat_reads[0]),
2109 #ifdef AFS_DEMAND_ATTACH_FS
2112 * get struct Volume out of the fileserver.
2114 * @param[in] volumeId volumeId for which we want state information
2115 * @param[in] pname partition name string
2116 * @param[inout] vp pointer to pointer to Volume object which
2117 * will be populated (see note)
2119 * @return operation status
2121 * @retval non-zero failure
2123 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2128 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2133 res.hdr.response_len = sizeof(res.hdr);
2134 res.payload.buf = *vp;
2135 res.payload.len = sizeof(Volume);
2137 code = FSYNC_VolOp(volumeId,
2143 if (code != SYNC_OK) {
2144 switch (res.hdr.reason) {
2145 case FSYNC_WRONG_PART:
2146 case FSYNC_UNKNOWN_VOLID:
2159 * mode of volume list operation.
2162 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2163 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2164 } vol_info_list_mode_t;
2167 * abstract interface to populate wire-format volume metadata structures.
2169 * @param[in] partId partition id
2170 * @param[in] volumeId volume id
2171 * @param[in] pname partition name
2172 * @param[in] volname volume file name
2173 * @param[in] handle handle to on-wire volume metadata object
2174 * @param[in] mode listing mode
2176 * @return operation status
2178 * @retval -2 DESTROY_ME flag is set
2179 * @retval -1 general failure; some data filled in
2180 * @retval -3 couldn't create vtrans; some data filled in
2183 GetVolInfo(afs_uint32 partId,
2184 afs_uint32 volumeId,
2187 volint_info_handle_t * handle,
2188 vol_info_list_mode_t mode)
2192 struct volser_trans *ttc = NULL;
2193 struct Volume *fill_tv, *tv = NULL;
2194 #ifdef AFS_DEMAND_ATTACH_FS
2195 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2196 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2197 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2198 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2200 /* Set up response handle for pending_vol_op */
2201 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2202 fs_res.payload.buf = fs_res_buf;
2203 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2206 ttc = NewTrans(volumeId, partId);
2209 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2210 VOLINT_INFO_STORE(handle, volid, volumeId);
2214 /* Get volume from volserver */
2215 if (mode == VOL_INFO_LIST_MULTIPLE)
2216 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2218 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2220 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2221 volumeId, pname, volname, error);
2226 * please note that destroyMe and needsSalvaged checks used to be ordered
2227 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2228 * more correct to check destroyMe before needsSalvaged.
2229 * -- tkeiser 11/28/2007
2232 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2234 case VOL_INFO_LIST_MULTIPLE:
2238 case VOL_INFO_LIST_SINGLE:
2239 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2240 volumeId, pname, volname);
2247 if (tv->header->diskstuff.needsSalvaged) {
2248 /*this volume will be salvaged */
2249 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2250 volumeId, pname, volname);
2253 #ifdef AFS_DEMAND_ATTACH_FS
2254 /* If using DAFS, get volume from fsserver */
2255 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2260 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2261 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2262 /* If we if the pending vol op */
2263 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2264 fs_tv->pending_vol_op=&pending_vol_op_res;
2266 fs_tv->pending_vol_op=NULL;
2269 /* populate the header from the volserver copy */
2270 fs_tv->header=tv->header;
2272 /* When using DAFS, use the fs volume info, populated with required structures */
2275 /* When not using DAFS, just use the local volume info */
2279 /* ok, we have all the data we need; fill in the on-wire struct */
2280 code = FillVolInfo(fill_tv, handle);
2284 VOLINT_INFO_STORE(handle, status, 0);
2285 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2286 VOLINT_INFO_STORE(handle, volid, volumeId);
2289 VDetachVolume(&error, tv);
2292 VOLINT_INFO_STORE(handle, status, 0);
2293 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2294 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2295 volumeId, pname, volname);
2299 DeleteTrans(ttc, 1);
2306 /*return the header information about the <volid> */
2308 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2309 afs_uint32 volumeId, volEntries *volumeInfo)
2313 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2314 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2319 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2320 afs_uint32 volumeId, volEntries *volumeInfo)
2322 struct DiskPartition64 *partP;
2323 char pname[9], volname[20];
2328 volint_info_handle_t handle;
2330 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2331 if (!volumeInfo->volEntries_val)
2333 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2335 volumeInfo->volEntries_len = 1;
2336 if (GetPartName(partid, pname))
2337 return VOLSERILLEGAL_PARTITION;
2338 if (!(partP = VGetPartition(pname, 0)))
2339 return VOLSERILLEGAL_PARTITION;
2340 dirp = opendir(VPartitionPath(partP));
2342 return VOLSERILLEGAL_PARTITION;
2344 strcpy(volname, "");
2346 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2348 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2349 GetNextVol(dirp, volname, &volid);
2350 continue; /*back to while loop */
2353 if (volid == volumeId) { /*copy other things too */
2358 GetNextVol(dirp, volname, &volid);
2362 #ifndef AFS_PTHREAD_ENV
2363 IOMGR_Poll(); /*make sure that the client does not time out */
2366 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2367 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2369 code = GetVolInfo(partid,
2374 VOL_INFO_LIST_SINGLE);
2379 return code ? ENODEV: 0;
2384 /*------------------------------------------------------------------------
2385 * EXPORTED SAFSVolXListOneVolume
2388 * Returns extended info on volume a_volID on partition a_partID.
2391 * a_rxCidP : Pointer to the Rx call we're performing.
2392 * a_partID : Partition for which we want the extended list.
2393 * a_volID : Volume ID we wish to know about.
2394 * a_volumeXInfoP : Ptr to the extended info blob.
2397 * 0 Successful operation
2398 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2401 * Nothing interesting.
2405 *------------------------------------------------------------------------*/
2408 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2409 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2413 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2414 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2419 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2420 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2421 { /*SAFSVolXListOneVolume */
2423 struct DiskPartition64 *partP; /*Ptr to partition */
2424 char pname[9], volname[20]; /*Partition, volume names */
2425 DIR *dirp; /*Partition directory ptr */
2426 afs_uint32 currVolID; /*Current volume ID */
2427 int found = 0; /*Did we find the volume we need? */
2429 volint_info_handle_t handle;
2432 * Set up our pointers for action, marking our structure to hold exactly
2433 * one entry. Also, assume we'll fail in our quest.
2435 a_volumeXInfoP->volXEntries_val =
2436 (volintXInfo *) malloc(sizeof(volintXInfo));
2437 if (!a_volumeXInfoP->volXEntries_val)
2439 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2441 a_volumeXInfoP->volXEntries_len = 1;
2445 * If the partition name we've been given is bad, bogue out.
2447 if (GetPartName(a_partID, pname))
2448 return (VOLSERILLEGAL_PARTITION);
2451 * Open the directory representing the given AFS parttion. If we can't
2454 if (!(partP = VGetPartition(pname, 0)))
2455 return VOLSERILLEGAL_PARTITION;
2456 dirp = opendir(VPartitionPath(partP));
2458 return (VOLSERILLEGAL_PARTITION);
2460 strcpy(volname, "");
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 (strcmp(volname, "EOD") && !found) {
2469 * If this is not a volume, move on to the next entry in the
2470 * partition's directory.
2472 if (!strcmp(volname, "")) {
2473 GetNextVol(dirp, volname, &currVolID);
2477 if (currVolID == a_volID) {
2479 * We found the volume entry we're interested. Pull out the
2480 * extended information, remembering to poll (so that the client
2481 * doesn't time out) and to set up a transaction on the volume.
2485 } /*Found desired volume */
2487 GetNextVol(dirp, volname, &currVolID);
2491 #ifndef AFS_PTHREAD_ENV
2495 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2496 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2498 code = GetVolInfo(a_partID,
2503 VOL_INFO_LIST_SINGLE);
2508 * Clean up before going to dinner: close the partition directory,
2509 * return the proper value.
2513 return code ? ENODEV: 0;
2516 } /*SAFSVolXListOneVolume */
2518 /*returns all the volumes on partition partid. If flags = 1 then all the
2519 * relevant info about the volumes is also returned */
2521 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2522 volEntries *volumeInfo)
2526 code = VolListVolumes(acid, partid, flags, volumeInfo);
2527 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2532 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2533 volEntries *volumeInfo)
2536 struct DiskPartition64 *partP;
2537 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2538 char pname[9], volname[20];
2542 volint_info_handle_t handle;
2544 volumeInfo->volEntries_val =
2545 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2546 if (!volumeInfo->volEntries_val)
2548 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2550 pntr = volumeInfo->volEntries_val;
2551 volumeInfo->volEntries_len = 0;
2552 if (GetPartName(partid, pname))
2553 return VOLSERILLEGAL_PARTITION;
2554 if (!(partP = VGetPartition(pname, 0)))
2555 return VOLSERILLEGAL_PARTITION;
2556 dirp = opendir(VPartitionPath(partP));
2558 return VOLSERILLEGAL_PARTITION;
2559 strcpy(volname, "");
2561 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2563 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2564 GetNextVol(dirp, volname, &volid);
2565 continue; /*back to while loop */
2568 if (flags) { /*copy other things too */
2569 #ifndef AFS_PTHREAD_ENV
2570 IOMGR_Poll(); /*make sure that the client does not time out */
2573 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2574 handle.volinfo_ptr.base = pntr;
2577 code = GetVolInfo(partid,
2582 VOL_INFO_LIST_MULTIPLE);
2583 if (code == -2) { /* DESTROY_ME flag set */
2587 pntr->volid = volid;
2588 /*just volids are needed */
2592 volumeInfo->volEntries_len += 1;
2593 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2594 /*running out of space, allocate more space */
2595 allocSize = (allocSize * 3) / 2;
2597 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2598 allocSize * sizeof(volintInfo));
2601 return VOLSERNO_MEMORY;
2603 volumeInfo->volEntries_val = pntr; /* point to new block */
2604 /* set pntr to the right position */
2605 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2610 GetNextVol(dirp, volname, &volid);
2618 /*------------------------------------------------------------------------
2619 * EXPORTED SAFSVolXListVolumes
2622 * Returns all the volumes on partition a_partID. If a_flags
2623 * is set to 1, then all the relevant extended volume information
2627 * a_rxCidP : Pointer to the Rx call we're performing.
2628 * a_partID : Partition for which we want the extended list.
2629 * a_flags : Various flags.
2630 * a_volumeXInfoP : Ptr to the extended info blob.
2633 * 0 Successful operation
2634 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2635 * VOLSERNO_MEMORY if we ran out of memory allocating
2639 * Nothing interesting.
2643 *------------------------------------------------------------------------*/
2646 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2647 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2651 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2652 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2657 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2658 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2659 { /*SAFSVolXListVolumes */
2661 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2662 struct DiskPartition64 *partP; /*Ptr to partition */
2663 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2664 char pname[9], volname[20]; /*Partition, volume names */
2665 DIR *dirp; /*Partition directory ptr */
2666 afs_uint32 volid; /*Current volume ID */
2668 volint_info_handle_t handle;
2671 * Allocate a large array of extended volume info structures, then
2672 * set it up for action.
2674 a_volumeXInfoP->volXEntries_val =
2675 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2676 if (!a_volumeXInfoP->volXEntries_val)
2678 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2680 xInfoP = a_volumeXInfoP->volXEntries_val;
2681 a_volumeXInfoP->volXEntries_len = 0;
2684 * If the partition name we've been given is bad, bogue out.
2686 if (GetPartName(a_partID, pname))
2687 return (VOLSERILLEGAL_PARTITION);
2690 * Open the directory representing the given AFS parttion. If we can't
2693 if (!(partP = VGetPartition(pname, 0)))
2694 return VOLSERILLEGAL_PARTITION;
2695 dirp = opendir(VPartitionPath(partP));
2697 return (VOLSERILLEGAL_PARTITION);
2698 strcpy(volname, "");
2701 * Sweep through the partition directory, acting on each entry. First,
2702 * of course, figure out how many stat bytes to copy out of each volume.
2704 while (strcmp(volname, "EOD")) {
2707 * If this is not a volume, move on to the next entry in the
2708 * partition's directory.
2710 if (!strcmp(volname, "")) {
2711 GetNextVol(dirp, volname, &volid);
2717 * Full info about the volume desired. Poll to make sure the
2718 * client doesn't time out, then start up a new transaction.
2720 #ifndef AFS_PTHREAD_ENV
2724 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2725 handle.volinfo_ptr.ext = xInfoP;
2727 code = GetVolInfo(a_partID,
2732 VOL_INFO_LIST_MULTIPLE);
2733 if (code == -2) { /* DESTROY_ME flag set */
2738 * Just volume IDs are needed.
2740 xInfoP->volid = volid;
2744 * Bump the pointer in the data area we're building, along with
2745 * the count of the number of entries it contains.
2748 (a_volumeXInfoP->volXEntries_len)++;
2749 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2751 * We're running out of space in the area we've built. Grow it.
2753 allocSize = (allocSize * 3) / 2;
2754 xInfoP = (volintXInfo *)
2755 realloc((char *)a_volumeXInfoP->volXEntries_val,
2756 (allocSize * sizeof(volintXInfo)));
2757 if (xInfoP == NULL) {
2759 * Bummer, no memory. Bag it, tell our caller what went wrong.
2762 return (VOLSERNO_MEMORY);
2766 * Memory reallocation worked. Correct our pointers so they
2767 * now point to the new block and the current open position within
2770 a_volumeXInfoP->volXEntries_val = xInfoP;
2772 a_volumeXInfoP->volXEntries_val +
2773 a_volumeXInfoP->volXEntries_len;
2777 GetNextVol(dirp, volname, &volid);
2778 } /*Sweep through the partition directory */
2781 * We've examined all entries in the partition directory. Close it,
2782 * delete our transaction (if any), and go home happy.
2787 } /*SAFSVolXListVolumes */
2789 /*this call is used to monitor the status of volser for debugging purposes.
2790 *information about all the active transactions is returned in transInfo*/
2792 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2796 code = VolMonitor(acid, transInfo);
2797 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2802 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2804 transDebugInfo *pntr;
2805 afs_int32 allocSize = 50;
2806 struct volser_trans *tt, *nt, *allTrans;
2808 transInfo->transDebugEntries_val =
2809 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2810 if (!transInfo->transDebugEntries_val)
2812 pntr = transInfo->transDebugEntries_val;
2813 transInfo->transDebugEntries_len = 0;
2816 allTrans = TransList();
2817 if (allTrans == (struct volser_trans *)0)
2818 goto done; /*no active transactions */
2819 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2821 VTRANS_OBJ_LOCK(tt);
2822 pntr->tid = tt->tid;
2823 pntr->time = tt->time;
2824 pntr->creationTime = tt->creationTime;
2825 pntr->returnCode = tt->returnCode;
2826 pntr->volid = tt->volid;
2827 pntr->partition = tt->partition;
2828 pntr->iflags = tt->iflags;
2829 pntr->vflags = tt->vflags;
2830 pntr->tflags = tt->tflags;
2831 strcpy(pntr->lastProcName, tt->lastProcName);
2832 pntr->callValid = 0;
2833 if (tt->rxCallPtr) { /*record call related info */
2834 pntr->callValid = 1;
2836 pntr->readNext = tt->rxCallPtr->rnext;
2837 pntr->transmitNext = tt->rxCallPtr->tnext;
2838 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2839 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2842 VTRANS_OBJ_UNLOCK(tt);
2844 transInfo->transDebugEntries_len += 1;
2845 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2846 allocSize = (allocSize * 3) / 2;
2848 (transDebugInfo *) realloc((char *)transInfo->
2849 transDebugEntries_val,
2851 sizeof(transDebugInfo));
2852 transInfo->transDebugEntries_val = pntr;
2854 transInfo->transDebugEntries_val +
2855 transInfo->transDebugEntries_len;
2856 /*set pntr to right position */
2867 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2868 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2869 afs_uint32 backupId)
2873 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2874 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2875 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2881 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2882 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2883 afs_uint32 backupId)
2887 struct volser_trans *tt;
2888 char caller[MAXKTCNAMELEN];
2890 if (strlen(name) > 31)
2891 return VOLSERBADNAME;
2892 if (!afsconf_SuperUser(tdir, acid, caller))
2893 return VOLSERBAD_ACCESS; /*not a super user */
2894 /* find the trans */
2895 tt = FindTrans(atid);
2898 if (tt->vflags & VTDeleted) {
2899 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2903 TSetRxCall(tt, acid, "SetIdsTypes");
2907 V_backupId(tv) = backupId;
2908 V_cloneId(tv) = cloneId;
2909 V_parentId(tv) = pId;
2910 strcpy((&V_disk(tv))->name, name);
2911 VUpdateVolume(&error, tv);
2913 Log("1 Volser: SetIdsTypes: 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 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2934 code = VolSetDate(acid, atid, cdate);
2935 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2941 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2945 struct volser_trans *tt;
2946 char caller[MAXKTCNAMELEN];
2948 if (!afsconf_SuperUser(tdir, acid, caller))
2949 return VOLSERBAD_ACCESS; /*not a super user */
2950 /* find the trans */
2951 tt = FindTrans(atid);
2954 if (tt->vflags & VTDeleted) {
2955 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2959 TSetRxCall(tt, acid, "SetDate");
2962 V_creationDate(tv) = cdate;
2963 VUpdateVolume(&error, tv);
2965 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2970 if (TRELE(tt) && !error)
2971 return VOLSERTRELE_ERROR;
2976 if (TRELE(tt) && !error)
2977 return VOLSERTRELE_ERROR;
2982 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2983 afs_uint32 volumeId)
2988 char caller[MAXKTCNAMELEN];
2990 struct volser_trans *ttc;
2991 char pname[16], volname[20];
2992 struct DiskPartition64 *partP;
2993 afs_int32 ret = ENODEV;
2996 if (!afsconf_SuperUser(tdir, acid, caller))
2997 return VOLSERBAD_ACCESS; /*not a super user */
2998 if (GetPartName(partId, pname))
2999 return VOLSERILLEGAL_PARTITION;
3000 if (!(partP = VGetPartition(pname, 0)))
3001 return VOLSERILLEGAL_PARTITION;
3002 dirp = opendir(VPartitionPath(partP));
3004 return VOLSERILLEGAL_PARTITION;
3005 strcpy(volname, "");
3006 ttc = (struct volser_trans *)0;
3008 while (strcmp(volname, "EOD")) {
3009 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3010 GetNextVol(dirp, volname, &volid);
3011 continue; /*back to while loop */
3014 if (volid == volumeId) { /*copy other things too */
3015 #ifndef AFS_PTHREAD_ENV
3016 IOMGR_Poll(); /*make sure that the client doesnot time out */
3018 ttc = NewTrans(volumeId, partId);
3020 return VOLSERVOLBUSY;
3022 #ifdef AFS_NAMEI_ENV
3023 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3025 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3029 GetNextVol(dirp, volname, &volid);
3033 DeleteTrans(ttc, 1);
3034 ttc = (struct volser_trans *)0;
3043 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3044 struct volintSize *size)
3047 struct volser_trans *tt;
3048 char caller[MAXKTCNAMELEN];
3050 if (!afsconf_SuperUser(tdir, acid, caller))
3051 return VOLSERBAD_ACCESS; /*not a super user */
3052 tt = FindTrans(fromTrans);
3055 if (tt->vflags & VTDeleted) {
3059 TSetRxCall(tt, acid, "GetSize");
3060 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3063 return VOLSERTRELE_ERROR;
3065 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3070 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3071 afs_uint32 where, afs_int32 verbose)
3073 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3075 Volume *vol=0, *newvol=0;
3076 struct volser_trans *tt = 0, *tt2 = 0;
3077 char caller[MAXKTCNAMELEN];
3080 if (!afsconf_SuperUser(tdir, acall, caller))
3083 vol = VAttachVolume(&code, vid, V_VOLUPD);
3089 newvol = VAttachVolume(&code, new, V_VOLUPD);
3091 VDetachVolume(&code2, vol);
3096 if (V_device(vol) != V_device(newvol)
3097 || V_uniquifier(newvol) != 2) {
3098 if (V_device(vol) != V_device(newvol)) {
3099 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3101 rx_Write(acall, line, strlen(line));
3103 if (V_uniquifier(newvol) != 2) {
3104 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3105 rx_Write(acall, line, strlen(line));
3108 rx_Write(acall, line, 1);
3109 VDetachVolume(&code2, vol);
3110 VDetachVolume(&code2, newvol);
3113 tt = NewTrans(vid, V_device(vol));
3115 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3116 rx_Write(acall, line, strlen(line));
3118 rx_Write(acall, line, 1);
3119 VDetachVolume(&code2, vol);
3120 VDetachVolume(&code2, newvol);
3121 return VOLSERVOLBUSY;
3123 VTRANS_OBJ_LOCK(tt);
3124 tt->iflags = ITBusy;
3126 TSetRxCall_r(tt, NULL, "SplitVolume");
3127 VTRANS_OBJ_UNLOCK(tt);
3129 tt2 = NewTrans(new, V_device(newvol));
3131 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3132 rx_Write(acall, line, strlen(line));
3134 rx_Write(acall, line, 1);
3136 VDetachVolume(&code2, vol);
3137 VDetachVolume(&code2, newvol);
3138 return VOLSERVOLBUSY;
3140 VTRANS_OBJ_LOCK(tt2);
3141 tt2->iflags = ITBusy;
3143 TSetRxCall_r(tt2, NULL, "SplitVolume");
3144 VTRANS_OBJ_UNLOCK(tt2);
3146 code = split_volume(acall, vol, newvol, where, verbose);
3148 VDetachVolume(&code2, vol);
3150 VDetachVolume(&code2, newvol);
3151 DeleteTrans(tt2, 1);
3158 /* GetPartName - map partid (a decimal number) into pname (a string)
3159 * Since for NT we actually want to return the drive name, we map through the
3163 GetPartName(afs_int32 partid, char *pname)
3168 strcpy(pname, "/vicep");
3169 pname[6] = 'a' + partid;
3172 } else if (partid < VOLMAXPARTS) {
3173 strcpy(pname, "/vicep");
3175 pname[6] = 'a' + (partid / 26);
3176 pname[7] = 'a' + (partid % 26);