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>
19 #include <sys/types.h>
28 #include <netinet/in.h>
37 #include <afs/afsint.h>
39 #ifdef AFS_PTHREAD_ENV
41 #else /* AFS_PTHREAD_ENV */
42 #include <afs/assert.h>
43 #endif /* AFS_PTHREAD_ENV */
44 #include <afs/prs_fs.h>
48 #include <afs/cellconfig.h>
51 #include <afs/ihandle.h>
53 #include <afs/ntops.h>
55 #include <afs/vnode.h>
56 #include <afs/volume.h>
57 #include <afs/volume_inline.h>
58 #include <afs/partition.h>
60 #include <afs/daemon_com.h>
61 #include <afs/fssync.h>
63 #include "afs/audit.h"
69 #include "volser_prototypes.h"
72 extern struct volser_trans *FindTrans(), *NewTrans(), *TransList();
73 extern struct afsconf_dir *tdir;
75 /* Needed by Irix. Leave, or include a header */
76 extern char *volutil_PartitionName();
78 extern void LogError(afs_int32 errcode);
80 /* Forward declarations */
81 static int GetPartName(afs_int32 partid, char *pname);
83 #define OneDay (24*60*60)
89 afs_int32 localTid = 1;
90 afs_int32 VolPartitionInfo(), VolNukeVolume(), VolCreateVolume(),
91 VolDeleteVolume(), VolClone();
92 afs_int32 VolReClone(), VolTransCreate(), VolGetNthVolume(), VolGetFlags(),
93 VolForward(), VolDump();
94 afs_int32 VolRestore(), VolEndTrans(), VolSetForwarding(), VolGetStatus(),
95 VolSetInfo(), VolGetName();
96 afs_int32 VolListPartitions(), VolListOneVolume(),
97 VolXListOneVolume(), VolXListVolumes();
98 afs_int32 VolListVolumes(), XVolListPartitions(), VolMonitor(),
99 VolSetIdsTypes(), VolSetDate(), VolSetFlags();
101 /* this call unlocks all of the partition locks we've set */
105 register struct DiskPartition64 *tp;
106 for (tp = DiskPartitionList; tp; tp = tp->next) {
107 if (tp->lock_fd != INVALID_FD) {
108 close(tp->lock_fd); /* releases flock held on this partition */
109 tp->lock_fd = INVALID_FD;
115 /* get partition id from a name */
117 PartitionID(char *aname)
120 register int code = 0;
125 return -1; /* unknown */
127 /* otherwise check for vicepa or /vicepa, or just plain "a" */
129 if (!strncmp(aname, "/vicep", 6)) {
130 strncpy(ascii, aname + 6, 2);
132 return -1; /* bad partition name */
133 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
134 * from 0. Do the appropriate conversion */
136 /* one char name, 0..25 */
137 if (ascii[0] < 'a' || ascii[0] > 'z')
138 return -1; /* wrongo */
139 return ascii[0] - 'a';
141 /* two char name, 26 .. <whatever> */
142 if (ascii[0] < 'a' || ascii[0] > 'z')
143 return -1; /* wrongo */
144 if (ascii[1] < 'a' || ascii[1] > 'z')
145 return -1; /* just as bad */
146 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
147 if (code > VOLMAXPARTS)
154 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
158 /* 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 */
159 (void)afs_snprintf(aname, asize, VFORMAT, (unsigned long)avol);
164 ConvertPartition(int apartno, char *aname, int asize)
170 strcpy(aname, "/vicep");
172 aname[6] = 'a' + apartno;
176 aname[6] = 'a' + (apartno / 26);
177 aname[7] = 'a' + (apartno % 26);
183 /* the only attach function that takes a partition is "...ByName", so we use it */
185 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
187 char pbuf[30], vbuf[20];
188 register struct Volume *tv;
190 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
194 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
198 tv = VAttachVolumeByName((Error *)error, pbuf, vbuf, amode);
202 /* Adapted from the file server; create a root directory for this volume */
204 ViceCreateRoot(Volume *vp)
207 struct acl_accessList *ACL;
209 Inode inodeNumber, nearInode;
210 struct VnodeDiskObject *vnode;
211 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
217 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
220 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
222 V_pref(vp, nearInode);
224 IH_CREATE(V_linkHandle(vp), V_device(vp),
225 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
227 assert(VALID_INO(inodeNumber));
229 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
230 did.Volume = V_id(vp);
231 did.Vnode = (VnodeId) 1;
234 assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
235 DFlush(); /* flush all modified dir buffers out */
236 DZap((afs_int32 *)&dir); /* Remove all buffers for this dir */
237 length = Length(&dir); /* Remember size of this directory */
239 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
241 /* build a single entry ACL that gives all rights to system:administrators */
242 /* this section of code assumes that access list format is not going to
245 ACL = VVnodeDiskACL(vnode);
246 ACL->size = sizeof(struct acl_accessList);
247 ACL->version = ACL_ACLVERSION;
251 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
252 ACL->entries[0].rights =
253 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
254 | PRSFS_LOCK | PRSFS_ADMINISTER;
256 vnode->type = vDirectory;
258 vnode->modeBits = 0777;
259 vnode->linkCount = 2;
260 VNDISK_SET_LEN(vnode, length);
261 vnode->uniquifier = 1;
262 V_uniquifier(vp) = vnode->uniquifier + 1;
263 vnode->dataVersion = 1;
264 VNDISK_SET_INO(vnode, inodeNumber);
265 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
269 vnode->vnodeMagic = vcp->magic;
271 IH_INIT(h, vp->device, V_parentId(vp),
272 vp->vnodeIndex[vLarge].handle->ih_ino);
275 code = FDH_SEEK(fdP, vnodeIndexOffset(vcp, 1), SEEK_SET);
277 code = FDH_WRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE);
278 assert(code == SIZEOF_LARGEDISKVNODE);
279 FDH_REALLYCLOSE(fdP);
281 VNDISK_GET_LEN(length, vnode);
282 V_diskused(vp) = nBlocks(length);
289 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
293 struct diskPartition64 *dp = (struct diskPartition64 *)
294 malloc(sizeof(struct diskPartition64));
296 code = VolPartitionInfo(acid, pname, dp);
298 strncpy(partition->name, dp->name, 32);
299 strncpy(partition->devName, dp->devName, 32);
300 partition->lock_fd = dp->lock_fd;
301 partition->free=RoundInt64ToInt32(dp->free);
302 partition->minFree=RoundInt64ToInt32(dp->minFree);
305 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
310 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
315 code = VolPartitionInfo(acid, pname, partition);
316 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
321 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
324 register struct DiskPartition64 *dp;
327 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
330 dp = VGetPartition(pname, 0);
332 strncpy(partition->name, dp->name, 32);
333 strncpy(partition->devName, dp->devName, 32);
334 partition->lock_fd = (int)dp->lock_fd;
335 partition->free = dp->free;
336 partition->minFree = dp->totalUsable;
339 return VOLSERILLEGAL_PARTITION;
342 /* obliterate a volume completely, and slowly. */
344 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
348 code = VolNukeVolume(acid, apartID, avolID);
349 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
354 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
358 register afs_int32 code;
360 char caller[MAXKTCNAMELEN];
362 /* check for access */
363 if (!afsconf_SuperUser(tdir, acid, caller))
364 return VOLSERBAD_ACCESS;
366 Log("%s is executing VolNukeVolume %u\n", caller, avolID);
368 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
370 /* we first try to attach the volume in update mode, so that the file
371 * server doesn't try to use it (and abort) while (or after) we delete it.
372 * If we don't get the volume, that's fine, too. We just won't put it back.
374 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
375 code = nuke(partName, avolID);
377 VDetachVolume(&error, tvp);
381 /* create a new volume, with name aname, on the specified partition (1..n)
382 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
383 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
384 * for the volume id (useful for things like volume restore).
385 * Return the new volume id in *avolid.
388 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
389 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
395 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
396 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
397 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
403 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
404 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
409 afs_int32 junk; /* discardable error code */
411 afs_int32 doCreateRoot = 1;
412 register struct volser_trans *tt;
414 char caller[MAXKTCNAMELEN];
416 if (strlen(aname) > 31)
417 return VOLSERBADNAME;
418 if (!afsconf_SuperUser(tdir, acid, caller))
419 return VOLSERBAD_ACCESS;
421 Log("%s is executing CreateVolume '%s'\n", caller, aname);
422 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
423 return error; /*a standard unix error */
424 if (atype != readwriteVolume && atype != readonlyVolume
425 && atype != backupVolume)
427 if ((volumeID = *avolid) == 0) {
429 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
433 if ((aparent == volumeID) && (atype == readwriteVolume)) {
438 tt = NewTrans(volumeID, apart);
440 Log("1 createvolume: failed to create trans\n");
441 return VOLSERVOLBUSY; /* volume already busy! */
443 vp = VCreateVolume(&error, ppath, volumeID, aparent);
445 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
450 V_uniquifier(vp) = 1;
451 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
452 V_inService(vp) = V_blessed(vp) = 1;
454 AssignVolumeName(&V_disk(vp), aname, 0);
457 V_destroyMe(vp) = DESTROY_ME;
459 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
460 VUpdateVolume(&error, vp);
462 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
465 VDetachVolume(&junk, vp); /* rather return the real error code */
470 strcpy(tt->lastProcName, "CreateVolume");
471 tt->rxCallPtr = acid;
472 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
473 tt->rxCallPtr = (struct rx_call *)0;
475 return VOLSERTRELE_ERROR;
479 /* delete the volume associated with this transaction */
481 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
485 code = VolDeleteVolume(acid, atrans);
486 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
491 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
493 register struct volser_trans *tt;
495 char caller[MAXKTCNAMELEN];
497 if (!afsconf_SuperUser(tdir, acid, caller))
498 return VOLSERBAD_ACCESS;
499 tt = FindTrans(atrans);
502 if (tt->vflags & VTDeleted) {
503 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
508 Log("%s is executing Delete Volume %u\n", caller, tt->volid);
509 strcpy(tt->lastProcName, "DeleteVolume");
510 tt->rxCallPtr = acid;
511 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
512 V_destroyMe(tt->volume) = DESTROY_ME; /* so endtrans does the right fssync opcode */
513 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
514 tt->rxCallPtr = (struct rx_call *)0;
516 return VOLSERTRELE_ERROR;
518 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
519 return 0; /* vpurgevolume doesn't set an error code */
522 /* make a clone of the volume associated with atrans, possibly giving it a new
523 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
524 * for the clone's id). The new clone is given the name newName. Finally, due to
525 * efficiency considerations, if purgeId is non-zero, we purge that volume when doing
526 * the clone operation. This may be useful when making new backup volumes, for instance
527 * since the net result of a clone and a purge generally leaves many inode ref counts
528 * the same, while doing them separately would result in far more iincs and idecs being
529 * peformed (and they are slow operations).
531 /* for efficiency reasons, sometimes faster to piggyback a purge here */
533 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
534 afs_int32 newType, char *newName, afs_uint32 *newNumber)
538 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
539 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
540 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
546 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
547 afs_int32 newType, char *newName, afs_uint32 *newNumber)
550 register struct Volume *originalvp, *purgevp, *newvp;
552 register struct volser_trans *tt, *ttc;
553 char caller[MAXKTCNAMELEN];
555 if (strlen(newName) > 31)
556 return VOLSERBADNAME;
557 if (!afsconf_SuperUser(tdir, acid, caller))
558 return VOLSERBAD_ACCESS; /*not a super user */
560 Log("%s is executing Clone Volume new name=%s\n", caller, newName);
562 originalvp = (Volume *) 0;
563 purgevp = (Volume *) 0;
564 newvp = (Volume *) 0;
565 tt = ttc = (struct volser_trans *)0;
567 if (!newNumber || !*newNumber) {
568 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
573 if (newType != readonlyVolume && newType != backupVolume)
575 tt = FindTrans(atrans);
578 if (tt->vflags & VTDeleted) {
579 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
583 ttc = NewTrans(newId, tt->partition);
584 if (!ttc) { /* someone is messing with the clone already */
588 strcpy(tt->lastProcName, "Clone");
589 tt->rxCallPtr = acid;
593 purgevp = VAttachVolume(&error, purgeId, V_VOLUPD);
595 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
601 originalvp = tt->volume;
602 if ((V_type(originalvp) == backupVolume)
603 || (V_type(originalvp) == readonlyVolume)) {
604 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
608 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
609 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
615 if (originalvp->device != purgevp->device) {
616 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
620 if (V_type(purgevp) != readonlyVolume) {
621 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
625 if (V_type(originalvp) == readonlyVolume
626 && V_parentId(originalvp) != V_parentId(purgevp)) {
627 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
631 if (V_type(originalvp) == readwriteVolume
632 && tt->volid != V_parentId(purgevp)) {
633 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
642 VCreateVolume(&error, originalvp->partition->name, newId,
643 V_parentId(originalvp));
645 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
646 newvp = (Volume *) 0;
649 if (newType == readonlyVolume)
650 V_cloneId(originalvp) = newId;
651 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
654 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
655 CloneVolume(&error, originalvp, newvp, purgevp);
656 purgevp = NULL; /* clone releases it, maybe even if error */
658 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
662 if (newType == readonlyVolume) {
663 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
664 V_type(newvp) = readonlyVolume;
665 } else if (newType == backupVolume) {
666 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
667 V_type(newvp) = backupVolume;
668 V_backupId(originalvp) = newId;
670 strcpy(newvp->header->diskstuff.name, newName);
671 V_creationDate(newvp) = V_copyDate(newvp);
672 ClearVolumeStats(&V_disk(newvp));
673 V_destroyMe(newvp) = DESTROY_ME;
674 V_inService(newvp) = 0;
675 if (newType == backupVolume) {
676 V_backupDate(originalvp) = V_copyDate(newvp);
677 V_backupDate(newvp) = V_copyDate(newvp);
680 VUpdateVolume(&error, newvp);
682 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
686 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
688 VUpdateVolume(&error, originalvp);
690 Log("1 Volser: Clone: original update %u\n", error);
694 tt->rxCallPtr = (struct rx_call *)0;
696 tt = (struct volser_trans *)0;
697 error = VOLSERTRELE_ERROR;
705 VDetachVolume(&code, purgevp);
707 VDetachVolume(&code, newvp);
709 tt->rxCallPtr = (struct rx_call *)0;
717 /* reclone this volume into the specified id */
719 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
723 code = VolReClone(acid, atrans, cloneId);
724 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
730 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
732 register struct Volume *originalvp, *clonevp;
735 register struct volser_trans *tt, *ttc;
736 char caller[MAXKTCNAMELEN];
738 /*not a super user */
739 if (!afsconf_SuperUser(tdir, acid, caller))
740 return VOLSERBAD_ACCESS;
742 Log("%s is executing Reclone Volume %u\n", caller, cloneId);
744 clonevp = originalvp = (Volume *) 0;
745 tt = (struct volser_trans *)0;
747 tt = FindTrans(atrans);
750 if (tt->vflags & VTDeleted) {
751 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
755 ttc = NewTrans(cloneId, tt->partition);
756 if (!ttc) { /* someone is messing with the clone already */
760 strcpy(tt->lastProcName, "ReClone");
761 tt->rxCallPtr = acid;
763 originalvp = tt->volume;
764 if ((V_type(originalvp) == backupVolume)
765 || (V_type(originalvp) == readonlyVolume)) {
766 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
770 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
771 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
777 clonevp = VAttachVolume(&error, cloneId, V_VOLUPD);
779 Log("1 Volser: can't attach clone %d\n", cloneId);
783 newType = V_type(clonevp); /* type of the new volume */
785 if (originalvp->device != clonevp->device) {
786 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
791 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
792 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
796 if (V_type(originalvp) == readonlyVolume
797 && V_parentId(originalvp) != V_parentId(clonevp)) {
798 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
802 if (V_type(originalvp) == readwriteVolume
803 && tt->volid != V_parentId(clonevp)) {
804 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
810 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
812 CloneVolume(&error, originalvp, clonevp, clonevp);
814 Log("1 Volser: Clone: reclone operation failed with code %d\n",
820 /* fix up volume name and type, CloneVolume just propagated RW's */
821 if (newType == readonlyVolume) {
822 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
823 V_type(clonevp) = readonlyVolume;
824 } else if (newType == backupVolume) {
825 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
826 V_type(clonevp) = backupVolume;
827 V_backupId(originalvp) = cloneId;
829 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
831 /* pretend recloned volume is a totally new instance */
832 V_copyDate(clonevp) = time(0);
833 V_creationDate(clonevp) = V_copyDate(clonevp);
834 ClearVolumeStats(&V_disk(clonevp));
835 V_destroyMe(clonevp) = 0;
836 V_inService(clonevp) = 0;
837 if (newType == backupVolume) {
838 V_backupDate(originalvp) = V_copyDate(clonevp);
839 V_backupDate(clonevp) = V_copyDate(clonevp);
841 V_inUse(clonevp) = 0;
842 VUpdateVolume(&error, clonevp);
844 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
848 /* VUpdateVolume succeeded. Mark it in service so there's no window
849 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
850 * specialStatus; this is a reclone and this volume started online
852 V_inService(clonevp) = 1;
853 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
855 VUpdateVolume(&error, originalvp);
857 Log("1 Volser: Clone: original update %u\n", error);
861 tt->rxCallPtr = (struct rx_call *)0;
863 tt = (struct volser_trans *)0;
864 error = VOLSERTRELE_ERROR;
871 struct DiskPartition64 *tpartp = originalvp->partition;
872 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
878 VDetachVolume(&code, clonevp);
880 tt->rxCallPtr = (struct rx_call *)0;
888 /* create a new transaction, associated with volume and partition. Type of
889 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
890 * See volser.h for definition of iflags (the constants are named IT*).
893 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
894 afs_int32 iflags, afs_int32 *ttid)
898 code = VolTransCreate(acid, volume, partition, iflags, ttid);
899 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
905 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
906 afs_int32 iflags, afs_int32 *ttid)
908 register struct volser_trans *tt;
910 afs_int32 error, code;
912 char caller[MAXKTCNAMELEN];
914 if (!afsconf_SuperUser(tdir, acid, caller))
915 return VOLSERBAD_ACCESS; /*not a super user */
916 if (iflags & ITCreate)
918 else if (iflags & ITBusy)
920 else if (iflags & ITReadOnly)
922 else if (iflags & ITOffline)
925 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
930 tt = NewTrans(volume, partition);
932 /* can't create a transaction? put the volume back */
933 Log("1 transcreate: can't create transaction\n");
934 return VOLSERVOLBUSY;
936 tv = XAttachVolume(&error, volume, partition, mode);
940 VDetachVolume(&code, tv);
948 strcpy(tt->lastProcName, "TransCreate");
950 return VOLSERTRELE_ERROR;
955 /* using aindex as a 0-based index, return the aindex'th volume on this server
956 * Both the volume number and partition number (one-based) are returned.
959 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
964 code = VolGetNthVolume(acid, aindex, avolume, apart);
965 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
970 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_int32 *avolume,
973 Log("1 Volser: GetNthVolume: Not yet implemented\n");
977 /* return the volume flags (VT* constants in volser.h) associated with this
981 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
985 code = VolGetFlags(acid, atid, aflags);
986 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
991 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
993 register struct volser_trans *tt;
995 tt = FindTrans(atid);
998 if (tt->vflags & VTDeleted) {
999 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1004 strcpy(tt->lastProcName, "GetFlags");
1005 tt->rxCallPtr = acid;
1006 *aflags = tt->vflags;
1007 tt->rxCallPtr = (struct rx_call *)0;
1009 return VOLSERTRELE_ERROR;
1014 /* Change the volume flags (VT* constants in volser.h) associated with this
1015 * transaction. Effects take place immediately on volume, although volume
1016 * remains attached as usual by the transaction.
1019 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1023 code = VolSetFlags(acid, atid, aflags);
1024 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1030 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1032 register struct volser_trans *tt;
1033 register struct Volume *vp;
1035 char caller[MAXKTCNAMELEN];
1037 if (!afsconf_SuperUser(tdir, acid, caller))
1038 return VOLSERBAD_ACCESS; /*not a super user */
1039 /* find the trans */
1040 tt = FindTrans(atid);
1043 if (tt->vflags & VTDeleted) {
1044 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1049 strcpy(tt->lastProcName, "SetFlags");
1050 tt->rxCallPtr = acid;
1051 vp = tt->volume; /* pull volume out of transaction */
1053 /* check if we're allowed to make any updates */
1054 if (tt->iflags & ITReadOnly) {
1059 /* handle delete-on-salvage flag */
1060 if (aflags & VTDeleteOnSalvage) {
1061 V_destroyMe(tt->volume) = DESTROY_ME;
1063 V_destroyMe(tt->volume) = 0;
1066 if (aflags & VTOutOfService) {
1067 V_inService(vp) = 0;
1069 V_inService(vp) = 1;
1071 VUpdateVolume(&error, vp);
1072 tt->vflags = aflags;
1073 tt->rxCallPtr = (struct rx_call *)0;
1074 if (TRELE(tt) && !error)
1075 return VOLSERTRELE_ERROR;
1080 /* dumpS the volume associated with a particular transaction from a particular
1081 * date. Send the dump to a different transaction (destTrans) on the server
1082 * specified by the destServer structure.
1085 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1086 struct destServer *destination, afs_int32 destTrans,
1087 struct restoreCookie *cookie)
1092 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1093 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1094 destination->destHost, AUD_LONG, destTrans, AUD_END);
1099 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1100 struct destServer *destination, afs_int32 destTrans,
1101 struct restoreCookie *cookie)
1103 register struct volser_trans *tt;
1104 register afs_int32 code;
1105 register struct rx_connection *tcon;
1106 struct rx_call *tcall;
1107 register struct Volume *vp;
1108 struct rx_securityClass *securityObject;
1109 afs_int32 securityIndex;
1110 char caller[MAXKTCNAMELEN];
1112 if (!afsconf_SuperUser(tdir, acid, caller))
1113 return VOLSERBAD_ACCESS; /*not a super user */
1114 /* initialize things */
1115 tcon = (struct rx_connection *)0;
1116 tt = (struct volser_trans *)0;
1118 /* find the local transaction */
1119 tt = FindTrans(fromTrans);
1122 if (tt->vflags & VTDeleted) {
1123 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1128 strcpy(tt->lastProcName, "Forward");
1130 /* get auth info for the this connection (uses afs from ticket file) */
1131 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1137 /* make an rpc connection to the other server */
1139 rx_NewConnection(htonl(destination->destHost),
1140 htons(destination->destPort), VOLSERVICE_ID,
1141 securityObject, securityIndex);
1143 tt->rxCallPtr = (struct rx_call *)0;
1147 tcall = rx_NewCall(tcon);
1148 tt->rxCallPtr = tcall;
1149 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1150 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1155 /* these next calls implictly call rx_Write when writing out data */
1156 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1159 EndAFSVolRestore(tcall); /* probably doesn't do much */
1160 tt->rxCallPtr = (struct rx_call *)0;
1161 code = rx_EndCall(tcall, 0);
1162 rx_DestroyConnection(tcon); /* done with the connection */
1167 return VOLSERTRELE_ERROR;
1173 (void)rx_EndCall(tcall, 0);
1174 rx_DestroyConnection(tcon);
1177 tt->rxCallPtr = (struct rx_call *)0;
1183 /* Start a dump and send it to multiple places simultaneously.
1184 * If this returns an error (eg, return ENOENT), it means that
1185 * none of the releases worked. If this returns 0, that means
1186 * that one or more of the releases worked, and the caller has
1187 * to examine the results array to see which one(s).
1188 * This will only do EITHER incremental or full, not both, so it's
1189 * the caller's responsibility to be sure that all the destinations
1190 * need just an incremental (and from the same time), if that's
1194 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1195 fromDate, manyDests *destinations, afs_int32 spare,
1196 struct restoreCookie *cookie, manyResults *results)
1198 afs_int32 securityIndex;
1199 struct rx_securityClass *securityObject;
1200 char caller[MAXKTCNAMELEN];
1201 struct volser_trans *tt;
1202 afs_int32 ec, code, *codes;
1203 struct rx_connection **tcons;
1204 struct rx_call **tcalls;
1206 int i, is_incremental;
1209 memset(results, 0, sizeof(manyResults));
1210 i = results->manyResults_len = destinations->manyDests_len;
1211 results->manyResults_val = codes =
1212 (afs_int32 *) malloc(i * sizeof(afs_int32));
1214 if (!results || !results->manyResults_val)
1217 if (!afsconf_SuperUser(tdir, acid, caller))
1218 return VOLSERBAD_ACCESS; /*not a super user */
1219 tt = FindTrans(fromTrans);
1222 if (tt->vflags & VTDeleted) {
1223 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1228 strcpy(tt->lastProcName, "ForwardMulti");
1230 /* (fromDate == 0) ==> full dump */
1231 is_incremental = (fromDate ? 1 : 0);
1234 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1238 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1244 /* get auth info for this connection (uses afs from ticket file) */
1245 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1247 goto fail; /* in order to audit each failure */
1250 /* make connections to all the other servers */
1251 for (i = 0; i < destinations->manyDests_len; i++) {
1252 struct replica *dest = &(destinations->manyDests_val[i]);
1254 rx_NewConnection(htonl(dest->server.destHost),
1255 htons(dest->server.destPort), VOLSERVICE_ID,
1256 securityObject, securityIndex);
1258 codes[i] = ENOTCONN;
1260 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1261 codes[i] = ENOTCONN;
1264 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1267 (void)rx_EndCall(tcalls[i], 0);
1269 rx_DestroyConnection(tcons[i]);
1276 /* these next calls implictly call rx_Write when writing out data */
1277 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1281 for (i--; i >= 0; i--) {
1282 struct replica *dest = &(destinations->manyDests_val[i]);
1284 if (!code && tcalls[i] && !codes[i]) {
1285 EndAFSVolRestore(tcalls[i]);
1288 ec = rx_EndCall(tcalls[i], 0);
1293 rx_DestroyConnection(tcons[i]); /* done with the connection */
1296 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1297 fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG,
1298 dest->trans, AUD_END);
1304 tt->rxCallPtr = (struct rx_call *)0;
1305 if (TRELE(tt) && !code) /* return the first code if it's set */
1306 return VOLSERTRELE_ERROR;
1313 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1317 code = VolDump(acid, fromTrans, fromDate, 0);
1318 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1323 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32 flags)
1327 code = VolDump(acid, fromTrans, fromDate, flags);
1328 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1333 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate, afs_int32 flags)
1336 register struct volser_trans *tt;
1337 char caller[MAXKTCNAMELEN];
1339 if (!afsconf_SuperUser(tdir, acid, caller))
1340 return VOLSERBAD_ACCESS; /*not a super user */
1341 tt = FindTrans(fromTrans);
1344 if (tt->vflags & VTDeleted) {
1345 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1349 strcpy(tt->lastProcName, "Dump");
1350 tt->rxCallPtr = acid;
1351 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1352 ? 0 : 1); /* squirt out the volume's data, too */
1354 tt->rxCallPtr = (struct rx_call *)0;
1358 tt->rxCallPtr = (struct rx_call *)0;
1361 return VOLSERTRELE_ERROR;
1367 * Ha! No more helper process!
1370 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1371 struct restoreCookie *cookie)
1375 code = VolRestore(acid, atrans, aflags, cookie);
1376 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1381 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1382 struct restoreCookie *cookie)
1384 register struct volser_trans *tt;
1385 register afs_int32 code, tcode;
1386 char caller[MAXKTCNAMELEN];
1388 if (!afsconf_SuperUser(tdir, acid, caller))
1389 return VOLSERBAD_ACCESS; /*not a super user */
1390 tt = FindTrans(atrans);
1393 if (tt->vflags & VTDeleted) {
1394 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1398 strcpy(tt->lastProcName, "Restore");
1399 tt->rxCallPtr = acid;
1401 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1403 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1404 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1405 tt->rxCallPtr = (struct rx_call *)0;
1408 return (code ? code : tcode);
1411 /* end a transaction, returning the transaction's final error code in rcode */
1413 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1417 code = VolEndTrans(acid, destTrans, rcode);
1418 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1423 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1425 register struct volser_trans *tt;
1426 char caller[MAXKTCNAMELEN];
1428 if (!afsconf_SuperUser(tdir, acid, caller))
1429 return VOLSERBAD_ACCESS; /*not a super user */
1430 tt = FindTrans(destTrans);
1434 *rcode = tt->returnCode;
1435 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1441 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1445 code = VolSetForwarding(acid, atid, anewsite);
1446 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1452 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1454 register struct volser_trans *tt;
1455 char caller[MAXKTCNAMELEN];
1458 if (!afsconf_SuperUser(tdir, acid, caller))
1459 return VOLSERBAD_ACCESS; /*not a super user */
1460 tt = FindTrans(atid);
1463 if (tt->vflags & VTDeleted) {
1464 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1469 strcpy(tt->lastProcName, "SetForwarding");
1470 tt->rxCallPtr = acid;
1471 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1474 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1475 tt->rxCallPtr = (struct rx_call *)0;
1477 return VOLSERTRELE_ERROR;
1483 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1484 register struct volser_status *astatus)
1488 code = VolGetStatus(acid, atrans, astatus);
1489 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1494 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1495 register struct volser_status *astatus)
1497 register struct Volume *tv;
1498 register struct VolumeDiskData *td;
1499 struct volser_trans *tt;
1502 tt = FindTrans(atrans);
1505 if (tt->vflags & VTDeleted) {
1506 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1511 strcpy(tt->lastProcName, "GetStatus");
1512 tt->rxCallPtr = acid;
1515 tt->rxCallPtr = (struct rx_call *)0;
1520 td = &tv->header->diskstuff;
1521 astatus->volID = td->id;
1522 astatus->nextUnique = td->uniquifier;
1523 astatus->type = td->type;
1524 astatus->parentID = td->parentId;
1525 astatus->cloneID = td->cloneId;
1526 astatus->backupID = td->backupId;
1527 astatus->restoredFromID = td->restoredFromId;
1528 astatus->maxQuota = td->maxquota;
1529 astatus->minQuota = td->minquota;
1530 astatus->owner = td->owner;
1531 astatus->creationDate = td->creationDate;
1532 astatus->accessDate = td->accessDate;
1533 astatus->updateDate = td->updateDate;
1534 astatus->expirationDate = td->expirationDate;
1535 astatus->backupDate = td->backupDate;
1536 astatus->copyDate = td->copyDate;
1537 tt->rxCallPtr = (struct rx_call *)0;
1539 return VOLSERTRELE_ERROR;
1545 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1546 register struct volintInfo *astatus)
1550 code = VolSetInfo(acid, atrans, astatus);
1551 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1556 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1557 register struct volintInfo *astatus)
1559 register struct Volume *tv;
1560 register struct VolumeDiskData *td;
1561 struct volser_trans *tt;
1562 char caller[MAXKTCNAMELEN];
1565 if (!afsconf_SuperUser(tdir, acid, caller))
1566 return VOLSERBAD_ACCESS; /*not a super user */
1567 tt = FindTrans(atrans);
1570 if (tt->vflags & VTDeleted) {
1571 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1575 strcpy(tt->lastProcName, "SetStatus");
1576 tt->rxCallPtr = acid;
1579 tt->rxCallPtr = (struct rx_call *)0;
1584 td = &tv->header->diskstuff;
1586 * Add more fields as necessary
1588 if (astatus->maxquota != -1)
1589 td->maxquota = astatus->maxquota;
1590 if (astatus->dayUse != -1)
1591 td->dayUse = astatus->dayUse;
1592 if (astatus->creationDate != -1)
1593 td->creationDate = astatus->creationDate;
1594 if (astatus->updateDate != -1)
1595 td->updateDate = astatus->updateDate;
1596 if (astatus->spare2 != -1)
1597 td->volUpdateCounter = (unsigned int)astatus->spare2;
1598 VUpdateVolume(&error, tv);
1599 tt->rxCallPtr = (struct rx_call *)0;
1601 return VOLSERTRELE_ERROR;
1607 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1611 code = VolGetName(acid, atrans, aname);
1612 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1617 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1619 register struct Volume *tv;
1620 register struct VolumeDiskData *td;
1621 struct volser_trans *tt;
1624 /* We need to at least fill it in */
1625 *aname = (char *)malloc(1);
1628 tt = FindTrans(atrans);
1631 if (tt->vflags & VTDeleted) {
1632 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1636 strcpy(tt->lastProcName, "GetName");
1637 tt->rxCallPtr = acid;
1640 tt->rxCallPtr = (struct rx_call *)0;
1645 td = &tv->header->diskstuff;
1646 len = strlen(td->name) + 1; /* don't forget the null */
1648 tt->rxCallPtr = (struct rx_call *)0;
1652 *aname = (char *)realloc(*aname, len);
1653 strcpy(*aname, td->name);
1654 tt->rxCallPtr = (struct rx_call *)0;
1656 return VOLSERTRELE_ERROR;
1661 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1664 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1665 afs_uint32 parentId, afs_uint32 cloneId)
1671 /*return a list of all partitions on the server. The non mounted
1672 *partitions are returned as -1 in the corresponding slot in partIds*/
1674 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1678 code = VolListPartitions(acid, partIds);
1679 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1684 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1689 strcpy(namehead, "/vicep"); /*7 including null terminator */
1691 /* Just return attached partitions. */
1693 for (i = 0; i < 26; i++) {
1694 namehead[6] = i + 'a';
1695 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1701 /*return a list of all partitions on the server. The non mounted
1702 *partitions are returned as -1 in the corresponding slot in partIds*/
1704 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1708 code = XVolListPartitions(acid, pEntries);
1709 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1714 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1717 struct partList partList;
1718 struct DiskPartition64 *dp;
1721 strcpy(namehead, "/vicep"); /*7 including null terminator */
1723 /* Only report attached partitions */
1724 for (i = 0; i < VOLMAXPARTS; i++) {
1725 #ifdef AFS_DEMAND_ATTACH_FS
1726 dp = VGetPartitionById(i, 0);
1729 namehead[6] = i + 'a';
1733 namehead[6] = 'a' + (k / 26);
1734 namehead[7] = 'a' + (k % 26);
1737 dp = VGetPartition(namehead, 0);
1740 partList.partId[j++] = i;
1742 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1743 if (!pEntries->partEntries_val)
1745 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1747 pEntries->partEntries_len = j;
1752 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1754 ExtractVolId(char vname[])
1757 char name[VOLSER_MAXVOLNAME + 1];
1759 strcpy(name, vname);
1761 while (name[i] == 'V' || name[i] == '0')
1764 name[11] = '\0'; /* smash the "." */
1765 return (atol(&name[i]));
1768 /*return the name of the next volume header in the directory associated with dirp and dp.
1769 *the volume id is returned in volid, and volume header name is returned in volname*/
1771 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1775 dp = readdir(dirp); /*read next entry in the directory */
1777 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1778 *volid = ExtractVolId(dp->d_name);
1779 strcpy(volname, dp->d_name);
1780 return 0; /*return the name of the file representing a volume */
1782 strcpy(volname, "");
1783 return 0; /*volname doesnot represent a volume */
1786 strcpy(volname, "EOD");
1787 return 0; /*end of directory */
1793 * volint vol info structure type.
1796 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1797 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1798 } volint_info_type_t;
1801 * handle to various on-wire vol info types.
1804 volint_info_type_t volinfo_type;
1810 } volint_info_handle_t;
1813 * store value to a field at the appropriate location in on-wire structure.
1815 #define VOLINT_INFO_STORE(handle, name, val) \
1817 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1818 (handle)->volinfo_ptr.base->name = (val); \
1820 (handle)->volinfo_ptr.ext->name = (val); \
1825 * get pointer to appropriate offset of field in on-wire structure.
1827 #define VOLINT_INFO_PTR(handle, name) \
1828 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1829 &((handle)->volinfo_ptr.base->name) : \
1830 &((handle)->volinfo_ptr.ext->name))
1833 * fill in appropriate type of on-wire volume metadata structure.
1835 * @param vp pointer to volume object
1836 * @param handle pointer to wire format handle object
1838 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1839 * @pre handle object must have a valid pointer and enumeration value
1841 * @note passing a NULL value for vp means that the fileserver doesn't
1842 * know about this particular volume, thus implying it is offline.
1844 * @return operation status
1849 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1851 unsigned int numStatBytes, now;
1852 register struct VolumeDiskData *hdr = &vp->header->diskstuff;
1854 /*read in the relevant info */
1855 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1856 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1857 VOLINT_INFO_STORE(handle, volid, hdr->id);
1858 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1859 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
1860 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
1861 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
1862 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
1863 VOLINT_INFO_STORE(handle, size, hdr->diskused);
1864 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
1865 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
1866 now = FT_ApproxTime();
1867 if ((now - hdr->dayUseDate) > OneDay) {
1868 VOLINT_INFO_STORE(handle, dayUse, 0);
1870 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
1872 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
1873 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
1874 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
1875 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
1877 #ifdef AFS_DEMAND_ATTACH_FS
1879 * for DAFS, we "lie" about volume state --
1880 * instead of returning the raw state from the disk header,
1881 * we compute state based upon the fileserver's internal
1882 * in-core state enumeration value reported to us via fssync,
1883 * along with the blessed and inService flags from the header.
1884 * -- tkeiser 11/27/2007
1887 /* Conditions that offline status is based on:
1888 volume is unattached state
1889 volume state is in (one of several error states)
1890 volume not in service
1891 volume is not marked as blessed (not on hold)
1892 volume in salvage req. state
1893 volume needsSalvaged
1894 next op would set volume offline
1895 next op would not leave volume online (based on several conditions)
1898 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1899 VIsErrorState(V_attachState(vp)) ||
1902 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
1903 hdr->needsSalvaged ||
1904 (vp->pending_vol_op &&
1905 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
1906 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
1909 VOLINT_INFO_STORE(handle, inUse, 0);
1911 VOLINT_INFO_STORE(handle, inUse, 1);
1914 /* offline status based on program type, where != fileServer enum (1) is offline */
1915 if (hdr->inUse == fileServer) {
1916 VOLINT_INFO_STORE(handle, inUse, 1);
1918 VOLINT_INFO_STORE(handle, inUse, 0);
1923 switch(handle->volinfo_type) {
1924 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
1925 case VOLINT_INFO_TYPE_BASE:
1927 #ifdef AFS_DEMAND_ATTACH_FS
1928 /* see comment above where we set inUse bit */
1929 if (hdr->needsSalvaged ||
1930 (vp && VIsErrorState(V_attachState(vp)))) {
1931 handle->volinfo_ptr.base->needsSalvaged = 1;
1933 handle->volinfo_ptr.base->needsSalvaged = 0;
1936 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
1938 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
1939 handle->volinfo_ptr.base->spare0 = hdr->minquota;
1940 handle->volinfo_ptr.base->spare1 =
1941 (long)hdr->weekUse[0] +
1942 (long)hdr->weekUse[1] +
1943 (long)hdr->weekUse[2] +
1944 (long)hdr->weekUse[3] +
1945 (long)hdr->weekUse[4] +
1946 (long)hdr->weekUse[5] +
1947 (long)hdr->weekUse[6];
1948 handle->volinfo_ptr.base->flags = 0;
1949 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
1950 handle->volinfo_ptr.base->spare3 = 0;
1954 case VOLINT_INFO_TYPE_EXT:
1956 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
1957 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
1960 * Copy out the stat fields in a single operation.
1962 if ((now - hdr->dayUseDate) > OneDay) {
1963 memset((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
1966 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
1967 (char *)&(hdr->stat_reads[0]),
1977 * get struct Volume out of the fileserver.
1979 * @param[in] volumeId volumeId for which we want state information
1980 * @param[in] pname partition name string
1981 * @param[inout] vp pointer to pointer to Volume object which
1982 * will be populated (see note)
1984 * @return operation status
1986 * @retval non-zero failure
1988 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
1993 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
1998 res.hdr.response_len = sizeof(res.hdr);
1999 res.payload.buf = *vp;
2000 res.payload.len = sizeof(Volume);
2002 code = FSYNC_VolOp(volumeId,
2008 if (code != SYNC_OK) {
2009 switch (res.hdr.reason) {
2010 case FSYNC_WRONG_PART:
2011 case FSYNC_UNKNOWN_VOLID:
2022 * mode of volume list operation.
2025 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2026 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2027 } vol_info_list_mode_t;
2030 * abstract interface to populate wire-format volume metadata structures.
2032 * @param[in] partId partition id
2033 * @param[in] volumeId volume id
2034 * @param[in] pname partition name
2035 * @param[in] volname volume file name
2036 * @param[in] handle handle to on-wire volume metadata object
2037 * @param[in] mode listing mode
2039 * @return operation status
2041 * @retval -2 DESTROY_ME flag is set
2042 * @retval -1 general failure; some data filled in
2043 * @retval -3 couldn't create vtrans; some data filled in
2046 GetVolInfo(afs_uint32 partId,
2047 afs_uint32 volumeId,
2050 volint_info_handle_t * handle,
2051 vol_info_list_mode_t mode)
2055 struct volser_trans *ttc = NULL;
2056 struct Volume *fill_tv, *tv = NULL;
2057 #ifdef AFS_DEMAND_ATTACH_FS
2058 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2059 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2060 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2061 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2063 /* Set up response handle for pending_vol_op */
2064 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2065 fs_res.payload.buf = fs_res_buf;
2066 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2069 ttc = NewTrans(volumeId, partId);
2072 VOLINT_INFO_STORE(handle, status, VBUSY);
2073 VOLINT_INFO_STORE(handle, volid, volumeId);
2077 /* Get volume from volserver */
2078 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2080 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2081 volumeId, pname, volname, error);
2086 * please note that destroyMe and needsSalvaged checks used to be ordered
2087 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2088 * more correct to check destroyMe before needsSalvaged.
2089 * -- tkeiser 11/28/2007
2092 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2094 case VOL_INFO_LIST_MULTIPLE:
2098 case VOL_INFO_LIST_SINGLE:
2099 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2100 volumeId, pname, volname);
2107 if (tv->header->diskstuff.needsSalvaged) {
2108 /*this volume will be salvaged */
2109 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2110 volumeId, pname, volname);
2113 #ifdef AFS_DEMAND_ATTACH_FS
2114 /* If using DAFS, get volume from fsserver */
2115 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK) {
2119 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2120 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2121 /* If we if the pending vol op */
2122 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2123 fs_tv->pending_vol_op=&pending_vol_op_res;
2125 fs_tv->pending_vol_op=NULL;
2128 /* populate the header from the volserver copy */
2129 fs_tv->header=tv->header;
2131 /* When using DAFS, use the fs volume info, populated with required structures */
2134 /* When not using DAFS, just use the local volume info */
2138 /* ok, we have all the data we need; fill in the on-wire struct */
2139 code = FillVolInfo(fill_tv, handle);
2143 VOLINT_INFO_STORE(handle, status, 0);
2144 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2145 VOLINT_INFO_STORE(handle, volid, volumeId);
2148 VDetachVolume(&error, tv);
2151 VOLINT_INFO_STORE(handle, status, 0);
2152 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2153 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2154 volumeId, pname, volname);
2158 DeleteTrans(ttc, 1);
2165 /*return the header information about the <volid> */
2167 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2168 afs_uint32 volumeId, volEntries *volumeInfo)
2172 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2173 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2178 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2179 afs_uint32 volumeId, volEntries *volumeInfo)
2182 struct DiskPartition64 *partP;
2183 char pname[9], volname[20];
2184 afs_int32 error = 0;
2189 volint_info_handle_t handle;
2191 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2192 if (!volumeInfo->volEntries_val)
2194 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2196 pntr = volumeInfo->volEntries_val;
2197 volumeInfo->volEntries_len = 1;
2198 if (GetPartName(partid, pname))
2199 return VOLSERILLEGAL_PARTITION;
2200 if (!(partP = VGetPartition(pname, 0)))
2201 return VOLSERILLEGAL_PARTITION;
2202 dirp = opendir(VPartitionPath(partP));
2204 return VOLSERILLEGAL_PARTITION;
2206 strcpy(volname, "");
2208 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2210 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2211 GetNextVol(dirp, volname, &volid);
2212 continue; /*back to while loop */
2215 if (volid == volumeId) { /*copy other things too */
2220 GetNextVol(dirp, volname, &volid);
2224 #ifndef AFS_PTHREAD_ENV
2225 IOMGR_Poll(); /*make sure that the client does not time out */
2228 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2229 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2231 code = GetVolInfo(partid,
2236 VOL_INFO_LIST_SINGLE);
2240 return (found) ? 0 : ENODEV;
2243 /*------------------------------------------------------------------------
2244 * EXPORTED SAFSVolXListOneVolume
2247 * Returns extended info on volume a_volID on partition a_partID.
2250 * a_rxCidP : Pointer to the Rx call we're performing.
2251 * a_partID : Partition for which we want the extended list.
2252 * a_volID : Volume ID we wish to know about.
2253 * a_volumeXInfoP : Ptr to the extended info blob.
2256 * 0 Successful operation
2257 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2260 * Nothing interesting.
2264 *------------------------------------------------------------------------*/
2267 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2268 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2272 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2273 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2278 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2279 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2280 { /*SAFSVolXListOneVolume */
2282 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2283 struct DiskPartition64 *partP; /*Ptr to partition */
2284 char pname[9], volname[20]; /*Partition, volume names */
2285 DIR *dirp; /*Partition directory ptr */
2286 afs_uint32 currVolID; /*Current volume ID */
2287 int found = 0; /*Did we find the volume we need? */
2289 volint_info_handle_t handle;
2292 * Set up our pointers for action, marking our structure to hold exactly
2293 * one entry. Also, assume we'll fail in our quest.
2295 a_volumeXInfoP->volXEntries_val =
2296 (volintXInfo *) malloc(sizeof(volintXInfo));
2297 if (!a_volumeXInfoP->volXEntries_val)
2299 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2301 xInfoP = a_volumeXInfoP->volXEntries_val;
2302 a_volumeXInfoP->volXEntries_len = 1;
2306 * If the partition name we've been given is bad, bogue out.
2308 if (GetPartName(a_partID, pname))
2309 return (VOLSERILLEGAL_PARTITION);
2312 * Open the directory representing the given AFS parttion. If we can't
2315 if (!(partP = VGetPartition(pname, 0)))
2316 return VOLSERILLEGAL_PARTITION;
2317 dirp = opendir(VPartitionPath(partP));
2319 return (VOLSERILLEGAL_PARTITION);
2321 strcpy(volname, "");
2324 * Sweep through the partition directory, looking for the desired entry.
2325 * First, of course, figure out how many stat bytes to copy out of each
2328 while (strcmp(volname, "EOD") && !found) {
2330 * If this is not a volume, move on to the next entry in the
2331 * partition's directory.
2333 if (!strcmp(volname, "")) {
2334 GetNextVol(dirp, volname, &currVolID);
2338 if (currVolID == a_volID) {
2340 * We found the volume entry we're interested. Pull out the
2341 * extended information, remembering to poll (so that the client
2342 * doesn't time out) and to set up a transaction on the volume.
2346 } /*Found desired volume */
2348 GetNextVol(dirp, volname, &currVolID);
2352 #ifndef AFS_PTHREAD_ENV
2356 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2357 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2359 code = GetVolInfo(a_partID,
2364 VOL_INFO_LIST_SINGLE);
2369 * Clean up before going to dinner: close the partition directory,
2370 * return the proper value.
2373 return (found) ? 0 : ENODEV;
2374 } /*SAFSVolXListOneVolume */
2376 /*returns all the volumes on partition partid. If flags = 1 then all the
2377 * relevant info about the volumes is also returned */
2379 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2380 volEntries *volumeInfo)
2384 code = VolListVolumes(acid, partid, flags, volumeInfo);
2385 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2390 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2391 volEntries *volumeInfo)
2394 struct DiskPartition64 *partP;
2395 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2396 char pname[9], volname[20];
2397 afs_int32 error = 0;
2401 volint_info_handle_t handle;
2403 volumeInfo->volEntries_val =
2404 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2405 if (!volumeInfo->volEntries_val)
2407 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2409 pntr = volumeInfo->volEntries_val;
2410 volumeInfo->volEntries_len = 0;
2411 if (GetPartName(partid, pname))
2412 return VOLSERILLEGAL_PARTITION;
2413 if (!(partP = VGetPartition(pname, 0)))
2414 return VOLSERILLEGAL_PARTITION;
2415 dirp = opendir(VPartitionPath(partP));
2417 return VOLSERILLEGAL_PARTITION;
2418 strcpy(volname, "");
2420 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2422 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2423 GetNextVol(dirp, volname, &volid);
2424 continue; /*back to while loop */
2427 if (flags) { /*copy other things too */
2428 #ifndef AFS_PTHREAD_ENV
2429 IOMGR_Poll(); /*make sure that the client does not time out */
2432 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2433 handle.volinfo_ptr.base = pntr;
2436 code = GetVolInfo(partid,
2441 VOL_INFO_LIST_MULTIPLE);
2442 if (code == -2) { /* DESTROY_ME flag set */
2446 pntr->volid = volid;
2447 /*just volids are needed */
2452 volumeInfo->volEntries_len += 1;
2453 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2454 /*running out of space, allocate more space */
2455 allocSize = (allocSize * 3) / 2;
2457 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2458 allocSize * sizeof(volintInfo));
2461 return VOLSERNO_MEMORY;
2463 volumeInfo->volEntries_val = pntr; /* point to new block */
2464 /* set pntr to the right position */
2465 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2470 GetNextVol(dirp, volname, &volid);
2478 /*------------------------------------------------------------------------
2479 * EXPORTED SAFSVolXListVolumes
2482 * Returns all the volumes on partition a_partID. If a_flags
2483 * is set to 1, then all the relevant extended volume information
2487 * a_rxCidP : Pointer to the Rx call we're performing.
2488 * a_partID : Partition for which we want the extended list.
2489 * a_flags : Various flags.
2490 * a_volumeXInfoP : Ptr to the extended info blob.
2493 * 0 Successful operation
2494 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2495 * VOLSERNO_MEMORY if we ran out of memory allocating
2499 * Nothing interesting.
2503 *------------------------------------------------------------------------*/
2506 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2507 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2511 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2512 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2517 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2518 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2519 { /*SAFSVolXListVolumes */
2521 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2522 struct DiskPartition64 *partP; /*Ptr to partition */
2523 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2524 char pname[9], volname[20]; /*Partition, volume names */
2525 afs_int32 error = 0; /*Return code */
2526 DIR *dirp; /*Partition directory ptr */
2527 afs_uint32 volid; /*Current volume ID */
2529 volint_info_handle_t handle;
2532 * Allocate a large array of extended volume info structures, then
2533 * set it up for action.
2535 a_volumeXInfoP->volXEntries_val =
2536 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2537 if (!a_volumeXInfoP->volXEntries_val)
2539 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2541 xInfoP = a_volumeXInfoP->volXEntries_val;
2542 a_volumeXInfoP->volXEntries_len = 0;
2545 * If the partition name we've been given is bad, bogue out.
2547 if (GetPartName(a_partID, pname))
2548 return (VOLSERILLEGAL_PARTITION);
2551 * Open the directory representing the given AFS parttion. If we can't
2554 if (!(partP = VGetPartition(pname, 0)))
2555 return VOLSERILLEGAL_PARTITION;
2556 dirp = opendir(VPartitionPath(partP));
2558 return (VOLSERILLEGAL_PARTITION);
2559 strcpy(volname, "");
2562 * Sweep through the partition directory, acting on each entry. First,
2563 * of course, figure out how many stat bytes to copy out of each volume.
2565 while (strcmp(volname, "EOD")) {
2568 * If this is not a volume, move on to the next entry in the
2569 * partition's directory.
2571 if (!strcmp(volname, "")) {
2572 GetNextVol(dirp, volname, &volid);
2578 * Full info about the volume desired. Poll to make sure the
2579 * client doesn't time out, then start up a new transaction.
2581 #ifndef AFS_PTHREAD_ENV
2585 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2586 handle.volinfo_ptr.ext = xInfoP;
2588 code = GetVolInfo(a_partID,
2593 VOL_INFO_LIST_MULTIPLE);
2594 if (code == -2) { /* DESTROY_ME flag set */
2599 * Just volume IDs are needed.
2601 xInfoP->volid = volid;
2606 * Bump the pointer in the data area we're building, along with
2607 * the count of the number of entries it contains.
2610 (a_volumeXInfoP->volXEntries_len)++;
2611 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2613 * We're running out of space in the area we've built. Grow it.
2615 allocSize = (allocSize * 3) / 2;
2616 xInfoP = (volintXInfo *)
2617 realloc((char *)a_volumeXInfoP->volXEntries_val,
2618 (allocSize * sizeof(volintXInfo)));
2619 if (xInfoP == NULL) {
2621 * Bummer, no memory. Bag it, tell our caller what went wrong.
2624 return (VOLSERNO_MEMORY);
2628 * Memory reallocation worked. Correct our pointers so they
2629 * now point to the new block and the current open position within
2632 a_volumeXInfoP->volXEntries_val = xInfoP;
2634 a_volumeXInfoP->volXEntries_val +
2635 a_volumeXInfoP->volXEntries_len;
2639 GetNextVol(dirp, volname, &volid);
2640 } /*Sweep through the partition directory */
2643 * We've examined all entries in the partition directory. Close it,
2644 * delete our transaction (if any), and go home happy.
2649 } /*SAFSVolXListVolumes */
2651 /*this call is used to monitor the status of volser for debugging purposes.
2652 *information about all the active transactions is returned in transInfo*/
2654 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2658 code = VolMonitor(acid, transInfo);
2659 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2664 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2666 transDebugInfo *pntr;
2667 afs_int32 allocSize = 50;
2668 struct volser_trans *tt, *allTrans;
2670 transInfo->transDebugEntries_val =
2671 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2672 if (!transInfo->transDebugEntries_val)
2674 pntr = transInfo->transDebugEntries_val;
2675 transInfo->transDebugEntries_len = 0;
2676 allTrans = TransList();
2677 if (allTrans == (struct volser_trans *)0)
2678 return 0; /*no active transactions */
2679 for (tt = allTrans; tt; tt = tt->next) { /*copy relevant info into pntr */
2680 pntr->tid = tt->tid;
2681 pntr->time = tt->time;
2682 pntr->creationTime = tt->creationTime;
2683 pntr->returnCode = tt->returnCode;
2684 pntr->volid = tt->volid;
2685 pntr->partition = tt->partition;
2686 pntr->iflags = tt->iflags;
2687 pntr->vflags = tt->vflags;
2688 pntr->tflags = tt->tflags;
2689 strcpy(pntr->lastProcName, tt->lastProcName);
2690 pntr->callValid = 0;
2691 if (tt->rxCallPtr) { /*record call related info */
2692 pntr->callValid = 1;
2693 pntr->readNext = tt->rxCallPtr->rnext;
2694 pntr->transmitNext = tt->rxCallPtr->tnext;
2695 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2696 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2699 transInfo->transDebugEntries_len += 1;
2700 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2701 allocSize = (allocSize * 3) / 2;
2703 (transDebugInfo *) realloc((char *)transInfo->
2704 transDebugEntries_val,
2706 sizeof(transDebugInfo));
2707 transInfo->transDebugEntries_val = pntr;
2709 transInfo->transDebugEntries_val +
2710 transInfo->transDebugEntries_len;
2711 /*set pntr to right position */
2720 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[], afs_int32 type, afs_uint32 pId, afs_uint32 cloneId, afs_uint32 backupId)
2724 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2725 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2726 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2732 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[], afs_int32 type, afs_uint32 pId, afs_uint32 cloneId, afs_uint32 backupId)
2735 afs_int32 error = 0;
2736 register struct volser_trans *tt;
2737 char caller[MAXKTCNAMELEN];
2739 if (strlen(name) > 31)
2740 return VOLSERBADNAME;
2741 if (!afsconf_SuperUser(tdir, acid, caller))
2742 return VOLSERBAD_ACCESS; /*not a super user */
2743 /* find the trans */
2744 tt = FindTrans(atid);
2747 if (tt->vflags & VTDeleted) {
2748 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2752 strcpy(tt->lastProcName, "SetIdsTypes");
2753 tt->rxCallPtr = acid;
2757 V_backupId(tv) = backupId;
2758 V_cloneId(tv) = cloneId;
2759 V_parentId(tv) = pId;
2760 strcpy((&V_disk(tv))->name, name);
2761 VUpdateVolume(&error, tv);
2763 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2767 tt->rxCallPtr = (struct rx_call *)0;
2768 if (TRELE(tt) && !error)
2769 return VOLSERTRELE_ERROR;
2773 tt->rxCallPtr = (struct rx_call *)0;
2774 if (TRELE(tt) && !error)
2775 return VOLSERTRELE_ERROR;
2780 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2784 code = VolSetDate(acid, atid, cdate);
2785 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2791 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2794 afs_int32 error = 0;
2795 register struct volser_trans *tt;
2796 char caller[MAXKTCNAMELEN];
2798 if (!afsconf_SuperUser(tdir, acid, caller))
2799 return VOLSERBAD_ACCESS; /*not a super user */
2800 /* find the trans */
2801 tt = FindTrans(atid);
2804 if (tt->vflags & VTDeleted) {
2805 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2809 strcpy(tt->lastProcName, "SetDate");
2810 tt->rxCallPtr = acid;
2813 V_creationDate(tv) = cdate;
2814 VUpdateVolume(&error, tv);
2816 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2820 tt->rxCallPtr = (struct rx_call *)0;
2821 if (TRELE(tt) && !error)
2822 return VOLSERTRELE_ERROR;
2826 tt->rxCallPtr = (struct rx_call *)0;
2827 if (TRELE(tt) && !error)
2828 return VOLSERTRELE_ERROR;
2833 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2834 afs_uint32 volumeId)
2839 char caller[MAXKTCNAMELEN];
2841 register struct volser_trans *ttc;
2842 char pname[16], volname[20];
2843 struct DiskPartition64 *partP;
2844 afs_int32 ret = ENODEV;
2847 if (!afsconf_SuperUser(tdir, acid, caller))
2848 return VOLSERBAD_ACCESS; /*not a super user */
2849 if (GetPartName(partId, pname))
2850 return VOLSERILLEGAL_PARTITION;
2851 if (!(partP = VGetPartition(pname, 0)))
2852 return VOLSERILLEGAL_PARTITION;
2853 dirp = opendir(VPartitionPath(partP));
2855 return VOLSERILLEGAL_PARTITION;
2856 strcpy(volname, "");
2857 ttc = (struct volser_trans *)0;
2859 while (strcmp(volname, "EOD")) {
2860 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2861 GetNextVol(dirp, volname, &volid);
2862 continue; /*back to while loop */
2865 if (volid == volumeId) { /*copy other things too */
2866 #ifndef AFS_PTHREAD_ENV
2867 IOMGR_Poll(); /*make sure that the client doesnot time out */
2869 ttc = NewTrans(volumeId, partId);
2873 #ifdef AFS_NAMEI_ENV
2874 ret = namei_ConvertROtoRWvolume(pname, volumeId);
2876 ret = inode_ConvertROtoRWvolume(pname, volumeId);
2880 GetNextVol(dirp, volname, &volid);
2884 DeleteTrans(ttc, 1);
2885 ttc = (struct volser_trans *)0;
2894 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
2895 register struct volintSize *size)
2898 register struct volser_trans *tt;
2899 char caller[MAXKTCNAMELEN];
2901 if (!afsconf_SuperUser(tdir, acid, caller))
2902 return VOLSERBAD_ACCESS; /*not a super user */
2903 tt = FindTrans(fromTrans);
2906 if (tt->vflags & VTDeleted) {
2910 strcpy(tt->lastProcName, "GetSize");
2911 tt->rxCallPtr = acid;
2912 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
2913 tt->rxCallPtr = (struct rx_call *)0;
2915 return VOLSERTRELE_ERROR;
2917 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
2922 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
2923 afs_uint32 where, afs_int32 verbose)
2925 afs_int32 code, code2;
2926 Volume *vol=0, *newvol=0;
2927 struct volser_trans *tt = 0, *tt2 = 0;
2928 char caller[MAXKTCNAMELEN];
2931 if (!afsconf_SuperUser(tdir, acall, caller))
2934 vol = VAttachVolume(&code, vid, V_VOLUPD);
2940 newvol = VAttachVolume(&code, new, V_VOLUPD);
2942 VDetachVolume(&code2, vol);
2947 if (V_device(vol) != V_device(newvol)
2948 || V_uniquifier(newvol) != 2) {
2949 if (V_device(vol) != V_device(newvol)) {
2950 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
2952 rx_Write(acall, line, strlen(line));
2954 if (V_uniquifier(newvol) != 2) {
2955 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
2956 rx_Write(acall, line, strlen(line));
2959 rx_Write(acall, line, 1);
2960 VDetachVolume(&code2, vol);
2961 VDetachVolume(&code2, newvol);
2964 tt = NewTrans(vid, V_device(vol));
2966 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
2967 rx_Write(acall, line, strlen(line));
2969 rx_Write(acall, line, 1);
2970 VDetachVolume(&code2, vol);
2971 VDetachVolume(&code2, newvol);
2972 return VOLSERVOLBUSY;
2974 tt->iflags = ITBusy;
2976 strcpy(tt->lastProcName, "SplitVolume");
2978 tt2 = NewTrans(new, V_device(newvol));
2980 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
2981 rx_Write(acall, line, strlen(line));
2983 rx_Write(acall, line, 1);
2985 VDetachVolume(&code2, vol);
2986 VDetachVolume(&code2, newvol);
2987 return VOLSERVOLBUSY;
2989 tt2->iflags = ITBusy;
2991 strcpy(tt2->lastProcName, "SplitVolume");
2993 code = split_volume(acall, vol, newvol, where, verbose);
2995 VDetachVolume(&code2, vol);
2997 VDetachVolume(&code2, newvol);
2998 DeleteTrans(tt2, 1);
3002 /* GetPartName - map partid (a decimal number) into pname (a string)
3003 * Since for NT we actually want to return the drive name, we map through the
3007 GetPartName(afs_int32 partid, char *pname)
3012 strcpy(pname, "/vicep");
3013 pname[6] = 'a' + partid;
3016 } else if (partid < VOLMAXPARTS) {
3017 strcpy(pname, "/vicep");
3019 pname[6] = 'a' + (partid / 26);
3020 pname[7] = 'a' + (partid % 26);