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/afs_assert.h>
22 #include <afs/prs_fs.h>
26 #include <afs/cellconfig.h>
29 #include <afs/ihandle.h>
31 #include <afs/ntops.h>
33 #include <afs/vnode.h>
34 #include <afs/volume.h>
35 #include <afs/volume_inline.h>
36 #include <afs/partition.h>
38 #include <afs/daemon_com.h>
39 #include <afs/fssync.h>
41 #include "afs/audit.h"
43 #include <afs/afsutil.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);
115 /* this call unlocks all of the partition locks we've set */
119 struct DiskPartition64 *tp;
120 for (tp = DiskPartitionList; tp; tp = tp->next) {
121 if (tp->lock_fd != INVALID_FD) {
122 OS_CLOSE(tp->lock_fd);
123 tp->lock_fd = INVALID_FD;
134 code = VPFullUnlock_r();
139 /* get partition id from a name */
141 PartitionID(char *aname)
149 return -1; /* unknown */
151 /* otherwise check for vicepa or /vicepa, or just plain "a" */
153 if (!strncmp(aname, "/vicep", 6)) {
154 strncpy(ascii, aname + 6, 2);
156 return -1; /* bad partition name */
157 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
158 * from 0. Do the appropriate conversion */
160 /* one char name, 0..25 */
161 if (ascii[0] < 'a' || ascii[0] > 'z')
162 return -1; /* wrongo */
163 return ascii[0] - 'a';
165 /* two char name, 26 .. <whatever> */
166 if (ascii[0] < 'a' || ascii[0] > 'z')
167 return -1; /* wrongo */
168 if (ascii[1] < 'a' || ascii[1] > 'z')
169 return -1; /* just as bad */
170 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
171 if (code > VOLMAXPARTS)
178 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
182 /* 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 */
183 snprintf(aname, asize, VFORMAT, (unsigned long)avol);
188 ConvertPartition(int apartno, char *aname, int asize)
194 strcpy(aname, "/vicep");
196 aname[6] = 'a' + apartno;
200 aname[6] = 'a' + (apartno / 26);
201 aname[7] = 'a' + (apartno % 26);
207 #ifdef AFS_DEMAND_ATTACH_FS
208 /* normally we should use the regular salvaging functions from the volume
209 * package, but this is a special case where we have a volume ID, but no
210 * volume structure to give the volume package */
212 SalvageUnknownVolume(VolumeId volid, char *part)
216 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
217 afs_printable_uint32_lu(volid), part);
219 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
220 FSYNC_SALVAGE, NULL);
222 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
223 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
227 #endif /* AFS_DEMAND_ATTACH_FS */
229 static struct Volume *
230 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
235 vp = VAttachVolumeByName(ec, partition, name, mode);
237 #ifdef AFS_DEMAND_ATTACH_FS
241 * The fileserver will take care of keeping track of how many
242 * demand-salvages have been performed, and will force the volume to
243 * ERROR if we've done too many. The limit on This loop is just a
244 * failsafe to prevent trying to salvage forever. We want to attempt
245 * attachment at least SALVAGE_COUNT_MAX times, since we want to
246 * avoid prematurely exiting this loop, if we can.
248 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
249 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
250 vp = VAttachVolumeByName(ec, partition, name, mode);
253 if (*ec == VSALVAGING) {
257 #endif /* AFS_DEMAND_ATTACH_FS */
262 static struct Volume *
263 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
268 vp = VAttachVolume(ec, avolid, amode);
270 #ifdef AFS_DEMAND_ATTACH_FS
273 /* see comment above in VAttachVolumeByName_retry */
274 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
275 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
276 vp = VAttachVolume(ec, avolid, amode);
279 if (*ec == VSALVAGING) {
283 #endif /* AFS_DEMAND_ATTACH_FS */
288 /* the only attach function that takes a partition is "...ByName", so we use it */
289 static struct Volume *
290 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
292 char pbuf[30], vbuf[20];
294 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
298 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
303 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
306 /* Adapted from the file server; create a root directory for this volume */
308 ViceCreateRoot(Volume *vp)
311 struct acl_accessList *ACL;
313 Inode inodeNumber, nearInode;
314 struct VnodeDiskObject *vnode;
315 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
321 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
324 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
326 V_pref(vp, nearInode);
328 IH_CREATE(V_linkHandle(vp), V_device(vp),
329 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
331 osi_Assert(VALID_INO(inodeNumber));
333 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
334 did.Volume = V_id(vp);
335 did.Vnode = (VnodeId) 1;
338 osi_Assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
339 DFlush(); /* flush all modified dir buffers out */
340 DZap((afs_int32 *)&dir); /* Remove all buffers for this dir */
341 length = Length(&dir); /* Remember size of this directory */
343 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
345 /* build a single entry ACL that gives all rights to system:administrators */
346 /* this section of code assumes that access list format is not going to
349 ACL = VVnodeDiskACL(vnode);
350 ACL->size = sizeof(struct acl_accessList);
351 ACL->version = ACL_ACLVERSION;
355 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
356 ACL->entries[0].rights =
357 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
358 | PRSFS_LOCK | PRSFS_ADMINISTER;
360 vnode->type = vDirectory;
362 vnode->modeBits = 0777;
363 vnode->linkCount = 2;
364 VNDISK_SET_LEN(vnode, length);
365 vnode->uniquifier = 1;
366 V_uniquifier(vp) = vnode->uniquifier + 1;
367 vnode->dataVersion = 1;
368 VNDISK_SET_INO(vnode, inodeNumber);
369 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
373 vnode->vnodeMagic = vcp->magic;
375 IH_INIT(h, vp->device, V_parentId(vp),
376 vp->vnodeIndex[vLarge].handle->ih_ino);
378 osi_Assert(fdP != NULL);
379 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
380 osi_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
381 FDH_REALLYCLOSE(fdP);
383 VNDISK_GET_LEN(length, vnode);
384 V_diskused(vp) = nBlocks(length);
391 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
395 struct diskPartition64 *dp = (struct diskPartition64 *)
396 malloc(sizeof(struct diskPartition64));
398 code = VolPartitionInfo(acid, pname, dp);
400 strncpy(partition->name, dp->name, 32);
401 strncpy(partition->devName, dp->devName, 32);
402 partition->lock_fd = dp->lock_fd;
403 partition->free=RoundInt64ToInt32(dp->free);
404 partition->minFree=RoundInt64ToInt32(dp->minFree);
407 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
412 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
417 code = VolPartitionInfo(acid, pname, partition);
418 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
423 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
426 struct DiskPartition64 *dp;
429 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
432 dp = VGetPartition(pname, 0);
434 strncpy(partition->name, dp->name, 32);
435 strncpy(partition->devName, dp->devName, 32);
436 partition->lock_fd = (int)dp->lock_fd;
437 partition->free = dp->free;
438 partition->minFree = dp->totalUsable;
441 return VOLSERILLEGAL_PARTITION;
444 /* obliterate a volume completely, and slowly. */
446 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
450 code = VolNukeVolume(acid, apartID, avolID);
451 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
456 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
463 char caller[MAXKTCNAMELEN];
465 /* check for access */
466 if (!afsconf_SuperUser(tdir, acid, caller))
467 return VOLSERBAD_ACCESS;
469 Log("%s is executing VolNukeVolume %u\n", caller, avolID);
471 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
473 /* we first try to attach the volume in update mode, so that the file
474 * server doesn't try to use it (and abort) while (or after) we delete it.
475 * If we don't get the volume, that's fine, too. We just won't put it back.
477 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
478 code = nuke(partName, avolID);
480 VDetachVolume(&verror, tvp);
484 /* create a new volume, with name aname, on the specified partition (1..n)
485 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
486 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
487 * for the volume id (useful for things like volume restore).
488 * Return the new volume id in *avolid.
491 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
492 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
498 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
499 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
500 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
506 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
507 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
512 Error junk; /* discardable error code */
514 afs_int32 doCreateRoot = 1;
515 struct volser_trans *tt;
517 char caller[MAXKTCNAMELEN];
519 if (strlen(aname) > 31)
520 return VOLSERBADNAME;
521 if (!afsconf_SuperUser(tdir, acid, caller))
522 return VOLSERBAD_ACCESS;
524 Log("%s is executing CreateVolume '%s'\n", caller, aname);
525 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
526 return error; /*a standard unix error */
527 if (atype != readwriteVolume && atype != readonlyVolume
528 && atype != backupVolume)
530 if ((volumeID = *avolid) == 0) {
532 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
536 if ((aparent == volumeID) && (atype == readwriteVolume)) {
541 tt = NewTrans(volumeID, apart);
543 Log("1 createvolume: failed to create trans\n");
544 return VOLSERVOLBUSY; /* volume already busy! */
546 vp = VCreateVolume(&error, ppath, volumeID, aparent);
548 #ifdef AFS_DEMAND_ATTACH_FS
549 if (error != VVOLEXISTS && error != EXDEV) {
550 SalvageUnknownVolume(volumeID, ppath);
553 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
558 V_uniquifier(vp) = 1;
559 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
560 V_inService(vp) = V_blessed(vp) = 1;
562 AssignVolumeName(&V_disk(vp), aname, 0);
565 V_destroyMe(vp) = DESTROY_ME;
567 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
568 VUpdateVolume(&error, vp);
570 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
573 VDetachVolume(&junk, vp); /* rather return the real error code */
579 TSetRxCall_r(tt, acid, "CreateVolume");
580 VTRANS_OBJ_UNLOCK(tt);
581 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
584 return VOLSERTRELE_ERROR;
588 /* delete the volume associated with this transaction */
590 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
594 code = VolDeleteVolume(acid, atrans);
595 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
600 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
602 struct volser_trans *tt;
604 char caller[MAXKTCNAMELEN];
606 if (!afsconf_SuperUser(tdir, acid, caller))
607 return VOLSERBAD_ACCESS;
608 tt = FindTrans(atrans);
611 if (tt->vflags & VTDeleted) {
612 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
617 Log("%s is executing Delete Volume %u\n", caller, tt->volid);
618 TSetRxCall(tt, acid, "DeleteVolume");
619 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
620 V_destroyMe(tt->volume) = DESTROY_ME;
621 if (tt->volume->needsPutBack) {
622 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
625 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
627 VTRANS_OBJ_UNLOCK(tt);
629 return VOLSERTRELE_ERROR;
631 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
632 return 0; /* vpurgevolume doesn't set an error code */
635 /* make a clone of the volume associated with atrans, possibly giving it a new
636 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
637 * for the clone's id). The new clone is given the name newName. Finally,
638 * due to efficiency considerations, if purgeId is non-zero, we purge that
639 * volume when doing the clone operation. This may be useful when making
640 * new backup volumes, for instance since the net result of a clone and a
641 * purge generally leaves many inode ref counts the same, while doing them
642 * separately would result in far more iincs and idecs being peformed
643 * (and they are slow operations).
645 /* for efficiency reasons, sometimes faster to piggyback a purge here */
647 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
648 afs_int32 newType, char *newName, afs_uint32 *newNumber)
652 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
653 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
654 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
660 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
661 afs_int32 newType, char *newName, afs_uint32 *newNumber)
664 struct Volume *originalvp, *purgevp, *newvp;
666 struct volser_trans *tt, *ttc;
667 char caller[MAXKTCNAMELEN];
668 #ifdef AFS_DEMAND_ATTACH_FS
669 struct Volume *salv_vp = NULL;
672 if (strlen(newName) > 31)
673 return VOLSERBADNAME;
674 if (!afsconf_SuperUser(tdir, acid, caller))
675 return VOLSERBAD_ACCESS; /*not a super user */
677 Log("%s is executing Clone Volume new name=%s\n", caller, newName);
679 originalvp = (Volume *) 0;
680 purgevp = (Volume *) 0;
681 newvp = (Volume *) 0;
682 tt = ttc = (struct volser_trans *)0;
684 if (!newNumber || !*newNumber) {
685 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
690 if (newType != readonlyVolume && newType != backupVolume)
692 tt = FindTrans(atrans);
695 if (tt->vflags & VTDeleted) {
696 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
700 ttc = NewTrans(newId, tt->partition);
701 if (!ttc) { /* someone is messing with the clone already */
703 return VOLSERVOLBUSY;
705 TSetRxCall(tt, acid, "Clone");
709 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
711 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
717 originalvp = tt->volume;
718 if ((V_type(originalvp) == backupVolume)
719 || (V_type(originalvp) == readonlyVolume)) {
720 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
724 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
725 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
731 if (originalvp->device != purgevp->device) {
732 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
736 if (V_type(purgevp) != readonlyVolume) {
737 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
741 if (V_type(originalvp) == readonlyVolume
742 && V_parentId(originalvp) != V_parentId(purgevp)) {
743 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
747 if (V_type(originalvp) == readwriteVolume
748 && tt->volid != V_parentId(purgevp)) {
749 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
756 #ifdef AFS_DEMAND_ATTACH_FS
757 salv_vp = originalvp;
761 VCreateVolume(&error, originalvp->partition->name, newId,
762 V_parentId(originalvp));
764 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
765 newvp = (Volume *) 0;
768 if (newType == readonlyVolume)
769 V_cloneId(originalvp) = newId;
770 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
773 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
774 CloneVolume(&error, originalvp, newvp, purgevp);
775 purgevp = NULL; /* clone releases it, maybe even if error */
777 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
781 if (newType == readonlyVolume) {
782 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
783 V_type(newvp) = readonlyVolume;
784 } else if (newType == backupVolume) {
785 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
786 V_type(newvp) = backupVolume;
787 V_backupId(originalvp) = newId;
789 strcpy(newvp->header->diskstuff.name, newName);
790 V_creationDate(newvp) = V_copyDate(newvp);
791 ClearVolumeStats(&V_disk(newvp));
792 V_destroyMe(newvp) = DESTROY_ME;
793 V_inService(newvp) = 0;
794 if (newType == backupVolume) {
795 V_backupDate(originalvp) = V_copyDate(newvp);
796 V_backupDate(newvp) = V_copyDate(newvp);
799 VUpdateVolume(&error, newvp);
801 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
805 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
807 VUpdateVolume(&error, originalvp);
809 Log("1 Volser: Clone: original update %u\n", error);
814 #ifdef AFS_DEMAND_ATTACH_FS
818 tt = (struct volser_trans *)0;
819 error = VOLSERTRELE_ERROR;
827 VDetachVolume(&code, purgevp);
829 VDetachVolume(&code, newvp);
836 #ifdef AFS_DEMAND_ATTACH_FS
837 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
839 VRequestSalvage_r(&salv_error, salv_vp, FSYNC_SALVAGE, 0);
841 #endif /* AFS_DEMAND_ATTACH_FS */
845 /* reclone this volume into the specified id */
847 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
851 code = VolReClone(acid, atrans, cloneId);
852 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
858 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
860 struct Volume *originalvp, *clonevp;
863 struct volser_trans *tt, *ttc;
864 char caller[MAXKTCNAMELEN];
866 /*not a super user */
867 if (!afsconf_SuperUser(tdir, acid, caller))
868 return VOLSERBAD_ACCESS;
870 Log("%s is executing Reclone Volume %u\n", caller, cloneId);
872 clonevp = originalvp = (Volume *) 0;
873 tt = (struct volser_trans *)0;
875 tt = FindTrans(atrans);
878 if (tt->vflags & VTDeleted) {
879 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
883 ttc = NewTrans(cloneId, tt->partition);
884 if (!ttc) { /* someone is messing with the clone already */
886 return VOLSERVOLBUSY;
888 TSetRxCall(tt, acid, "ReClone");
890 originalvp = tt->volume;
891 if ((V_type(originalvp) == backupVolume)
892 || (V_type(originalvp) == readonlyVolume)) {
893 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
897 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
898 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
904 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
906 Log("1 Volser: can't attach clone %d\n", cloneId);
910 newType = V_type(clonevp); /* type of the new volume */
912 if (originalvp->device != clonevp->device) {
913 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
918 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
919 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
923 if (V_type(originalvp) == readonlyVolume
924 && V_parentId(originalvp) != V_parentId(clonevp)) {
925 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
929 if (V_type(originalvp) == readwriteVolume
930 && tt->volid != V_parentId(clonevp)) {
931 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
937 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
939 CloneVolume(&error, originalvp, clonevp, clonevp);
941 Log("1 Volser: Clone: reclone operation failed with code %d\n",
947 /* fix up volume name and type, CloneVolume just propagated RW's */
948 if (newType == readonlyVolume) {
949 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
950 V_type(clonevp) = readonlyVolume;
951 } else if (newType == backupVolume) {
952 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
953 V_type(clonevp) = backupVolume;
954 V_backupId(originalvp) = cloneId;
956 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
958 /* pretend recloned volume is a totally new instance */
959 V_copyDate(clonevp) = time(0);
960 V_creationDate(clonevp) = V_copyDate(clonevp);
961 ClearVolumeStats(&V_disk(clonevp));
962 V_destroyMe(clonevp) = 0;
963 V_inService(clonevp) = 0;
964 if (newType == backupVolume) {
965 V_backupDate(originalvp) = V_copyDate(clonevp);
966 V_backupDate(clonevp) = V_copyDate(clonevp);
968 V_inUse(clonevp) = 0;
969 VUpdateVolume(&error, clonevp);
971 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
975 /* VUpdateVolume succeeded. Mark it in service so there's no window
976 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
977 * specialStatus; this is a reclone and this volume started online
979 V_inService(clonevp) = 1;
980 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
982 VUpdateVolume(&error, originalvp);
984 Log("1 Volser: Clone: original update %u\n", error);
990 tt = (struct volser_trans *)0;
991 error = VOLSERTRELE_ERROR;
998 struct DiskPartition64 *tpartp = originalvp->partition;
999 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1005 VDetachVolume(&code, clonevp);
1011 DeleteTrans(ttc, 1);
1015 /* create a new transaction, associated with volume and partition. Type of
1016 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1017 * See volser.h for definition of iflags (the constants are named IT*).
1020 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1021 afs_int32 iflags, afs_int32 *ttid)
1025 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1026 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1032 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1033 afs_int32 iflags, afs_int32 *ttid)
1035 struct volser_trans *tt;
1040 char caller[MAXKTCNAMELEN];
1042 if (!afsconf_SuperUser(tdir, acid, caller))
1043 return VOLSERBAD_ACCESS; /*not a super user */
1044 if (iflags & ITCreate)
1046 else if (iflags & ITBusy)
1048 else if (iflags & ITReadOnly)
1050 else if (iflags & ITOffline)
1053 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1058 tt = NewTrans(volume, partition);
1060 /* can't create a transaction? put the volume back */
1061 Log("1 transcreate: can't create transaction\n");
1062 return VOLSERVOLBUSY;
1064 tv = XAttachVolume(&error, volume, partition, mode);
1068 VDetachVolume(&code, tv);
1072 VTRANS_OBJ_LOCK(tt);
1075 tt->iflags = iflags;
1077 TSetRxCall_r(tt, NULL, "TransCreate");
1078 VTRANS_OBJ_UNLOCK(tt);
1080 return VOLSERTRELE_ERROR;
1085 /* using aindex as a 0-based index, return the aindex'th volume on this server
1086 * Both the volume number and partition number (one-based) are returned.
1089 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1094 code = VolGetNthVolume(acid, aindex, avolume, apart);
1095 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1100 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1103 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1107 /* return the volume flags (VT* constants in volser.h) associated with this
1111 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1115 code = VolGetFlags(acid, atid, aflags);
1116 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1121 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1123 struct volser_trans *tt;
1125 tt = FindTrans(atid);
1128 if (tt->vflags & VTDeleted) {
1129 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1134 TSetRxCall(tt, acid, "GetFlags");
1135 *aflags = tt->vflags;
1138 return VOLSERTRELE_ERROR;
1143 /* Change the volume flags (VT* constants in volser.h) associated with this
1144 * transaction. Effects take place immediately on volume, although volume
1145 * remains attached as usual by the transaction.
1148 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1152 code = VolSetFlags(acid, atid, aflags);
1153 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1159 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1161 struct volser_trans *tt;
1164 char caller[MAXKTCNAMELEN];
1166 if (!afsconf_SuperUser(tdir, acid, caller))
1167 return VOLSERBAD_ACCESS; /*not a super user */
1168 /* find the trans */
1169 tt = FindTrans(atid);
1172 if (tt->vflags & VTDeleted) {
1173 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1178 TSetRxCall(tt, acid, "SetFlags");
1179 vp = tt->volume; /* pull volume out of transaction */
1181 /* check if we're allowed to make any updates */
1182 if (tt->iflags & ITReadOnly) {
1187 /* handle delete-on-salvage flag */
1188 if (aflags & VTDeleteOnSalvage) {
1189 V_destroyMe(tt->volume) = DESTROY_ME;
1191 V_destroyMe(tt->volume) = 0;
1194 if (aflags & VTOutOfService) {
1195 V_inService(vp) = 0;
1197 V_inService(vp) = 1;
1199 VUpdateVolume(&error, vp);
1200 VTRANS_OBJ_LOCK(tt);
1201 tt->vflags = aflags;
1203 VTRANS_OBJ_UNLOCK(tt);
1204 if (TRELE(tt) && !error)
1205 return VOLSERTRELE_ERROR;
1210 /* dumpS the volume associated with a particular transaction from a particular
1211 * date. Send the dump to a different transaction (destTrans) on the server
1212 * specified by the destServer structure.
1215 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1216 struct destServer *destination, afs_int32 destTrans,
1217 struct restoreCookie *cookie)
1222 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1223 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1224 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1229 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1230 struct destServer *destination, afs_int32 destTrans,
1231 struct restoreCookie *cookie)
1233 struct volser_trans *tt;
1235 struct rx_connection *tcon;
1236 struct rx_call *tcall;
1238 struct rx_securityClass *securityObject;
1239 afs_int32 securityIndex;
1240 char caller[MAXKTCNAMELEN];
1242 if (!afsconf_SuperUser(tdir, acid, caller))
1243 return VOLSERBAD_ACCESS; /*not a super user */
1244 /* initialize things */
1245 tcon = (struct rx_connection *)0;
1246 tt = (struct volser_trans *)0;
1248 /* find the local transaction */
1249 tt = FindTrans(fromTrans);
1252 if (tt->vflags & VTDeleted) {
1253 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1258 TSetRxCall(tt, NULL, "Forward");
1260 /* get auth info for the this connection (uses afs from ticket file) */
1261 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1267 /* make an rpc connection to the other server */
1269 rx_NewConnection(htonl(destination->destHost),
1270 htons(destination->destPort), VOLSERVICE_ID,
1271 securityObject, securityIndex);
1277 tcall = rx_NewCall(tcon);
1278 TSetRxCall(tt, tcall, "Forward");
1279 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1280 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1285 /* these next calls implictly call rx_Write when writing out data */
1286 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1289 EndAFSVolRestore(tcall); /* probably doesn't do much */
1291 code = rx_EndCall(tcall, 0);
1292 rx_DestroyConnection(tcon); /* done with the connection */
1297 return VOLSERTRELE_ERROR;
1303 (void)rx_EndCall(tcall, 0);
1304 rx_DestroyConnection(tcon);
1313 /* Start a dump and send it to multiple places simultaneously.
1314 * If this returns an error (eg, return ENOENT), it means that
1315 * none of the releases worked. If this returns 0, that means
1316 * that one or more of the releases worked, and the caller has
1317 * to examine the results array to see which one(s).
1318 * This will only do EITHER incremental or full, not both, so it's
1319 * the caller's responsibility to be sure that all the destinations
1320 * need just an incremental (and from the same time), if that's
1324 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1325 fromDate, manyDests *destinations, afs_int32 spare,
1326 struct restoreCookie *cookie, manyResults *results)
1328 afs_int32 securityIndex;
1329 struct rx_securityClass *securityObject;
1330 char caller[MAXKTCNAMELEN];
1331 struct volser_trans *tt;
1332 afs_int32 ec, code, *codes;
1333 struct rx_connection **tcons;
1334 struct rx_call **tcalls;
1336 int i, is_incremental;
1339 memset(results, 0, sizeof(manyResults));
1340 i = results->manyResults_len = destinations->manyDests_len;
1341 results->manyResults_val = codes =
1342 (afs_int32 *) malloc(i * sizeof(afs_int32));
1344 if (!results || !results->manyResults_val)
1347 if (!afsconf_SuperUser(tdir, acid, caller))
1348 return VOLSERBAD_ACCESS; /*not a super user */
1349 tt = FindTrans(fromTrans);
1352 if (tt->vflags & VTDeleted) {
1353 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1358 TSetRxCall(tt, NULL, "ForwardMulti");
1360 /* (fromDate == 0) ==> full dump */
1361 is_incremental = (fromDate ? 1 : 0);
1364 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1368 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1374 /* get auth info for this connection (uses afs from ticket file) */
1375 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1377 goto fail; /* in order to audit each failure */
1380 /* make connections to all the other servers */
1381 for (i = 0; i < destinations->manyDests_len; i++) {
1382 struct replica *dest = &(destinations->manyDests_val[i]);
1384 rx_NewConnection(htonl(dest->server.destHost),
1385 htons(dest->server.destPort), VOLSERVICE_ID,
1386 securityObject, securityIndex);
1388 codes[i] = ENOTCONN;
1390 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1391 codes[i] = ENOTCONN;
1394 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1397 (void)rx_EndCall(tcalls[i], 0);
1399 rx_DestroyConnection(tcons[i]);
1406 /* these next calls implictly call rx_Write when writing out data */
1407 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1411 for (i--; i >= 0; i--) {
1412 struct replica *dest = &(destinations->manyDests_val[i]);
1414 if (!code && tcalls[i] && !codes[i]) {
1415 EndAFSVolRestore(tcalls[i]);
1418 ec = rx_EndCall(tcalls[i], 0);
1423 rx_DestroyConnection(tcons[i]); /* done with the connection */
1426 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1427 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1428 dest->trans, AUD_END);
1435 if (TRELE(tt) && !code) /* return the first code if it's set */
1436 return VOLSERTRELE_ERROR;
1443 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1447 code = VolDump(acid, fromTrans, fromDate, 0);
1448 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1453 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1458 code = VolDump(acid, fromTrans, fromDate, flags);
1459 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1464 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1468 struct volser_trans *tt;
1469 char caller[MAXKTCNAMELEN];
1471 if (!afsconf_SuperUser(tdir, acid, caller))
1472 return VOLSERBAD_ACCESS; /*not a super user */
1473 tt = FindTrans(fromTrans);
1476 if (tt->vflags & VTDeleted) {
1477 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1481 TSetRxCall(tt, acid, "Dump");
1482 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1483 ? 0 : 1); /* squirt out the volume's data, too */
1492 return VOLSERTRELE_ERROR;
1498 * Ha! No more helper process!
1501 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1502 struct restoreCookie *cookie)
1506 code = VolRestore(acid, atrans, aflags, cookie);
1507 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1512 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1513 struct restoreCookie *cookie)
1515 struct volser_trans *tt;
1516 afs_int32 code, tcode;
1517 char caller[MAXKTCNAMELEN];
1519 if (!afsconf_SuperUser(tdir, acid, caller))
1520 return VOLSERBAD_ACCESS; /*not a super user */
1521 tt = FindTrans(atrans);
1524 if (tt->vflags & VTDeleted) {
1525 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1529 TSetRxCall(tt, acid, "Restore");
1531 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1533 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1534 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1538 return (code ? code : tcode);
1541 /* end a transaction, returning the transaction's final error code in rcode */
1543 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1547 code = VolEndTrans(acid, destTrans, rcode);
1548 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1553 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1555 struct volser_trans *tt;
1556 char caller[MAXKTCNAMELEN];
1558 if (!afsconf_SuperUser(tdir, acid, caller))
1559 return VOLSERBAD_ACCESS; /*not a super user */
1560 tt = FindTrans(destTrans);
1564 *rcode = tt->returnCode;
1565 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1571 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1575 code = VolSetForwarding(acid, atid, anewsite);
1576 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1577 htonl(anewsite), AUD_END);
1582 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1584 struct volser_trans *tt;
1585 char caller[MAXKTCNAMELEN];
1588 if (!afsconf_SuperUser(tdir, acid, caller))
1589 return VOLSERBAD_ACCESS; /*not a super user */
1590 tt = FindTrans(atid);
1593 if (tt->vflags & VTDeleted) {
1594 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1599 TSetRxCall(tt, acid, "SetForwarding");
1600 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1603 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1606 return VOLSERTRELE_ERROR;
1612 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1613 struct volser_status *astatus)
1617 code = VolGetStatus(acid, atrans, astatus);
1618 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1623 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1624 struct volser_status *astatus)
1627 struct VolumeDiskData *td;
1628 struct volser_trans *tt;
1631 tt = FindTrans(atrans);
1634 if (tt->vflags & VTDeleted) {
1635 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1640 TSetRxCall(tt, acid, "GetStatus");
1648 td = &tv->header->diskstuff;
1649 astatus->volID = td->id;
1650 astatus->nextUnique = td->uniquifier;
1651 astatus->type = td->type;
1652 astatus->parentID = td->parentId;
1653 astatus->cloneID = td->cloneId;
1654 astatus->backupID = td->backupId;
1655 astatus->restoredFromID = td->restoredFromId;
1656 astatus->maxQuota = td->maxquota;
1657 astatus->minQuota = td->minquota;
1658 astatus->owner = td->owner;
1659 astatus->creationDate = td->creationDate;
1660 astatus->accessDate = td->accessDate;
1661 astatus->updateDate = td->updateDate;
1662 astatus->expirationDate = td->expirationDate;
1663 astatus->backupDate = td->backupDate;
1664 astatus->copyDate = td->copyDate;
1667 return VOLSERTRELE_ERROR;
1673 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1674 struct volintInfo *astatus)
1678 code = VolSetInfo(acid, atrans, astatus);
1679 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1684 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1685 struct volintInfo *astatus)
1688 struct VolumeDiskData *td;
1689 struct volser_trans *tt;
1690 char caller[MAXKTCNAMELEN];
1693 if (!afsconf_SuperUser(tdir, acid, caller))
1694 return VOLSERBAD_ACCESS; /*not a super user */
1695 tt = FindTrans(atrans);
1698 if (tt->vflags & VTDeleted) {
1699 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1703 TSetRxCall(tt, acid, "SetStatus");
1711 td = &tv->header->diskstuff;
1713 * Add more fields as necessary
1715 if (astatus->maxquota != -1)
1716 td->maxquota = astatus->maxquota;
1717 if (astatus->dayUse != -1)
1718 td->dayUse = astatus->dayUse;
1719 if (astatus->creationDate != -1)
1720 td->creationDate = astatus->creationDate;
1721 if (astatus->updateDate != -1)
1722 td->updateDate = astatus->updateDate;
1723 if (astatus->spare2 != -1)
1724 td->volUpdateCounter = (unsigned int)astatus->spare2;
1725 VUpdateVolume(&error, tv);
1728 return VOLSERTRELE_ERROR;
1734 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1738 code = VolGetName(acid, atrans, aname);
1739 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1744 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1747 struct VolumeDiskData *td;
1748 struct volser_trans *tt;
1751 /* We need to at least fill it in */
1752 *aname = (char *)malloc(1);
1755 tt = FindTrans(atrans);
1758 if (tt->vflags & VTDeleted) {
1759 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1763 TSetRxCall(tt, acid, "GetName");
1771 td = &tv->header->diskstuff;
1772 len = strlen(td->name) + 1; /* don't forget the null */
1778 *aname = (char *)realloc(*aname, len);
1779 strcpy(*aname, td->name);
1782 return VOLSERTRELE_ERROR;
1787 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1790 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1791 afs_uint32 parentId, afs_uint32 cloneId)
1797 /*return a list of all partitions on the server. The non mounted
1798 *partitions are returned as -1 in the corresponding slot in partIds*/
1800 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1804 code = VolListPartitions(acid, partIds);
1805 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1810 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1815 strcpy(namehead, "/vicep"); /*7 including null terminator */
1817 /* Just return attached partitions. */
1819 for (i = 0; i < 26; i++) {
1820 namehead[6] = i + 'a';
1821 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1827 /*return a list of all partitions on the server. The non mounted
1828 *partitions are returned as -1 in the corresponding slot in partIds*/
1830 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1834 code = XVolListPartitions(acid, pEntries);
1835 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1840 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1843 struct partList partList;
1844 struct DiskPartition64 *dp;
1847 strcpy(namehead, "/vicep"); /*7 including null terminator */
1849 /* Only report attached partitions */
1850 for (i = 0; i < VOLMAXPARTS; i++) {
1851 #ifdef AFS_DEMAND_ATTACH_FS
1852 dp = VGetPartitionById(i, 0);
1855 namehead[6] = i + 'a';
1861 namehead[6] = 'a' + (k / 26);
1862 namehead[7] = 'a' + (k % 26);
1865 dp = VGetPartition(namehead, 0);
1868 partList.partId[j++] = i;
1871 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1872 if (!pEntries->partEntries_val)
1874 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1876 pEntries->partEntries_len = j;
1878 pEntries->partEntries_val = NULL;
1879 pEntries->partEntries_len = 0;
1885 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1887 ExtractVolId(char vname[])
1890 char name[VOLSER_MAXVOLNAME + 1];
1892 strcpy(name, vname);
1894 while (name[i] == 'V' || name[i] == '0')
1897 name[11] = '\0'; /* smash the "." */
1898 return (atol(&name[i]));
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 = ExtractVolId(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);
2378 return (found) ? 0 : ENODEV;
2381 /*------------------------------------------------------------------------
2382 * EXPORTED SAFSVolXListOneVolume
2385 * Returns extended info on volume a_volID on partition a_partID.
2388 * a_rxCidP : Pointer to the Rx call we're performing.
2389 * a_partID : Partition for which we want the extended list.
2390 * a_volID : Volume ID we wish to know about.
2391 * a_volumeXInfoP : Ptr to the extended info blob.
2394 * 0 Successful operation
2395 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2398 * Nothing interesting.
2402 *------------------------------------------------------------------------*/
2405 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2406 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2410 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2411 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2416 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2417 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2418 { /*SAFSVolXListOneVolume */
2420 struct DiskPartition64 *partP; /*Ptr to partition */
2421 char pname[9], volname[20]; /*Partition, volume names */
2422 DIR *dirp; /*Partition directory ptr */
2423 afs_uint32 currVolID; /*Current volume ID */
2424 int found = 0; /*Did we find the volume we need? */
2426 volint_info_handle_t handle;
2429 * Set up our pointers for action, marking our structure to hold exactly
2430 * one entry. Also, assume we'll fail in our quest.
2432 a_volumeXInfoP->volXEntries_val =
2433 (volintXInfo *) malloc(sizeof(volintXInfo));
2434 if (!a_volumeXInfoP->volXEntries_val)
2436 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2438 a_volumeXInfoP->volXEntries_len = 1;
2442 * If the partition name we've been given is bad, bogue out.
2444 if (GetPartName(a_partID, pname))
2445 return (VOLSERILLEGAL_PARTITION);
2448 * Open the directory representing the given AFS parttion. If we can't
2451 if (!(partP = VGetPartition(pname, 0)))
2452 return VOLSERILLEGAL_PARTITION;
2453 dirp = opendir(VPartitionPath(partP));
2455 return (VOLSERILLEGAL_PARTITION);
2457 strcpy(volname, "");
2460 * Sweep through the partition directory, looking for the desired entry.
2461 * First, of course, figure out how many stat bytes to copy out of each
2464 while (strcmp(volname, "EOD") && !found) {
2466 * If this is not a volume, move on to the next entry in the
2467 * partition's directory.
2469 if (!strcmp(volname, "")) {
2470 GetNextVol(dirp, volname, &currVolID);
2474 if (currVolID == a_volID) {
2476 * We found the volume entry we're interested. Pull out the
2477 * extended information, remembering to poll (so that the client
2478 * doesn't time out) and to set up a transaction on the volume.
2482 } /*Found desired volume */
2484 GetNextVol(dirp, volname, &currVolID);
2488 #ifndef AFS_PTHREAD_ENV
2492 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2493 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2495 code = GetVolInfo(a_partID,
2500 VOL_INFO_LIST_SINGLE);
2505 * Clean up before going to dinner: close the partition directory,
2506 * return the proper value.
2509 return (found) ? 0 : ENODEV;
2510 } /*SAFSVolXListOneVolume */
2512 /*returns all the volumes on partition partid. If flags = 1 then all the
2513 * relevant info about the volumes is also returned */
2515 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2516 volEntries *volumeInfo)
2520 code = VolListVolumes(acid, partid, flags, volumeInfo);
2521 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2526 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2527 volEntries *volumeInfo)
2530 struct DiskPartition64 *partP;
2531 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2532 char pname[9], volname[20];
2536 volint_info_handle_t handle;
2538 volumeInfo->volEntries_val =
2539 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2540 if (!volumeInfo->volEntries_val)
2542 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2544 pntr = volumeInfo->volEntries_val;
2545 volumeInfo->volEntries_len = 0;
2546 if (GetPartName(partid, pname))
2547 return VOLSERILLEGAL_PARTITION;
2548 if (!(partP = VGetPartition(pname, 0)))
2549 return VOLSERILLEGAL_PARTITION;
2550 dirp = opendir(VPartitionPath(partP));
2552 return VOLSERILLEGAL_PARTITION;
2553 strcpy(volname, "");
2555 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2557 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2558 GetNextVol(dirp, volname, &volid);
2559 continue; /*back to while loop */
2562 if (flags) { /*copy other things too */
2563 #ifndef AFS_PTHREAD_ENV
2564 IOMGR_Poll(); /*make sure that the client does not time out */
2567 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2568 handle.volinfo_ptr.base = pntr;
2571 code = GetVolInfo(partid,
2576 VOL_INFO_LIST_MULTIPLE);
2577 if (code == -2) { /* DESTROY_ME flag set */
2581 pntr->volid = volid;
2582 /*just volids are needed */
2586 volumeInfo->volEntries_len += 1;
2587 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2588 /*running out of space, allocate more space */
2589 allocSize = (allocSize * 3) / 2;
2591 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2592 allocSize * sizeof(volintInfo));
2595 return VOLSERNO_MEMORY;
2597 volumeInfo->volEntries_val = pntr; /* point to new block */
2598 /* set pntr to the right position */
2599 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2604 GetNextVol(dirp, volname, &volid);
2612 /*------------------------------------------------------------------------
2613 * EXPORTED SAFSVolXListVolumes
2616 * Returns all the volumes on partition a_partID. If a_flags
2617 * is set to 1, then all the relevant extended volume information
2621 * a_rxCidP : Pointer to the Rx call we're performing.
2622 * a_partID : Partition for which we want the extended list.
2623 * a_flags : Various flags.
2624 * a_volumeXInfoP : Ptr to the extended info blob.
2627 * 0 Successful operation
2628 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2629 * VOLSERNO_MEMORY if we ran out of memory allocating
2633 * Nothing interesting.
2637 *------------------------------------------------------------------------*/
2640 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2641 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2645 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2646 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2651 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2652 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2653 { /*SAFSVolXListVolumes */
2655 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2656 struct DiskPartition64 *partP; /*Ptr to partition */
2657 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2658 char pname[9], volname[20]; /*Partition, volume names */
2659 DIR *dirp; /*Partition directory ptr */
2660 afs_uint32 volid; /*Current volume ID */
2662 volint_info_handle_t handle;
2665 * Allocate a large array of extended volume info structures, then
2666 * set it up for action.
2668 a_volumeXInfoP->volXEntries_val =
2669 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2670 if (!a_volumeXInfoP->volXEntries_val)
2672 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2674 xInfoP = a_volumeXInfoP->volXEntries_val;
2675 a_volumeXInfoP->volXEntries_len = 0;
2678 * If the partition name we've been given is bad, bogue out.
2680 if (GetPartName(a_partID, pname))
2681 return (VOLSERILLEGAL_PARTITION);
2684 * Open the directory representing the given AFS parttion. If we can't
2687 if (!(partP = VGetPartition(pname, 0)))
2688 return VOLSERILLEGAL_PARTITION;
2689 dirp = opendir(VPartitionPath(partP));
2691 return (VOLSERILLEGAL_PARTITION);
2692 strcpy(volname, "");
2695 * Sweep through the partition directory, acting on each entry. First,
2696 * of course, figure out how many stat bytes to copy out of each volume.
2698 while (strcmp(volname, "EOD")) {
2701 * If this is not a volume, move on to the next entry in the
2702 * partition's directory.
2704 if (!strcmp(volname, "")) {
2705 GetNextVol(dirp, volname, &volid);
2711 * Full info about the volume desired. Poll to make sure the
2712 * client doesn't time out, then start up a new transaction.
2714 #ifndef AFS_PTHREAD_ENV
2718 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2719 handle.volinfo_ptr.ext = xInfoP;
2721 code = GetVolInfo(a_partID,
2726 VOL_INFO_LIST_MULTIPLE);
2727 if (code == -2) { /* DESTROY_ME flag set */
2732 * Just volume IDs are needed.
2734 xInfoP->volid = volid;
2738 * Bump the pointer in the data area we're building, along with
2739 * the count of the number of entries it contains.
2742 (a_volumeXInfoP->volXEntries_len)++;
2743 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2745 * We're running out of space in the area we've built. Grow it.
2747 allocSize = (allocSize * 3) / 2;
2748 xInfoP = (volintXInfo *)
2749 realloc((char *)a_volumeXInfoP->volXEntries_val,
2750 (allocSize * sizeof(volintXInfo)));
2751 if (xInfoP == NULL) {
2753 * Bummer, no memory. Bag it, tell our caller what went wrong.
2756 return (VOLSERNO_MEMORY);
2760 * Memory reallocation worked. Correct our pointers so they
2761 * now point to the new block and the current open position within
2764 a_volumeXInfoP->volXEntries_val = xInfoP;
2766 a_volumeXInfoP->volXEntries_val +
2767 a_volumeXInfoP->volXEntries_len;
2771 GetNextVol(dirp, volname, &volid);
2772 } /*Sweep through the partition directory */
2775 * We've examined all entries in the partition directory. Close it,
2776 * delete our transaction (if any), and go home happy.
2781 } /*SAFSVolXListVolumes */
2783 /*this call is used to monitor the status of volser for debugging purposes.
2784 *information about all the active transactions is returned in transInfo*/
2786 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2790 code = VolMonitor(acid, transInfo);
2791 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2796 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2798 transDebugInfo *pntr;
2799 afs_int32 allocSize = 50;
2800 struct volser_trans *tt, *nt, *allTrans;
2802 transInfo->transDebugEntries_val =
2803 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2804 if (!transInfo->transDebugEntries_val)
2806 pntr = transInfo->transDebugEntries_val;
2807 transInfo->transDebugEntries_len = 0;
2810 allTrans = TransList();
2811 if (allTrans == (struct volser_trans *)0)
2812 goto done; /*no active transactions */
2813 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2815 VTRANS_OBJ_LOCK(tt);
2816 pntr->tid = tt->tid;
2817 pntr->time = tt->time;
2818 pntr->creationTime = tt->creationTime;
2819 pntr->returnCode = tt->returnCode;
2820 pntr->volid = tt->volid;
2821 pntr->partition = tt->partition;
2822 pntr->iflags = tt->iflags;
2823 pntr->vflags = tt->vflags;
2824 pntr->tflags = tt->tflags;
2825 strcpy(pntr->lastProcName, tt->lastProcName);
2826 pntr->callValid = 0;
2827 if (tt->rxCallPtr) { /*record call related info */
2828 pntr->callValid = 1;
2829 pntr->readNext = tt->rxCallPtr->rnext;
2830 pntr->transmitNext = tt->rxCallPtr->tnext;
2831 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2832 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2834 VTRANS_OBJ_UNLOCK(tt);
2836 transInfo->transDebugEntries_len += 1;
2837 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2838 allocSize = (allocSize * 3) / 2;
2840 (transDebugInfo *) realloc((char *)transInfo->
2841 transDebugEntries_val,
2843 sizeof(transDebugInfo));
2844 transInfo->transDebugEntries_val = pntr;
2846 transInfo->transDebugEntries_val +
2847 transInfo->transDebugEntries_len;
2848 /*set pntr to right position */
2859 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2860 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2861 afs_uint32 backupId)
2865 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2866 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2867 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2873 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2874 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2875 afs_uint32 backupId)
2879 struct volser_trans *tt;
2880 char caller[MAXKTCNAMELEN];
2882 if (strlen(name) > 31)
2883 return VOLSERBADNAME;
2884 if (!afsconf_SuperUser(tdir, acid, caller))
2885 return VOLSERBAD_ACCESS; /*not a super user */
2886 /* find the trans */
2887 tt = FindTrans(atid);
2890 if (tt->vflags & VTDeleted) {
2891 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2895 TSetRxCall(tt, acid, "SetIdsTypes");
2899 V_backupId(tv) = backupId;
2900 V_cloneId(tv) = cloneId;
2901 V_parentId(tv) = pId;
2902 strcpy((&V_disk(tv))->name, name);
2903 VUpdateVolume(&error, tv);
2905 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2910 if (TRELE(tt) && !error)
2911 return VOLSERTRELE_ERROR;
2916 if (TRELE(tt) && !error)
2917 return VOLSERTRELE_ERROR;
2922 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2926 code = VolSetDate(acid, atid, cdate);
2927 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2933 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2937 struct volser_trans *tt;
2938 char caller[MAXKTCNAMELEN];
2940 if (!afsconf_SuperUser(tdir, acid, caller))
2941 return VOLSERBAD_ACCESS; /*not a super user */
2942 /* find the trans */
2943 tt = FindTrans(atid);
2946 if (tt->vflags & VTDeleted) {
2947 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2951 TSetRxCall(tt, acid, "SetDate");
2954 V_creationDate(tv) = cdate;
2955 VUpdateVolume(&error, tv);
2957 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2962 if (TRELE(tt) && !error)
2963 return VOLSERTRELE_ERROR;
2968 if (TRELE(tt) && !error)
2969 return VOLSERTRELE_ERROR;
2974 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2975 afs_uint32 volumeId)
2980 char caller[MAXKTCNAMELEN];
2982 struct volser_trans *ttc;
2983 char pname[16], volname[20];
2984 struct DiskPartition64 *partP;
2985 afs_int32 ret = ENODEV;
2988 if (!afsconf_SuperUser(tdir, acid, caller))
2989 return VOLSERBAD_ACCESS; /*not a super user */
2990 if (GetPartName(partId, pname))
2991 return VOLSERILLEGAL_PARTITION;
2992 if (!(partP = VGetPartition(pname, 0)))
2993 return VOLSERILLEGAL_PARTITION;
2994 dirp = opendir(VPartitionPath(partP));
2996 return VOLSERILLEGAL_PARTITION;
2997 strcpy(volname, "");
2998 ttc = (struct volser_trans *)0;
3000 while (strcmp(volname, "EOD")) {
3001 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3002 GetNextVol(dirp, volname, &volid);
3003 continue; /*back to while loop */
3006 if (volid == volumeId) { /*copy other things too */
3007 #ifndef AFS_PTHREAD_ENV
3008 IOMGR_Poll(); /*make sure that the client doesnot time out */
3010 ttc = NewTrans(volumeId, partId);
3012 return VOLSERVOLBUSY;
3014 #ifdef AFS_NAMEI_ENV
3015 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3017 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3021 GetNextVol(dirp, volname, &volid);
3025 DeleteTrans(ttc, 1);
3026 ttc = (struct volser_trans *)0;
3035 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3036 struct volintSize *size)
3039 struct volser_trans *tt;
3040 char caller[MAXKTCNAMELEN];
3042 if (!afsconf_SuperUser(tdir, acid, caller))
3043 return VOLSERBAD_ACCESS; /*not a super user */
3044 tt = FindTrans(fromTrans);
3047 if (tt->vflags & VTDeleted) {
3051 TSetRxCall(tt, acid, "GetSize");
3052 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3055 return VOLSERTRELE_ERROR;
3057 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3062 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3063 afs_uint32 where, afs_int32 verbose)
3065 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3067 Volume *vol=0, *newvol=0;
3068 struct volser_trans *tt = 0, *tt2 = 0;
3069 char caller[MAXKTCNAMELEN];
3072 if (!afsconf_SuperUser(tdir, acall, caller))
3075 vol = VAttachVolume(&code, vid, V_VOLUPD);
3081 newvol = VAttachVolume(&code, new, V_VOLUPD);
3083 VDetachVolume(&code2, vol);
3088 if (V_device(vol) != V_device(newvol)
3089 || V_uniquifier(newvol) != 2) {
3090 if (V_device(vol) != V_device(newvol)) {
3091 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3093 rx_Write(acall, line, strlen(line));
3095 if (V_uniquifier(newvol) != 2) {
3096 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3097 rx_Write(acall, line, strlen(line));
3100 rx_Write(acall, line, 1);
3101 VDetachVolume(&code2, vol);
3102 VDetachVolume(&code2, newvol);
3105 tt = NewTrans(vid, V_device(vol));
3107 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3108 rx_Write(acall, line, strlen(line));
3110 rx_Write(acall, line, 1);
3111 VDetachVolume(&code2, vol);
3112 VDetachVolume(&code2, newvol);
3113 return VOLSERVOLBUSY;
3115 VTRANS_OBJ_LOCK(tt);
3116 tt->iflags = ITBusy;
3118 TSetRxCall_r(tt, NULL, "SplitVolume");
3119 VTRANS_OBJ_UNLOCK(tt);
3121 tt2 = NewTrans(new, V_device(newvol));
3123 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3124 rx_Write(acall, line, strlen(line));
3126 rx_Write(acall, line, 1);
3128 VDetachVolume(&code2, vol);
3129 VDetachVolume(&code2, newvol);
3130 return VOLSERVOLBUSY;
3132 VTRANS_OBJ_LOCK(tt2);
3133 tt2->iflags = ITBusy;
3135 TSetRxCall_r(tt2, NULL, "SplitVolume");
3136 VTRANS_OBJ_UNLOCK(tt2);
3138 code = split_volume(acall, vol, newvol, where, verbose);
3140 VDetachVolume(&code2, vol);
3142 VDetachVolume(&code2, newvol);
3143 DeleteTrans(tt2, 1);
3150 /* GetPartName - map partid (a decimal number) into pname (a string)
3151 * Since for NT we actually want to return the drive name, we map through the
3155 GetPartName(afs_int32 partid, char *pname)
3160 strcpy(pname, "/vicep");
3161 pname[6] = 'a' + partid;
3164 } else if (partid < VOLMAXPARTS) {
3165 strcpy(pname, "/vicep");
3167 pname[6] = 'a' + (partid / 26);
3168 pname[7] = 'a' + (partid % 26);