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 #ifdef AFS_DEMAND_ATTACH_FS
228 /* normally we should use the regular salvaging functions from the volume
229 * package, but this is a special case where we have a volume ID, but no
230 * volume structure to give the volume package */
232 SalvageUnknownVolume(VolumeId volid, char *part)
236 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
237 afs_printable_uint32_lu(volid), part);
239 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
240 FSYNC_SALVAGE, NULL);
242 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
243 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
247 #endif /* AFS_DEMAND_ATTACH_FS */
249 static struct Volume *
250 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
255 vp = VAttachVolumeByName(ec, partition, name, mode);
257 #ifdef AFS_DEMAND_ATTACH_FS
261 * The fileserver will take care of keeping track of how many
262 * demand-salvages have been performed, and will force the volume to
263 * ERROR if we've done too many. The limit on This loop is just a
264 * failsafe to prevent trying to salvage forever. We want to attempt
265 * attachment at least SALVAGE_COUNT_MAX times, since we want to
266 * avoid prematurely exiting this loop, if we can.
268 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
269 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
270 vp = VAttachVolumeByName(ec, partition, name, mode);
273 if (*ec == VSALVAGING) {
277 #endif /* AFS_DEMAND_ATTACH_FS */
282 static struct Volume *
283 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
288 vp = VAttachVolume(ec, avolid, amode);
290 #ifdef AFS_DEMAND_ATTACH_FS
293 /* see comment above in VAttachVolumeByName_retry */
294 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
295 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
296 vp = VAttachVolume(ec, avolid, amode);
299 if (*ec == VSALVAGING) {
303 #endif /* AFS_DEMAND_ATTACH_FS */
308 /* the only attach function that takes a partition is "...ByName", so we use it */
309 static struct Volume *
310 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
312 char pbuf[30], vbuf[20];
314 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
318 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
323 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
326 /* Adapted from the file server; create a root directory for this volume */
328 ViceCreateRoot(Volume *vp)
331 struct acl_accessList *ACL;
333 Inode inodeNumber, nearInode;
334 struct VnodeDiskObject *vnode;
335 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
342 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
345 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
347 V_pref(vp, nearInode);
349 IH_CREATE(V_linkHandle(vp), V_device(vp),
350 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
352 assert(VALID_INO(inodeNumber));
354 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
355 did.Volume = V_id(vp);
356 did.Vnode = (VnodeId) 1;
359 assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
360 DFlush(); /* flush all modified dir buffers out */
361 DZap((afs_int32 *)&dir); /* Remove all buffers for this dir */
362 length = Length(&dir); /* Remember size of this directory */
364 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
366 /* build a single entry ACL that gives all rights to system:administrators */
367 /* this section of code assumes that access list format is not going to
370 ACL = VVnodeDiskACL(vnode);
371 ACL->size = sizeof(struct acl_accessList);
372 ACL->version = ACL_ACLVERSION;
376 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
377 ACL->entries[0].rights =
378 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
379 | PRSFS_LOCK | PRSFS_ADMINISTER;
381 vnode->type = vDirectory;
383 vnode->modeBits = 0777;
384 vnode->linkCount = 2;
385 VNDISK_SET_LEN(vnode, length);
386 vnode->uniquifier = 1;
387 V_uniquifier(vp) = vnode->uniquifier + 1;
388 vnode->dataVersion = 1;
389 VNDISK_SET_INO(vnode, inodeNumber);
390 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
394 vnode->vnodeMagic = vcp->magic;
396 IH_INIT(h, vp->device, V_parentId(vp),
397 vp->vnodeIndex[vLarge].handle->ih_ino);
400 off = FDH_SEEK(fdP, vnodeIndexOffset(vcp, 1), SEEK_SET);
402 nBytes = FDH_WRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE);
403 assert(nBytes == SIZEOF_LARGEDISKVNODE);
404 FDH_REALLYCLOSE(fdP);
406 VNDISK_GET_LEN(length, vnode);
407 V_diskused(vp) = nBlocks(length);
414 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
418 struct diskPartition64 *dp = (struct diskPartition64 *)
419 malloc(sizeof(struct diskPartition64));
421 code = VolPartitionInfo(acid, pname, dp);
423 strncpy(partition->name, dp->name, 32);
424 strncpy(partition->devName, dp->devName, 32);
425 partition->lock_fd = dp->lock_fd;
426 partition->free=RoundInt64ToInt32(dp->free);
427 partition->minFree=RoundInt64ToInt32(dp->minFree);
430 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
435 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
440 code = VolPartitionInfo(acid, pname, partition);
441 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
446 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
449 register struct DiskPartition64 *dp;
452 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
455 dp = VGetPartition(pname, 0);
457 strncpy(partition->name, dp->name, 32);
458 strncpy(partition->devName, dp->devName, 32);
459 partition->lock_fd = (int)dp->lock_fd;
460 partition->free = dp->free;
461 partition->minFree = dp->totalUsable;
464 return VOLSERILLEGAL_PARTITION;
467 /* obliterate a volume completely, and slowly. */
469 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
473 code = VolNukeVolume(acid, apartID, avolID);
474 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
479 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
484 register afs_int32 code;
486 char caller[MAXKTCNAMELEN];
488 /* check for access */
489 if (!afsconf_SuperUser(tdir, acid, caller))
490 return VOLSERBAD_ACCESS;
492 Log("%s is executing VolNukeVolume %u\n", caller, avolID);
494 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
496 /* we first try to attach the volume in update mode, so that the file
497 * server doesn't try to use it (and abort) while (or after) we delete it.
498 * If we don't get the volume, that's fine, too. We just won't put it back.
500 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
501 code = nuke(partName, avolID);
503 VDetachVolume(&verror, tvp);
507 /* create a new volume, with name aname, on the specified partition (1..n)
508 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
509 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
510 * for the volume id (useful for things like volume restore).
511 * Return the new volume id in *avolid.
514 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
515 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
521 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
522 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
523 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
529 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
530 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
535 Error junk; /* discardable error code */
537 afs_int32 doCreateRoot = 1;
538 register struct volser_trans *tt;
540 char caller[MAXKTCNAMELEN];
542 if (strlen(aname) > 31)
543 return VOLSERBADNAME;
544 if (!afsconf_SuperUser(tdir, acid, caller))
545 return VOLSERBAD_ACCESS;
547 Log("%s is executing CreateVolume '%s'\n", caller, aname);
548 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
549 return error; /*a standard unix error */
550 if (atype != readwriteVolume && atype != readonlyVolume
551 && atype != backupVolume)
553 if ((volumeID = *avolid) == 0) {
555 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
559 if ((aparent == volumeID) && (atype == readwriteVolume)) {
564 tt = NewTrans(volumeID, apart);
566 Log("1 createvolume: failed to create trans\n");
567 return VOLSERVOLBUSY; /* volume already busy! */
569 vp = VCreateVolume(&error, ppath, volumeID, aparent);
571 #ifdef AFS_DEMAND_ATTACH_FS
572 if (error != VVOLEXISTS && error != EXDEV) {
573 SalvageUnknownVolume(volumeID, ppath);
576 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
581 V_uniquifier(vp) = 1;
582 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
583 V_inService(vp) = V_blessed(vp) = 1;
585 AssignVolumeName(&V_disk(vp), aname, 0);
588 V_destroyMe(vp) = DESTROY_ME;
590 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
591 VUpdateVolume(&error, vp);
593 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
596 VDetachVolume(&junk, vp); /* rather return the real error code */
602 TSetRxCall_r(tt, acid, "CreateVolume");
603 VTRANS_OBJ_UNLOCK(tt);
604 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
607 return VOLSERTRELE_ERROR;
611 /* delete the volume associated with this transaction */
613 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
617 code = VolDeleteVolume(acid, atrans);
618 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
623 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
625 register struct volser_trans *tt;
627 char caller[MAXKTCNAMELEN];
629 if (!afsconf_SuperUser(tdir, acid, caller))
630 return VOLSERBAD_ACCESS;
631 tt = FindTrans(atrans);
634 if (tt->vflags & VTDeleted) {
635 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
640 Log("%s is executing Delete Volume %u\n", caller, tt->volid);
641 TSetRxCall(tt, acid, "DeleteVolume");
642 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
643 V_destroyMe(tt->volume) = DESTROY_ME; /* so endtrans does the right fssync opcode */
645 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
647 VTRANS_OBJ_UNLOCK(tt);
649 return VOLSERTRELE_ERROR;
651 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
652 return 0; /* vpurgevolume doesn't set an error code */
655 /* make a clone of the volume associated with atrans, possibly giving it a new
656 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
657 * for the clone's id). The new clone is given the name newName. Finally,
658 * due to efficiency considerations, if purgeId is non-zero, we purge that
659 * volume when doing the clone operation. This may be useful when making
660 * new backup volumes, for instance since the net result of a clone and a
661 * purge generally leaves many inode ref counts the same, while doing them
662 * separately would result in far more iincs and idecs being peformed
663 * (and they are slow operations).
665 /* for efficiency reasons, sometimes faster to piggyback a purge here */
667 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
668 afs_int32 newType, char *newName, afs_uint32 *newNumber)
672 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
673 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
674 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
680 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
681 afs_int32 newType, char *newName, afs_uint32 *newNumber)
684 register struct Volume *originalvp, *purgevp, *newvp;
686 register struct volser_trans *tt, *ttc;
687 char caller[MAXKTCNAMELEN];
688 #ifdef AFS_DEMAND_ATTACH_FS
689 struct Volume *salv_vp = NULL;
692 if (strlen(newName) > 31)
693 return VOLSERBADNAME;
694 if (!afsconf_SuperUser(tdir, acid, caller))
695 return VOLSERBAD_ACCESS; /*not a super user */
697 Log("%s is executing Clone Volume new name=%s\n", caller, newName);
699 originalvp = (Volume *) 0;
700 purgevp = (Volume *) 0;
701 newvp = (Volume *) 0;
702 tt = ttc = (struct volser_trans *)0;
704 if (!newNumber || !*newNumber) {
705 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
710 if (newType != readonlyVolume && newType != backupVolume)
712 tt = FindTrans(atrans);
715 if (tt->vflags & VTDeleted) {
716 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
720 ttc = NewTrans(newId, tt->partition);
721 if (!ttc) { /* someone is messing with the clone already */
723 return VOLSERVOLBUSY;
725 TSetRxCall(tt, acid, "Clone");
729 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
731 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
737 originalvp = tt->volume;
738 if ((V_type(originalvp) == backupVolume)
739 || (V_type(originalvp) == readonlyVolume)) {
740 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
744 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
745 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
751 if (originalvp->device != purgevp->device) {
752 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
756 if (V_type(purgevp) != readonlyVolume) {
757 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
761 if (V_type(originalvp) == readonlyVolume
762 && V_parentId(originalvp) != V_parentId(purgevp)) {
763 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
767 if (V_type(originalvp) == readwriteVolume
768 && tt->volid != V_parentId(purgevp)) {
769 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
776 #ifdef AFS_DEMAND_ATTACH_FS
777 salv_vp = originalvp;
781 VCreateVolume(&error, originalvp->partition->name, newId,
782 V_parentId(originalvp));
784 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
785 newvp = (Volume *) 0;
788 if (newType == readonlyVolume)
789 V_cloneId(originalvp) = newId;
790 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
793 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
794 CloneVolume(&error, originalvp, newvp, purgevp);
795 purgevp = NULL; /* clone releases it, maybe even if error */
797 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
801 if (newType == readonlyVolume) {
802 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
803 V_type(newvp) = readonlyVolume;
804 } else if (newType == backupVolume) {
805 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
806 V_type(newvp) = backupVolume;
807 V_backupId(originalvp) = newId;
809 strcpy(newvp->header->diskstuff.name, newName);
810 V_creationDate(newvp) = V_copyDate(newvp);
811 ClearVolumeStats(&V_disk(newvp));
812 V_destroyMe(newvp) = DESTROY_ME;
813 V_inService(newvp) = 0;
814 if (newType == backupVolume) {
815 V_backupDate(originalvp) = V_copyDate(newvp);
816 V_backupDate(newvp) = V_copyDate(newvp);
819 VUpdateVolume(&error, newvp);
821 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
825 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
827 VUpdateVolume(&error, originalvp);
829 Log("1 Volser: Clone: original update %u\n", error);
834 #ifdef AFS_DEMAND_ATTACH_FS
838 tt = (struct volser_trans *)0;
839 error = VOLSERTRELE_ERROR;
847 VDetachVolume(&code, purgevp);
849 VDetachVolume(&code, newvp);
856 #ifdef AFS_DEMAND_ATTACH_FS
857 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
859 VRequestSalvage_r(&salv_error, salv_vp, FSYNC_SALVAGE, 0);
861 #endif /* AFS_DEMAND_ATTACH_FS */
865 /* reclone this volume into the specified id */
867 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
871 code = VolReClone(acid, atrans, cloneId);
872 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
878 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
880 register struct Volume *originalvp, *clonevp;
883 register struct volser_trans *tt, *ttc;
884 char caller[MAXKTCNAMELEN];
886 /*not a super user */
887 if (!afsconf_SuperUser(tdir, acid, caller))
888 return VOLSERBAD_ACCESS;
890 Log("%s is executing Reclone Volume %u\n", caller, cloneId);
892 clonevp = originalvp = (Volume *) 0;
893 tt = (struct volser_trans *)0;
895 tt = FindTrans(atrans);
898 if (tt->vflags & VTDeleted) {
899 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
903 ttc = NewTrans(cloneId, tt->partition);
904 if (!ttc) { /* someone is messing with the clone already */
906 return VOLSERVOLBUSY;
908 TSetRxCall(tt, acid, "ReClone");
910 originalvp = tt->volume;
911 if ((V_type(originalvp) == backupVolume)
912 || (V_type(originalvp) == readonlyVolume)) {
913 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
917 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
918 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
924 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
926 Log("1 Volser: can't attach clone %d\n", cloneId);
930 newType = V_type(clonevp); /* type of the new volume */
932 if (originalvp->device != clonevp->device) {
933 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
938 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
939 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
943 if (V_type(originalvp) == readonlyVolume
944 && V_parentId(originalvp) != V_parentId(clonevp)) {
945 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
949 if (V_type(originalvp) == readwriteVolume
950 && tt->volid != V_parentId(clonevp)) {
951 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
957 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
959 CloneVolume(&error, originalvp, clonevp, clonevp);
961 Log("1 Volser: Clone: reclone operation failed with code %d\n",
967 /* fix up volume name and type, CloneVolume just propagated RW's */
968 if (newType == readonlyVolume) {
969 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
970 V_type(clonevp) = readonlyVolume;
971 } else if (newType == backupVolume) {
972 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
973 V_type(clonevp) = backupVolume;
974 V_backupId(originalvp) = cloneId;
976 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
978 /* pretend recloned volume is a totally new instance */
979 V_copyDate(clonevp) = time(0);
980 V_creationDate(clonevp) = V_copyDate(clonevp);
981 ClearVolumeStats(&V_disk(clonevp));
982 V_destroyMe(clonevp) = 0;
983 V_inService(clonevp) = 0;
984 if (newType == backupVolume) {
985 V_backupDate(originalvp) = V_copyDate(clonevp);
986 V_backupDate(clonevp) = V_copyDate(clonevp);
988 V_inUse(clonevp) = 0;
989 VUpdateVolume(&error, clonevp);
991 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
995 /* VUpdateVolume succeeded. Mark it in service so there's no window
996 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
997 * specialStatus; this is a reclone and this volume started online
999 V_inService(clonevp) = 1;
1000 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
1002 VUpdateVolume(&error, originalvp);
1004 Log("1 Volser: Clone: original update %u\n", error);
1010 tt = (struct volser_trans *)0;
1011 error = VOLSERTRELE_ERROR;
1015 DeleteTrans(ttc, 1);
1018 struct DiskPartition64 *tpartp = originalvp->partition;
1019 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1025 VDetachVolume(&code, clonevp);
1031 DeleteTrans(ttc, 1);
1035 /* create a new transaction, associated with volume and partition. Type of
1036 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1037 * See volser.h for definition of iflags (the constants are named IT*).
1040 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1041 afs_int32 iflags, afs_int32 *ttid)
1045 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1046 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1052 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1053 afs_int32 iflags, afs_int32 *ttid)
1055 register struct volser_trans *tt;
1056 register Volume *tv;
1060 char caller[MAXKTCNAMELEN];
1062 if (!afsconf_SuperUser(tdir, acid, caller))
1063 return VOLSERBAD_ACCESS; /*not a super user */
1064 if (iflags & ITCreate)
1066 else if (iflags & ITBusy)
1068 else if (iflags & ITReadOnly)
1070 else if (iflags & ITOffline)
1073 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1078 tt = NewTrans(volume, partition);
1080 /* can't create a transaction? put the volume back */
1081 Log("1 transcreate: can't create transaction\n");
1082 return VOLSERVOLBUSY;
1084 tv = XAttachVolume(&error, volume, partition, mode);
1088 VDetachVolume(&code, tv);
1092 VTRANS_OBJ_LOCK(tt);
1095 tt->iflags = iflags;
1097 TSetRxCall_r(tt, NULL, "TransCreate");
1098 VTRANS_OBJ_UNLOCK(tt);
1100 return VOLSERTRELE_ERROR;
1105 /* using aindex as a 0-based index, return the aindex'th volume on this server
1106 * Both the volume number and partition number (one-based) are returned.
1109 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1114 code = VolGetNthVolume(acid, aindex, avolume, apart);
1115 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1120 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1123 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1127 /* return the volume flags (VT* constants in volser.h) associated with this
1131 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1135 code = VolGetFlags(acid, atid, aflags);
1136 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1141 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1143 register struct volser_trans *tt;
1145 tt = FindTrans(atid);
1148 if (tt->vflags & VTDeleted) {
1149 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1154 TSetRxCall(tt, acid, "GetFlags");
1155 *aflags = tt->vflags;
1158 return VOLSERTRELE_ERROR;
1163 /* Change the volume flags (VT* constants in volser.h) associated with this
1164 * transaction. Effects take place immediately on volume, although volume
1165 * remains attached as usual by the transaction.
1168 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1172 code = VolSetFlags(acid, atid, aflags);
1173 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1179 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1181 register struct volser_trans *tt;
1182 register struct Volume *vp;
1184 char caller[MAXKTCNAMELEN];
1186 if (!afsconf_SuperUser(tdir, acid, caller))
1187 return VOLSERBAD_ACCESS; /*not a super user */
1188 /* find the trans */
1189 tt = FindTrans(atid);
1192 if (tt->vflags & VTDeleted) {
1193 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1198 TSetRxCall(tt, acid, "SetFlags");
1199 vp = tt->volume; /* pull volume out of transaction */
1201 /* check if we're allowed to make any updates */
1202 if (tt->iflags & ITReadOnly) {
1207 /* handle delete-on-salvage flag */
1208 if (aflags & VTDeleteOnSalvage) {
1209 V_destroyMe(tt->volume) = DESTROY_ME;
1211 V_destroyMe(tt->volume) = 0;
1214 if (aflags & VTOutOfService) {
1215 V_inService(vp) = 0;
1217 V_inService(vp) = 1;
1219 VUpdateVolume(&error, vp);
1220 VTRANS_OBJ_LOCK(tt);
1221 tt->vflags = aflags;
1223 VTRANS_OBJ_UNLOCK(tt);
1224 if (TRELE(tt) && !error)
1225 return VOLSERTRELE_ERROR;
1230 /* dumpS the volume associated with a particular transaction from a particular
1231 * date. Send the dump to a different transaction (destTrans) on the server
1232 * specified by the destServer structure.
1235 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1236 struct destServer *destination, afs_int32 destTrans,
1237 struct restoreCookie *cookie)
1242 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1243 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1244 destination->destHost, AUD_LONG, destTrans, AUD_END);
1249 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1250 struct destServer *destination, afs_int32 destTrans,
1251 struct restoreCookie *cookie)
1253 register struct volser_trans *tt;
1254 register afs_int32 code;
1255 register struct rx_connection *tcon;
1256 struct rx_call *tcall;
1257 register struct Volume *vp;
1258 struct rx_securityClass *securityObject;
1259 afs_int32 securityIndex;
1260 char caller[MAXKTCNAMELEN];
1262 if (!afsconf_SuperUser(tdir, acid, caller))
1263 return VOLSERBAD_ACCESS; /*not a super user */
1264 /* initialize things */
1265 tcon = (struct rx_connection *)0;
1266 tt = (struct volser_trans *)0;
1268 /* find the local transaction */
1269 tt = FindTrans(fromTrans);
1272 if (tt->vflags & VTDeleted) {
1273 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1278 TSetRxCall(tt, NULL, "Forward");
1280 /* get auth info for the this connection (uses afs from ticket file) */
1281 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1287 /* make an rpc connection to the other server */
1289 rx_NewConnection(htonl(destination->destHost),
1290 htons(destination->destPort), VOLSERVICE_ID,
1291 securityObject, securityIndex);
1297 tcall = rx_NewCall(tcon);
1298 TSetRxCall(tt, tcall, "Forward");
1299 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1300 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1305 /* these next calls implictly call rx_Write when writing out data */
1306 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1309 EndAFSVolRestore(tcall); /* probably doesn't do much */
1311 code = rx_EndCall(tcall, 0);
1312 rx_DestroyConnection(tcon); /* done with the connection */
1317 return VOLSERTRELE_ERROR;
1323 (void)rx_EndCall(tcall, 0);
1324 rx_DestroyConnection(tcon);
1333 /* Start a dump and send it to multiple places simultaneously.
1334 * If this returns an error (eg, return ENOENT), it means that
1335 * none of the releases worked. If this returns 0, that means
1336 * that one or more of the releases worked, and the caller has
1337 * to examine the results array to see which one(s).
1338 * This will only do EITHER incremental or full, not both, so it's
1339 * the caller's responsibility to be sure that all the destinations
1340 * need just an incremental (and from the same time), if that's
1344 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1345 fromDate, manyDests *destinations, afs_int32 spare,
1346 struct restoreCookie *cookie, manyResults *results)
1348 afs_int32 securityIndex;
1349 struct rx_securityClass *securityObject;
1350 char caller[MAXKTCNAMELEN];
1351 struct volser_trans *tt;
1352 afs_int32 ec, code, *codes;
1353 struct rx_connection **tcons;
1354 struct rx_call **tcalls;
1356 int i, is_incremental;
1359 memset(results, 0, sizeof(manyResults));
1360 i = results->manyResults_len = destinations->manyDests_len;
1361 results->manyResults_val = codes =
1362 (afs_int32 *) malloc(i * sizeof(afs_int32));
1364 if (!results || !results->manyResults_val)
1367 if (!afsconf_SuperUser(tdir, acid, caller))
1368 return VOLSERBAD_ACCESS; /*not a super user */
1369 tt = FindTrans(fromTrans);
1372 if (tt->vflags & VTDeleted) {
1373 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1378 TSetRxCall(tt, NULL, "ForwardMulti");
1380 /* (fromDate == 0) ==> full dump */
1381 is_incremental = (fromDate ? 1 : 0);
1384 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1388 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1394 /* get auth info for this connection (uses afs from ticket file) */
1395 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1397 goto fail; /* in order to audit each failure */
1400 /* make connections to all the other servers */
1401 for (i = 0; i < destinations->manyDests_len; i++) {
1402 struct replica *dest = &(destinations->manyDests_val[i]);
1404 rx_NewConnection(htonl(dest->server.destHost),
1405 htons(dest->server.destPort), VOLSERVICE_ID,
1406 securityObject, securityIndex);
1408 codes[i] = ENOTCONN;
1410 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1411 codes[i] = ENOTCONN;
1414 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1417 (void)rx_EndCall(tcalls[i], 0);
1419 rx_DestroyConnection(tcons[i]);
1426 /* these next calls implictly call rx_Write when writing out data */
1427 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1431 for (i--; i >= 0; i--) {
1432 struct replica *dest = &(destinations->manyDests_val[i]);
1434 if (!code && tcalls[i] && !codes[i]) {
1435 EndAFSVolRestore(tcalls[i]);
1438 ec = rx_EndCall(tcalls[i], 0);
1443 rx_DestroyConnection(tcons[i]); /* done with the connection */
1446 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1447 fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG,
1448 dest->trans, AUD_END);
1455 if (TRELE(tt) && !code) /* return the first code if it's set */
1456 return VOLSERTRELE_ERROR;
1463 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1467 code = VolDump(acid, fromTrans, fromDate, 0);
1468 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1473 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1478 code = VolDump(acid, fromTrans, fromDate, flags);
1479 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1484 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1488 register struct volser_trans *tt;
1489 char caller[MAXKTCNAMELEN];
1491 if (!afsconf_SuperUser(tdir, acid, caller))
1492 return VOLSERBAD_ACCESS; /*not a super user */
1493 tt = FindTrans(fromTrans);
1496 if (tt->vflags & VTDeleted) {
1497 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1501 TSetRxCall(tt, acid, "Dump");
1502 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1503 ? 0 : 1); /* squirt out the volume's data, too */
1512 return VOLSERTRELE_ERROR;
1518 * Ha! No more helper process!
1521 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1522 struct restoreCookie *cookie)
1526 code = VolRestore(acid, atrans, aflags, cookie);
1527 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1532 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1533 struct restoreCookie *cookie)
1535 register struct volser_trans *tt;
1536 register afs_int32 code, tcode;
1537 char caller[MAXKTCNAMELEN];
1539 if (!afsconf_SuperUser(tdir, acid, caller))
1540 return VOLSERBAD_ACCESS; /*not a super user */
1541 tt = FindTrans(atrans);
1544 if (tt->vflags & VTDeleted) {
1545 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1549 TSetRxCall(tt, acid, "Restore");
1551 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1553 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1554 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1558 return (code ? code : tcode);
1561 /* end a transaction, returning the transaction's final error code in rcode */
1563 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1567 code = VolEndTrans(acid, destTrans, rcode);
1568 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1573 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1575 register struct volser_trans *tt;
1576 char caller[MAXKTCNAMELEN];
1578 if (!afsconf_SuperUser(tdir, acid, caller))
1579 return VOLSERBAD_ACCESS; /*not a super user */
1580 tt = FindTrans(destTrans);
1584 *rcode = tt->returnCode;
1585 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1591 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1595 code = VolSetForwarding(acid, atid, anewsite);
1596 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1602 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1604 register struct volser_trans *tt;
1605 char caller[MAXKTCNAMELEN];
1608 if (!afsconf_SuperUser(tdir, acid, caller))
1609 return VOLSERBAD_ACCESS; /*not a super user */
1610 tt = FindTrans(atid);
1613 if (tt->vflags & VTDeleted) {
1614 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1619 TSetRxCall(tt, acid, "SetForwarding");
1620 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1623 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1626 return VOLSERTRELE_ERROR;
1632 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1633 register struct volser_status *astatus)
1637 code = VolGetStatus(acid, atrans, astatus);
1638 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1643 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1644 register struct volser_status *astatus)
1646 register struct Volume *tv;
1647 register struct VolumeDiskData *td;
1648 struct volser_trans *tt;
1651 tt = FindTrans(atrans);
1654 if (tt->vflags & VTDeleted) {
1655 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1660 TSetRxCall(tt, acid, "GetStatus");
1668 td = &tv->header->diskstuff;
1669 astatus->volID = td->id;
1670 astatus->nextUnique = td->uniquifier;
1671 astatus->type = td->type;
1672 astatus->parentID = td->parentId;
1673 astatus->cloneID = td->cloneId;
1674 astatus->backupID = td->backupId;
1675 astatus->restoredFromID = td->restoredFromId;
1676 astatus->maxQuota = td->maxquota;
1677 astatus->minQuota = td->minquota;
1678 astatus->owner = td->owner;
1679 astatus->creationDate = td->creationDate;
1680 astatus->accessDate = td->accessDate;
1681 astatus->updateDate = td->updateDate;
1682 astatus->expirationDate = td->expirationDate;
1683 astatus->backupDate = td->backupDate;
1684 astatus->copyDate = td->copyDate;
1687 return VOLSERTRELE_ERROR;
1693 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1694 register struct volintInfo *astatus)
1698 code = VolSetInfo(acid, atrans, astatus);
1699 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1704 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1705 register struct volintInfo *astatus)
1707 register struct Volume *tv;
1708 register struct VolumeDiskData *td;
1709 struct volser_trans *tt;
1710 char caller[MAXKTCNAMELEN];
1713 if (!afsconf_SuperUser(tdir, acid, caller))
1714 return VOLSERBAD_ACCESS; /*not a super user */
1715 tt = FindTrans(atrans);
1718 if (tt->vflags & VTDeleted) {
1719 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1723 TSetRxCall(tt, acid, "SetStatus");
1731 td = &tv->header->diskstuff;
1733 * Add more fields as necessary
1735 if (astatus->maxquota != -1)
1736 td->maxquota = astatus->maxquota;
1737 if (astatus->dayUse != -1)
1738 td->dayUse = astatus->dayUse;
1739 if (astatus->creationDate != -1)
1740 td->creationDate = astatus->creationDate;
1741 if (astatus->updateDate != -1)
1742 td->updateDate = astatus->updateDate;
1743 if (astatus->spare2 != -1)
1744 td->volUpdateCounter = (unsigned int)astatus->spare2;
1745 VUpdateVolume(&error, tv);
1748 return VOLSERTRELE_ERROR;
1754 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1758 code = VolGetName(acid, atrans, aname);
1759 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1764 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1766 register struct Volume *tv;
1767 register struct VolumeDiskData *td;
1768 struct volser_trans *tt;
1771 /* We need to at least fill it in */
1772 *aname = (char *)malloc(1);
1775 tt = FindTrans(atrans);
1778 if (tt->vflags & VTDeleted) {
1779 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1783 TSetRxCall(tt, acid, "GetName");
1791 td = &tv->header->diskstuff;
1792 len = strlen(td->name) + 1; /* don't forget the null */
1798 *aname = (char *)realloc(*aname, len);
1799 strcpy(*aname, td->name);
1802 return VOLSERTRELE_ERROR;
1807 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1810 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1811 afs_uint32 parentId, afs_uint32 cloneId)
1817 /*return a list of all partitions on the server. The non mounted
1818 *partitions are returned as -1 in the corresponding slot in partIds*/
1820 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1824 code = VolListPartitions(acid, partIds);
1825 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1830 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1835 strcpy(namehead, "/vicep"); /*7 including null terminator */
1837 /* Just return attached partitions. */
1839 for (i = 0; i < 26; i++) {
1840 namehead[6] = i + 'a';
1841 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1847 /*return a list of all partitions on the server. The non mounted
1848 *partitions are returned as -1 in the corresponding slot in partIds*/
1850 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1854 code = XVolListPartitions(acid, pEntries);
1855 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1860 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1863 struct partList partList;
1864 struct DiskPartition64 *dp;
1867 strcpy(namehead, "/vicep"); /*7 including null terminator */
1869 /* Only report attached partitions */
1870 for (i = 0; i < VOLMAXPARTS; i++) {
1871 #ifdef AFS_DEMAND_ATTACH_FS
1872 dp = VGetPartitionById(i, 0);
1875 namehead[6] = i + 'a';
1881 namehead[6] = 'a' + (k / 26);
1882 namehead[7] = 'a' + (k % 26);
1885 dp = VGetPartition(namehead, 0);
1888 partList.partId[j++] = i;
1890 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1891 if (!pEntries->partEntries_val)
1893 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1895 pEntries->partEntries_len = j;
1900 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1902 ExtractVolId(char vname[])
1905 char name[VOLSER_MAXVOLNAME + 1];
1907 strcpy(name, vname);
1909 while (name[i] == 'V' || name[i] == '0')
1912 name[11] = '\0'; /* smash the "." */
1913 return (atol(&name[i]));
1916 /*return the name of the next volume header in the directory associated with dirp and dp.
1917 *the volume id is returned in volid, and volume header name is returned in volname*/
1919 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1923 dp = readdir(dirp); /*read next entry in the directory */
1925 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1926 *volid = ExtractVolId(dp->d_name);
1927 strcpy(volname, dp->d_name);
1928 return 0; /*return the name of the file representing a volume */
1930 strcpy(volname, "");
1931 return 0; /*volname doesnot represent a volume */
1934 strcpy(volname, "EOD");
1935 return 0; /*end of directory */
1941 * volint vol info structure type.
1944 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1945 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1946 } volint_info_type_t;
1949 * handle to various on-wire vol info types.
1952 volint_info_type_t volinfo_type;
1958 } volint_info_handle_t;
1961 * store value to a field at the appropriate location in on-wire structure.
1963 #define VOLINT_INFO_STORE(handle, name, val) \
1965 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1966 (handle)->volinfo_ptr.base->name = (val); \
1968 (handle)->volinfo_ptr.ext->name = (val); \
1973 * get pointer to appropriate offset of field in on-wire structure.
1975 #define VOLINT_INFO_PTR(handle, name) \
1976 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1977 &((handle)->volinfo_ptr.base->name) : \
1978 &((handle)->volinfo_ptr.ext->name))
1981 * fill in appropriate type of on-wire volume metadata structure.
1983 * @param vp pointer to volume object
1984 * @param handle pointer to wire format handle object
1986 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1987 * @pre handle object must have a valid pointer and enumeration value
1989 * @note passing a NULL value for vp means that the fileserver doesn't
1990 * know about this particular volume, thus implying it is offline.
1992 * @return operation status
1997 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1999 unsigned int numStatBytes, now;
2000 register struct VolumeDiskData *hdr = &vp->header->diskstuff;
2002 /*read in the relevant info */
2003 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2004 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
2005 VOLINT_INFO_STORE(handle, volid, hdr->id);
2006 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2007 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2008 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2009 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2010 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2011 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2012 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2013 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2014 now = FT_ApproxTime();
2015 if ((now - hdr->dayUseDate) > OneDay) {
2016 VOLINT_INFO_STORE(handle, dayUse, 0);
2018 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2020 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2021 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2022 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2023 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2025 #ifdef AFS_DEMAND_ATTACH_FS
2027 * for DAFS, we "lie" about volume state --
2028 * instead of returning the raw state from the disk header,
2029 * we compute state based upon the fileserver's internal
2030 * in-core state enumeration value reported to us via fssync,
2031 * along with the blessed and inService flags from the header.
2032 * -- tkeiser 11/27/2007
2035 /* Conditions that offline status is based on:
2036 volume is unattached state
2037 volume state is in (one of several error states)
2038 volume not in service
2039 volume is not marked as blessed (not on hold)
2040 volume in salvage req. state
2041 volume needsSalvaged
2042 next op would set volume offline
2043 next op would not leave volume online (based on several conditions)
2046 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2047 VIsErrorState(V_attachState(vp)) ||
2050 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2051 hdr->needsSalvaged ||
2052 (vp->pending_vol_op &&
2053 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2054 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2057 VOLINT_INFO_STORE(handle, inUse, 0);
2059 VOLINT_INFO_STORE(handle, inUse, 1);
2062 /* offline status based on program type, where != fileServer enum (1) is offline */
2063 if (hdr->inUse == fileServer) {
2064 VOLINT_INFO_STORE(handle, inUse, 1);
2066 VOLINT_INFO_STORE(handle, inUse, 0);
2071 switch(handle->volinfo_type) {
2072 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2073 case VOLINT_INFO_TYPE_BASE:
2075 #ifdef AFS_DEMAND_ATTACH_FS
2076 /* see comment above where we set inUse bit */
2077 if (hdr->needsSalvaged ||
2078 (vp && VIsErrorState(V_attachState(vp)))) {
2079 handle->volinfo_ptr.base->needsSalvaged = 1;
2081 handle->volinfo_ptr.base->needsSalvaged = 0;
2084 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2086 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2087 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2088 handle->volinfo_ptr.base->spare1 =
2089 (long)hdr->weekUse[0] +
2090 (long)hdr->weekUse[1] +
2091 (long)hdr->weekUse[2] +
2092 (long)hdr->weekUse[3] +
2093 (long)hdr->weekUse[4] +
2094 (long)hdr->weekUse[5] +
2095 (long)hdr->weekUse[6];
2096 handle->volinfo_ptr.base->flags = 0;
2097 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2098 handle->volinfo_ptr.base->spare3 = 0;
2102 case VOLINT_INFO_TYPE_EXT:
2104 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2105 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2108 * Copy out the stat fields in a single operation.
2110 if ((now - hdr->dayUseDate) > OneDay) {
2111 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2114 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2115 (char *)&(hdr->stat_reads[0]),
2124 #ifdef AFS_DEMAND_ATTACH_FS
2127 * get struct Volume out of the fileserver.
2129 * @param[in] volumeId volumeId for which we want state information
2130 * @param[in] pname partition name string
2131 * @param[inout] vp pointer to pointer to Volume object which
2132 * will be populated (see note)
2134 * @return operation status
2136 * @retval non-zero failure
2138 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2143 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2148 res.hdr.response_len = sizeof(res.hdr);
2149 res.payload.buf = *vp;
2150 res.payload.len = sizeof(Volume);
2152 code = FSYNC_VolOp(volumeId,
2158 if (code != SYNC_OK) {
2159 switch (res.hdr.reason) {
2160 case FSYNC_WRONG_PART:
2161 case FSYNC_UNKNOWN_VOLID:
2174 * mode of volume list operation.
2177 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2178 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2179 } vol_info_list_mode_t;
2182 * abstract interface to populate wire-format volume metadata structures.
2184 * @param[in] partId partition id
2185 * @param[in] volumeId volume id
2186 * @param[in] pname partition name
2187 * @param[in] volname volume file name
2188 * @param[in] handle handle to on-wire volume metadata object
2189 * @param[in] mode listing mode
2191 * @return operation status
2193 * @retval -2 DESTROY_ME flag is set
2194 * @retval -1 general failure; some data filled in
2195 * @retval -3 couldn't create vtrans; some data filled in
2198 GetVolInfo(afs_uint32 partId,
2199 afs_uint32 volumeId,
2202 volint_info_handle_t * handle,
2203 vol_info_list_mode_t mode)
2207 struct volser_trans *ttc = NULL;
2208 struct Volume *fill_tv, *tv = NULL;
2209 #ifdef AFS_DEMAND_ATTACH_FS
2210 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2211 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2212 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2213 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2215 /* Set up response handle for pending_vol_op */
2216 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2217 fs_res.payload.buf = fs_res_buf;
2218 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2221 ttc = NewTrans(volumeId, partId);
2224 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2225 VOLINT_INFO_STORE(handle, volid, volumeId);
2229 /* Get volume from volserver */
2230 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2232 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2233 volumeId, pname, volname, error);
2238 * please note that destroyMe and needsSalvaged checks used to be ordered
2239 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2240 * more correct to check destroyMe before needsSalvaged.
2241 * -- tkeiser 11/28/2007
2244 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2246 case VOL_INFO_LIST_MULTIPLE:
2250 case VOL_INFO_LIST_SINGLE:
2251 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2252 volumeId, pname, volname);
2259 if (tv->header->diskstuff.needsSalvaged) {
2260 /*this volume will be salvaged */
2261 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2262 volumeId, pname, volname);
2265 #ifdef AFS_DEMAND_ATTACH_FS
2266 /* If using DAFS, get volume from fsserver */
2267 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2272 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2273 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2274 /* If we if the pending vol op */
2275 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2276 fs_tv->pending_vol_op=&pending_vol_op_res;
2278 fs_tv->pending_vol_op=NULL;
2281 /* populate the header from the volserver copy */
2282 fs_tv->header=tv->header;
2284 /* When using DAFS, use the fs volume info, populated with required structures */
2287 /* When not using DAFS, just use the local volume info */
2291 /* ok, we have all the data we need; fill in the on-wire struct */
2292 code = FillVolInfo(fill_tv, handle);
2296 VOLINT_INFO_STORE(handle, status, 0);
2297 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2298 VOLINT_INFO_STORE(handle, volid, volumeId);
2301 VDetachVolume(&error, tv);
2304 VOLINT_INFO_STORE(handle, status, 0);
2305 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2306 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2307 volumeId, pname, volname);
2311 DeleteTrans(ttc, 1);
2318 /*return the header information about the <volid> */
2320 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2321 afs_uint32 volumeId, volEntries *volumeInfo)
2325 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2326 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2331 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2332 afs_uint32 volumeId, volEntries *volumeInfo)
2335 struct DiskPartition64 *partP;
2336 char pname[9], volname[20];
2341 volint_info_handle_t handle;
2343 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2344 if (!volumeInfo->volEntries_val)
2346 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2348 pntr = volumeInfo->volEntries_val;
2349 volumeInfo->volEntries_len = 1;
2350 if (GetPartName(partid, pname))
2351 return VOLSERILLEGAL_PARTITION;
2352 if (!(partP = VGetPartition(pname, 0)))
2353 return VOLSERILLEGAL_PARTITION;
2354 dirp = opendir(VPartitionPath(partP));
2356 return VOLSERILLEGAL_PARTITION;
2358 strcpy(volname, "");
2360 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2362 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2363 GetNextVol(dirp, volname, &volid);
2364 continue; /*back to while loop */
2367 if (volid == volumeId) { /*copy other things too */
2372 GetNextVol(dirp, volname, &volid);
2376 #ifndef AFS_PTHREAD_ENV
2377 IOMGR_Poll(); /*make sure that the client does not time out */
2380 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2381 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2383 code = GetVolInfo(partid,
2388 VOL_INFO_LIST_SINGLE);
2392 return (found) ? 0 : ENODEV;
2395 /*------------------------------------------------------------------------
2396 * EXPORTED SAFSVolXListOneVolume
2399 * Returns extended info on volume a_volID on partition a_partID.
2402 * a_rxCidP : Pointer to the Rx call we're performing.
2403 * a_partID : Partition for which we want the extended list.
2404 * a_volID : Volume ID we wish to know about.
2405 * a_volumeXInfoP : Ptr to the extended info blob.
2408 * 0 Successful operation
2409 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2412 * Nothing interesting.
2416 *------------------------------------------------------------------------*/
2419 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2420 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2424 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2425 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2430 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2431 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2432 { /*SAFSVolXListOneVolume */
2434 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2435 struct DiskPartition64 *partP; /*Ptr to partition */
2436 char pname[9], volname[20]; /*Partition, volume names */
2437 DIR *dirp; /*Partition directory ptr */
2438 afs_uint32 currVolID; /*Current volume ID */
2439 int found = 0; /*Did we find the volume we need? */
2441 volint_info_handle_t handle;
2444 * Set up our pointers for action, marking our structure to hold exactly
2445 * one entry. Also, assume we'll fail in our quest.
2447 a_volumeXInfoP->volXEntries_val =
2448 (volintXInfo *) malloc(sizeof(volintXInfo));
2449 if (!a_volumeXInfoP->volXEntries_val)
2451 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2453 xInfoP = a_volumeXInfoP->volXEntries_val;
2454 a_volumeXInfoP->volXEntries_len = 1;
2458 * If the partition name we've been given is bad, bogue out.
2460 if (GetPartName(a_partID, pname))
2461 return (VOLSERILLEGAL_PARTITION);
2464 * Open the directory representing the given AFS parttion. If we can't
2467 if (!(partP = VGetPartition(pname, 0)))
2468 return VOLSERILLEGAL_PARTITION;
2469 dirp = opendir(VPartitionPath(partP));
2471 return (VOLSERILLEGAL_PARTITION);
2473 strcpy(volname, "");
2476 * Sweep through the partition directory, looking for the desired entry.
2477 * First, of course, figure out how many stat bytes to copy out of each
2480 while (strcmp(volname, "EOD") && !found) {
2482 * If this is not a volume, move on to the next entry in the
2483 * partition's directory.
2485 if (!strcmp(volname, "")) {
2486 GetNextVol(dirp, volname, &currVolID);
2490 if (currVolID == a_volID) {
2492 * We found the volume entry we're interested. Pull out the
2493 * extended information, remembering to poll (so that the client
2494 * doesn't time out) and to set up a transaction on the volume.
2498 } /*Found desired volume */
2500 GetNextVol(dirp, volname, &currVolID);
2504 #ifndef AFS_PTHREAD_ENV
2508 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2509 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2511 code = GetVolInfo(a_partID,
2516 VOL_INFO_LIST_SINGLE);
2521 * Clean up before going to dinner: close the partition directory,
2522 * return the proper value.
2525 return (found) ? 0 : ENODEV;
2526 } /*SAFSVolXListOneVolume */
2528 /*returns all the volumes on partition partid. If flags = 1 then all the
2529 * relevant info about the volumes is also returned */
2531 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2532 volEntries *volumeInfo)
2536 code = VolListVolumes(acid, partid, flags, volumeInfo);
2537 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2542 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2543 volEntries *volumeInfo)
2546 struct DiskPartition64 *partP;
2547 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2548 char pname[9], volname[20];
2552 volint_info_handle_t handle;
2554 volumeInfo->volEntries_val =
2555 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2556 if (!volumeInfo->volEntries_val)
2558 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2560 pntr = volumeInfo->volEntries_val;
2561 volumeInfo->volEntries_len = 0;
2562 if (GetPartName(partid, pname))
2563 return VOLSERILLEGAL_PARTITION;
2564 if (!(partP = VGetPartition(pname, 0)))
2565 return VOLSERILLEGAL_PARTITION;
2566 dirp = opendir(VPartitionPath(partP));
2568 return VOLSERILLEGAL_PARTITION;
2569 strcpy(volname, "");
2571 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2573 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2574 GetNextVol(dirp, volname, &volid);
2575 continue; /*back to while loop */
2578 if (flags) { /*copy other things too */
2579 #ifndef AFS_PTHREAD_ENV
2580 IOMGR_Poll(); /*make sure that the client does not time out */
2583 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2584 handle.volinfo_ptr.base = pntr;
2587 code = GetVolInfo(partid,
2592 VOL_INFO_LIST_MULTIPLE);
2593 if (code == -2) { /* DESTROY_ME flag set */
2597 pntr->volid = volid;
2598 /*just volids are needed */
2602 volumeInfo->volEntries_len += 1;
2603 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2604 /*running out of space, allocate more space */
2605 allocSize = (allocSize * 3) / 2;
2607 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2608 allocSize * sizeof(volintInfo));
2611 return VOLSERNO_MEMORY;
2613 volumeInfo->volEntries_val = pntr; /* point to new block */
2614 /* set pntr to the right position */
2615 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2620 GetNextVol(dirp, volname, &volid);
2628 /*------------------------------------------------------------------------
2629 * EXPORTED SAFSVolXListVolumes
2632 * Returns all the volumes on partition a_partID. If a_flags
2633 * is set to 1, then all the relevant extended volume information
2637 * a_rxCidP : Pointer to the Rx call we're performing.
2638 * a_partID : Partition for which we want the extended list.
2639 * a_flags : Various flags.
2640 * a_volumeXInfoP : Ptr to the extended info blob.
2643 * 0 Successful operation
2644 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2645 * VOLSERNO_MEMORY if we ran out of memory allocating
2649 * Nothing interesting.
2653 *------------------------------------------------------------------------*/
2656 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2657 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2661 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2662 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2667 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2668 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2669 { /*SAFSVolXListVolumes */
2671 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2672 struct DiskPartition64 *partP; /*Ptr to partition */
2673 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2674 char pname[9], volname[20]; /*Partition, volume names */
2675 DIR *dirp; /*Partition directory ptr */
2676 afs_uint32 volid; /*Current volume ID */
2678 volint_info_handle_t handle;
2681 * Allocate a large array of extended volume info structures, then
2682 * set it up for action.
2684 a_volumeXInfoP->volXEntries_val =
2685 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2686 if (!a_volumeXInfoP->volXEntries_val)
2688 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2690 xInfoP = a_volumeXInfoP->volXEntries_val;
2691 a_volumeXInfoP->volXEntries_len = 0;
2694 * If the partition name we've been given is bad, bogue out.
2696 if (GetPartName(a_partID, pname))
2697 return (VOLSERILLEGAL_PARTITION);
2700 * Open the directory representing the given AFS parttion. If we can't
2703 if (!(partP = VGetPartition(pname, 0)))
2704 return VOLSERILLEGAL_PARTITION;
2705 dirp = opendir(VPartitionPath(partP));
2707 return (VOLSERILLEGAL_PARTITION);
2708 strcpy(volname, "");
2711 * Sweep through the partition directory, acting on each entry. First,
2712 * of course, figure out how many stat bytes to copy out of each volume.
2714 while (strcmp(volname, "EOD")) {
2717 * If this is not a volume, move on to the next entry in the
2718 * partition's directory.
2720 if (!strcmp(volname, "")) {
2721 GetNextVol(dirp, volname, &volid);
2727 * Full info about the volume desired. Poll to make sure the
2728 * client doesn't time out, then start up a new transaction.
2730 #ifndef AFS_PTHREAD_ENV
2734 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2735 handle.volinfo_ptr.ext = xInfoP;
2737 code = GetVolInfo(a_partID,
2742 VOL_INFO_LIST_MULTIPLE);
2743 if (code == -2) { /* DESTROY_ME flag set */
2748 * Just volume IDs are needed.
2750 xInfoP->volid = volid;
2754 * Bump the pointer in the data area we're building, along with
2755 * the count of the number of entries it contains.
2758 (a_volumeXInfoP->volXEntries_len)++;
2759 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2761 * We're running out of space in the area we've built. Grow it.
2763 allocSize = (allocSize * 3) / 2;
2764 xInfoP = (volintXInfo *)
2765 realloc((char *)a_volumeXInfoP->volXEntries_val,
2766 (allocSize * sizeof(volintXInfo)));
2767 if (xInfoP == NULL) {
2769 * Bummer, no memory. Bag it, tell our caller what went wrong.
2772 return (VOLSERNO_MEMORY);
2776 * Memory reallocation worked. Correct our pointers so they
2777 * now point to the new block and the current open position within
2780 a_volumeXInfoP->volXEntries_val = xInfoP;
2782 a_volumeXInfoP->volXEntries_val +
2783 a_volumeXInfoP->volXEntries_len;
2787 GetNextVol(dirp, volname, &volid);
2788 } /*Sweep through the partition directory */
2791 * We've examined all entries in the partition directory. Close it,
2792 * delete our transaction (if any), and go home happy.
2797 } /*SAFSVolXListVolumes */
2799 /*this call is used to monitor the status of volser for debugging purposes.
2800 *information about all the active transactions is returned in transInfo*/
2802 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2806 code = VolMonitor(acid, transInfo);
2807 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2812 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2814 transDebugInfo *pntr;
2815 afs_int32 allocSize = 50;
2816 struct volser_trans *tt, *nt, *allTrans;
2818 transInfo->transDebugEntries_val =
2819 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2820 if (!transInfo->transDebugEntries_val)
2822 pntr = transInfo->transDebugEntries_val;
2823 transInfo->transDebugEntries_len = 0;
2826 allTrans = TransList();
2827 if (allTrans == (struct volser_trans *)0)
2828 goto done; /*no active transactions */
2829 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2831 VTRANS_OBJ_LOCK(tt);
2832 pntr->tid = tt->tid;
2833 pntr->time = tt->time;
2834 pntr->creationTime = tt->creationTime;
2835 pntr->returnCode = tt->returnCode;
2836 pntr->volid = tt->volid;
2837 pntr->partition = tt->partition;
2838 pntr->iflags = tt->iflags;
2839 pntr->vflags = tt->vflags;
2840 pntr->tflags = tt->tflags;
2841 strcpy(pntr->lastProcName, tt->lastProcName);
2842 pntr->callValid = 0;
2843 if (tt->rxCallPtr) { /*record call related info */
2844 pntr->callValid = 1;
2845 pntr->readNext = tt->rxCallPtr->rnext;
2846 pntr->transmitNext = tt->rxCallPtr->tnext;
2847 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2848 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2850 VTRANS_OBJ_UNLOCK(tt);
2852 transInfo->transDebugEntries_len += 1;
2853 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2854 allocSize = (allocSize * 3) / 2;
2856 (transDebugInfo *) realloc((char *)transInfo->
2857 transDebugEntries_val,
2859 sizeof(transDebugInfo));
2860 transInfo->transDebugEntries_val = pntr;
2862 transInfo->transDebugEntries_val +
2863 transInfo->transDebugEntries_len;
2864 /*set pntr to right position */
2875 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2876 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2877 afs_uint32 backupId)
2881 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2882 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2883 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2889 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2890 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2891 afs_uint32 backupId)
2895 register struct volser_trans *tt;
2896 char caller[MAXKTCNAMELEN];
2898 if (strlen(name) > 31)
2899 return VOLSERBADNAME;
2900 if (!afsconf_SuperUser(tdir, acid, caller))
2901 return VOLSERBAD_ACCESS; /*not a super user */
2902 /* find the trans */
2903 tt = FindTrans(atid);
2906 if (tt->vflags & VTDeleted) {
2907 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2911 TSetRxCall(tt, acid, "SetIdsTypes");
2915 V_backupId(tv) = backupId;
2916 V_cloneId(tv) = cloneId;
2917 V_parentId(tv) = pId;
2918 strcpy((&V_disk(tv))->name, name);
2919 VUpdateVolume(&error, tv);
2921 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2926 if (TRELE(tt) && !error)
2927 return VOLSERTRELE_ERROR;
2932 if (TRELE(tt) && !error)
2933 return VOLSERTRELE_ERROR;
2938 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2942 code = VolSetDate(acid, atid, cdate);
2943 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2949 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2953 register struct volser_trans *tt;
2954 char caller[MAXKTCNAMELEN];
2956 if (!afsconf_SuperUser(tdir, acid, caller))
2957 return VOLSERBAD_ACCESS; /*not a super user */
2958 /* find the trans */
2959 tt = FindTrans(atid);
2962 if (tt->vflags & VTDeleted) {
2963 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2967 TSetRxCall(tt, acid, "SetDate");
2970 V_creationDate(tv) = cdate;
2971 VUpdateVolume(&error, tv);
2973 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2978 if (TRELE(tt) && !error)
2979 return VOLSERTRELE_ERROR;
2984 if (TRELE(tt) && !error)
2985 return VOLSERTRELE_ERROR;
2990 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2991 afs_uint32 volumeId)
2996 char caller[MAXKTCNAMELEN];
2998 register struct volser_trans *ttc;
2999 char pname[16], volname[20];
3000 struct DiskPartition64 *partP;
3001 afs_int32 ret = ENODEV;
3004 if (!afsconf_SuperUser(tdir, acid, caller))
3005 return VOLSERBAD_ACCESS; /*not a super user */
3006 if (GetPartName(partId, pname))
3007 return VOLSERILLEGAL_PARTITION;
3008 if (!(partP = VGetPartition(pname, 0)))
3009 return VOLSERILLEGAL_PARTITION;
3010 dirp = opendir(VPartitionPath(partP));
3012 return VOLSERILLEGAL_PARTITION;
3013 strcpy(volname, "");
3014 ttc = (struct volser_trans *)0;
3016 while (strcmp(volname, "EOD")) {
3017 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3018 GetNextVol(dirp, volname, &volid);
3019 continue; /*back to while loop */
3022 if (volid == volumeId) { /*copy other things too */
3023 #ifndef AFS_PTHREAD_ENV
3024 IOMGR_Poll(); /*make sure that the client doesnot time out */
3026 ttc = NewTrans(volumeId, partId);
3028 return VOLSERVOLBUSY;
3030 #ifdef AFS_NAMEI_ENV
3031 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3033 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3037 GetNextVol(dirp, volname, &volid);
3041 DeleteTrans(ttc, 1);
3042 ttc = (struct volser_trans *)0;
3051 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3052 register struct volintSize *size)
3055 register struct volser_trans *tt;
3056 char caller[MAXKTCNAMELEN];
3058 if (!afsconf_SuperUser(tdir, acid, caller))
3059 return VOLSERBAD_ACCESS; /*not a super user */
3060 tt = FindTrans(fromTrans);
3063 if (tt->vflags & VTDeleted) {
3067 TSetRxCall(tt, acid, "GetSize");
3068 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3071 return VOLSERTRELE_ERROR;
3073 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3078 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3079 afs_uint32 where, afs_int32 verbose)
3081 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3083 Volume *vol=0, *newvol=0;
3084 struct volser_trans *tt = 0, *tt2 = 0;
3085 char caller[MAXKTCNAMELEN];
3088 if (!afsconf_SuperUser(tdir, acall, caller))
3091 vol = VAttachVolume(&code, vid, V_VOLUPD);
3097 newvol = VAttachVolume(&code, new, V_VOLUPD);
3099 VDetachVolume(&code2, vol);
3104 if (V_device(vol) != V_device(newvol)
3105 || V_uniquifier(newvol) != 2) {
3106 if (V_device(vol) != V_device(newvol)) {
3107 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3109 rx_Write(acall, line, strlen(line));
3111 if (V_uniquifier(newvol) != 2) {
3112 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3113 rx_Write(acall, line, strlen(line));
3116 rx_Write(acall, line, 1);
3117 VDetachVolume(&code2, vol);
3118 VDetachVolume(&code2, newvol);
3121 tt = NewTrans(vid, V_device(vol));
3123 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3124 rx_Write(acall, line, strlen(line));
3126 rx_Write(acall, line, 1);
3127 VDetachVolume(&code2, vol);
3128 VDetachVolume(&code2, newvol);
3129 return VOLSERVOLBUSY;
3131 VTRANS_OBJ_LOCK(tt);
3132 tt->iflags = ITBusy;
3134 TSetRxCall_r(tt, NULL, "SplitVolume");
3135 VTRANS_OBJ_UNLOCK(tt);
3137 tt2 = NewTrans(new, V_device(newvol));
3139 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3140 rx_Write(acall, line, strlen(line));
3142 rx_Write(acall, line, 1);
3144 VDetachVolume(&code2, vol);
3145 VDetachVolume(&code2, newvol);
3146 return VOLSERVOLBUSY;
3148 VTRANS_OBJ_LOCK(tt2);
3149 tt2->iflags = ITBusy;
3151 TSetRxCall_r(tt2, NULL, "SplitVolume");
3152 VTRANS_OBJ_UNLOCK(tt2);
3154 code = split_volume(acall, vol, newvol, where, verbose);
3156 VDetachVolume(&code2, vol);
3158 VDetachVolume(&code2, newvol);
3159 DeleteTrans(tt2, 1);
3166 /* GetPartName - map partid (a decimal number) into pname (a string)
3167 * Since for NT we actually want to return the drive name, we map through the
3171 GetPartName(afs_int32 partid, char *pname)
3176 strcpy(pname, "/vicep");
3177 pname[6] = 'a' + partid;
3180 } else if (partid < VOLMAXPARTS) {
3181 strcpy(pname, "/vicep");
3183 pname[6] = 'a' + (partid / 26);
3184 pname[7] = 'a' + (partid % 26);