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>
17 #include <sys/types.h>
26 #include <netinet/in.h>
35 #include <afs/afsint.h>
37 #ifdef AFS_PTHREAD_ENV
39 #else /* AFS_PTHREAD_ENV */
40 #include <afs/assert.h>
41 #endif /* AFS_PTHREAD_ENV */
42 #include <afs/prs_fs.h>
46 #include <afs/cellconfig.h>
49 #include <afs/ihandle.h>
51 #include <afs/ntops.h>
53 #include <afs/vnode.h>
54 #include <afs/volume.h>
55 #include <afs/volume_inline.h>
56 #include <afs/partition.h>
58 #include <afs/daemon_com.h>
59 #include <afs/fssync.h>
61 #include "afs/audit.h"
63 #include <afs/afsutil.h>
64 #include <afs/vol_prototypes.h>
65 #include <afs/errors.h>
68 #include "voltrans_inline.h"
71 #include "volser_internal.h"
73 #include "dumpstuff.h"
76 extern struct afsconf_dir *tdir;
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;
91 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
92 struct diskPartition64 *);
93 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
94 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
95 afs_int32, afs_uint32, afs_uint32 *,
97 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
98 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
99 afs_int32, char *, afs_uint32 *);
100 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
101 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
102 afs_int32, afs_int32 *);
103 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
105 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
106 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
107 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
108 struct destServer *destination, afs_int32,
109 struct restoreCookie *cookie);
110 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
111 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
112 struct restoreCookie *);
113 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
114 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
115 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
116 struct volser_status *);
117 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
118 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
119 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
120 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
121 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
123 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
125 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
127 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
129 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
130 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
131 afs_int32, afs_uint32, afs_uint32,
133 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
135 /* this call unlocks all of the partition locks we've set */
139 register struct DiskPartition64 *tp;
140 for (tp = DiskPartitionList; tp; tp = tp->next) {
141 if (tp->lock_fd != INVALID_FD) {
142 close(tp->lock_fd); /* releases flock held on this partition */
143 tp->lock_fd = INVALID_FD;
154 code = VPFullUnlock_r();
159 /* get partition id from a name */
161 PartitionID(char *aname)
164 register int code = 0;
169 return -1; /* unknown */
171 /* otherwise check for vicepa or /vicepa, or just plain "a" */
173 if (!strncmp(aname, "/vicep", 6)) {
174 strncpy(ascii, aname + 6, 2);
176 return -1; /* bad partition name */
177 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
178 * from 0. Do the appropriate conversion */
180 /* one char name, 0..25 */
181 if (ascii[0] < 'a' || ascii[0] > 'z')
182 return -1; /* wrongo */
183 return ascii[0] - 'a';
185 /* two char name, 26 .. <whatever> */
186 if (ascii[0] < 'a' || ascii[0] > 'z')
187 return -1; /* wrongo */
188 if (ascii[1] < 'a' || ascii[1] > 'z')
189 return -1; /* just as bad */
190 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
191 if (code > VOLMAXPARTS)
198 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
202 /* 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 */
203 (void)afs_snprintf(aname, asize, VFORMAT, (unsigned long)avol);
208 ConvertPartition(int apartno, char *aname, int asize)
214 strcpy(aname, "/vicep");
216 aname[6] = 'a' + apartno;
220 aname[6] = 'a' + (apartno / 26);
221 aname[7] = 'a' + (apartno % 26);
227 static struct Volume *
228 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
233 vp = VAttachVolumeByName(ec, partition, name, mode);
235 #ifdef AFS_DEMAND_ATTACH_FS
239 * The fileserver will take care of keeping track of how many
240 * demand-salvages have been performed, and will force the volume to
241 * ERROR if we've done too many. The limit on This loop is just a
242 * failsafe to prevent trying to salvage forever. We want to attempt
243 * attachment at least SALVAGE_COUNT_MAX times, since we want to
244 * avoid prematurely exiting this loop, if we can.
246 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
247 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
248 vp = VAttachVolumeByName(ec, partition, name, mode);
251 if (*ec == VSALVAGING) {
255 #endif /* AFS_DEMAND_ATTACH_FS */
260 static struct Volume *
261 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
266 vp = VAttachVolume(ec, avolid, amode);
268 #ifdef AFS_DEMAND_ATTACH_FS
271 /* see comment above in VAttachVolumeByName_retry */
272 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
273 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
274 vp = VAttachVolume(ec, avolid, amode);
277 if (*ec == VSALVAGING) {
281 #endif /* AFS_DEMAND_ATTACH_FS */
286 /* the only attach function that takes a partition is "...ByName", so we use it */
287 static struct Volume *
288 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
290 char pbuf[30], vbuf[20];
292 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
296 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
301 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
304 /* Adapted from the file server; create a root directory for this volume */
306 ViceCreateRoot(Volume *vp)
309 struct acl_accessList *ACL;
311 Inode inodeNumber, nearInode;
312 struct VnodeDiskObject *vnode;
313 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
320 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
323 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
325 V_pref(vp, nearInode);
327 IH_CREATE(V_linkHandle(vp), V_device(vp),
328 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
330 assert(VALID_INO(inodeNumber));
332 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
333 did.Volume = V_id(vp);
334 did.Vnode = (VnodeId) 1;
337 assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
338 DFlush(); /* flush all modified dir buffers out */
339 DZap((afs_int32 *)&dir); /* Remove all buffers for this dir */
340 length = Length(&dir); /* Remember size of this directory */
342 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
344 /* build a single entry ACL that gives all rights to system:administrators */
345 /* this section of code assumes that access list format is not going to
348 ACL = VVnodeDiskACL(vnode);
349 ACL->size = sizeof(struct acl_accessList);
350 ACL->version = ACL_ACLVERSION;
354 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
355 ACL->entries[0].rights =
356 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
357 | PRSFS_LOCK | PRSFS_ADMINISTER;
359 vnode->type = vDirectory;
361 vnode->modeBits = 0777;
362 vnode->linkCount = 2;
363 VNDISK_SET_LEN(vnode, length);
364 vnode->uniquifier = 1;
365 V_uniquifier(vp) = vnode->uniquifier + 1;
366 vnode->dataVersion = 1;
367 VNDISK_SET_INO(vnode, inodeNumber);
368 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
372 vnode->vnodeMagic = vcp->magic;
374 IH_INIT(h, vp->device, V_parentId(vp),
375 vp->vnodeIndex[vLarge].handle->ih_ino);
378 off = FDH_SEEK(fdP, vnodeIndexOffset(vcp, 1), SEEK_SET);
380 nBytes = FDH_WRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE);
381 assert(nBytes == SIZEOF_LARGEDISKVNODE);
382 FDH_REALLYCLOSE(fdP);
384 VNDISK_GET_LEN(length, vnode);
385 V_diskused(vp) = nBlocks(length);
392 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
396 struct diskPartition64 *dp = (struct diskPartition64 *)
397 malloc(sizeof(struct diskPartition64));
399 code = VolPartitionInfo(acid, pname, dp);
401 strncpy(partition->name, dp->name, 32);
402 strncpy(partition->devName, dp->devName, 32);
403 partition->lock_fd = dp->lock_fd;
404 partition->free=RoundInt64ToInt32(dp->free);
405 partition->minFree=RoundInt64ToInt32(dp->minFree);
408 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
413 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
418 code = VolPartitionInfo(acid, pname, partition);
419 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
424 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
427 register struct DiskPartition64 *dp;
430 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
433 dp = VGetPartition(pname, 0);
435 strncpy(partition->name, dp->name, 32);
436 strncpy(partition->devName, dp->devName, 32);
437 partition->lock_fd = (int)dp->lock_fd;
438 partition->free = dp->free;
439 partition->minFree = dp->totalUsable;
442 return VOLSERILLEGAL_PARTITION;
445 /* obliterate a volume completely, and slowly. */
447 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
451 code = VolNukeVolume(acid, apartID, avolID);
452 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
457 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
462 register afs_int32 code;
464 char caller[MAXKTCNAMELEN];
466 /* check for access */
467 if (!afsconf_SuperUser(tdir, acid, caller))
468 return VOLSERBAD_ACCESS;
470 Log("%s is executing VolNukeVolume %u\n", caller, avolID);
472 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
474 /* we first try to attach the volume in update mode, so that the file
475 * server doesn't try to use it (and abort) while (or after) we delete it.
476 * If we don't get the volume, that's fine, too. We just won't put it back.
478 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
479 code = nuke(partName, avolID);
481 VDetachVolume(&verror, tvp);
485 /* create a new volume, with name aname, on the specified partition (1..n)
486 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
487 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
488 * for the volume id (useful for things like volume restore).
489 * Return the new volume id in *avolid.
492 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
493 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
499 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
500 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
501 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
507 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
508 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
513 Error junk; /* discardable error code */
515 afs_int32 doCreateRoot = 1;
516 register struct volser_trans *tt;
518 char caller[MAXKTCNAMELEN];
520 if (strlen(aname) > 31)
521 return VOLSERBADNAME;
522 if (!afsconf_SuperUser(tdir, acid, caller))
523 return VOLSERBAD_ACCESS;
525 Log("%s is executing CreateVolume '%s'\n", caller, aname);
526 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
527 return error; /*a standard unix error */
528 if (atype != readwriteVolume && atype != readonlyVolume
529 && atype != backupVolume)
531 if ((volumeID = *avolid) == 0) {
533 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
537 if ((aparent == volumeID) && (atype == readwriteVolume)) {
542 tt = NewTrans(volumeID, apart);
544 Log("1 createvolume: failed to create trans\n");
545 return VOLSERVOLBUSY; /* volume already busy! */
547 vp = VCreateVolume(&error, ppath, volumeID, aparent);
549 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
554 V_uniquifier(vp) = 1;
555 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
556 V_inService(vp) = V_blessed(vp) = 1;
558 AssignVolumeName(&V_disk(vp), aname, 0);
561 V_destroyMe(vp) = DESTROY_ME;
563 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
564 VUpdateVolume(&error, vp);
566 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
569 VDetachVolume(&junk, vp); /* rather return the real error code */
575 TSetRxCall_r(tt, acid, "CreateVolume");
576 VTRANS_OBJ_UNLOCK(tt);
577 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
580 return VOLSERTRELE_ERROR;
584 /* delete the volume associated with this transaction */
586 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
590 code = VolDeleteVolume(acid, atrans);
591 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
596 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
598 register struct volser_trans *tt;
600 char caller[MAXKTCNAMELEN];
602 if (!afsconf_SuperUser(tdir, acid, caller))
603 return VOLSERBAD_ACCESS;
604 tt = FindTrans(atrans);
607 if (tt->vflags & VTDeleted) {
608 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
613 Log("%s is executing Delete Volume %u\n", caller, tt->volid);
614 TSetRxCall(tt, acid, "DeleteVolume");
615 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
616 V_destroyMe(tt->volume) = DESTROY_ME; /* so endtrans does the right fssync opcode */
618 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
620 VTRANS_OBJ_UNLOCK(tt);
622 return VOLSERTRELE_ERROR;
624 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
625 return 0; /* vpurgevolume doesn't set an error code */
628 /* make a clone of the volume associated with atrans, possibly giving it a new
629 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
630 * for the clone's id). The new clone is given the name newName. Finally,
631 * due to efficiency considerations, if purgeId is non-zero, we purge that
632 * volume when doing the clone operation. This may be useful when making
633 * new backup volumes, for instance since the net result of a clone and a
634 * purge generally leaves many inode ref counts the same, while doing them
635 * separately would result in far more iincs and idecs being peformed
636 * (and they are slow operations).
638 /* for efficiency reasons, sometimes faster to piggyback a purge here */
640 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
641 afs_int32 newType, char *newName, afs_uint32 *newNumber)
645 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
646 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
647 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
653 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
654 afs_int32 newType, char *newName, afs_uint32 *newNumber)
657 register struct Volume *originalvp, *purgevp, *newvp;
659 register struct volser_trans *tt, *ttc;
660 char caller[MAXKTCNAMELEN];
662 if (strlen(newName) > 31)
663 return VOLSERBADNAME;
664 if (!afsconf_SuperUser(tdir, acid, caller))
665 return VOLSERBAD_ACCESS; /*not a super user */
667 Log("%s is executing Clone Volume new name=%s\n", caller, newName);
669 originalvp = (Volume *) 0;
670 purgevp = (Volume *) 0;
671 newvp = (Volume *) 0;
672 tt = ttc = (struct volser_trans *)0;
674 if (!newNumber || !*newNumber) {
675 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
680 if (newType != readonlyVolume && newType != backupVolume)
682 tt = FindTrans(atrans);
685 if (tt->vflags & VTDeleted) {
686 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
690 ttc = NewTrans(newId, tt->partition);
691 if (!ttc) { /* someone is messing with the clone already */
693 return VOLSERVOLBUSY;
695 TSetRxCall(tt, acid, "Clone");
699 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
701 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
707 originalvp = tt->volume;
708 if ((V_type(originalvp) == backupVolume)
709 || (V_type(originalvp) == readonlyVolume)) {
710 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
714 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
715 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
721 if (originalvp->device != purgevp->device) {
722 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
726 if (V_type(purgevp) != readonlyVolume) {
727 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
731 if (V_type(originalvp) == readonlyVolume
732 && V_parentId(originalvp) != V_parentId(purgevp)) {
733 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
737 if (V_type(originalvp) == readwriteVolume
738 && tt->volid != V_parentId(purgevp)) {
739 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
748 VCreateVolume(&error, originalvp->partition->name, newId,
749 V_parentId(originalvp));
751 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
752 newvp = (Volume *) 0;
755 if (newType == readonlyVolume)
756 V_cloneId(originalvp) = newId;
757 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
760 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
761 CloneVolume(&error, originalvp, newvp, purgevp);
762 purgevp = NULL; /* clone releases it, maybe even if error */
764 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
768 if (newType == readonlyVolume) {
769 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
770 V_type(newvp) = readonlyVolume;
771 } else if (newType == backupVolume) {
772 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
773 V_type(newvp) = backupVolume;
774 V_backupId(originalvp) = newId;
776 strcpy(newvp->header->diskstuff.name, newName);
777 V_creationDate(newvp) = V_copyDate(newvp);
778 ClearVolumeStats(&V_disk(newvp));
779 V_destroyMe(newvp) = DESTROY_ME;
780 V_inService(newvp) = 0;
781 if (newType == backupVolume) {
782 V_backupDate(originalvp) = V_copyDate(newvp);
783 V_backupDate(newvp) = V_copyDate(newvp);
786 VUpdateVolume(&error, newvp);
788 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
792 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
794 VUpdateVolume(&error, originalvp);
796 Log("1 Volser: Clone: original update %u\n", error);
802 tt = (struct volser_trans *)0;
803 error = VOLSERTRELE_ERROR;
811 VDetachVolume(&code, purgevp);
813 VDetachVolume(&code, newvp);
823 /* reclone this volume into the specified id */
825 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
829 code = VolReClone(acid, atrans, cloneId);
830 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
836 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
838 register struct Volume *originalvp, *clonevp;
841 register struct volser_trans *tt, *ttc;
842 char caller[MAXKTCNAMELEN];
844 /*not a super user */
845 if (!afsconf_SuperUser(tdir, acid, caller))
846 return VOLSERBAD_ACCESS;
848 Log("%s is executing Reclone Volume %u\n", caller, cloneId);
850 clonevp = originalvp = (Volume *) 0;
851 tt = (struct volser_trans *)0;
853 tt = FindTrans(atrans);
856 if (tt->vflags & VTDeleted) {
857 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
861 ttc = NewTrans(cloneId, tt->partition);
862 if (!ttc) { /* someone is messing with the clone already */
864 return VOLSERVOLBUSY;
866 TSetRxCall(tt, acid, "ReClone");
868 originalvp = tt->volume;
869 if ((V_type(originalvp) == backupVolume)
870 || (V_type(originalvp) == readonlyVolume)) {
871 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
875 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
876 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
882 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
884 Log("1 Volser: can't attach clone %d\n", cloneId);
888 newType = V_type(clonevp); /* type of the new volume */
890 if (originalvp->device != clonevp->device) {
891 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
896 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
897 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
901 if (V_type(originalvp) == readonlyVolume
902 && V_parentId(originalvp) != V_parentId(clonevp)) {
903 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
907 if (V_type(originalvp) == readwriteVolume
908 && tt->volid != V_parentId(clonevp)) {
909 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
915 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
917 CloneVolume(&error, originalvp, clonevp, clonevp);
919 Log("1 Volser: Clone: reclone operation failed with code %d\n",
925 /* fix up volume name and type, CloneVolume just propagated RW's */
926 if (newType == readonlyVolume) {
927 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
928 V_type(clonevp) = readonlyVolume;
929 } else if (newType == backupVolume) {
930 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
931 V_type(clonevp) = backupVolume;
932 V_backupId(originalvp) = cloneId;
934 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
936 /* pretend recloned volume is a totally new instance */
937 V_copyDate(clonevp) = time(0);
938 V_creationDate(clonevp) = V_copyDate(clonevp);
939 ClearVolumeStats(&V_disk(clonevp));
940 V_destroyMe(clonevp) = 0;
941 V_inService(clonevp) = 0;
942 if (newType == backupVolume) {
943 V_backupDate(originalvp) = V_copyDate(clonevp);
944 V_backupDate(clonevp) = V_copyDate(clonevp);
946 V_inUse(clonevp) = 0;
947 VUpdateVolume(&error, clonevp);
949 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
953 /* VUpdateVolume succeeded. Mark it in service so there's no window
954 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
955 * specialStatus; this is a reclone and this volume started online
957 V_inService(clonevp) = 1;
958 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
960 VUpdateVolume(&error, originalvp);
962 Log("1 Volser: Clone: original update %u\n", error);
968 tt = (struct volser_trans *)0;
969 error = VOLSERTRELE_ERROR;
976 struct DiskPartition64 *tpartp = originalvp->partition;
977 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
983 VDetachVolume(&code, clonevp);
993 /* create a new transaction, associated with volume and partition. Type of
994 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
995 * See volser.h for definition of iflags (the constants are named IT*).
998 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
999 afs_int32 iflags, afs_int32 *ttid)
1003 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1004 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1010 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1011 afs_int32 iflags, afs_int32 *ttid)
1013 register struct volser_trans *tt;
1014 register Volume *tv;
1018 char caller[MAXKTCNAMELEN];
1020 if (!afsconf_SuperUser(tdir, acid, caller))
1021 return VOLSERBAD_ACCESS; /*not a super user */
1022 if (iflags & ITCreate)
1024 else if (iflags & ITBusy)
1026 else if (iflags & ITReadOnly)
1028 else if (iflags & ITOffline)
1031 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1036 tt = NewTrans(volume, partition);
1038 /* can't create a transaction? put the volume back */
1039 Log("1 transcreate: can't create transaction\n");
1040 return VOLSERVOLBUSY;
1042 tv = XAttachVolume(&error, volume, partition, mode);
1046 VDetachVolume(&code, tv);
1050 VTRANS_OBJ_LOCK(tt);
1053 tt->iflags = iflags;
1055 TSetRxCall_r(tt, NULL, "TransCreate");
1056 VTRANS_OBJ_UNLOCK(tt);
1058 return VOLSERTRELE_ERROR;
1063 /* using aindex as a 0-based index, return the aindex'th volume on this server
1064 * Both the volume number and partition number (one-based) are returned.
1067 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1072 code = VolGetNthVolume(acid, aindex, avolume, apart);
1073 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1078 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1081 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1085 /* return the volume flags (VT* constants in volser.h) associated with this
1089 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1093 code = VolGetFlags(acid, atid, aflags);
1094 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1099 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1101 register struct volser_trans *tt;
1103 tt = FindTrans(atid);
1106 if (tt->vflags & VTDeleted) {
1107 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1112 TSetRxCall(tt, acid, "GetFlags");
1113 *aflags = tt->vflags;
1116 return VOLSERTRELE_ERROR;
1121 /* Change the volume flags (VT* constants in volser.h) associated with this
1122 * transaction. Effects take place immediately on volume, although volume
1123 * remains attached as usual by the transaction.
1126 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1130 code = VolSetFlags(acid, atid, aflags);
1131 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1137 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1139 register struct volser_trans *tt;
1140 register struct Volume *vp;
1142 char caller[MAXKTCNAMELEN];
1144 if (!afsconf_SuperUser(tdir, acid, caller))
1145 return VOLSERBAD_ACCESS; /*not a super user */
1146 /* find the trans */
1147 tt = FindTrans(atid);
1150 if (tt->vflags & VTDeleted) {
1151 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1156 TSetRxCall(tt, acid, "SetFlags");
1157 vp = tt->volume; /* pull volume out of transaction */
1159 /* check if we're allowed to make any updates */
1160 if (tt->iflags & ITReadOnly) {
1165 /* handle delete-on-salvage flag */
1166 if (aflags & VTDeleteOnSalvage) {
1167 V_destroyMe(tt->volume) = DESTROY_ME;
1169 V_destroyMe(tt->volume) = 0;
1172 if (aflags & VTOutOfService) {
1173 V_inService(vp) = 0;
1175 V_inService(vp) = 1;
1177 VUpdateVolume(&error, vp);
1178 VTRANS_OBJ_LOCK(tt);
1179 tt->vflags = aflags;
1181 VTRANS_OBJ_UNLOCK(tt);
1182 if (TRELE(tt) && !error)
1183 return VOLSERTRELE_ERROR;
1188 /* dumpS the volume associated with a particular transaction from a particular
1189 * date. Send the dump to a different transaction (destTrans) on the server
1190 * specified by the destServer structure.
1193 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1194 struct destServer *destination, afs_int32 destTrans,
1195 struct restoreCookie *cookie)
1200 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1201 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1202 destination->destHost, AUD_LONG, destTrans, AUD_END);
1207 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1208 struct destServer *destination, afs_int32 destTrans,
1209 struct restoreCookie *cookie)
1211 register struct volser_trans *tt;
1212 register afs_int32 code;
1213 register struct rx_connection *tcon;
1214 struct rx_call *tcall;
1215 register struct Volume *vp;
1216 struct rx_securityClass *securityObject;
1217 afs_int32 securityIndex;
1218 char caller[MAXKTCNAMELEN];
1220 if (!afsconf_SuperUser(tdir, acid, caller))
1221 return VOLSERBAD_ACCESS; /*not a super user */
1222 /* initialize things */
1223 tcon = (struct rx_connection *)0;
1224 tt = (struct volser_trans *)0;
1226 /* find the local transaction */
1227 tt = FindTrans(fromTrans);
1230 if (tt->vflags & VTDeleted) {
1231 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1236 TSetRxCall(tt, NULL, "Forward");
1238 /* get auth info for the this connection (uses afs from ticket file) */
1239 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1245 /* make an rpc connection to the other server */
1247 rx_NewConnection(htonl(destination->destHost),
1248 htons(destination->destPort), VOLSERVICE_ID,
1249 securityObject, securityIndex);
1255 tcall = rx_NewCall(tcon);
1256 TSetRxCall(tt, tcall, "Forward");
1257 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1258 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1263 /* these next calls implictly call rx_Write when writing out data */
1264 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1267 EndAFSVolRestore(tcall); /* probably doesn't do much */
1269 code = rx_EndCall(tcall, 0);
1270 rx_DestroyConnection(tcon); /* done with the connection */
1275 return VOLSERTRELE_ERROR;
1281 (void)rx_EndCall(tcall, 0);
1282 rx_DestroyConnection(tcon);
1291 /* Start a dump and send it to multiple places simultaneously.
1292 * If this returns an error (eg, return ENOENT), it means that
1293 * none of the releases worked. If this returns 0, that means
1294 * that one or more of the releases worked, and the caller has
1295 * to examine the results array to see which one(s).
1296 * This will only do EITHER incremental or full, not both, so it's
1297 * the caller's responsibility to be sure that all the destinations
1298 * need just an incremental (and from the same time), if that's
1302 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1303 fromDate, manyDests *destinations, afs_int32 spare,
1304 struct restoreCookie *cookie, manyResults *results)
1306 afs_int32 securityIndex;
1307 struct rx_securityClass *securityObject;
1308 char caller[MAXKTCNAMELEN];
1309 struct volser_trans *tt;
1310 afs_int32 ec, code, *codes;
1311 struct rx_connection **tcons;
1312 struct rx_call **tcalls;
1314 int i, is_incremental;
1317 memset(results, 0, sizeof(manyResults));
1318 i = results->manyResults_len = destinations->manyDests_len;
1319 results->manyResults_val = codes =
1320 (afs_int32 *) malloc(i * sizeof(afs_int32));
1322 if (!results || !results->manyResults_val)
1325 if (!afsconf_SuperUser(tdir, acid, caller))
1326 return VOLSERBAD_ACCESS; /*not a super user */
1327 tt = FindTrans(fromTrans);
1330 if (tt->vflags & VTDeleted) {
1331 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1336 TSetRxCall(tt, NULL, "ForwardMulti");
1338 /* (fromDate == 0) ==> full dump */
1339 is_incremental = (fromDate ? 1 : 0);
1342 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1346 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1352 /* get auth info for this connection (uses afs from ticket file) */
1353 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1355 goto fail; /* in order to audit each failure */
1358 /* make connections to all the other servers */
1359 for (i = 0; i < destinations->manyDests_len; i++) {
1360 struct replica *dest = &(destinations->manyDests_val[i]);
1362 rx_NewConnection(htonl(dest->server.destHost),
1363 htons(dest->server.destPort), VOLSERVICE_ID,
1364 securityObject, securityIndex);
1366 codes[i] = ENOTCONN;
1368 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1369 codes[i] = ENOTCONN;
1372 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1375 (void)rx_EndCall(tcalls[i], 0);
1377 rx_DestroyConnection(tcons[i]);
1384 /* these next calls implictly call rx_Write when writing out data */
1385 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1389 for (i--; i >= 0; i--) {
1390 struct replica *dest = &(destinations->manyDests_val[i]);
1392 if (!code && tcalls[i] && !codes[i]) {
1393 EndAFSVolRestore(tcalls[i]);
1396 ec = rx_EndCall(tcalls[i], 0);
1401 rx_DestroyConnection(tcons[i]); /* done with the connection */
1404 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1405 fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG,
1406 dest->trans, AUD_END);
1413 if (TRELE(tt) && !code) /* return the first code if it's set */
1414 return VOLSERTRELE_ERROR;
1421 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1425 code = VolDump(acid, fromTrans, fromDate, 0);
1426 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1431 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1436 code = VolDump(acid, fromTrans, fromDate, flags);
1437 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1442 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1446 register struct volser_trans *tt;
1447 char caller[MAXKTCNAMELEN];
1449 if (!afsconf_SuperUser(tdir, acid, caller))
1450 return VOLSERBAD_ACCESS; /*not a super user */
1451 tt = FindTrans(fromTrans);
1454 if (tt->vflags & VTDeleted) {
1455 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1459 TSetRxCall(tt, acid, "Dump");
1460 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1461 ? 0 : 1); /* squirt out the volume's data, too */
1470 return VOLSERTRELE_ERROR;
1476 * Ha! No more helper process!
1479 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1480 struct restoreCookie *cookie)
1484 code = VolRestore(acid, atrans, aflags, cookie);
1485 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1490 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1491 struct restoreCookie *cookie)
1493 register struct volser_trans *tt;
1494 register afs_int32 code, tcode;
1495 char caller[MAXKTCNAMELEN];
1497 if (!afsconf_SuperUser(tdir, acid, caller))
1498 return VOLSERBAD_ACCESS; /*not a super user */
1499 tt = FindTrans(atrans);
1502 if (tt->vflags & VTDeleted) {
1503 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1507 TSetRxCall(tt, acid, "Restore");
1509 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1511 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1512 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1516 return (code ? code : tcode);
1519 /* end a transaction, returning the transaction's final error code in rcode */
1521 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1525 code = VolEndTrans(acid, destTrans, rcode);
1526 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1531 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1533 register struct volser_trans *tt;
1534 char caller[MAXKTCNAMELEN];
1536 if (!afsconf_SuperUser(tdir, acid, caller))
1537 return VOLSERBAD_ACCESS; /*not a super user */
1538 tt = FindTrans(destTrans);
1542 *rcode = tt->returnCode;
1543 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1549 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1553 code = VolSetForwarding(acid, atid, anewsite);
1554 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1560 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1562 register struct volser_trans *tt;
1563 char caller[MAXKTCNAMELEN];
1566 if (!afsconf_SuperUser(tdir, acid, caller))
1567 return VOLSERBAD_ACCESS; /*not a super user */
1568 tt = FindTrans(atid);
1571 if (tt->vflags & VTDeleted) {
1572 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1577 TSetRxCall(tt, acid, "SetForwarding");
1578 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1581 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1584 return VOLSERTRELE_ERROR;
1590 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1591 register struct volser_status *astatus)
1595 code = VolGetStatus(acid, atrans, astatus);
1596 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1601 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1602 register struct volser_status *astatus)
1604 register struct Volume *tv;
1605 register struct VolumeDiskData *td;
1606 struct volser_trans *tt;
1609 tt = FindTrans(atrans);
1612 if (tt->vflags & VTDeleted) {
1613 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1618 TSetRxCall(tt, acid, "GetStatus");
1626 td = &tv->header->diskstuff;
1627 astatus->volID = td->id;
1628 astatus->nextUnique = td->uniquifier;
1629 astatus->type = td->type;
1630 astatus->parentID = td->parentId;
1631 astatus->cloneID = td->cloneId;
1632 astatus->backupID = td->backupId;
1633 astatus->restoredFromID = td->restoredFromId;
1634 astatus->maxQuota = td->maxquota;
1635 astatus->minQuota = td->minquota;
1636 astatus->owner = td->owner;
1637 astatus->creationDate = td->creationDate;
1638 astatus->accessDate = td->accessDate;
1639 astatus->updateDate = td->updateDate;
1640 astatus->expirationDate = td->expirationDate;
1641 astatus->backupDate = td->backupDate;
1642 astatus->copyDate = td->copyDate;
1645 return VOLSERTRELE_ERROR;
1651 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1652 register struct volintInfo *astatus)
1656 code = VolSetInfo(acid, atrans, astatus);
1657 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1662 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1663 register struct volintInfo *astatus)
1665 register struct Volume *tv;
1666 register struct VolumeDiskData *td;
1667 struct volser_trans *tt;
1668 char caller[MAXKTCNAMELEN];
1671 if (!afsconf_SuperUser(tdir, acid, caller))
1672 return VOLSERBAD_ACCESS; /*not a super user */
1673 tt = FindTrans(atrans);
1676 if (tt->vflags & VTDeleted) {
1677 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1681 TSetRxCall(tt, acid, "SetStatus");
1689 td = &tv->header->diskstuff;
1691 * Add more fields as necessary
1693 if (astatus->maxquota != -1)
1694 td->maxquota = astatus->maxquota;
1695 if (astatus->dayUse != -1)
1696 td->dayUse = astatus->dayUse;
1697 if (astatus->creationDate != -1)
1698 td->creationDate = astatus->creationDate;
1699 if (astatus->updateDate != -1)
1700 td->updateDate = astatus->updateDate;
1701 if (astatus->spare2 != -1)
1702 td->volUpdateCounter = (unsigned int)astatus->spare2;
1703 VUpdateVolume(&error, tv);
1706 return VOLSERTRELE_ERROR;
1712 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1716 code = VolGetName(acid, atrans, aname);
1717 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1722 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1724 register struct Volume *tv;
1725 register struct VolumeDiskData *td;
1726 struct volser_trans *tt;
1729 /* We need to at least fill it in */
1730 *aname = (char *)malloc(1);
1733 tt = FindTrans(atrans);
1736 if (tt->vflags & VTDeleted) {
1737 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1741 TSetRxCall(tt, acid, "GetName");
1749 td = &tv->header->diskstuff;
1750 len = strlen(td->name) + 1; /* don't forget the null */
1756 *aname = (char *)realloc(*aname, len);
1757 strcpy(*aname, td->name);
1760 return VOLSERTRELE_ERROR;
1765 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1768 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1769 afs_uint32 parentId, afs_uint32 cloneId)
1775 /*return a list of all partitions on the server. The non mounted
1776 *partitions are returned as -1 in the corresponding slot in partIds*/
1778 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1782 code = VolListPartitions(acid, partIds);
1783 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1788 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1793 strcpy(namehead, "/vicep"); /*7 including null terminator */
1795 /* Just return attached partitions. */
1797 for (i = 0; i < 26; i++) {
1798 namehead[6] = i + 'a';
1799 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1805 /*return a list of all partitions on the server. The non mounted
1806 *partitions are returned as -1 in the corresponding slot in partIds*/
1808 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1812 code = XVolListPartitions(acid, pEntries);
1813 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1818 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1821 struct partList partList;
1822 struct DiskPartition64 *dp;
1825 strcpy(namehead, "/vicep"); /*7 including null terminator */
1827 /* Only report attached partitions */
1828 for (i = 0; i < VOLMAXPARTS; i++) {
1829 #ifdef AFS_DEMAND_ATTACH_FS
1830 dp = VGetPartitionById(i, 0);
1833 namehead[6] = i + 'a';
1839 namehead[6] = 'a' + (k / 26);
1840 namehead[7] = 'a' + (k % 26);
1843 dp = VGetPartition(namehead, 0);
1846 partList.partId[j++] = i;
1848 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1849 if (!pEntries->partEntries_val)
1851 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1853 pEntries->partEntries_len = j;
1858 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1860 ExtractVolId(char vname[])
1863 char name[VOLSER_MAXVOLNAME + 1];
1865 strcpy(name, vname);
1867 while (name[i] == 'V' || name[i] == '0')
1870 name[11] = '\0'; /* smash the "." */
1871 return (atol(&name[i]));
1874 /*return the name of the next volume header in the directory associated with dirp and dp.
1875 *the volume id is returned in volid, and volume header name is returned in volname*/
1877 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1881 dp = readdir(dirp); /*read next entry in the directory */
1883 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1884 *volid = ExtractVolId(dp->d_name);
1885 strcpy(volname, dp->d_name);
1886 return 0; /*return the name of the file representing a volume */
1888 strcpy(volname, "");
1889 return 0; /*volname doesnot represent a volume */
1892 strcpy(volname, "EOD");
1893 return 0; /*end of directory */
1899 * volint vol info structure type.
1902 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1903 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1904 } volint_info_type_t;
1907 * handle to various on-wire vol info types.
1910 volint_info_type_t volinfo_type;
1916 } volint_info_handle_t;
1919 * store value to a field at the appropriate location in on-wire structure.
1921 #define VOLINT_INFO_STORE(handle, name, val) \
1923 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1924 (handle)->volinfo_ptr.base->name = (val); \
1926 (handle)->volinfo_ptr.ext->name = (val); \
1931 * get pointer to appropriate offset of field in on-wire structure.
1933 #define VOLINT_INFO_PTR(handle, name) \
1934 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1935 &((handle)->volinfo_ptr.base->name) : \
1936 &((handle)->volinfo_ptr.ext->name))
1939 * fill in appropriate type of on-wire volume metadata structure.
1941 * @param vp pointer to volume object
1942 * @param handle pointer to wire format handle object
1944 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1945 * @pre handle object must have a valid pointer and enumeration value
1947 * @note passing a NULL value for vp means that the fileserver doesn't
1948 * know about this particular volume, thus implying it is offline.
1950 * @return operation status
1955 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1957 unsigned int numStatBytes, now;
1958 register struct VolumeDiskData *hdr = &vp->header->diskstuff;
1960 /*read in the relevant info */
1961 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1962 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1963 VOLINT_INFO_STORE(handle, volid, hdr->id);
1964 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1965 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
1966 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
1967 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
1968 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
1969 VOLINT_INFO_STORE(handle, size, hdr->diskused);
1970 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
1971 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
1972 now = FT_ApproxTime();
1973 if ((now - hdr->dayUseDate) > OneDay) {
1974 VOLINT_INFO_STORE(handle, dayUse, 0);
1976 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
1978 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
1979 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
1980 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
1981 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
1983 #ifdef AFS_DEMAND_ATTACH_FS
1985 * for DAFS, we "lie" about volume state --
1986 * instead of returning the raw state from the disk header,
1987 * we compute state based upon the fileserver's internal
1988 * in-core state enumeration value reported to us via fssync,
1989 * along with the blessed and inService flags from the header.
1990 * -- tkeiser 11/27/2007
1993 /* Conditions that offline status is based on:
1994 volume is unattached state
1995 volume state is in (one of several error states)
1996 volume not in service
1997 volume is not marked as blessed (not on hold)
1998 volume in salvage req. state
1999 volume needsSalvaged
2000 next op would set volume offline
2001 next op would not leave volume online (based on several conditions)
2004 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2005 VIsErrorState(V_attachState(vp)) ||
2008 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2009 hdr->needsSalvaged ||
2010 (vp->pending_vol_op &&
2011 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2012 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2015 VOLINT_INFO_STORE(handle, inUse, 0);
2017 VOLINT_INFO_STORE(handle, inUse, 1);
2020 /* offline status based on program type, where != fileServer enum (1) is offline */
2021 if (hdr->inUse == fileServer) {
2022 VOLINT_INFO_STORE(handle, inUse, 1);
2024 VOLINT_INFO_STORE(handle, inUse, 0);
2029 switch(handle->volinfo_type) {
2030 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2031 case VOLINT_INFO_TYPE_BASE:
2033 #ifdef AFS_DEMAND_ATTACH_FS
2034 /* see comment above where we set inUse bit */
2035 if (hdr->needsSalvaged ||
2036 (vp && VIsErrorState(V_attachState(vp)))) {
2037 handle->volinfo_ptr.base->needsSalvaged = 1;
2039 handle->volinfo_ptr.base->needsSalvaged = 0;
2042 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2044 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2045 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2046 handle->volinfo_ptr.base->spare1 =
2047 (long)hdr->weekUse[0] +
2048 (long)hdr->weekUse[1] +
2049 (long)hdr->weekUse[2] +
2050 (long)hdr->weekUse[3] +
2051 (long)hdr->weekUse[4] +
2052 (long)hdr->weekUse[5] +
2053 (long)hdr->weekUse[6];
2054 handle->volinfo_ptr.base->flags = 0;
2055 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2056 handle->volinfo_ptr.base->spare3 = 0;
2060 case VOLINT_INFO_TYPE_EXT:
2062 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2063 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2066 * Copy out the stat fields in a single operation.
2068 if ((now - hdr->dayUseDate) > OneDay) {
2069 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2072 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2073 (char *)&(hdr->stat_reads[0]),
2082 #ifdef AFS_DEMAND_ATTACH_FS
2085 * get struct Volume out of the fileserver.
2087 * @param[in] volumeId volumeId for which we want state information
2088 * @param[in] pname partition name string
2089 * @param[inout] vp pointer to pointer to Volume object which
2090 * will be populated (see note)
2092 * @return operation status
2094 * @retval non-zero failure
2096 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2101 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2106 res.hdr.response_len = sizeof(res.hdr);
2107 res.payload.buf = *vp;
2108 res.payload.len = sizeof(Volume);
2110 code = FSYNC_VolOp(volumeId,
2116 if (code != SYNC_OK) {
2117 switch (res.hdr.reason) {
2118 case FSYNC_WRONG_PART:
2119 case FSYNC_UNKNOWN_VOLID:
2132 * mode of volume list operation.
2135 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2136 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2137 } vol_info_list_mode_t;
2140 * abstract interface to populate wire-format volume metadata structures.
2142 * @param[in] partId partition id
2143 * @param[in] volumeId volume id
2144 * @param[in] pname partition name
2145 * @param[in] volname volume file name
2146 * @param[in] handle handle to on-wire volume metadata object
2147 * @param[in] mode listing mode
2149 * @return operation status
2151 * @retval -2 DESTROY_ME flag is set
2152 * @retval -1 general failure; some data filled in
2153 * @retval -3 couldn't create vtrans; some data filled in
2156 GetVolInfo(afs_uint32 partId,
2157 afs_uint32 volumeId,
2160 volint_info_handle_t * handle,
2161 vol_info_list_mode_t mode)
2165 struct volser_trans *ttc = NULL;
2166 struct Volume *fill_tv, *tv = NULL;
2167 #ifdef AFS_DEMAND_ATTACH_FS
2168 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2169 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2170 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2171 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2173 /* Set up response handle for pending_vol_op */
2174 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2175 fs_res.payload.buf = fs_res_buf;
2176 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2179 ttc = NewTrans(volumeId, partId);
2182 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2183 VOLINT_INFO_STORE(handle, volid, volumeId);
2187 /* Get volume from volserver */
2188 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2190 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2191 volumeId, pname, volname, error);
2196 * please note that destroyMe and needsSalvaged checks used to be ordered
2197 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2198 * more correct to check destroyMe before needsSalvaged.
2199 * -- tkeiser 11/28/2007
2202 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2204 case VOL_INFO_LIST_MULTIPLE:
2208 case VOL_INFO_LIST_SINGLE:
2209 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2210 volumeId, pname, volname);
2217 if (tv->header->diskstuff.needsSalvaged) {
2218 /*this volume will be salvaged */
2219 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2220 volumeId, pname, volname);
2223 #ifdef AFS_DEMAND_ATTACH_FS
2224 /* If using DAFS, get volume from fsserver */
2225 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2230 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2231 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2232 /* If we if the pending vol op */
2233 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2234 fs_tv->pending_vol_op=&pending_vol_op_res;
2236 fs_tv->pending_vol_op=NULL;
2239 /* populate the header from the volserver copy */
2240 fs_tv->header=tv->header;
2242 /* When using DAFS, use the fs volume info, populated with required structures */
2245 /* When not using DAFS, just use the local volume info */
2249 /* ok, we have all the data we need; fill in the on-wire struct */
2250 code = FillVolInfo(fill_tv, handle);
2254 VOLINT_INFO_STORE(handle, status, 0);
2255 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2256 VOLINT_INFO_STORE(handle, volid, volumeId);
2259 VDetachVolume(&error, tv);
2262 VOLINT_INFO_STORE(handle, status, 0);
2263 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2264 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2265 volumeId, pname, volname);
2269 DeleteTrans(ttc, 1);
2276 /*return the header information about the <volid> */
2278 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2279 afs_uint32 volumeId, volEntries *volumeInfo)
2283 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2284 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2289 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2290 afs_uint32 volumeId, volEntries *volumeInfo)
2293 struct DiskPartition64 *partP;
2294 char pname[9], volname[20];
2299 volint_info_handle_t handle;
2301 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2302 if (!volumeInfo->volEntries_val)
2304 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2306 pntr = volumeInfo->volEntries_val;
2307 volumeInfo->volEntries_len = 1;
2308 if (GetPartName(partid, pname))
2309 return VOLSERILLEGAL_PARTITION;
2310 if (!(partP = VGetPartition(pname, 0)))
2311 return VOLSERILLEGAL_PARTITION;
2312 dirp = opendir(VPartitionPath(partP));
2314 return VOLSERILLEGAL_PARTITION;
2316 strcpy(volname, "");
2318 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2320 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2321 GetNextVol(dirp, volname, &volid);
2322 continue; /*back to while loop */
2325 if (volid == volumeId) { /*copy other things too */
2330 GetNextVol(dirp, volname, &volid);
2334 #ifndef AFS_PTHREAD_ENV
2335 IOMGR_Poll(); /*make sure that the client does not time out */
2338 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2339 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2341 code = GetVolInfo(partid,
2346 VOL_INFO_LIST_SINGLE);
2350 return (found) ? 0 : ENODEV;
2353 /*------------------------------------------------------------------------
2354 * EXPORTED SAFSVolXListOneVolume
2357 * Returns extended info on volume a_volID on partition a_partID.
2360 * a_rxCidP : Pointer to the Rx call we're performing.
2361 * a_partID : Partition for which we want the extended list.
2362 * a_volID : Volume ID we wish to know about.
2363 * a_volumeXInfoP : Ptr to the extended info blob.
2366 * 0 Successful operation
2367 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2370 * Nothing interesting.
2374 *------------------------------------------------------------------------*/
2377 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2378 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2382 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2383 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2388 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2389 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2390 { /*SAFSVolXListOneVolume */
2392 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2393 struct DiskPartition64 *partP; /*Ptr to partition */
2394 char pname[9], volname[20]; /*Partition, volume names */
2395 DIR *dirp; /*Partition directory ptr */
2396 afs_uint32 currVolID; /*Current volume ID */
2397 int found = 0; /*Did we find the volume we need? */
2399 volint_info_handle_t handle;
2402 * Set up our pointers for action, marking our structure to hold exactly
2403 * one entry. Also, assume we'll fail in our quest.
2405 a_volumeXInfoP->volXEntries_val =
2406 (volintXInfo *) malloc(sizeof(volintXInfo));
2407 if (!a_volumeXInfoP->volXEntries_val)
2409 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2411 xInfoP = a_volumeXInfoP->volXEntries_val;
2412 a_volumeXInfoP->volXEntries_len = 1;
2416 * If the partition name we've been given is bad, bogue out.
2418 if (GetPartName(a_partID, pname))
2419 return (VOLSERILLEGAL_PARTITION);
2422 * Open the directory representing the given AFS parttion. If we can't
2425 if (!(partP = VGetPartition(pname, 0)))
2426 return VOLSERILLEGAL_PARTITION;
2427 dirp = opendir(VPartitionPath(partP));
2429 return (VOLSERILLEGAL_PARTITION);
2431 strcpy(volname, "");
2434 * Sweep through the partition directory, looking for the desired entry.
2435 * First, of course, figure out how many stat bytes to copy out of each
2438 while (strcmp(volname, "EOD") && !found) {
2440 * If this is not a volume, move on to the next entry in the
2441 * partition's directory.
2443 if (!strcmp(volname, "")) {
2444 GetNextVol(dirp, volname, &currVolID);
2448 if (currVolID == a_volID) {
2450 * We found the volume entry we're interested. Pull out the
2451 * extended information, remembering to poll (so that the client
2452 * doesn't time out) and to set up a transaction on the volume.
2456 } /*Found desired volume */
2458 GetNextVol(dirp, volname, &currVolID);
2462 #ifndef AFS_PTHREAD_ENV
2466 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2467 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2469 code = GetVolInfo(a_partID,
2474 VOL_INFO_LIST_SINGLE);
2479 * Clean up before going to dinner: close the partition directory,
2480 * return the proper value.
2483 return (found) ? 0 : ENODEV;
2484 } /*SAFSVolXListOneVolume */
2486 /*returns all the volumes on partition partid. If flags = 1 then all the
2487 * relevant info about the volumes is also returned */
2489 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2490 volEntries *volumeInfo)
2494 code = VolListVolumes(acid, partid, flags, volumeInfo);
2495 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2500 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2501 volEntries *volumeInfo)
2504 struct DiskPartition64 *partP;
2505 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2506 char pname[9], volname[20];
2510 volint_info_handle_t handle;
2512 volumeInfo->volEntries_val =
2513 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2514 if (!volumeInfo->volEntries_val)
2516 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2518 pntr = volumeInfo->volEntries_val;
2519 volumeInfo->volEntries_len = 0;
2520 if (GetPartName(partid, pname))
2521 return VOLSERILLEGAL_PARTITION;
2522 if (!(partP = VGetPartition(pname, 0)))
2523 return VOLSERILLEGAL_PARTITION;
2524 dirp = opendir(VPartitionPath(partP));
2526 return VOLSERILLEGAL_PARTITION;
2527 strcpy(volname, "");
2529 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2531 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2532 GetNextVol(dirp, volname, &volid);
2533 continue; /*back to while loop */
2536 if (flags) { /*copy other things too */
2537 #ifndef AFS_PTHREAD_ENV
2538 IOMGR_Poll(); /*make sure that the client does not time out */
2541 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2542 handle.volinfo_ptr.base = pntr;
2545 code = GetVolInfo(partid,
2550 VOL_INFO_LIST_MULTIPLE);
2551 if (code == -2) { /* DESTROY_ME flag set */
2555 pntr->volid = volid;
2556 /*just volids are needed */
2560 volumeInfo->volEntries_len += 1;
2561 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2562 /*running out of space, allocate more space */
2563 allocSize = (allocSize * 3) / 2;
2565 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2566 allocSize * sizeof(volintInfo));
2569 return VOLSERNO_MEMORY;
2571 volumeInfo->volEntries_val = pntr; /* point to new block */
2572 /* set pntr to the right position */
2573 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2578 GetNextVol(dirp, volname, &volid);
2586 /*------------------------------------------------------------------------
2587 * EXPORTED SAFSVolXListVolumes
2590 * Returns all the volumes on partition a_partID. If a_flags
2591 * is set to 1, then all the relevant extended volume information
2595 * a_rxCidP : Pointer to the Rx call we're performing.
2596 * a_partID : Partition for which we want the extended list.
2597 * a_flags : Various flags.
2598 * a_volumeXInfoP : Ptr to the extended info blob.
2601 * 0 Successful operation
2602 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2603 * VOLSERNO_MEMORY if we ran out of memory allocating
2607 * Nothing interesting.
2611 *------------------------------------------------------------------------*/
2614 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2615 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2619 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2620 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2625 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2626 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2627 { /*SAFSVolXListVolumes */
2629 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2630 struct DiskPartition64 *partP; /*Ptr to partition */
2631 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2632 char pname[9], volname[20]; /*Partition, volume names */
2633 DIR *dirp; /*Partition directory ptr */
2634 afs_uint32 volid; /*Current volume ID */
2636 volint_info_handle_t handle;
2639 * Allocate a large array of extended volume info structures, then
2640 * set it up for action.
2642 a_volumeXInfoP->volXEntries_val =
2643 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2644 if (!a_volumeXInfoP->volXEntries_val)
2646 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2648 xInfoP = a_volumeXInfoP->volXEntries_val;
2649 a_volumeXInfoP->volXEntries_len = 0;
2652 * If the partition name we've been given is bad, bogue out.
2654 if (GetPartName(a_partID, pname))
2655 return (VOLSERILLEGAL_PARTITION);
2658 * Open the directory representing the given AFS parttion. If we can't
2661 if (!(partP = VGetPartition(pname, 0)))
2662 return VOLSERILLEGAL_PARTITION;
2663 dirp = opendir(VPartitionPath(partP));
2665 return (VOLSERILLEGAL_PARTITION);
2666 strcpy(volname, "");
2669 * Sweep through the partition directory, acting on each entry. First,
2670 * of course, figure out how many stat bytes to copy out of each volume.
2672 while (strcmp(volname, "EOD")) {
2675 * If this is not a volume, move on to the next entry in the
2676 * partition's directory.
2678 if (!strcmp(volname, "")) {
2679 GetNextVol(dirp, volname, &volid);
2685 * Full info about the volume desired. Poll to make sure the
2686 * client doesn't time out, then start up a new transaction.
2688 #ifndef AFS_PTHREAD_ENV
2692 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2693 handle.volinfo_ptr.ext = xInfoP;
2695 code = GetVolInfo(a_partID,
2700 VOL_INFO_LIST_MULTIPLE);
2701 if (code == -2) { /* DESTROY_ME flag set */
2706 * Just volume IDs are needed.
2708 xInfoP->volid = volid;
2712 * Bump the pointer in the data area we're building, along with
2713 * the count of the number of entries it contains.
2716 (a_volumeXInfoP->volXEntries_len)++;
2717 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2719 * We're running out of space in the area we've built. Grow it.
2721 allocSize = (allocSize * 3) / 2;
2722 xInfoP = (volintXInfo *)
2723 realloc((char *)a_volumeXInfoP->volXEntries_val,
2724 (allocSize * sizeof(volintXInfo)));
2725 if (xInfoP == NULL) {
2727 * Bummer, no memory. Bag it, tell our caller what went wrong.
2730 return (VOLSERNO_MEMORY);
2734 * Memory reallocation worked. Correct our pointers so they
2735 * now point to the new block and the current open position within
2738 a_volumeXInfoP->volXEntries_val = xInfoP;
2740 a_volumeXInfoP->volXEntries_val +
2741 a_volumeXInfoP->volXEntries_len;
2745 GetNextVol(dirp, volname, &volid);
2746 } /*Sweep through the partition directory */
2749 * We've examined all entries in the partition directory. Close it,
2750 * delete our transaction (if any), and go home happy.
2755 } /*SAFSVolXListVolumes */
2757 /*this call is used to monitor the status of volser for debugging purposes.
2758 *information about all the active transactions is returned in transInfo*/
2760 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2764 code = VolMonitor(acid, transInfo);
2765 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2770 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2772 transDebugInfo *pntr;
2773 afs_int32 allocSize = 50;
2774 struct volser_trans *tt, *nt, *allTrans;
2776 transInfo->transDebugEntries_val =
2777 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2778 if (!transInfo->transDebugEntries_val)
2780 pntr = transInfo->transDebugEntries_val;
2781 transInfo->transDebugEntries_len = 0;
2784 allTrans = TransList();
2785 if (allTrans == (struct volser_trans *)0)
2786 goto done; /*no active transactions */
2787 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2789 VTRANS_OBJ_LOCK(tt);
2790 pntr->tid = tt->tid;
2791 pntr->time = tt->time;
2792 pntr->creationTime = tt->creationTime;
2793 pntr->returnCode = tt->returnCode;
2794 pntr->volid = tt->volid;
2795 pntr->partition = tt->partition;
2796 pntr->iflags = tt->iflags;
2797 pntr->vflags = tt->vflags;
2798 pntr->tflags = tt->tflags;
2799 strcpy(pntr->lastProcName, tt->lastProcName);
2800 pntr->callValid = 0;
2801 if (tt->rxCallPtr) { /*record call related info */
2802 pntr->callValid = 1;
2803 pntr->readNext = tt->rxCallPtr->rnext;
2804 pntr->transmitNext = tt->rxCallPtr->tnext;
2805 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2806 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2808 VTRANS_OBJ_UNLOCK(tt);
2810 transInfo->transDebugEntries_len += 1;
2811 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2812 allocSize = (allocSize * 3) / 2;
2814 (transDebugInfo *) realloc((char *)transInfo->
2815 transDebugEntries_val,
2817 sizeof(transDebugInfo));
2818 transInfo->transDebugEntries_val = pntr;
2820 transInfo->transDebugEntries_val +
2821 transInfo->transDebugEntries_len;
2822 /*set pntr to right position */
2833 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2834 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2835 afs_uint32 backupId)
2839 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2840 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2841 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2847 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2848 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2849 afs_uint32 backupId)
2853 register struct volser_trans *tt;
2854 char caller[MAXKTCNAMELEN];
2856 if (strlen(name) > 31)
2857 return VOLSERBADNAME;
2858 if (!afsconf_SuperUser(tdir, acid, caller))
2859 return VOLSERBAD_ACCESS; /*not a super user */
2860 /* find the trans */
2861 tt = FindTrans(atid);
2864 if (tt->vflags & VTDeleted) {
2865 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2869 TSetRxCall(tt, acid, "SetIdsTypes");
2873 V_backupId(tv) = backupId;
2874 V_cloneId(tv) = cloneId;
2875 V_parentId(tv) = pId;
2876 strcpy((&V_disk(tv))->name, name);
2877 VUpdateVolume(&error, tv);
2879 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2884 if (TRELE(tt) && !error)
2885 return VOLSERTRELE_ERROR;
2890 if (TRELE(tt) && !error)
2891 return VOLSERTRELE_ERROR;
2896 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2900 code = VolSetDate(acid, atid, cdate);
2901 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2907 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2911 register struct volser_trans *tt;
2912 char caller[MAXKTCNAMELEN];
2914 if (!afsconf_SuperUser(tdir, acid, caller))
2915 return VOLSERBAD_ACCESS; /*not a super user */
2916 /* find the trans */
2917 tt = FindTrans(atid);
2920 if (tt->vflags & VTDeleted) {
2921 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2925 TSetRxCall(tt, acid, "SetDate");
2928 V_creationDate(tv) = cdate;
2929 VUpdateVolume(&error, tv);
2931 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2936 if (TRELE(tt) && !error)
2937 return VOLSERTRELE_ERROR;
2942 if (TRELE(tt) && !error)
2943 return VOLSERTRELE_ERROR;
2948 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2949 afs_uint32 volumeId)
2954 char caller[MAXKTCNAMELEN];
2956 register struct volser_trans *ttc;
2957 char pname[16], volname[20];
2958 struct DiskPartition64 *partP;
2959 afs_int32 ret = ENODEV;
2962 if (!afsconf_SuperUser(tdir, acid, caller))
2963 return VOLSERBAD_ACCESS; /*not a super user */
2964 if (GetPartName(partId, pname))
2965 return VOLSERILLEGAL_PARTITION;
2966 if (!(partP = VGetPartition(pname, 0)))
2967 return VOLSERILLEGAL_PARTITION;
2968 dirp = opendir(VPartitionPath(partP));
2970 return VOLSERILLEGAL_PARTITION;
2971 strcpy(volname, "");
2972 ttc = (struct volser_trans *)0;
2974 while (strcmp(volname, "EOD")) {
2975 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2976 GetNextVol(dirp, volname, &volid);
2977 continue; /*back to while loop */
2980 if (volid == volumeId) { /*copy other things too */
2981 #ifndef AFS_PTHREAD_ENV
2982 IOMGR_Poll(); /*make sure that the client doesnot time out */
2984 ttc = NewTrans(volumeId, partId);
2986 return VOLSERVOLBUSY;
2988 #ifdef AFS_NAMEI_ENV
2989 ret = namei_ConvertROtoRWvolume(pname, volumeId);
2991 ret = inode_ConvertROtoRWvolume(pname, volumeId);
2995 GetNextVol(dirp, volname, &volid);
2999 DeleteTrans(ttc, 1);
3000 ttc = (struct volser_trans *)0;
3009 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3010 register struct volintSize *size)
3013 register struct volser_trans *tt;
3014 char caller[MAXKTCNAMELEN];
3016 if (!afsconf_SuperUser(tdir, acid, caller))
3017 return VOLSERBAD_ACCESS; /*not a super user */
3018 tt = FindTrans(fromTrans);
3021 if (tt->vflags & VTDeleted) {
3025 TSetRxCall(tt, acid, "GetSize");
3026 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3029 return VOLSERTRELE_ERROR;
3031 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3036 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3037 afs_uint32 where, afs_int32 verbose)
3039 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3041 Volume *vol=0, *newvol=0;
3042 struct volser_trans *tt = 0, *tt2 = 0;
3043 char caller[MAXKTCNAMELEN];
3046 if (!afsconf_SuperUser(tdir, acall, caller))
3049 vol = VAttachVolume(&code, vid, V_VOLUPD);
3055 newvol = VAttachVolume(&code, new, V_VOLUPD);
3057 VDetachVolume(&code2, vol);
3062 if (V_device(vol) != V_device(newvol)
3063 || V_uniquifier(newvol) != 2) {
3064 if (V_device(vol) != V_device(newvol)) {
3065 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3067 rx_Write(acall, line, strlen(line));
3069 if (V_uniquifier(newvol) != 2) {
3070 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3071 rx_Write(acall, line, strlen(line));
3074 rx_Write(acall, line, 1);
3075 VDetachVolume(&code2, vol);
3076 VDetachVolume(&code2, newvol);
3079 tt = NewTrans(vid, V_device(vol));
3081 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3082 rx_Write(acall, line, strlen(line));
3084 rx_Write(acall, line, 1);
3085 VDetachVolume(&code2, vol);
3086 VDetachVolume(&code2, newvol);
3087 return VOLSERVOLBUSY;
3089 VTRANS_OBJ_LOCK(tt);
3090 tt->iflags = ITBusy;
3092 TSetRxCall_r(tt, NULL, "SplitVolume");
3093 VTRANS_OBJ_UNLOCK(tt);
3095 tt2 = NewTrans(new, V_device(newvol));
3097 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3098 rx_Write(acall, line, strlen(line));
3100 rx_Write(acall, line, 1);
3102 VDetachVolume(&code2, vol);
3103 VDetachVolume(&code2, newvol);
3104 return VOLSERVOLBUSY;
3106 VTRANS_OBJ_LOCK(tt2);
3107 tt2->iflags = ITBusy;
3109 TSetRxCall_r(tt2, NULL, "SplitVolume");
3110 VTRANS_OBJ_UNLOCK(tt2);
3112 code = split_volume(acall, vol, newvol, where, verbose);
3114 VDetachVolume(&code2, vol);
3116 VDetachVolume(&code2, newvol);
3117 DeleteTrans(tt2, 1);
3124 /* GetPartName - map partid (a decimal number) into pname (a string)
3125 * Since for NT we actually want to return the drive name, we map through the
3129 GetPartName(afs_int32 partid, char *pname)
3134 strcpy(pname, "/vicep");
3135 pname[6] = 'a' + partid;
3138 } else if (partid < VOLMAXPARTS) {
3139 strcpy(pname, "/vicep");
3141 pname[6] = 'a' + (partid / 26);
3142 pname[7] = 'a' + (partid % 26);