2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
9 * Portions Copyright (c) 2007-2008 Sine Nomine Associates
12 #include <afsconfig.h>
13 #include <afs/param.h>
18 #include <sys/types.h>
27 #include <netinet/in.h>
36 #include <afs/afsint.h>
38 #include <afs/afs_assert.h>
39 #include <afs/prs_fs.h>
43 #include <afs/cellconfig.h>
46 #include <afs/ihandle.h>
48 #include <afs/ntops.h>
50 #include <afs/vnode.h>
51 #include <afs/volume.h>
52 #include <afs/volume_inline.h>
53 #include <afs/partition.h>
55 #include <afs/daemon_com.h>
56 #include <afs/fssync.h>
58 #include "afs/audit.h"
60 #include <afs/afsutil.h>
61 #include <afs/vol_prototypes.h>
62 #include <afs/errors.h>
65 #include "voltrans_inline.h"
68 #include "volser_internal.h"
70 #include "dumpstuff.h"
73 extern struct afsconf_dir *tdir;
75 extern void LogError(afs_int32 errcode);
77 /* Forward declarations */
78 static int GetPartName(afs_int32 partid, char *pname);
80 #define OneDay (24*60*60)
86 afs_int32 localTid = 1;
88 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
89 struct diskPartition64 *);
90 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
91 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
92 afs_int32, afs_uint32, afs_uint32 *,
94 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
95 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
96 afs_int32, char *, afs_uint32 *);
97 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
98 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
99 afs_int32, afs_int32 *);
100 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
102 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
103 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
104 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
105 struct destServer *destination, afs_int32,
106 struct restoreCookie *cookie);
107 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
108 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
109 struct restoreCookie *);
110 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
111 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
112 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
113 struct volser_status *);
114 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
115 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
116 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
117 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
118 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
120 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
122 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
124 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
126 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
127 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
128 afs_int32, afs_uint32, afs_uint32,
130 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
132 /* this call unlocks all of the partition locks we've set */
136 struct DiskPartition64 *tp;
137 for (tp = DiskPartitionList; tp; tp = tp->next) {
138 if (tp->lock_fd != INVALID_FD) {
139 close(tp->lock_fd); /* releases flock held on this partition */
140 tp->lock_fd = INVALID_FD;
151 code = VPFullUnlock_r();
156 /* get partition id from a name */
158 PartitionID(char *aname)
166 return -1; /* unknown */
168 /* otherwise check for vicepa or /vicepa, or just plain "a" */
170 if (!strncmp(aname, "/vicep", 6)) {
171 strncpy(ascii, aname + 6, 2);
173 return -1; /* bad partition name */
174 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
175 * from 0. Do the appropriate conversion */
177 /* one char name, 0..25 */
178 if (ascii[0] < 'a' || ascii[0] > 'z')
179 return -1; /* wrongo */
180 return ascii[0] - 'a';
182 /* two char name, 26 .. <whatever> */
183 if (ascii[0] < 'a' || ascii[0] > 'z')
184 return -1; /* wrongo */
185 if (ascii[1] < 'a' || ascii[1] > 'z')
186 return -1; /* just as bad */
187 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
188 if (code > VOLMAXPARTS)
195 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
199 /* 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 */
200 (void)afs_snprintf(aname, asize, VFORMAT, (unsigned long)avol);
205 ConvertPartition(int apartno, char *aname, int asize)
211 strcpy(aname, "/vicep");
213 aname[6] = 'a' + apartno;
217 aname[6] = 'a' + (apartno / 26);
218 aname[7] = 'a' + (apartno % 26);
224 #ifdef AFS_DEMAND_ATTACH_FS
225 /* normally we should use the regular salvaging functions from the volume
226 * package, but this is a special case where we have a volume ID, but no
227 * volume structure to give the volume package */
229 SalvageUnknownVolume(VolumeId volid, char *part)
233 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
234 afs_printable_uint32_lu(volid), part);
236 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
237 FSYNC_SALVAGE, NULL);
239 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
240 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
244 #endif /* AFS_DEMAND_ATTACH_FS */
246 static struct Volume *
247 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
252 vp = VAttachVolumeByName(ec, partition, name, mode);
254 #ifdef AFS_DEMAND_ATTACH_FS
258 * The fileserver will take care of keeping track of how many
259 * demand-salvages have been performed, and will force the volume to
260 * ERROR if we've done too many. The limit on This loop is just a
261 * failsafe to prevent trying to salvage forever. We want to attempt
262 * attachment at least SALVAGE_COUNT_MAX times, since we want to
263 * avoid prematurely exiting this loop, if we can.
265 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
266 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
267 vp = VAttachVolumeByName(ec, partition, name, mode);
270 if (*ec == VSALVAGING) {
274 #endif /* AFS_DEMAND_ATTACH_FS */
279 static struct Volume *
280 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
285 vp = VAttachVolume(ec, avolid, amode);
287 #ifdef AFS_DEMAND_ATTACH_FS
290 /* see comment above in VAttachVolumeByName_retry */
291 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
292 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
293 vp = VAttachVolume(ec, avolid, amode);
296 if (*ec == VSALVAGING) {
300 #endif /* AFS_DEMAND_ATTACH_FS */
305 /* the only attach function that takes a partition is "...ByName", so we use it */
306 static struct Volume *
307 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
309 char pbuf[30], vbuf[20];
311 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
315 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
320 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
323 /* Adapted from the file server; create a root directory for this volume */
325 ViceCreateRoot(Volume *vp)
328 struct acl_accessList *ACL;
330 Inode inodeNumber, nearInode;
331 struct VnodeDiskObject *vnode;
332 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
338 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
341 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
343 V_pref(vp, nearInode);
345 IH_CREATE(V_linkHandle(vp), V_device(vp),
346 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
348 osi_Assert(VALID_INO(inodeNumber));
350 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
351 did.Volume = V_id(vp);
352 did.Vnode = (VnodeId) 1;
355 osi_Assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
356 DFlush(); /* flush all modified dir buffers out */
357 DZap((afs_int32 *)&dir); /* Remove all buffers for this dir */
358 length = Length(&dir); /* Remember size of this directory */
360 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
362 /* build a single entry ACL that gives all rights to system:administrators */
363 /* this section of code assumes that access list format is not going to
366 ACL = VVnodeDiskACL(vnode);
367 ACL->size = sizeof(struct acl_accessList);
368 ACL->version = ACL_ACLVERSION;
372 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
373 ACL->entries[0].rights =
374 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
375 | PRSFS_LOCK | PRSFS_ADMINISTER;
377 vnode->type = vDirectory;
379 vnode->modeBits = 0777;
380 vnode->linkCount = 2;
381 VNDISK_SET_LEN(vnode, length);
382 vnode->uniquifier = 1;
383 V_uniquifier(vp) = vnode->uniquifier + 1;
384 vnode->dataVersion = 1;
385 VNDISK_SET_INO(vnode, inodeNumber);
386 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
390 vnode->vnodeMagic = vcp->magic;
392 IH_INIT(h, vp->device, V_parentId(vp),
393 vp->vnodeIndex[vLarge].handle->ih_ino);
395 osi_Assert(fdP != NULL);
396 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
397 osi_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
398 FDH_REALLYCLOSE(fdP);
400 VNDISK_GET_LEN(length, vnode);
401 V_diskused(vp) = nBlocks(length);
408 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
412 struct diskPartition64 *dp = (struct diskPartition64 *)
413 malloc(sizeof(struct diskPartition64));
415 code = VolPartitionInfo(acid, pname, dp);
417 strncpy(partition->name, dp->name, 32);
418 strncpy(partition->devName, dp->devName, 32);
419 partition->lock_fd = dp->lock_fd;
420 partition->free=RoundInt64ToInt32(dp->free);
421 partition->minFree=RoundInt64ToInt32(dp->minFree);
424 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
429 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
434 code = VolPartitionInfo(acid, pname, partition);
435 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
440 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
443 struct DiskPartition64 *dp;
446 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
449 dp = VGetPartition(pname, 0);
451 strncpy(partition->name, dp->name, 32);
452 strncpy(partition->devName, dp->devName, 32);
453 partition->lock_fd = (int)dp->lock_fd;
454 partition->free = dp->free;
455 partition->minFree = dp->totalUsable;
458 return VOLSERILLEGAL_PARTITION;
461 /* obliterate a volume completely, and slowly. */
463 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
467 code = VolNukeVolume(acid, apartID, avolID);
468 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
473 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
480 char caller[MAXKTCNAMELEN];
482 /* check for access */
483 if (!afsconf_SuperUser(tdir, acid, caller))
484 return VOLSERBAD_ACCESS;
486 Log("%s is executing VolNukeVolume %u\n", caller, avolID);
488 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
490 /* we first try to attach the volume in update mode, so that the file
491 * server doesn't try to use it (and abort) while (or after) we delete it.
492 * If we don't get the volume, that's fine, too. We just won't put it back.
494 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
495 code = nuke(partName, avolID);
497 VDetachVolume(&verror, tvp);
501 /* create a new volume, with name aname, on the specified partition (1..n)
502 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
503 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
504 * for the volume id (useful for things like volume restore).
505 * Return the new volume id in *avolid.
508 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
509 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
515 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
516 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
517 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
523 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
524 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
529 Error junk; /* discardable error code */
531 afs_int32 doCreateRoot = 1;
532 struct volser_trans *tt;
534 char caller[MAXKTCNAMELEN];
536 if (strlen(aname) > 31)
537 return VOLSERBADNAME;
538 if (!afsconf_SuperUser(tdir, acid, caller))
539 return VOLSERBAD_ACCESS;
541 Log("%s is executing CreateVolume '%s'\n", caller, aname);
542 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
543 return error; /*a standard unix error */
544 if (atype != readwriteVolume && atype != readonlyVolume
545 && atype != backupVolume)
547 if ((volumeID = *avolid) == 0) {
549 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
553 if ((aparent == volumeID) && (atype == readwriteVolume)) {
558 tt = NewTrans(volumeID, apart);
560 Log("1 createvolume: failed to create trans\n");
561 return VOLSERVOLBUSY; /* volume already busy! */
563 vp = VCreateVolume(&error, ppath, volumeID, aparent);
565 #ifdef AFS_DEMAND_ATTACH_FS
566 if (error != VVOLEXISTS && error != EXDEV) {
567 SalvageUnknownVolume(volumeID, ppath);
570 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
575 V_uniquifier(vp) = 1;
576 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
577 V_inService(vp) = V_blessed(vp) = 1;
579 AssignVolumeName(&V_disk(vp), aname, 0);
582 V_destroyMe(vp) = DESTROY_ME;
584 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
585 VUpdateVolume(&error, vp);
587 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
590 VDetachVolume(&junk, vp); /* rather return the real error code */
596 TSetRxCall_r(tt, acid, "CreateVolume");
597 VTRANS_OBJ_UNLOCK(tt);
598 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
601 return VOLSERTRELE_ERROR;
605 /* delete the volume associated with this transaction */
607 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
611 code = VolDeleteVolume(acid, atrans);
612 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
617 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
619 struct volser_trans *tt;
621 char caller[MAXKTCNAMELEN];
623 if (!afsconf_SuperUser(tdir, acid, caller))
624 return VOLSERBAD_ACCESS;
625 tt = FindTrans(atrans);
628 if (tt->vflags & VTDeleted) {
629 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
634 Log("%s is executing Delete Volume %u\n", caller, tt->volid);
635 TSetRxCall(tt, acid, "DeleteVolume");
636 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
637 V_destroyMe(tt->volume) = DESTROY_ME;
638 if (tt->volume->needsPutBack) {
639 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
642 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
644 VTRANS_OBJ_UNLOCK(tt);
646 return VOLSERTRELE_ERROR;
648 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
649 return 0; /* vpurgevolume doesn't set an error code */
652 /* make a clone of the volume associated with atrans, possibly giving it a new
653 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
654 * for the clone's id). The new clone is given the name newName. Finally,
655 * due to efficiency considerations, if purgeId is non-zero, we purge that
656 * volume when doing the clone operation. This may be useful when making
657 * new backup volumes, for instance since the net result of a clone and a
658 * purge generally leaves many inode ref counts the same, while doing them
659 * separately would result in far more iincs and idecs being peformed
660 * (and they are slow operations).
662 /* for efficiency reasons, sometimes faster to piggyback a purge here */
664 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
665 afs_int32 newType, char *newName, afs_uint32 *newNumber)
669 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
670 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
671 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
677 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
678 afs_int32 newType, char *newName, afs_uint32 *newNumber)
681 struct Volume *originalvp, *purgevp, *newvp;
683 struct volser_trans *tt, *ttc;
684 char caller[MAXKTCNAMELEN];
685 #ifdef AFS_DEMAND_ATTACH_FS
686 struct Volume *salv_vp = NULL;
689 if (strlen(newName) > 31)
690 return VOLSERBADNAME;
691 if (!afsconf_SuperUser(tdir, acid, caller))
692 return VOLSERBAD_ACCESS; /*not a super user */
694 Log("%s is executing Clone Volume new name=%s\n", caller, newName);
696 originalvp = (Volume *) 0;
697 purgevp = (Volume *) 0;
698 newvp = (Volume *) 0;
699 tt = ttc = (struct volser_trans *)0;
701 if (!newNumber || !*newNumber) {
702 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
707 if (newType != readonlyVolume && newType != backupVolume)
709 tt = FindTrans(atrans);
712 if (tt->vflags & VTDeleted) {
713 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
717 ttc = NewTrans(newId, tt->partition);
718 if (!ttc) { /* someone is messing with the clone already */
720 return VOLSERVOLBUSY;
722 TSetRxCall(tt, acid, "Clone");
726 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
728 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
734 originalvp = tt->volume;
735 if ((V_type(originalvp) == backupVolume)
736 || (V_type(originalvp) == readonlyVolume)) {
737 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
741 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
742 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
748 if (originalvp->device != purgevp->device) {
749 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
753 if (V_type(purgevp) != readonlyVolume) {
754 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
758 if (V_type(originalvp) == readonlyVolume
759 && V_parentId(originalvp) != V_parentId(purgevp)) {
760 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
764 if (V_type(originalvp) == readwriteVolume
765 && tt->volid != V_parentId(purgevp)) {
766 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
773 #ifdef AFS_DEMAND_ATTACH_FS
774 salv_vp = originalvp;
778 VCreateVolume(&error, originalvp->partition->name, newId,
779 V_parentId(originalvp));
781 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
782 newvp = (Volume *) 0;
785 if (newType == readonlyVolume)
786 V_cloneId(originalvp) = newId;
787 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
790 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
791 CloneVolume(&error, originalvp, newvp, purgevp);
792 purgevp = NULL; /* clone releases it, maybe even if error */
794 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
798 if (newType == readonlyVolume) {
799 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
800 V_type(newvp) = readonlyVolume;
801 } else if (newType == backupVolume) {
802 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
803 V_type(newvp) = backupVolume;
804 V_backupId(originalvp) = newId;
806 strcpy(newvp->header->diskstuff.name, newName);
807 V_creationDate(newvp) = V_copyDate(newvp);
808 ClearVolumeStats(&V_disk(newvp));
809 V_destroyMe(newvp) = DESTROY_ME;
810 V_inService(newvp) = 0;
811 if (newType == backupVolume) {
812 V_backupDate(originalvp) = V_copyDate(newvp);
813 V_backupDate(newvp) = V_copyDate(newvp);
816 VUpdateVolume(&error, newvp);
818 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
822 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
824 VUpdateVolume(&error, originalvp);
826 Log("1 Volser: Clone: original update %u\n", error);
831 #ifdef AFS_DEMAND_ATTACH_FS
835 tt = (struct volser_trans *)0;
836 error = VOLSERTRELE_ERROR;
844 VDetachVolume(&code, purgevp);
846 VDetachVolume(&code, newvp);
853 #ifdef AFS_DEMAND_ATTACH_FS
854 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
856 VRequestSalvage_r(&salv_error, salv_vp, FSYNC_SALVAGE, 0);
858 #endif /* AFS_DEMAND_ATTACH_FS */
862 /* reclone this volume into the specified id */
864 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
868 code = VolReClone(acid, atrans, cloneId);
869 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
875 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
877 struct Volume *originalvp, *clonevp;
880 struct volser_trans *tt, *ttc;
881 char caller[MAXKTCNAMELEN];
883 /*not a super user */
884 if (!afsconf_SuperUser(tdir, acid, caller))
885 return VOLSERBAD_ACCESS;
887 Log("%s is executing Reclone Volume %u\n", caller, cloneId);
889 clonevp = originalvp = (Volume *) 0;
890 tt = (struct volser_trans *)0;
892 tt = FindTrans(atrans);
895 if (tt->vflags & VTDeleted) {
896 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
900 ttc = NewTrans(cloneId, tt->partition);
901 if (!ttc) { /* someone is messing with the clone already */
903 return VOLSERVOLBUSY;
905 TSetRxCall(tt, acid, "ReClone");
907 originalvp = tt->volume;
908 if ((V_type(originalvp) == backupVolume)
909 || (V_type(originalvp) == readonlyVolume)) {
910 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
914 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
915 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
921 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
923 Log("1 Volser: can't attach clone %d\n", cloneId);
927 newType = V_type(clonevp); /* type of the new volume */
929 if (originalvp->device != clonevp->device) {
930 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
935 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
936 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
940 if (V_type(originalvp) == readonlyVolume
941 && V_parentId(originalvp) != V_parentId(clonevp)) {
942 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
946 if (V_type(originalvp) == readwriteVolume
947 && tt->volid != V_parentId(clonevp)) {
948 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
954 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
956 CloneVolume(&error, originalvp, clonevp, clonevp);
958 Log("1 Volser: Clone: reclone operation failed with code %d\n",
964 /* fix up volume name and type, CloneVolume just propagated RW's */
965 if (newType == readonlyVolume) {
966 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
967 V_type(clonevp) = readonlyVolume;
968 } else if (newType == backupVolume) {
969 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
970 V_type(clonevp) = backupVolume;
971 V_backupId(originalvp) = cloneId;
973 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
975 /* pretend recloned volume is a totally new instance */
976 V_copyDate(clonevp) = time(0);
977 V_creationDate(clonevp) = V_copyDate(clonevp);
978 ClearVolumeStats(&V_disk(clonevp));
979 V_destroyMe(clonevp) = 0;
980 V_inService(clonevp) = 0;
981 if (newType == backupVolume) {
982 V_backupDate(originalvp) = V_copyDate(clonevp);
983 V_backupDate(clonevp) = V_copyDate(clonevp);
985 V_inUse(clonevp) = 0;
986 VUpdateVolume(&error, clonevp);
988 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
992 /* VUpdateVolume succeeded. Mark it in service so there's no window
993 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
994 * specialStatus; this is a reclone and this volume started online
996 V_inService(clonevp) = 1;
997 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
999 VUpdateVolume(&error, originalvp);
1001 Log("1 Volser: Clone: original update %u\n", error);
1007 tt = (struct volser_trans *)0;
1008 error = VOLSERTRELE_ERROR;
1012 DeleteTrans(ttc, 1);
1015 struct DiskPartition64 *tpartp = originalvp->partition;
1016 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1022 VDetachVolume(&code, clonevp);
1028 DeleteTrans(ttc, 1);
1032 /* create a new transaction, associated with volume and partition. Type of
1033 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1034 * See volser.h for definition of iflags (the constants are named IT*).
1037 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1038 afs_int32 iflags, afs_int32 *ttid)
1042 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1043 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1049 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1050 afs_int32 iflags, afs_int32 *ttid)
1052 struct volser_trans *tt;
1057 char caller[MAXKTCNAMELEN];
1059 if (!afsconf_SuperUser(tdir, acid, caller))
1060 return VOLSERBAD_ACCESS; /*not a super user */
1061 if (iflags & ITCreate)
1063 else if (iflags & ITBusy)
1065 else if (iflags & ITReadOnly)
1067 else if (iflags & ITOffline)
1070 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1075 tt = NewTrans(volume, partition);
1077 /* can't create a transaction? put the volume back */
1078 Log("1 transcreate: can't create transaction\n");
1079 return VOLSERVOLBUSY;
1081 tv = XAttachVolume(&error, volume, partition, mode);
1085 VDetachVolume(&code, tv);
1089 VTRANS_OBJ_LOCK(tt);
1092 tt->iflags = iflags;
1094 TSetRxCall_r(tt, NULL, "TransCreate");
1095 VTRANS_OBJ_UNLOCK(tt);
1097 return VOLSERTRELE_ERROR;
1102 /* using aindex as a 0-based index, return the aindex'th volume on this server
1103 * Both the volume number and partition number (one-based) are returned.
1106 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1111 code = VolGetNthVolume(acid, aindex, avolume, apart);
1112 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1117 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1120 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1124 /* return the volume flags (VT* constants in volser.h) associated with this
1128 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1132 code = VolGetFlags(acid, atid, aflags);
1133 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1138 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1140 struct volser_trans *tt;
1142 tt = FindTrans(atid);
1145 if (tt->vflags & VTDeleted) {
1146 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1151 TSetRxCall(tt, acid, "GetFlags");
1152 *aflags = tt->vflags;
1155 return VOLSERTRELE_ERROR;
1160 /* Change the volume flags (VT* constants in volser.h) associated with this
1161 * transaction. Effects take place immediately on volume, although volume
1162 * remains attached as usual by the transaction.
1165 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1169 code = VolSetFlags(acid, atid, aflags);
1170 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1176 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1178 struct volser_trans *tt;
1181 char caller[MAXKTCNAMELEN];
1183 if (!afsconf_SuperUser(tdir, acid, caller))
1184 return VOLSERBAD_ACCESS; /*not a super user */
1185 /* find the trans */
1186 tt = FindTrans(atid);
1189 if (tt->vflags & VTDeleted) {
1190 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1195 TSetRxCall(tt, acid, "SetFlags");
1196 vp = tt->volume; /* pull volume out of transaction */
1198 /* check if we're allowed to make any updates */
1199 if (tt->iflags & ITReadOnly) {
1204 /* handle delete-on-salvage flag */
1205 if (aflags & VTDeleteOnSalvage) {
1206 V_destroyMe(tt->volume) = DESTROY_ME;
1208 V_destroyMe(tt->volume) = 0;
1211 if (aflags & VTOutOfService) {
1212 V_inService(vp) = 0;
1214 V_inService(vp) = 1;
1216 VUpdateVolume(&error, vp);
1217 VTRANS_OBJ_LOCK(tt);
1218 tt->vflags = aflags;
1220 VTRANS_OBJ_UNLOCK(tt);
1221 if (TRELE(tt) && !error)
1222 return VOLSERTRELE_ERROR;
1227 /* dumpS the volume associated with a particular transaction from a particular
1228 * date. Send the dump to a different transaction (destTrans) on the server
1229 * specified by the destServer structure.
1232 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1233 struct destServer *destination, afs_int32 destTrans,
1234 struct restoreCookie *cookie)
1239 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1240 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1241 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1246 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1247 struct destServer *destination, afs_int32 destTrans,
1248 struct restoreCookie *cookie)
1250 struct volser_trans *tt;
1252 struct rx_connection *tcon;
1253 struct rx_call *tcall;
1255 struct rx_securityClass *securityObject;
1256 afs_int32 securityIndex;
1257 char caller[MAXKTCNAMELEN];
1259 if (!afsconf_SuperUser(tdir, acid, caller))
1260 return VOLSERBAD_ACCESS; /*not a super user */
1261 /* initialize things */
1262 tcon = (struct rx_connection *)0;
1263 tt = (struct volser_trans *)0;
1265 /* find the local transaction */
1266 tt = FindTrans(fromTrans);
1269 if (tt->vflags & VTDeleted) {
1270 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1275 TSetRxCall(tt, NULL, "Forward");
1277 /* get auth info for the this connection (uses afs from ticket file) */
1278 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1284 /* make an rpc connection to the other server */
1286 rx_NewConnection(htonl(destination->destHost),
1287 htons(destination->destPort), VOLSERVICE_ID,
1288 securityObject, securityIndex);
1294 tcall = rx_NewCall(tcon);
1295 TSetRxCall(tt, tcall, "Forward");
1296 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1297 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1302 /* these next calls implictly call rx_Write when writing out data */
1303 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1306 EndAFSVolRestore(tcall); /* probably doesn't do much */
1308 code = rx_EndCall(tcall, 0);
1309 rx_DestroyConnection(tcon); /* done with the connection */
1314 return VOLSERTRELE_ERROR;
1320 (void)rx_EndCall(tcall, 0);
1321 rx_DestroyConnection(tcon);
1330 /* Start a dump and send it to multiple places simultaneously.
1331 * If this returns an error (eg, return ENOENT), it means that
1332 * none of the releases worked. If this returns 0, that means
1333 * that one or more of the releases worked, and the caller has
1334 * to examine the results array to see which one(s).
1335 * This will only do EITHER incremental or full, not both, so it's
1336 * the caller's responsibility to be sure that all the destinations
1337 * need just an incremental (and from the same time), if that's
1341 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1342 fromDate, manyDests *destinations, afs_int32 spare,
1343 struct restoreCookie *cookie, manyResults *results)
1345 afs_int32 securityIndex;
1346 struct rx_securityClass *securityObject;
1347 char caller[MAXKTCNAMELEN];
1348 struct volser_trans *tt;
1349 afs_int32 ec, code, *codes;
1350 struct rx_connection **tcons;
1351 struct rx_call **tcalls;
1353 int i, is_incremental;
1356 memset(results, 0, sizeof(manyResults));
1357 i = results->manyResults_len = destinations->manyDests_len;
1358 results->manyResults_val = codes =
1359 (afs_int32 *) malloc(i * sizeof(afs_int32));
1361 if (!results || !results->manyResults_val)
1364 if (!afsconf_SuperUser(tdir, acid, caller))
1365 return VOLSERBAD_ACCESS; /*not a super user */
1366 tt = FindTrans(fromTrans);
1369 if (tt->vflags & VTDeleted) {
1370 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1375 TSetRxCall(tt, NULL, "ForwardMulti");
1377 /* (fromDate == 0) ==> full dump */
1378 is_incremental = (fromDate ? 1 : 0);
1381 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1385 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1391 /* get auth info for this connection (uses afs from ticket file) */
1392 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1394 goto fail; /* in order to audit each failure */
1397 /* make connections to all the other servers */
1398 for (i = 0; i < destinations->manyDests_len; i++) {
1399 struct replica *dest = &(destinations->manyDests_val[i]);
1401 rx_NewConnection(htonl(dest->server.destHost),
1402 htons(dest->server.destPort), VOLSERVICE_ID,
1403 securityObject, securityIndex);
1405 codes[i] = ENOTCONN;
1407 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1408 codes[i] = ENOTCONN;
1411 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1414 (void)rx_EndCall(tcalls[i], 0);
1416 rx_DestroyConnection(tcons[i]);
1423 /* these next calls implictly call rx_Write when writing out data */
1424 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1428 for (i--; i >= 0; i--) {
1429 struct replica *dest = &(destinations->manyDests_val[i]);
1431 if (!code && tcalls[i] && !codes[i]) {
1432 EndAFSVolRestore(tcalls[i]);
1435 ec = rx_EndCall(tcalls[i], 0);
1440 rx_DestroyConnection(tcons[i]); /* done with the connection */
1443 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1444 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1445 dest->trans, AUD_END);
1452 if (TRELE(tt) && !code) /* return the first code if it's set */
1453 return VOLSERTRELE_ERROR;
1460 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1464 code = VolDump(acid, fromTrans, fromDate, 0);
1465 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1470 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1475 code = VolDump(acid, fromTrans, fromDate, flags);
1476 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1481 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1485 struct volser_trans *tt;
1486 char caller[MAXKTCNAMELEN];
1488 if (!afsconf_SuperUser(tdir, acid, caller))
1489 return VOLSERBAD_ACCESS; /*not a super user */
1490 tt = FindTrans(fromTrans);
1493 if (tt->vflags & VTDeleted) {
1494 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1498 TSetRxCall(tt, acid, "Dump");
1499 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1500 ? 0 : 1); /* squirt out the volume's data, too */
1509 return VOLSERTRELE_ERROR;
1515 * Ha! No more helper process!
1518 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1519 struct restoreCookie *cookie)
1523 code = VolRestore(acid, atrans, aflags, cookie);
1524 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1529 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1530 struct restoreCookie *cookie)
1532 struct volser_trans *tt;
1533 afs_int32 code, tcode;
1534 char caller[MAXKTCNAMELEN];
1536 if (!afsconf_SuperUser(tdir, acid, caller))
1537 return VOLSERBAD_ACCESS; /*not a super user */
1538 tt = FindTrans(atrans);
1541 if (tt->vflags & VTDeleted) {
1542 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1546 TSetRxCall(tt, acid, "Restore");
1548 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1550 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1551 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1555 return (code ? code : tcode);
1558 /* end a transaction, returning the transaction's final error code in rcode */
1560 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1564 code = VolEndTrans(acid, destTrans, rcode);
1565 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1570 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1572 struct volser_trans *tt;
1573 char caller[MAXKTCNAMELEN];
1575 if (!afsconf_SuperUser(tdir, acid, caller))
1576 return VOLSERBAD_ACCESS; /*not a super user */
1577 tt = FindTrans(destTrans);
1581 *rcode = tt->returnCode;
1582 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1588 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1592 code = VolSetForwarding(acid, atid, anewsite);
1593 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1594 htonl(anewsite), AUD_END);
1599 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1601 struct volser_trans *tt;
1602 char caller[MAXKTCNAMELEN];
1605 if (!afsconf_SuperUser(tdir, acid, caller))
1606 return VOLSERBAD_ACCESS; /*not a super user */
1607 tt = FindTrans(atid);
1610 if (tt->vflags & VTDeleted) {
1611 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1616 TSetRxCall(tt, acid, "SetForwarding");
1617 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1620 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1623 return VOLSERTRELE_ERROR;
1629 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1630 struct volser_status *astatus)
1634 code = VolGetStatus(acid, atrans, astatus);
1635 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1640 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1641 struct volser_status *astatus)
1644 struct VolumeDiskData *td;
1645 struct volser_trans *tt;
1648 tt = FindTrans(atrans);
1651 if (tt->vflags & VTDeleted) {
1652 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1657 TSetRxCall(tt, acid, "GetStatus");
1665 td = &tv->header->diskstuff;
1666 astatus->volID = td->id;
1667 astatus->nextUnique = td->uniquifier;
1668 astatus->type = td->type;
1669 astatus->parentID = td->parentId;
1670 astatus->cloneID = td->cloneId;
1671 astatus->backupID = td->backupId;
1672 astatus->restoredFromID = td->restoredFromId;
1673 astatus->maxQuota = td->maxquota;
1674 astatus->minQuota = td->minquota;
1675 astatus->owner = td->owner;
1676 astatus->creationDate = td->creationDate;
1677 astatus->accessDate = td->accessDate;
1678 astatus->updateDate = td->updateDate;
1679 astatus->expirationDate = td->expirationDate;
1680 astatus->backupDate = td->backupDate;
1681 astatus->copyDate = td->copyDate;
1684 return VOLSERTRELE_ERROR;
1690 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1691 struct volintInfo *astatus)
1695 code = VolSetInfo(acid, atrans, astatus);
1696 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1701 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1702 struct volintInfo *astatus)
1705 struct VolumeDiskData *td;
1706 struct volser_trans *tt;
1707 char caller[MAXKTCNAMELEN];
1710 if (!afsconf_SuperUser(tdir, acid, caller))
1711 return VOLSERBAD_ACCESS; /*not a super user */
1712 tt = FindTrans(atrans);
1715 if (tt->vflags & VTDeleted) {
1716 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1720 TSetRxCall(tt, acid, "SetStatus");
1728 td = &tv->header->diskstuff;
1730 * Add more fields as necessary
1732 if (astatus->maxquota != -1)
1733 td->maxquota = astatus->maxquota;
1734 if (astatus->dayUse != -1)
1735 td->dayUse = astatus->dayUse;
1736 if (astatus->creationDate != -1)
1737 td->creationDate = astatus->creationDate;
1738 if (astatus->updateDate != -1)
1739 td->updateDate = astatus->updateDate;
1740 if (astatus->spare2 != -1)
1741 td->volUpdateCounter = (unsigned int)astatus->spare2;
1742 VUpdateVolume(&error, tv);
1745 return VOLSERTRELE_ERROR;
1751 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1755 code = VolGetName(acid, atrans, aname);
1756 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1761 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1764 struct VolumeDiskData *td;
1765 struct volser_trans *tt;
1768 /* We need to at least fill it in */
1769 *aname = (char *)malloc(1);
1772 tt = FindTrans(atrans);
1775 if (tt->vflags & VTDeleted) {
1776 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1780 TSetRxCall(tt, acid, "GetName");
1788 td = &tv->header->diskstuff;
1789 len = strlen(td->name) + 1; /* don't forget the null */
1795 *aname = (char *)realloc(*aname, len);
1796 strcpy(*aname, td->name);
1799 return VOLSERTRELE_ERROR;
1804 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1807 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1808 afs_uint32 parentId, afs_uint32 cloneId)
1814 /*return a list of all partitions on the server. The non mounted
1815 *partitions are returned as -1 in the corresponding slot in partIds*/
1817 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1821 code = VolListPartitions(acid, partIds);
1822 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1827 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1832 strcpy(namehead, "/vicep"); /*7 including null terminator */
1834 /* Just return attached partitions. */
1836 for (i = 0; i < 26; i++) {
1837 namehead[6] = i + 'a';
1838 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1844 /*return a list of all partitions on the server. The non mounted
1845 *partitions are returned as -1 in the corresponding slot in partIds*/
1847 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1851 code = XVolListPartitions(acid, pEntries);
1852 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1857 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1860 struct partList partList;
1861 struct DiskPartition64 *dp;
1864 strcpy(namehead, "/vicep"); /*7 including null terminator */
1866 /* Only report attached partitions */
1867 for (i = 0; i < VOLMAXPARTS; i++) {
1868 #ifdef AFS_DEMAND_ATTACH_FS
1869 dp = VGetPartitionById(i, 0);
1872 namehead[6] = i + 'a';
1878 namehead[6] = 'a' + (k / 26);
1879 namehead[7] = 'a' + (k % 26);
1882 dp = VGetPartition(namehead, 0);
1885 partList.partId[j++] = i;
1888 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1889 if (!pEntries->partEntries_val)
1891 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1893 pEntries->partEntries_len = j;
1895 pEntries->partEntries_val = NULL;
1896 pEntries->partEntries_len = 0;
1902 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1904 ExtractVolId(char vname[])
1907 char name[VOLSER_MAXVOLNAME + 1];
1909 strcpy(name, vname);
1911 while (name[i] == 'V' || name[i] == '0')
1914 name[11] = '\0'; /* smash the "." */
1915 return (atol(&name[i]));
1918 /*return the name of the next volume header in the directory associated with dirp and dp.
1919 *the volume id is returned in volid, and volume header name is returned in volname*/
1921 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1925 dp = readdir(dirp); /*read next entry in the directory */
1927 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1928 *volid = ExtractVolId(dp->d_name);
1929 strcpy(volname, dp->d_name);
1930 return 0; /*return the name of the file representing a volume */
1932 strcpy(volname, "");
1933 return 0; /*volname doesnot represent a volume */
1936 strcpy(volname, "EOD");
1937 return 0; /*end of directory */
1943 * volint vol info structure type.
1946 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1947 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1948 } volint_info_type_t;
1951 * handle to various on-wire vol info types.
1954 volint_info_type_t volinfo_type;
1960 } volint_info_handle_t;
1963 * store value to a field at the appropriate location in on-wire structure.
1965 #define VOLINT_INFO_STORE(handle, name, val) \
1967 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1968 (handle)->volinfo_ptr.base->name = (val); \
1970 (handle)->volinfo_ptr.ext->name = (val); \
1975 * get pointer to appropriate offset of field in on-wire structure.
1977 #define VOLINT_INFO_PTR(handle, name) \
1978 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1979 &((handle)->volinfo_ptr.base->name) : \
1980 &((handle)->volinfo_ptr.ext->name))
1983 * fill in appropriate type of on-wire volume metadata structure.
1985 * @param vp pointer to volume object
1986 * @param handle pointer to wire format handle object
1988 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1989 * @pre handle object must have a valid pointer and enumeration value
1991 * @note passing a NULL value for vp means that the fileserver doesn't
1992 * know about this particular volume, thus implying it is offline.
1994 * @return operation status
1999 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
2001 unsigned int numStatBytes, now;
2002 struct VolumeDiskData *hdr = &vp->header->diskstuff;
2004 /*read in the relevant info */
2005 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2006 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
2007 VOLINT_INFO_STORE(handle, volid, hdr->id);
2008 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2009 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2010 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2011 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2012 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2013 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2014 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2015 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2016 now = FT_ApproxTime();
2017 if ((now - hdr->dayUseDate) > OneDay) {
2018 VOLINT_INFO_STORE(handle, dayUse, 0);
2020 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2022 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2023 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2024 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2025 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2027 #ifdef AFS_DEMAND_ATTACH_FS
2029 * for DAFS, we "lie" about volume state --
2030 * instead of returning the raw state from the disk header,
2031 * we compute state based upon the fileserver's internal
2032 * in-core state enumeration value reported to us via fssync,
2033 * along with the blessed and inService flags from the header.
2034 * -- tkeiser 11/27/2007
2037 /* Conditions that offline status is based on:
2038 volume is unattached state
2039 volume state is in (one of several error states)
2040 volume not in service
2041 volume is not marked as blessed (not on hold)
2042 volume in salvage req. state
2043 volume needsSalvaged
2044 next op would set volume offline
2045 next op would not leave volume online (based on several conditions)
2048 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2049 VIsErrorState(V_attachState(vp)) ||
2052 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2053 hdr->needsSalvaged ||
2054 (vp->pending_vol_op &&
2055 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2056 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2059 VOLINT_INFO_STORE(handle, inUse, 0);
2061 VOLINT_INFO_STORE(handle, inUse, 1);
2064 /* offline status based on program type, where != fileServer enum (1) is offline */
2065 if (hdr->inUse == fileServer) {
2066 VOLINT_INFO_STORE(handle, inUse, 1);
2068 VOLINT_INFO_STORE(handle, inUse, 0);
2073 switch(handle->volinfo_type) {
2074 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2075 case VOLINT_INFO_TYPE_BASE:
2077 #ifdef AFS_DEMAND_ATTACH_FS
2078 /* see comment above where we set inUse bit */
2079 if (hdr->needsSalvaged ||
2080 (vp && VIsErrorState(V_attachState(vp)))) {
2081 handle->volinfo_ptr.base->needsSalvaged = 1;
2083 handle->volinfo_ptr.base->needsSalvaged = 0;
2086 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2088 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2089 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2090 handle->volinfo_ptr.base->spare1 =
2091 (long)hdr->weekUse[0] +
2092 (long)hdr->weekUse[1] +
2093 (long)hdr->weekUse[2] +
2094 (long)hdr->weekUse[3] +
2095 (long)hdr->weekUse[4] +
2096 (long)hdr->weekUse[5] +
2097 (long)hdr->weekUse[6];
2098 handle->volinfo_ptr.base->flags = 0;
2099 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2100 handle->volinfo_ptr.base->spare3 = 0;
2104 case VOLINT_INFO_TYPE_EXT:
2106 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2107 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2110 * Copy out the stat fields in a single operation.
2112 if ((now - hdr->dayUseDate) > OneDay) {
2113 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2116 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2117 (char *)&(hdr->stat_reads[0]),
2126 #ifdef AFS_DEMAND_ATTACH_FS
2129 * get struct Volume out of the fileserver.
2131 * @param[in] volumeId volumeId for which we want state information
2132 * @param[in] pname partition name string
2133 * @param[inout] vp pointer to pointer to Volume object which
2134 * will be populated (see note)
2136 * @return operation status
2138 * @retval non-zero failure
2140 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2145 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2150 res.hdr.response_len = sizeof(res.hdr);
2151 res.payload.buf = *vp;
2152 res.payload.len = sizeof(Volume);
2154 code = FSYNC_VolOp(volumeId,
2160 if (code != SYNC_OK) {
2161 switch (res.hdr.reason) {
2162 case FSYNC_WRONG_PART:
2163 case FSYNC_UNKNOWN_VOLID:
2176 * mode of volume list operation.
2179 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2180 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2181 } vol_info_list_mode_t;
2184 * abstract interface to populate wire-format volume metadata structures.
2186 * @param[in] partId partition id
2187 * @param[in] volumeId volume id
2188 * @param[in] pname partition name
2189 * @param[in] volname volume file name
2190 * @param[in] handle handle to on-wire volume metadata object
2191 * @param[in] mode listing mode
2193 * @return operation status
2195 * @retval -2 DESTROY_ME flag is set
2196 * @retval -1 general failure; some data filled in
2197 * @retval -3 couldn't create vtrans; some data filled in
2200 GetVolInfo(afs_uint32 partId,
2201 afs_uint32 volumeId,
2204 volint_info_handle_t * handle,
2205 vol_info_list_mode_t mode)
2209 struct volser_trans *ttc = NULL;
2210 struct Volume *fill_tv, *tv = NULL;
2211 #ifdef AFS_DEMAND_ATTACH_FS
2212 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2213 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2214 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2215 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2217 /* Set up response handle for pending_vol_op */
2218 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2219 fs_res.payload.buf = fs_res_buf;
2220 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2223 ttc = NewTrans(volumeId, partId);
2226 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2227 VOLINT_INFO_STORE(handle, volid, volumeId);
2231 /* Get volume from volserver */
2232 if (mode == VOL_INFO_LIST_MULTIPLE)
2233 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2235 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2237 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2238 volumeId, pname, volname, error);
2243 * please note that destroyMe and needsSalvaged checks used to be ordered
2244 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2245 * more correct to check destroyMe before needsSalvaged.
2246 * -- tkeiser 11/28/2007
2249 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2251 case VOL_INFO_LIST_MULTIPLE:
2255 case VOL_INFO_LIST_SINGLE:
2256 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2257 volumeId, pname, volname);
2264 if (tv->header->diskstuff.needsSalvaged) {
2265 /*this volume will be salvaged */
2266 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2267 volumeId, pname, volname);
2270 #ifdef AFS_DEMAND_ATTACH_FS
2271 /* If using DAFS, get volume from fsserver */
2272 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2277 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2278 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2279 /* If we if the pending vol op */
2280 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2281 fs_tv->pending_vol_op=&pending_vol_op_res;
2283 fs_tv->pending_vol_op=NULL;
2286 /* populate the header from the volserver copy */
2287 fs_tv->header=tv->header;
2289 /* When using DAFS, use the fs volume info, populated with required structures */
2292 /* When not using DAFS, just use the local volume info */
2296 /* ok, we have all the data we need; fill in the on-wire struct */
2297 code = FillVolInfo(fill_tv, handle);
2301 VOLINT_INFO_STORE(handle, status, 0);
2302 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2303 VOLINT_INFO_STORE(handle, volid, volumeId);
2306 VDetachVolume(&error, tv);
2309 VOLINT_INFO_STORE(handle, status, 0);
2310 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2311 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2312 volumeId, pname, volname);
2316 DeleteTrans(ttc, 1);
2323 /*return the header information about the <volid> */
2325 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2326 afs_uint32 volumeId, volEntries *volumeInfo)
2330 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2331 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2336 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2337 afs_uint32 volumeId, volEntries *volumeInfo)
2339 struct DiskPartition64 *partP;
2340 char pname[9], volname[20];
2345 volint_info_handle_t handle;
2347 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2348 if (!volumeInfo->volEntries_val)
2350 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2352 volumeInfo->volEntries_len = 1;
2353 if (GetPartName(partid, pname))
2354 return VOLSERILLEGAL_PARTITION;
2355 if (!(partP = VGetPartition(pname, 0)))
2356 return VOLSERILLEGAL_PARTITION;
2357 dirp = opendir(VPartitionPath(partP));
2359 return VOLSERILLEGAL_PARTITION;
2361 strcpy(volname, "");
2363 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2365 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2366 GetNextVol(dirp, volname, &volid);
2367 continue; /*back to while loop */
2370 if (volid == volumeId) { /*copy other things too */
2375 GetNextVol(dirp, volname, &volid);
2379 #ifndef AFS_PTHREAD_ENV
2380 IOMGR_Poll(); /*make sure that the client does not time out */
2383 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2384 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2386 code = GetVolInfo(partid,
2391 VOL_INFO_LIST_SINGLE);
2395 return (found) ? 0 : ENODEV;
2398 /*------------------------------------------------------------------------
2399 * EXPORTED SAFSVolXListOneVolume
2402 * Returns extended info on volume a_volID on partition a_partID.
2405 * a_rxCidP : Pointer to the Rx call we're performing.
2406 * a_partID : Partition for which we want the extended list.
2407 * a_volID : Volume ID we wish to know about.
2408 * a_volumeXInfoP : Ptr to the extended info blob.
2411 * 0 Successful operation
2412 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2415 * Nothing interesting.
2419 *------------------------------------------------------------------------*/
2422 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2423 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2427 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2428 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2433 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2434 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2435 { /*SAFSVolXListOneVolume */
2437 struct DiskPartition64 *partP; /*Ptr to partition */
2438 char pname[9], volname[20]; /*Partition, volume names */
2439 DIR *dirp; /*Partition directory ptr */
2440 afs_uint32 currVolID; /*Current volume ID */
2441 int found = 0; /*Did we find the volume we need? */
2443 volint_info_handle_t handle;
2446 * Set up our pointers for action, marking our structure to hold exactly
2447 * one entry. Also, assume we'll fail in our quest.
2449 a_volumeXInfoP->volXEntries_val =
2450 (volintXInfo *) malloc(sizeof(volintXInfo));
2451 if (!a_volumeXInfoP->volXEntries_val)
2453 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2455 a_volumeXInfoP->volXEntries_len = 1;
2459 * If the partition name we've been given is bad, bogue out.
2461 if (GetPartName(a_partID, pname))
2462 return (VOLSERILLEGAL_PARTITION);
2465 * Open the directory representing the given AFS parttion. If we can't
2468 if (!(partP = VGetPartition(pname, 0)))
2469 return VOLSERILLEGAL_PARTITION;
2470 dirp = opendir(VPartitionPath(partP));
2472 return (VOLSERILLEGAL_PARTITION);
2474 strcpy(volname, "");
2477 * Sweep through the partition directory, looking for the desired entry.
2478 * First, of course, figure out how many stat bytes to copy out of each
2481 while (strcmp(volname, "EOD") && !found) {
2483 * If this is not a volume, move on to the next entry in the
2484 * partition's directory.
2486 if (!strcmp(volname, "")) {
2487 GetNextVol(dirp, volname, &currVolID);
2491 if (currVolID == a_volID) {
2493 * We found the volume entry we're interested. Pull out the
2494 * extended information, remembering to poll (so that the client
2495 * doesn't time out) and to set up a transaction on the volume.
2499 } /*Found desired volume */
2501 GetNextVol(dirp, volname, &currVolID);
2505 #ifndef AFS_PTHREAD_ENV
2509 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2510 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2512 code = GetVolInfo(a_partID,
2517 VOL_INFO_LIST_SINGLE);
2522 * Clean up before going to dinner: close the partition directory,
2523 * return the proper value.
2526 return (found) ? 0 : ENODEV;
2527 } /*SAFSVolXListOneVolume */
2529 /*returns all the volumes on partition partid. If flags = 1 then all the
2530 * relevant info about the volumes is also returned */
2532 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2533 volEntries *volumeInfo)
2537 code = VolListVolumes(acid, partid, flags, volumeInfo);
2538 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2543 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2544 volEntries *volumeInfo)
2547 struct DiskPartition64 *partP;
2548 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2549 char pname[9], volname[20];
2553 volint_info_handle_t handle;
2555 volumeInfo->volEntries_val =
2556 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2557 if (!volumeInfo->volEntries_val)
2559 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2561 pntr = volumeInfo->volEntries_val;
2562 volumeInfo->volEntries_len = 0;
2563 if (GetPartName(partid, pname))
2564 return VOLSERILLEGAL_PARTITION;
2565 if (!(partP = VGetPartition(pname, 0)))
2566 return VOLSERILLEGAL_PARTITION;
2567 dirp = opendir(VPartitionPath(partP));
2569 return VOLSERILLEGAL_PARTITION;
2570 strcpy(volname, "");
2572 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2574 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2575 GetNextVol(dirp, volname, &volid);
2576 continue; /*back to while loop */
2579 if (flags) { /*copy other things too */
2580 #ifndef AFS_PTHREAD_ENV
2581 IOMGR_Poll(); /*make sure that the client does not time out */
2584 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2585 handle.volinfo_ptr.base = pntr;
2588 code = GetVolInfo(partid,
2593 VOL_INFO_LIST_MULTIPLE);
2594 if (code == -2) { /* DESTROY_ME flag set */
2598 pntr->volid = volid;
2599 /*just volids are needed */
2603 volumeInfo->volEntries_len += 1;
2604 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2605 /*running out of space, allocate more space */
2606 allocSize = (allocSize * 3) / 2;
2608 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2609 allocSize * sizeof(volintInfo));
2612 return VOLSERNO_MEMORY;
2614 volumeInfo->volEntries_val = pntr; /* point to new block */
2615 /* set pntr to the right position */
2616 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2621 GetNextVol(dirp, volname, &volid);
2629 /*------------------------------------------------------------------------
2630 * EXPORTED SAFSVolXListVolumes
2633 * Returns all the volumes on partition a_partID. If a_flags
2634 * is set to 1, then all the relevant extended volume information
2638 * a_rxCidP : Pointer to the Rx call we're performing.
2639 * a_partID : Partition for which we want the extended list.
2640 * a_flags : Various flags.
2641 * a_volumeXInfoP : Ptr to the extended info blob.
2644 * 0 Successful operation
2645 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2646 * VOLSERNO_MEMORY if we ran out of memory allocating
2650 * Nothing interesting.
2654 *------------------------------------------------------------------------*/
2657 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2658 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2662 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2663 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2668 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2669 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2670 { /*SAFSVolXListVolumes */
2672 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2673 struct DiskPartition64 *partP; /*Ptr to partition */
2674 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2675 char pname[9], volname[20]; /*Partition, volume names */
2676 DIR *dirp; /*Partition directory ptr */
2677 afs_uint32 volid; /*Current volume ID */
2679 volint_info_handle_t handle;
2682 * Allocate a large array of extended volume info structures, then
2683 * set it up for action.
2685 a_volumeXInfoP->volXEntries_val =
2686 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2687 if (!a_volumeXInfoP->volXEntries_val)
2689 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2691 xInfoP = a_volumeXInfoP->volXEntries_val;
2692 a_volumeXInfoP->volXEntries_len = 0;
2695 * If the partition name we've been given is bad, bogue out.
2697 if (GetPartName(a_partID, pname))
2698 return (VOLSERILLEGAL_PARTITION);
2701 * Open the directory representing the given AFS parttion. If we can't
2704 if (!(partP = VGetPartition(pname, 0)))
2705 return VOLSERILLEGAL_PARTITION;
2706 dirp = opendir(VPartitionPath(partP));
2708 return (VOLSERILLEGAL_PARTITION);
2709 strcpy(volname, "");
2712 * Sweep through the partition directory, acting on each entry. First,
2713 * of course, figure out how many stat bytes to copy out of each volume.
2715 while (strcmp(volname, "EOD")) {
2718 * If this is not a volume, move on to the next entry in the
2719 * partition's directory.
2721 if (!strcmp(volname, "")) {
2722 GetNextVol(dirp, volname, &volid);
2728 * Full info about the volume desired. Poll to make sure the
2729 * client doesn't time out, then start up a new transaction.
2731 #ifndef AFS_PTHREAD_ENV
2735 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2736 handle.volinfo_ptr.ext = xInfoP;
2738 code = GetVolInfo(a_partID,
2743 VOL_INFO_LIST_MULTIPLE);
2744 if (code == -2) { /* DESTROY_ME flag set */
2749 * Just volume IDs are needed.
2751 xInfoP->volid = volid;
2755 * Bump the pointer in the data area we're building, along with
2756 * the count of the number of entries it contains.
2759 (a_volumeXInfoP->volXEntries_len)++;
2760 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2762 * We're running out of space in the area we've built. Grow it.
2764 allocSize = (allocSize * 3) / 2;
2765 xInfoP = (volintXInfo *)
2766 realloc((char *)a_volumeXInfoP->volXEntries_val,
2767 (allocSize * sizeof(volintXInfo)));
2768 if (xInfoP == NULL) {
2770 * Bummer, no memory. Bag it, tell our caller what went wrong.
2773 return (VOLSERNO_MEMORY);
2777 * Memory reallocation worked. Correct our pointers so they
2778 * now point to the new block and the current open position within
2781 a_volumeXInfoP->volXEntries_val = xInfoP;
2783 a_volumeXInfoP->volXEntries_val +
2784 a_volumeXInfoP->volXEntries_len;
2788 GetNextVol(dirp, volname, &volid);
2789 } /*Sweep through the partition directory */
2792 * We've examined all entries in the partition directory. Close it,
2793 * delete our transaction (if any), and go home happy.
2798 } /*SAFSVolXListVolumes */
2800 /*this call is used to monitor the status of volser for debugging purposes.
2801 *information about all the active transactions is returned in transInfo*/
2803 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2807 code = VolMonitor(acid, transInfo);
2808 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2813 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2815 transDebugInfo *pntr;
2816 afs_int32 allocSize = 50;
2817 struct volser_trans *tt, *nt, *allTrans;
2819 transInfo->transDebugEntries_val =
2820 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2821 if (!transInfo->transDebugEntries_val)
2823 pntr = transInfo->transDebugEntries_val;
2824 transInfo->transDebugEntries_len = 0;
2827 allTrans = TransList();
2828 if (allTrans == (struct volser_trans *)0)
2829 goto done; /*no active transactions */
2830 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2832 VTRANS_OBJ_LOCK(tt);
2833 pntr->tid = tt->tid;
2834 pntr->time = tt->time;
2835 pntr->creationTime = tt->creationTime;
2836 pntr->returnCode = tt->returnCode;
2837 pntr->volid = tt->volid;
2838 pntr->partition = tt->partition;
2839 pntr->iflags = tt->iflags;
2840 pntr->vflags = tt->vflags;
2841 pntr->tflags = tt->tflags;
2842 strcpy(pntr->lastProcName, tt->lastProcName);
2843 pntr->callValid = 0;
2844 if (tt->rxCallPtr) { /*record call related info */
2845 pntr->callValid = 1;
2846 pntr->readNext = tt->rxCallPtr->rnext;
2847 pntr->transmitNext = tt->rxCallPtr->tnext;
2848 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2849 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2851 VTRANS_OBJ_UNLOCK(tt);
2853 transInfo->transDebugEntries_len += 1;
2854 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2855 allocSize = (allocSize * 3) / 2;
2857 (transDebugInfo *) realloc((char *)transInfo->
2858 transDebugEntries_val,
2860 sizeof(transDebugInfo));
2861 transInfo->transDebugEntries_val = pntr;
2863 transInfo->transDebugEntries_val +
2864 transInfo->transDebugEntries_len;
2865 /*set pntr to right position */
2876 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2877 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2878 afs_uint32 backupId)
2882 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2883 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2884 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2890 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2891 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2892 afs_uint32 backupId)
2896 struct volser_trans *tt;
2897 char caller[MAXKTCNAMELEN];
2899 if (strlen(name) > 31)
2900 return VOLSERBADNAME;
2901 if (!afsconf_SuperUser(tdir, acid, caller))
2902 return VOLSERBAD_ACCESS; /*not a super user */
2903 /* find the trans */
2904 tt = FindTrans(atid);
2907 if (tt->vflags & VTDeleted) {
2908 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2912 TSetRxCall(tt, acid, "SetIdsTypes");
2916 V_backupId(tv) = backupId;
2917 V_cloneId(tv) = cloneId;
2918 V_parentId(tv) = pId;
2919 strcpy((&V_disk(tv))->name, name);
2920 VUpdateVolume(&error, tv);
2922 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2927 if (TRELE(tt) && !error)
2928 return VOLSERTRELE_ERROR;
2933 if (TRELE(tt) && !error)
2934 return VOLSERTRELE_ERROR;
2939 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2943 code = VolSetDate(acid, atid, cdate);
2944 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2950 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2954 struct volser_trans *tt;
2955 char caller[MAXKTCNAMELEN];
2957 if (!afsconf_SuperUser(tdir, acid, caller))
2958 return VOLSERBAD_ACCESS; /*not a super user */
2959 /* find the trans */
2960 tt = FindTrans(atid);
2963 if (tt->vflags & VTDeleted) {
2964 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2968 TSetRxCall(tt, acid, "SetDate");
2971 V_creationDate(tv) = cdate;
2972 VUpdateVolume(&error, tv);
2974 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2979 if (TRELE(tt) && !error)
2980 return VOLSERTRELE_ERROR;
2985 if (TRELE(tt) && !error)
2986 return VOLSERTRELE_ERROR;
2991 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2992 afs_uint32 volumeId)
2997 char caller[MAXKTCNAMELEN];
2999 struct volser_trans *ttc;
3000 char pname[16], volname[20];
3001 struct DiskPartition64 *partP;
3002 afs_int32 ret = ENODEV;
3005 if (!afsconf_SuperUser(tdir, acid, caller))
3006 return VOLSERBAD_ACCESS; /*not a super user */
3007 if (GetPartName(partId, pname))
3008 return VOLSERILLEGAL_PARTITION;
3009 if (!(partP = VGetPartition(pname, 0)))
3010 return VOLSERILLEGAL_PARTITION;
3011 dirp = opendir(VPartitionPath(partP));
3013 return VOLSERILLEGAL_PARTITION;
3014 strcpy(volname, "");
3015 ttc = (struct volser_trans *)0;
3017 while (strcmp(volname, "EOD")) {
3018 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3019 GetNextVol(dirp, volname, &volid);
3020 continue; /*back to while loop */
3023 if (volid == volumeId) { /*copy other things too */
3024 #ifndef AFS_PTHREAD_ENV
3025 IOMGR_Poll(); /*make sure that the client doesnot time out */
3027 ttc = NewTrans(volumeId, partId);
3029 return VOLSERVOLBUSY;
3031 #ifdef AFS_NAMEI_ENV
3032 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3034 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3038 GetNextVol(dirp, volname, &volid);
3042 DeleteTrans(ttc, 1);
3043 ttc = (struct volser_trans *)0;
3052 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3053 struct volintSize *size)
3056 struct volser_trans *tt;
3057 char caller[MAXKTCNAMELEN];
3059 if (!afsconf_SuperUser(tdir, acid, caller))
3060 return VOLSERBAD_ACCESS; /*not a super user */
3061 tt = FindTrans(fromTrans);
3064 if (tt->vflags & VTDeleted) {
3068 TSetRxCall(tt, acid, "GetSize");
3069 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3072 return VOLSERTRELE_ERROR;
3074 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3079 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3080 afs_uint32 where, afs_int32 verbose)
3082 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3084 Volume *vol=0, *newvol=0;
3085 struct volser_trans *tt = 0, *tt2 = 0;
3086 char caller[MAXKTCNAMELEN];
3089 if (!afsconf_SuperUser(tdir, acall, caller))
3092 vol = VAttachVolume(&code, vid, V_VOLUPD);
3098 newvol = VAttachVolume(&code, new, V_VOLUPD);
3100 VDetachVolume(&code2, vol);
3105 if (V_device(vol) != V_device(newvol)
3106 || V_uniquifier(newvol) != 2) {
3107 if (V_device(vol) != V_device(newvol)) {
3108 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3110 rx_Write(acall, line, strlen(line));
3112 if (V_uniquifier(newvol) != 2) {
3113 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3114 rx_Write(acall, line, strlen(line));
3117 rx_Write(acall, line, 1);
3118 VDetachVolume(&code2, vol);
3119 VDetachVolume(&code2, newvol);
3122 tt = NewTrans(vid, V_device(vol));
3124 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3125 rx_Write(acall, line, strlen(line));
3127 rx_Write(acall, line, 1);
3128 VDetachVolume(&code2, vol);
3129 VDetachVolume(&code2, newvol);
3130 return VOLSERVOLBUSY;
3132 VTRANS_OBJ_LOCK(tt);
3133 tt->iflags = ITBusy;
3135 TSetRxCall_r(tt, NULL, "SplitVolume");
3136 VTRANS_OBJ_UNLOCK(tt);
3138 tt2 = NewTrans(new, V_device(newvol));
3140 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3141 rx_Write(acall, line, strlen(line));
3143 rx_Write(acall, line, 1);
3145 VDetachVolume(&code2, vol);
3146 VDetachVolume(&code2, newvol);
3147 return VOLSERVOLBUSY;
3149 VTRANS_OBJ_LOCK(tt2);
3150 tt2->iflags = ITBusy;
3152 TSetRxCall_r(tt2, NULL, "SplitVolume");
3153 VTRANS_OBJ_UNLOCK(tt2);
3155 code = split_volume(acall, vol, newvol, where, verbose);
3157 VDetachVolume(&code2, vol);
3159 VDetachVolume(&code2, newvol);
3160 DeleteTrans(tt2, 1);
3167 /* GetPartName - map partid (a decimal number) into pname (a string)
3168 * Since for NT we actually want to return the drive name, we map through the
3172 GetPartName(afs_int32 partid, char *pname)
3177 strcpy(pname, "/vicep");
3178 pname[6] = 'a' + partid;
3181 } else if (partid < VOLMAXPARTS) {
3182 strcpy(pname, "/vicep");
3184 pname[6] = 'a' + (partid / 26);
3185 pname[7] = 'a' + (partid % 26);