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;
57 extern int DoPreserveVolumeStats;
59 extern void LogError(afs_int32 errcode);
61 /* Forward declarations */
62 static int GetPartName(afs_int32 partid, char *pname);
64 #define OneDay (24*60*60)
70 afs_int32 localTid = 1;
72 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
73 struct diskPartition64 *);
74 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
75 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
76 afs_int32, afs_uint32, afs_uint32 *,
78 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
79 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
80 afs_int32, char *, afs_uint32 *);
81 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
82 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
83 afs_int32, afs_int32 *);
84 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
86 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
87 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
88 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
89 struct destServer *destination, afs_int32,
90 struct restoreCookie *cookie);
91 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
92 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
93 struct restoreCookie *);
94 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
95 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
96 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
97 struct volser_status *);
98 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
99 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
100 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
101 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
102 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
104 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
106 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
108 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
110 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
111 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
112 afs_int32, afs_uint32, afs_uint32,
114 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
117 * Return the host address of the caller as a string.
119 * @param[in] acid incoming rx call
120 * @param[out] buffer buffer to be filled with the addess string
122 * @return address as formatted by inet_ntoa
125 callerAddress(struct rx_call *acid, char *buffer)
127 afs_uint32 ip = rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid)));
128 return afs_inet_ntoa_r(ip, buffer);
131 /* this call unlocks all of the partition locks we've set */
135 struct DiskPartition64 *tp;
136 for (tp = DiskPartitionList; tp; tp = tp->next) {
137 if (tp->lock_fd != INVALID_FD) {
138 OS_CLOSE(tp->lock_fd);
139 tp->lock_fd = INVALID_FD;
150 code = VPFullUnlock_r();
155 /* get partition id from a name */
157 PartitionID(char *aname)
165 return -1; /* unknown */
167 /* otherwise check for vicepa or /vicepa, or just plain "a" */
169 if (!strncmp(aname, "/vicep", 6)) {
170 strncpy(ascii, aname + 6, 2);
172 return -1; /* bad partition name */
173 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
174 * from 0. Do the appropriate conversion */
176 /* one char name, 0..25 */
177 if (ascii[0] < 'a' || ascii[0] > 'z')
178 return -1; /* wrongo */
179 return ascii[0] - 'a';
181 /* two char name, 26 .. <whatever> */
182 if (ascii[0] < 'a' || ascii[0] > 'z')
183 return -1; /* wrongo */
184 if (ascii[1] < 'a' || ascii[1] > 'z')
185 return -1; /* just as bad */
186 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
187 if (code > VOLMAXPARTS)
194 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
198 /* 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 */
199 snprintf(aname, asize, VFORMAT, (unsigned long)avol);
204 ConvertPartition(int apartno, char *aname, int asize)
210 strcpy(aname, "/vicep");
212 aname[6] = 'a' + apartno;
216 aname[6] = 'a' + (apartno / 26);
217 aname[7] = 'a' + (apartno % 26);
223 #ifdef AFS_DEMAND_ATTACH_FS
224 /* normally we should use the regular salvaging functions from the volume
225 * package, but this is a special case where we have a volume ID, but no
226 * volume structure to give the volume package */
228 SalvageUnknownVolume(VolumeId volid, char *part)
232 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
233 afs_printable_uint32_lu(volid), part);
235 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
236 FSYNC_SALVAGE, NULL);
238 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
239 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
243 #endif /* AFS_DEMAND_ATTACH_FS */
245 static struct Volume *
246 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
251 vp = VAttachVolumeByName(ec, partition, name, mode);
253 #ifdef AFS_DEMAND_ATTACH_FS
257 * The fileserver will take care of keeping track of how many
258 * demand-salvages have been performed, and will force the volume to
259 * ERROR if we've done too many. The limit on This loop is just a
260 * failsafe to prevent trying to salvage forever. We want to attempt
261 * attachment at least SALVAGE_COUNT_MAX times, since we want to
262 * avoid prematurely exiting this loop, if we can.
264 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
265 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
266 vp = VAttachVolumeByName(ec, partition, name, mode);
269 if (*ec == VSALVAGING) {
273 #endif /* AFS_DEMAND_ATTACH_FS */
278 static struct Volume *
279 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
284 vp = VAttachVolume(ec, avolid, amode);
286 #ifdef AFS_DEMAND_ATTACH_FS
289 /* see comment above in VAttachVolumeByName_retry */
290 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
291 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
292 vp = VAttachVolume(ec, avolid, amode);
295 if (*ec == VSALVAGING) {
299 #endif /* AFS_DEMAND_ATTACH_FS */
304 /* the only attach function that takes a partition is "...ByName", so we use it */
305 static struct Volume *
306 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
308 char pbuf[30], vbuf[20];
310 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
314 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
319 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
322 /* Adapted from the file server; create a root directory for this volume */
324 ViceCreateRoot(Volume *vp)
327 struct acl_accessList *ACL;
329 Inode inodeNumber, AFS_UNUSED nearInode;
330 struct VnodeDiskObject *vnode;
331 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
337 vnode = calloc(1, 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_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
757 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
763 if (originalvp->device != purgevp->device) {
764 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
768 if (V_type(purgevp) != readonlyVolume) {
769 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
773 if (V_parentId(originalvp) != V_parentId(purgevp)) {
774 Log("1 Volser: Clone: Volume %u and volume %u were not originally cloned from the same parent; aborted\n", purgeId, tt->volid);
781 #ifdef AFS_DEMAND_ATTACH_FS
782 salv_vp = originalvp;
785 if (purgeId == newId) {
789 VCreateVolume(&error, originalvp->partition->name, newId,
790 V_parentId(originalvp));
792 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
793 newvp = (Volume *) 0;
797 if (newType == readonlyVolume)
798 V_cloneId(originalvp) = newId;
799 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
802 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
803 CloneVolume(&error, originalvp, newvp, purgevp);
804 purgevp = NULL; /* clone releases it, maybe even if error */
806 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
810 if (newType == readonlyVolume) {
811 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
812 V_type(newvp) = readonlyVolume;
813 } else if (newType == backupVolume) {
814 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
815 V_type(newvp) = backupVolume;
816 V_backupId(originalvp) = newId;
818 strcpy(newvp->header->diskstuff.name, newName);
819 V_creationDate(newvp) = V_copyDate(newvp);
820 ClearVolumeStats(&V_disk(newvp));
821 V_destroyMe(newvp) = DESTROY_ME;
822 V_inService(newvp) = 0;
823 if (newType == backupVolume) {
824 V_backupDate(originalvp) = V_copyDate(newvp);
825 V_backupDate(newvp) = V_copyDate(newvp);
828 VUpdateVolume(&error, newvp);
830 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
834 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
836 VUpdateVolume(&error, originalvp);
838 Log("1 Volser: Clone: original update %u\n", error);
843 #ifdef AFS_DEMAND_ATTACH_FS
847 tt = (struct volser_trans *)0;
848 error = VOLSERTRELE_ERROR;
856 VDetachVolume(&code, purgevp);
858 VDetachVolume(&code, newvp);
865 #ifdef AFS_DEMAND_ATTACH_FS
866 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
867 V_needsSalvaged(salv_vp) = 1;
869 #endif /* AFS_DEMAND_ATTACH_FS */
873 /* reclone this volume into the specified id */
875 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
879 code = VolReClone(acid, atrans, cloneId);
880 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
886 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
888 struct Volume *originalvp, *clonevp;
891 struct volser_trans *tt, *ttc;
892 char caller[MAXKTCNAMELEN];
893 VolumeDiskData saved_header;
895 /*not a super user */
896 if (!afsconf_SuperUser(tdir, acid, caller))
897 return VOLSERBAD_ACCESS;
900 Log("%s on %s is executing Reclone Volume %u\n", caller,
901 callerAddress(acid, buffer), cloneId);
904 clonevp = originalvp = (Volume *) 0;
905 tt = (struct volser_trans *)0;
907 tt = FindTrans(atrans);
910 if (tt->vflags & VTDeleted) {
911 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
915 ttc = NewTrans(cloneId, tt->partition);
916 if (!ttc) { /* someone is messing with the clone already */
918 return VOLSERVOLBUSY;
920 TSetRxCall(tt, acid, "ReClone");
922 originalvp = tt->volume;
923 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
924 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
930 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
932 Log("1 Volser: can't attach clone %d\n", cloneId);
936 newType = V_type(clonevp); /* type of the new volume */
938 if (originalvp->device != clonevp->device) {
939 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
944 if (V_parentId(originalvp) != V_parentId(clonevp)) {
945 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
950 if (DoPreserveVolumeStats) {
951 CopyVolumeStats(&V_disk(clonevp), &saved_header);
955 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
957 CloneVolume(&error, originalvp, clonevp, clonevp);
959 Log("1 Volser: Clone: reclone operation failed with code %d\n",
965 /* fix up volume name and type, CloneVolume just propagated RW's */
966 if (newType == readonlyVolume) {
967 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
968 V_type(clonevp) = readonlyVolume;
969 } else if (newType == backupVolume) {
970 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
971 V_type(clonevp) = backupVolume;
972 V_backupId(originalvp) = cloneId;
974 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
976 /* update the creationDate, since this represents the last cloning date
977 * for ROs. But do not update copyDate; let it stay so we can identify
978 * when the clone was first created. */
979 V_creationDate(clonevp) = time(0);
980 if (DoPreserveVolumeStats) {
981 CopyVolumeStats(&saved_header, &V_disk(clonevp));
983 ClearVolumeStats(&V_disk(clonevp));
985 V_destroyMe(clonevp) = 0;
986 V_inService(clonevp) = 0;
987 if (newType == backupVolume) {
988 V_backupDate(originalvp) = V_creationDate(clonevp);
989 V_backupDate(clonevp) = V_creationDate(clonevp);
991 V_inUse(clonevp) = 0;
992 VUpdateVolume(&error, clonevp);
994 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
998 /* VUpdateVolume succeeded. Mark it in service so there's no window
999 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
1000 * specialStatus; this is a reclone and this volume started online
1002 V_inService(clonevp) = 1;
1003 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
1005 VUpdateVolume(&error, originalvp);
1007 Log("1 Volser: Clone: original update %u\n", error);
1013 tt = (struct volser_trans *)0;
1014 error = VOLSERTRELE_ERROR;
1018 DeleteTrans(ttc, 1);
1021 struct DiskPartition64 *tpartp = originalvp->partition;
1022 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1028 VDetachVolume(&code, clonevp);
1034 DeleteTrans(ttc, 1);
1038 /* create a new transaction, associated with volume and partition. Type of
1039 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1040 * See volser.h for definition of iflags (the constants are named IT*).
1043 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1044 afs_int32 iflags, afs_int32 *ttid)
1048 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1049 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1055 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1056 afs_int32 iflags, afs_int32 *ttid)
1058 struct volser_trans *tt;
1063 char caller[MAXKTCNAMELEN];
1065 if (!afsconf_SuperUser(tdir, acid, caller))
1066 return VOLSERBAD_ACCESS; /*not a super user */
1067 if (iflags & ITCreate)
1069 else if (iflags & ITBusy)
1071 else if (iflags & ITReadOnly)
1073 else if (iflags & ITOffline)
1076 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1081 tt = NewTrans(volume, partition);
1083 /* can't create a transaction? put the volume back */
1084 Log("1 transcreate: can't create transaction\n");
1085 return VOLSERVOLBUSY;
1087 tv = XAttachVolume(&error, volume, partition, mode);
1091 VDetachVolume(&code, tv);
1095 VTRANS_OBJ_LOCK(tt);
1098 tt->iflags = iflags;
1100 TSetRxCall_r(tt, NULL, "TransCreate");
1101 VTRANS_OBJ_UNLOCK(tt);
1103 return VOLSERTRELE_ERROR;
1108 /* using aindex as a 0-based index, return the aindex'th volume on this server
1109 * Both the volume number and partition number (one-based) are returned.
1112 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1117 code = VolGetNthVolume(acid, aindex, avolume, apart);
1118 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1123 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1126 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1130 /* return the volume flags (VT* constants in volser.h) associated with this
1134 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1138 code = VolGetFlags(acid, atid, aflags);
1139 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1144 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1146 struct volser_trans *tt;
1148 tt = FindTrans(atid);
1151 if (tt->vflags & VTDeleted) {
1152 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1157 TSetRxCall(tt, acid, "GetFlags");
1158 *aflags = tt->vflags;
1161 return VOLSERTRELE_ERROR;
1166 /* Change the volume flags (VT* constants in volser.h) associated with this
1167 * transaction. Effects take place immediately on volume, although volume
1168 * remains attached as usual by the transaction.
1171 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1175 code = VolSetFlags(acid, atid, aflags);
1176 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1182 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1184 struct volser_trans *tt;
1187 char caller[MAXKTCNAMELEN];
1189 if (!afsconf_SuperUser(tdir, acid, caller))
1190 return VOLSERBAD_ACCESS; /*not a super user */
1191 /* find the trans */
1192 tt = FindTrans(atid);
1195 if (tt->vflags & VTDeleted) {
1196 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1201 TSetRxCall(tt, acid, "SetFlags");
1202 vp = tt->volume; /* pull volume out of transaction */
1204 /* check if we're allowed to make any updates */
1205 if (tt->iflags & ITReadOnly) {
1210 /* handle delete-on-salvage flag */
1211 if (aflags & VTDeleteOnSalvage) {
1212 V_destroyMe(tt->volume) = DESTROY_ME;
1214 V_destroyMe(tt->volume) = 0;
1217 if (aflags & VTOutOfService) {
1218 V_inService(vp) = 0;
1220 V_inService(vp) = 1;
1222 VUpdateVolume(&error, vp);
1223 VTRANS_OBJ_LOCK(tt);
1224 tt->vflags = aflags;
1226 VTRANS_OBJ_UNLOCK(tt);
1227 if (TRELE(tt) && !error)
1228 return VOLSERTRELE_ERROR;
1233 /* dumpS the volume associated with a particular transaction from a particular
1234 * date. Send the dump to a different transaction (destTrans) on the server
1235 * specified by the destServer structure.
1238 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1239 struct destServer *destination, afs_int32 destTrans,
1240 struct restoreCookie *cookie)
1245 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1246 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1247 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1252 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1253 struct destServer *destination, afs_int32 destTrans,
1254 struct restoreCookie *cookie)
1256 struct volser_trans *tt;
1258 struct rx_connection *tcon;
1259 struct rx_call *tcall;
1261 struct rx_securityClass *securityObject;
1262 afs_int32 securityIndex;
1263 char caller[MAXKTCNAMELEN];
1265 if (!afsconf_SuperUser(tdir, acid, caller))
1266 return VOLSERBAD_ACCESS; /*not a super user */
1267 /* initialize things */
1268 tcon = (struct rx_connection *)0;
1269 tt = (struct volser_trans *)0;
1271 /* find the local transaction */
1272 tt = FindTrans(fromTrans);
1275 if (tt->vflags & VTDeleted) {
1276 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1281 TSetRxCall(tt, NULL, "Forward");
1283 /* get auth info for the this connection (uses afs from ticket file) */
1284 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1290 /* make an rpc connection to the other server */
1292 rx_NewConnection(htonl(destination->destHost),
1293 htons(destination->destPort), VOLSERVICE_ID,
1294 securityObject, securityIndex);
1300 tcall = rx_NewCall(tcon);
1301 TSetRxCall(tt, tcall, "Forward");
1302 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1303 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1308 /* these next calls implictly call rx_Write when writing out data */
1309 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1312 EndAFSVolRestore(tcall); /* probably doesn't do much */
1314 code = rx_EndCall(tcall, 0);
1315 rx_DestroyConnection(tcon); /* done with the connection */
1320 return VOLSERTRELE_ERROR;
1326 (void)rx_EndCall(tcall, 0);
1327 rx_DestroyConnection(tcon);
1336 /* Start a dump and send it to multiple places simultaneously.
1337 * If this returns an error (eg, return ENOENT), it means that
1338 * none of the releases worked. If this returns 0, that means
1339 * that one or more of the releases worked, and the caller has
1340 * to examine the results array to see which one(s).
1341 * This will only do EITHER incremental or full, not both, so it's
1342 * the caller's responsibility to be sure that all the destinations
1343 * need just an incremental (and from the same time), if that's
1347 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1348 fromDate, manyDests *destinations, afs_int32 spare,
1349 struct restoreCookie *cookie, manyResults *results)
1351 afs_int32 securityIndex;
1352 struct rx_securityClass *securityObject;
1353 char caller[MAXKTCNAMELEN];
1354 struct volser_trans *tt;
1355 afs_int32 ec, code, *codes;
1356 struct rx_connection **tcons;
1357 struct rx_call **tcalls;
1359 int i, is_incremental;
1362 memset(results, 0, sizeof(manyResults));
1363 i = results->manyResults_len = destinations->manyDests_len;
1364 results->manyResults_val = codes =
1365 (afs_int32 *) malloc(i * sizeof(afs_int32));
1367 if (!results || !results->manyResults_val)
1370 if (!afsconf_SuperUser(tdir, acid, caller))
1371 return VOLSERBAD_ACCESS; /*not a super user */
1372 tt = FindTrans(fromTrans);
1375 if (tt->vflags & VTDeleted) {
1376 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1381 TSetRxCall(tt, NULL, "ForwardMulti");
1383 /* (fromDate == 0) ==> full dump */
1384 is_incremental = (fromDate ? 1 : 0);
1387 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1391 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1397 /* get auth info for this connection (uses afs from ticket file) */
1398 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1400 goto fail; /* in order to audit each failure */
1403 /* make connections to all the other servers */
1404 for (i = 0; i < destinations->manyDests_len; i++) {
1405 struct replica *dest = &(destinations->manyDests_val[i]);
1407 rx_NewConnection(htonl(dest->server.destHost),
1408 htons(dest->server.destPort), VOLSERVICE_ID,
1409 securityObject, securityIndex);
1411 codes[i] = ENOTCONN;
1413 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1414 codes[i] = ENOTCONN;
1417 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1420 (void)rx_EndCall(tcalls[i], 0);
1422 rx_DestroyConnection(tcons[i]);
1429 /* these next calls implictly call rx_Write when writing out data */
1430 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1434 for (i--; i >= 0; i--) {
1435 struct replica *dest = &(destinations->manyDests_val[i]);
1437 if (!code && tcalls[i] && !codes[i]) {
1438 EndAFSVolRestore(tcalls[i]);
1441 ec = rx_EndCall(tcalls[i], 0);
1446 rx_DestroyConnection(tcons[i]); /* done with the connection */
1449 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1450 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1451 dest->trans, AUD_END);
1458 if (TRELE(tt) && !code) /* return the first code if it's set */
1459 return VOLSERTRELE_ERROR;
1466 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1470 code = VolDump(acid, fromTrans, fromDate, 0);
1471 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1476 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1481 code = VolDump(acid, fromTrans, fromDate, flags);
1482 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1487 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1491 struct volser_trans *tt;
1492 char caller[MAXKTCNAMELEN];
1494 if (!afsconf_SuperUser(tdir, acid, caller))
1495 return VOLSERBAD_ACCESS; /*not a super user */
1496 tt = FindTrans(fromTrans);
1499 if (tt->vflags & VTDeleted) {
1500 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1504 TSetRxCall(tt, acid, "Dump");
1505 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1506 ? 0 : 1); /* squirt out the volume's data, too */
1515 return VOLSERTRELE_ERROR;
1521 * Ha! No more helper process!
1524 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1525 struct restoreCookie *cookie)
1529 code = VolRestore(acid, atrans, aflags, cookie);
1530 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1535 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1536 struct restoreCookie *cookie)
1538 struct volser_trans *tt;
1539 afs_int32 code, tcode;
1540 char caller[MAXKTCNAMELEN];
1542 if (!afsconf_SuperUser(tdir, acid, caller))
1543 return VOLSERBAD_ACCESS; /*not a super user */
1544 tt = FindTrans(atrans);
1547 if (tt->vflags & VTDeleted) {
1548 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1552 TSetRxCall(tt, acid, "Restore");
1554 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1556 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1557 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1561 return (code ? code : tcode);
1564 /* end a transaction, returning the transaction's final error code in rcode */
1566 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1570 code = VolEndTrans(acid, destTrans, rcode);
1571 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1576 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1578 struct volser_trans *tt;
1579 char caller[MAXKTCNAMELEN];
1581 if (!afsconf_SuperUser(tdir, acid, caller))
1582 return VOLSERBAD_ACCESS; /*not a super user */
1583 tt = FindTrans(destTrans);
1587 *rcode = tt->returnCode;
1588 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1594 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1598 code = VolSetForwarding(acid, atid, anewsite);
1599 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1600 htonl(anewsite), AUD_END);
1605 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1607 struct volser_trans *tt;
1608 char caller[MAXKTCNAMELEN];
1611 if (!afsconf_SuperUser(tdir, acid, caller))
1612 return VOLSERBAD_ACCESS; /*not a super user */
1613 tt = FindTrans(atid);
1616 if (tt->vflags & VTDeleted) {
1617 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1622 TSetRxCall(tt, acid, "SetForwarding");
1623 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1626 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1629 return VOLSERTRELE_ERROR;
1635 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1636 struct volser_status *astatus)
1640 code = VolGetStatus(acid, atrans, astatus);
1641 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1646 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1647 struct volser_status *astatus)
1650 struct VolumeDiskData *td;
1651 struct volser_trans *tt;
1654 tt = FindTrans(atrans);
1657 if (tt->vflags & VTDeleted) {
1658 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1663 TSetRxCall(tt, acid, "GetStatus");
1671 td = &tv->header->diskstuff;
1672 astatus->volID = td->id;
1673 astatus->nextUnique = td->uniquifier;
1674 astatus->type = td->type;
1675 astatus->parentID = td->parentId;
1676 astatus->cloneID = td->cloneId;
1677 astatus->backupID = td->backupId;
1678 astatus->restoredFromID = td->restoredFromId;
1679 astatus->maxQuota = td->maxquota;
1680 astatus->minQuota = td->minquota;
1681 astatus->owner = td->owner;
1682 astatus->creationDate = td->creationDate;
1683 astatus->accessDate = td->accessDate;
1684 astatus->updateDate = td->updateDate;
1685 astatus->expirationDate = td->expirationDate;
1686 astatus->backupDate = td->backupDate;
1687 astatus->copyDate = td->copyDate;
1690 return VOLSERTRELE_ERROR;
1696 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1697 struct volintInfo *astatus)
1701 code = VolSetInfo(acid, atrans, astatus);
1702 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1707 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1708 struct volintInfo *astatus)
1711 struct VolumeDiskData *td;
1712 struct volser_trans *tt;
1713 char caller[MAXKTCNAMELEN];
1716 if (!afsconf_SuperUser(tdir, acid, caller))
1717 return VOLSERBAD_ACCESS; /*not a super user */
1718 tt = FindTrans(atrans);
1721 if (tt->vflags & VTDeleted) {
1722 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1726 TSetRxCall(tt, acid, "SetStatus");
1734 td = &tv->header->diskstuff;
1736 * Add more fields as necessary
1738 if (astatus->maxquota != -1)
1739 td->maxquota = astatus->maxquota;
1740 if (astatus->dayUse != -1)
1741 td->dayUse = astatus->dayUse;
1742 if (astatus->creationDate != -1)
1743 td->creationDate = astatus->creationDate;
1744 if (astatus->updateDate != -1)
1745 td->updateDate = astatus->updateDate;
1746 if (astatus->spare2 != -1)
1747 td->volUpdateCounter = (unsigned int)astatus->spare2;
1748 VUpdateVolume(&error, tv);
1751 return VOLSERTRELE_ERROR;
1757 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1761 code = VolGetName(acid, atrans, aname);
1762 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1767 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1770 struct VolumeDiskData *td;
1771 struct volser_trans *tt;
1774 /* We need to at least fill it in */
1775 *aname = (char *)malloc(1);
1778 tt = FindTrans(atrans);
1781 if (tt->vflags & VTDeleted) {
1782 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1786 TSetRxCall(tt, acid, "GetName");
1794 td = &tv->header->diskstuff;
1795 len = strlen(td->name) + 1; /* don't forget the null */
1801 *aname = (char *)realloc(*aname, len);
1802 strcpy(*aname, td->name);
1805 return VOLSERTRELE_ERROR;
1810 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1813 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1814 afs_uint32 parentId, afs_uint32 cloneId)
1820 /*return a list of all partitions on the server. The non mounted
1821 *partitions are returned as -1 in the corresponding slot in partIds*/
1823 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1827 code = VolListPartitions(acid, partIds);
1828 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1833 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1838 strcpy(namehead, "/vicep"); /*7 including null terminator */
1840 /* Just return attached partitions. */
1842 for (i = 0; i < 26; i++) {
1843 namehead[6] = i + 'a';
1844 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1850 /*return a list of all partitions on the server. The non mounted
1851 *partitions are returned as -1 in the corresponding slot in partIds*/
1853 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1857 code = XVolListPartitions(acid, pEntries);
1858 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1863 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1866 struct partList partList;
1867 struct DiskPartition64 *dp;
1870 strcpy(namehead, "/vicep"); /*7 including null terminator */
1872 /* Only report attached partitions */
1873 for (i = 0; i < VOLMAXPARTS; i++) {
1874 #ifdef AFS_DEMAND_ATTACH_FS
1875 dp = VGetPartitionById(i, 0);
1878 namehead[6] = i + 'a';
1884 namehead[6] = 'a' + (k / 26);
1885 namehead[7] = 'a' + (k % 26);
1888 dp = VGetPartition(namehead, 0);
1891 partList.partId[j++] = i;
1894 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1895 if (!pEntries->partEntries_val)
1897 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1899 pEntries->partEntries_len = j;
1901 pEntries->partEntries_val = NULL;
1902 pEntries->partEntries_len = 0;
1908 /*return the name of the next volume header in the directory associated with dirp and dp.
1909 *the volume id is returned in volid, and volume header name is returned in volname*/
1911 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1915 dp = readdir(dirp); /*read next entry in the directory */
1917 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1918 *volid = VolumeNumber(dp->d_name);
1919 strcpy(volname, dp->d_name);
1920 return 0; /*return the name of the file representing a volume */
1922 strcpy(volname, "");
1923 return 0; /*volname doesnot represent a volume */
1926 strcpy(volname, "EOD");
1927 return 0; /*end of directory */
1933 * volint vol info structure type.
1936 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1937 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1938 } volint_info_type_t;
1941 * handle to various on-wire vol info types.
1944 volint_info_type_t volinfo_type;
1950 } volint_info_handle_t;
1953 * store value to a field at the appropriate location in on-wire structure.
1955 #define VOLINT_INFO_STORE(handle, name, val) \
1957 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1958 (handle)->volinfo_ptr.base->name = (val); \
1960 (handle)->volinfo_ptr.ext->name = (val); \
1965 * get pointer to appropriate offset of field in on-wire structure.
1967 #define VOLINT_INFO_PTR(handle, name) \
1968 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1969 &((handle)->volinfo_ptr.base->name) : \
1970 &((handle)->volinfo_ptr.ext->name))
1973 * fill in appropriate type of on-wire volume metadata structure.
1975 * @param vp pointer to volume object
1976 * @param handle pointer to wire format handle object
1978 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1979 * @pre handle object must have a valid pointer and enumeration value
1981 * @note passing a NULL value for vp means that the fileserver doesn't
1982 * know about this particular volume, thus implying it is offline.
1984 * @return operation status
1989 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1991 unsigned int numStatBytes, now;
1992 struct VolumeDiskData *hdr = &vp->header->diskstuff;
1994 /*read in the relevant info */
1995 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1996 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1997 VOLINT_INFO_STORE(handle, volid, hdr->id);
1998 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1999 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2000 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2001 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2002 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2003 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2004 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2005 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2006 now = FT_ApproxTime();
2007 if ((now - hdr->dayUseDate) > OneDay) {
2008 VOLINT_INFO_STORE(handle, dayUse, 0);
2010 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2012 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2013 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2014 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2015 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2017 #ifdef AFS_DEMAND_ATTACH_FS
2019 * for DAFS, we "lie" about volume state --
2020 * instead of returning the raw state from the disk header,
2021 * we compute state based upon the fileserver's internal
2022 * in-core state enumeration value reported to us via fssync,
2023 * along with the blessed and inService flags from the header.
2024 * -- tkeiser 11/27/2007
2027 /* Conditions that offline status is based on:
2028 volume is unattached state
2029 volume state is in (one of several error states)
2030 volume not in service
2031 volume is not marked as blessed (not on hold)
2032 volume in salvage req. state
2033 volume needsSalvaged
2034 next op would set volume offline
2035 next op would not leave volume online (based on several conditions)
2038 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2039 VIsErrorState(V_attachState(vp)) ||
2042 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2043 hdr->needsSalvaged ||
2044 (vp->pending_vol_op &&
2045 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2046 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2049 VOLINT_INFO_STORE(handle, inUse, 0);
2051 VOLINT_INFO_STORE(handle, inUse, 1);
2054 /* offline status based on program type, where != fileServer enum (1) is offline */
2055 if (hdr->inUse == fileServer) {
2056 VOLINT_INFO_STORE(handle, inUse, 1);
2058 VOLINT_INFO_STORE(handle, inUse, 0);
2063 switch(handle->volinfo_type) {
2064 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2065 case VOLINT_INFO_TYPE_BASE:
2067 #ifdef AFS_DEMAND_ATTACH_FS
2068 /* see comment above where we set inUse bit */
2069 if (hdr->needsSalvaged ||
2070 (vp && VIsErrorState(V_attachState(vp)))) {
2071 handle->volinfo_ptr.base->needsSalvaged = 1;
2073 handle->volinfo_ptr.base->needsSalvaged = 0;
2076 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2078 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2079 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2080 handle->volinfo_ptr.base->spare1 =
2081 (long)hdr->weekUse[0] +
2082 (long)hdr->weekUse[1] +
2083 (long)hdr->weekUse[2] +
2084 (long)hdr->weekUse[3] +
2085 (long)hdr->weekUse[4] +
2086 (long)hdr->weekUse[5] +
2087 (long)hdr->weekUse[6];
2088 handle->volinfo_ptr.base->flags = 0;
2089 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2090 handle->volinfo_ptr.base->spare3 = 0;
2094 case VOLINT_INFO_TYPE_EXT:
2096 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2097 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2100 * Copy out the stat fields in a single operation.
2102 if ((now - hdr->dayUseDate) > OneDay) {
2103 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2106 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2107 (char *)&(hdr->stat_reads[0]),
2116 #ifdef AFS_DEMAND_ATTACH_FS
2119 * get struct Volume out of the fileserver.
2121 * @param[in] volumeId volumeId for which we want state information
2122 * @param[in] pname partition name string
2123 * @param[inout] vp pointer to pointer to Volume object which
2124 * will be populated (see note)
2126 * @return operation status
2128 * @retval non-zero failure
2130 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2135 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2140 res.hdr.response_len = sizeof(res.hdr);
2141 res.payload.buf = *vp;
2142 res.payload.len = sizeof(Volume);
2144 code = FSYNC_VolOp(volumeId,
2150 if (code != SYNC_OK) {
2151 switch (res.hdr.reason) {
2152 case FSYNC_WRONG_PART:
2153 case FSYNC_UNKNOWN_VOLID:
2166 * mode of volume list operation.
2169 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2170 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2171 } vol_info_list_mode_t;
2174 * abstract interface to populate wire-format volume metadata structures.
2176 * @param[in] partId partition id
2177 * @param[in] volumeId volume id
2178 * @param[in] pname partition name
2179 * @param[in] volname volume file name
2180 * @param[in] handle handle to on-wire volume metadata object
2181 * @param[in] mode listing mode
2183 * @return operation status
2185 * @retval -2 DESTROY_ME flag is set
2186 * @retval -1 general failure; some data filled in
2187 * @retval -3 couldn't create vtrans; some data filled in
2190 GetVolInfo(afs_uint32 partId,
2191 afs_uint32 volumeId,
2194 volint_info_handle_t * handle,
2195 vol_info_list_mode_t mode)
2199 struct volser_trans *ttc = NULL;
2200 struct Volume *fill_tv, *tv = NULL;
2201 #ifdef AFS_DEMAND_ATTACH_FS
2202 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2203 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2204 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2205 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2207 /* Set up response handle for pending_vol_op */
2208 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2209 fs_res.payload.buf = fs_res_buf;
2210 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2213 ttc = NewTrans(volumeId, partId);
2216 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2217 VOLINT_INFO_STORE(handle, volid, volumeId);
2221 /* Get volume from volserver */
2222 if (mode == VOL_INFO_LIST_MULTIPLE)
2223 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2225 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2227 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2228 volumeId, pname, volname, error);
2233 * please note that destroyMe and needsSalvaged checks used to be ordered
2234 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2235 * more correct to check destroyMe before needsSalvaged.
2236 * -- tkeiser 11/28/2007
2239 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2241 case VOL_INFO_LIST_MULTIPLE:
2245 case VOL_INFO_LIST_SINGLE:
2246 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2247 volumeId, pname, volname);
2254 if (tv->header->diskstuff.needsSalvaged) {
2255 /*this volume will be salvaged */
2256 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2257 volumeId, pname, volname);
2260 #ifdef AFS_DEMAND_ATTACH_FS
2261 /* If using DAFS, get volume from fsserver */
2262 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2267 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2268 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2269 /* If we if the pending vol op */
2270 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2271 fs_tv->pending_vol_op=&pending_vol_op_res;
2273 fs_tv->pending_vol_op=NULL;
2276 /* populate the header from the volserver copy */
2277 fs_tv->header=tv->header;
2279 /* When using DAFS, use the fs volume info, populated with required structures */
2282 /* When not using DAFS, just use the local volume info */
2286 /* ok, we have all the data we need; fill in the on-wire struct */
2287 code = FillVolInfo(fill_tv, handle);
2291 VOLINT_INFO_STORE(handle, status, 0);
2292 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2293 VOLINT_INFO_STORE(handle, volid, volumeId);
2296 VDetachVolume(&error, tv);
2299 VOLINT_INFO_STORE(handle, status, 0);
2300 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2301 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2302 volumeId, pname, volname);
2306 DeleteTrans(ttc, 1);
2313 /*return the header information about the <volid> */
2315 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2316 afs_uint32 volumeId, volEntries *volumeInfo)
2320 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2321 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2326 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2327 afs_uint32 volumeId, volEntries *volumeInfo)
2329 struct DiskPartition64 *partP;
2330 char pname[9], volname[20];
2335 volint_info_handle_t handle;
2337 volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2338 if (!volumeInfo->volEntries_val)
2341 volumeInfo->volEntries_len = 1;
2342 if (GetPartName(partid, pname))
2343 return VOLSERILLEGAL_PARTITION;
2344 if (!(partP = VGetPartition(pname, 0)))
2345 return VOLSERILLEGAL_PARTITION;
2346 dirp = opendir(VPartitionPath(partP));
2348 return VOLSERILLEGAL_PARTITION;
2350 strcpy(volname, "");
2352 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2354 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2355 GetNextVol(dirp, volname, &volid);
2356 continue; /*back to while loop */
2359 if (volid == volumeId) { /*copy other things too */
2364 GetNextVol(dirp, volname, &volid);
2368 #ifndef AFS_PTHREAD_ENV
2369 IOMGR_Poll(); /*make sure that the client does not time out */
2372 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2373 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2375 code = GetVolInfo(partid,
2380 VOL_INFO_LIST_SINGLE);
2385 return code ? ENODEV: 0;
2390 /*------------------------------------------------------------------------
2391 * EXPORTED SAFSVolXListOneVolume
2394 * Returns extended info on volume a_volID on partition a_partID.
2397 * a_rxCidP : Pointer to the Rx call we're performing.
2398 * a_partID : Partition for which we want the extended list.
2399 * a_volID : Volume ID we wish to know about.
2400 * a_volumeXInfoP : Ptr to the extended info blob.
2403 * 0 Successful operation
2404 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2407 * Nothing interesting.
2411 *------------------------------------------------------------------------*/
2414 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2415 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2419 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2420 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2425 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2426 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2427 { /*SAFSVolXListOneVolume */
2429 struct DiskPartition64 *partP; /*Ptr to partition */
2430 char pname[9], volname[20]; /*Partition, volume names */
2431 DIR *dirp; /*Partition directory ptr */
2432 afs_uint32 currVolID; /*Current volume ID */
2433 int found = 0; /*Did we find the volume we need? */
2435 volint_info_handle_t handle;
2438 * Set up our pointers for action, marking our structure to hold exactly
2439 * one entry. Also, assume we'll fail in our quest.
2441 a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2442 if (!a_volumeXInfoP->volXEntries_val)
2445 a_volumeXInfoP->volXEntries_len = 1;
2449 * If the partition name we've been given is bad, bogue out.
2451 if (GetPartName(a_partID, pname))
2452 return (VOLSERILLEGAL_PARTITION);
2455 * Open the directory representing the given AFS parttion. If we can't
2458 if (!(partP = VGetPartition(pname, 0)))
2459 return VOLSERILLEGAL_PARTITION;
2460 dirp = opendir(VPartitionPath(partP));
2462 return (VOLSERILLEGAL_PARTITION);
2464 strcpy(volname, "");
2467 * Sweep through the partition directory, looking for the desired entry.
2468 * First, of course, figure out how many stat bytes to copy out of each
2471 while (strcmp(volname, "EOD") && !found) {
2473 * If this is not a volume, move on to the next entry in the
2474 * partition's directory.
2476 if (!strcmp(volname, "")) {
2477 GetNextVol(dirp, volname, &currVolID);
2481 if (currVolID == a_volID) {
2483 * We found the volume entry we're interested. Pull out the
2484 * extended information, remembering to poll (so that the client
2485 * doesn't time out) and to set up a transaction on the volume.
2489 } /*Found desired volume */
2491 GetNextVol(dirp, volname, &currVolID);
2495 #ifndef AFS_PTHREAD_ENV
2499 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2500 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2502 code = GetVolInfo(a_partID,
2507 VOL_INFO_LIST_SINGLE);
2512 * Clean up before going to dinner: close the partition directory,
2513 * return the proper value.
2517 return code ? ENODEV: 0;
2520 } /*SAFSVolXListOneVolume */
2522 /*returns all the volumes on partition partid. If flags = 1 then all the
2523 * relevant info about the volumes is also returned */
2525 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2526 volEntries *volumeInfo)
2530 code = VolListVolumes(acid, partid, flags, volumeInfo);
2531 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2536 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2537 volEntries *volumeInfo)
2540 struct DiskPartition64 *partP;
2541 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2542 char pname[9], volname[20];
2546 volint_info_handle_t handle;
2548 volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2549 if (!volumeInfo->volEntries_val)
2552 pntr = volumeInfo->volEntries_val;
2553 volumeInfo->volEntries_len = 0;
2554 if (GetPartName(partid, pname))
2555 return VOLSERILLEGAL_PARTITION;
2556 if (!(partP = VGetPartition(pname, 0)))
2557 return VOLSERILLEGAL_PARTITION;
2558 dirp = opendir(VPartitionPath(partP));
2560 return VOLSERILLEGAL_PARTITION;
2561 strcpy(volname, "");
2563 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2565 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2566 GetNextVol(dirp, volname, &volid);
2567 continue; /*back to while loop */
2570 if (flags) { /*copy other things too */
2571 #ifndef AFS_PTHREAD_ENV
2572 IOMGR_Poll(); /*make sure that the client does not time out */
2575 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2576 handle.volinfo_ptr.base = pntr;
2579 code = GetVolInfo(partid,
2584 VOL_INFO_LIST_MULTIPLE);
2585 if (code == -2) { /* DESTROY_ME flag set */
2589 pntr->volid = volid;
2590 /*just volids are needed */
2594 volumeInfo->volEntries_len += 1;
2595 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2596 /*running out of space, allocate more space */
2597 allocSize = (allocSize * 3) / 2;
2599 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2600 allocSize * sizeof(volintInfo));
2603 return VOLSERNO_MEMORY;
2605 volumeInfo->volEntries_val = pntr; /* point to new block */
2606 /* set pntr to the right position */
2607 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2612 GetNextVol(dirp, volname, &volid);
2620 /*------------------------------------------------------------------------
2621 * EXPORTED SAFSVolXListVolumes
2624 * Returns all the volumes on partition a_partID. If a_flags
2625 * is set to 1, then all the relevant extended volume information
2629 * a_rxCidP : Pointer to the Rx call we're performing.
2630 * a_partID : Partition for which we want the extended list.
2631 * a_flags : Various flags.
2632 * a_volumeXInfoP : Ptr to the extended info blob.
2635 * 0 Successful operation
2636 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2637 * VOLSERNO_MEMORY if we ran out of memory allocating
2641 * Nothing interesting.
2645 *------------------------------------------------------------------------*/
2648 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2649 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2653 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2654 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2659 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2660 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2661 { /*SAFSVolXListVolumes */
2663 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2664 struct DiskPartition64 *partP; /*Ptr to partition */
2665 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2666 char pname[9], volname[20]; /*Partition, volume names */
2667 DIR *dirp; /*Partition directory ptr */
2668 afs_uint32 volid; /*Current volume ID */
2670 volint_info_handle_t handle;
2673 * Allocate a large array of extended volume info structures, then
2674 * set it up for action.
2676 a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2677 if (!a_volumeXInfoP->volXEntries_val)
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);