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 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)
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];
341 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
344 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
346 V_pref(vp, nearInode);
348 IH_CREATE(V_linkHandle(vp), V_device(vp),
349 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
351 assert(VALID_INO(inodeNumber));
353 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
354 did.Volume = V_id(vp);
355 did.Vnode = (VnodeId) 1;
358 assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
359 DFlush(); /* flush all modified dir buffers out */
360 DZap((afs_int32 *)&dir); /* Remove all buffers for this dir */
361 length = Length(&dir); /* Remember size of this directory */
363 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
365 /* build a single entry ACL that gives all rights to system:administrators */
366 /* this section of code assumes that access list format is not going to
369 ACL = VVnodeDiskACL(vnode);
370 ACL->size = sizeof(struct acl_accessList);
371 ACL->version = ACL_ACLVERSION;
375 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
376 ACL->entries[0].rights =
377 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
378 | PRSFS_LOCK | PRSFS_ADMINISTER;
380 vnode->type = vDirectory;
382 vnode->modeBits = 0777;
383 vnode->linkCount = 2;
384 VNDISK_SET_LEN(vnode, length);
385 vnode->uniquifier = 1;
386 V_uniquifier(vp) = vnode->uniquifier + 1;
387 vnode->dataVersion = 1;
388 VNDISK_SET_INO(vnode, inodeNumber);
389 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
393 vnode->vnodeMagic = vcp->magic;
395 IH_INIT(h, vp->device, V_parentId(vp),
396 vp->vnodeIndex[vLarge].handle->ih_ino);
399 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
400 assert(nBytes == SIZEOF_LARGEDISKVNODE);
401 FDH_REALLYCLOSE(fdP);
403 VNDISK_GET_LEN(length, vnode);
404 V_diskused(vp) = nBlocks(length);
411 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
415 struct diskPartition64 *dp = (struct diskPartition64 *)
416 malloc(sizeof(struct diskPartition64));
418 code = VolPartitionInfo(acid, pname, dp);
420 strncpy(partition->name, dp->name, 32);
421 strncpy(partition->devName, dp->devName, 32);
422 partition->lock_fd = dp->lock_fd;
423 partition->free=RoundInt64ToInt32(dp->free);
424 partition->minFree=RoundInt64ToInt32(dp->minFree);
427 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
432 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
437 code = VolPartitionInfo(acid, pname, partition);
438 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
443 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
446 struct DiskPartition64 *dp;
449 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
452 dp = VGetPartition(pname, 0);
454 strncpy(partition->name, dp->name, 32);
455 strncpy(partition->devName, dp->devName, 32);
456 partition->lock_fd = (int)dp->lock_fd;
457 partition->free = dp->free;
458 partition->minFree = dp->totalUsable;
461 return VOLSERILLEGAL_PARTITION;
464 /* obliterate a volume completely, and slowly. */
466 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
470 code = VolNukeVolume(acid, apartID, avolID);
471 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
476 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
483 char caller[MAXKTCNAMELEN];
485 /* check for access */
486 if (!afsconf_SuperUser(tdir, acid, caller))
487 return VOLSERBAD_ACCESS;
489 Log("%s is executing VolNukeVolume %u\n", caller, avolID);
491 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
493 /* we first try to attach the volume in update mode, so that the file
494 * server doesn't try to use it (and abort) while (or after) we delete it.
495 * If we don't get the volume, that's fine, too. We just won't put it back.
497 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
498 code = nuke(partName, avolID);
500 VDetachVolume(&verror, tvp);
504 /* create a new volume, with name aname, on the specified partition (1..n)
505 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
506 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
507 * for the volume id (useful for things like volume restore).
508 * Return the new volume id in *avolid.
511 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
512 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
518 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
519 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
520 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
526 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
527 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
532 Error junk; /* discardable error code */
534 afs_int32 doCreateRoot = 1;
535 struct volser_trans *tt;
537 char caller[MAXKTCNAMELEN];
539 if (strlen(aname) > 31)
540 return VOLSERBADNAME;
541 if (!afsconf_SuperUser(tdir, acid, caller))
542 return VOLSERBAD_ACCESS;
544 Log("%s is executing CreateVolume '%s'\n", caller, aname);
545 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
546 return error; /*a standard unix error */
547 if (atype != readwriteVolume && atype != readonlyVolume
548 && atype != backupVolume)
550 if ((volumeID = *avolid) == 0) {
552 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
556 if ((aparent == volumeID) && (atype == readwriteVolume)) {
561 tt = NewTrans(volumeID, apart);
563 Log("1 createvolume: failed to create trans\n");
564 return VOLSERVOLBUSY; /* volume already busy! */
566 vp = VCreateVolume(&error, ppath, volumeID, aparent);
568 #ifdef AFS_DEMAND_ATTACH_FS
569 if (error != VVOLEXISTS && error != EXDEV) {
570 SalvageUnknownVolume(volumeID, ppath);
573 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
578 V_uniquifier(vp) = 1;
579 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
580 V_inService(vp) = V_blessed(vp) = 1;
582 AssignVolumeName(&V_disk(vp), aname, 0);
585 V_destroyMe(vp) = DESTROY_ME;
587 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
588 VUpdateVolume(&error, vp);
590 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
593 VDetachVolume(&junk, vp); /* rather return the real error code */
599 TSetRxCall_r(tt, acid, "CreateVolume");
600 VTRANS_OBJ_UNLOCK(tt);
601 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
604 return VOLSERTRELE_ERROR;
608 /* delete the volume associated with this transaction */
610 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
614 code = VolDeleteVolume(acid, atrans);
615 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
620 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
622 struct volser_trans *tt;
624 char caller[MAXKTCNAMELEN];
626 if (!afsconf_SuperUser(tdir, acid, caller))
627 return VOLSERBAD_ACCESS;
628 tt = FindTrans(atrans);
631 if (tt->vflags & VTDeleted) {
632 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
637 Log("%s is executing Delete Volume %u\n", caller, tt->volid);
638 TSetRxCall(tt, acid, "DeleteVolume");
639 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
640 V_destroyMe(tt->volume) = DESTROY_ME; /* so endtrans does the right fssync opcode */
642 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
644 VTRANS_OBJ_UNLOCK(tt);
646 return VOLSERTRELE_ERROR;
648 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
649 return 0; /* vpurgevolume doesn't set an error code */
652 /* make a clone of the volume associated with atrans, possibly giving it a new
653 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
654 * for the clone's id). The new clone is given the name newName. Finally,
655 * due to efficiency considerations, if purgeId is non-zero, we purge that
656 * volume when doing the clone operation. This may be useful when making
657 * new backup volumes, for instance since the net result of a clone and a
658 * purge generally leaves many inode ref counts the same, while doing them
659 * separately would result in far more iincs and idecs being peformed
660 * (and they are slow operations).
662 /* for efficiency reasons, sometimes faster to piggyback a purge here */
664 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
665 afs_int32 newType, char *newName, afs_uint32 *newNumber)
669 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
670 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
671 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
677 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
678 afs_int32 newType, char *newName, afs_uint32 *newNumber)
681 struct Volume *originalvp, *purgevp, *newvp;
683 struct volser_trans *tt, *ttc;
684 char caller[MAXKTCNAMELEN];
685 #ifdef AFS_DEMAND_ATTACH_FS
686 struct Volume *salv_vp = NULL;
689 if (strlen(newName) > 31)
690 return VOLSERBADNAME;
691 if (!afsconf_SuperUser(tdir, acid, caller))
692 return VOLSERBAD_ACCESS; /*not a super user */
694 Log("%s is executing Clone Volume new name=%s\n", caller, newName);
696 originalvp = (Volume *) 0;
697 purgevp = (Volume *) 0;
698 newvp = (Volume *) 0;
699 tt = ttc = (struct volser_trans *)0;
701 if (!newNumber || !*newNumber) {
702 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
707 if (newType != readonlyVolume && newType != backupVolume)
709 tt = FindTrans(atrans);
712 if (tt->vflags & VTDeleted) {
713 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
717 ttc = NewTrans(newId, tt->partition);
718 if (!ttc) { /* someone is messing with the clone already */
720 return VOLSERVOLBUSY;
722 TSetRxCall(tt, acid, "Clone");
726 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
728 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
734 originalvp = tt->volume;
735 if ((V_type(originalvp) == backupVolume)
736 || (V_type(originalvp) == readonlyVolume)) {
737 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
741 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
742 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
748 if (originalvp->device != purgevp->device) {
749 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
753 if (V_type(purgevp) != readonlyVolume) {
754 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
758 if (V_type(originalvp) == readonlyVolume
759 && V_parentId(originalvp) != V_parentId(purgevp)) {
760 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
764 if (V_type(originalvp) == readwriteVolume
765 && tt->volid != V_parentId(purgevp)) {
766 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
773 #ifdef AFS_DEMAND_ATTACH_FS
774 salv_vp = originalvp;
778 VCreateVolume(&error, originalvp->partition->name, newId,
779 V_parentId(originalvp));
781 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
782 newvp = (Volume *) 0;
785 if (newType == readonlyVolume)
786 V_cloneId(originalvp) = newId;
787 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
790 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
791 CloneVolume(&error, originalvp, newvp, purgevp);
792 purgevp = NULL; /* clone releases it, maybe even if error */
794 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
798 if (newType == readonlyVolume) {
799 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
800 V_type(newvp) = readonlyVolume;
801 } else if (newType == backupVolume) {
802 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
803 V_type(newvp) = backupVolume;
804 V_backupId(originalvp) = newId;
806 strcpy(newvp->header->diskstuff.name, newName);
807 V_creationDate(newvp) = V_copyDate(newvp);
808 ClearVolumeStats(&V_disk(newvp));
809 V_destroyMe(newvp) = DESTROY_ME;
810 V_inService(newvp) = 0;
811 if (newType == backupVolume) {
812 V_backupDate(originalvp) = V_copyDate(newvp);
813 V_backupDate(newvp) = V_copyDate(newvp);
816 VUpdateVolume(&error, newvp);
818 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
822 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
824 VUpdateVolume(&error, originalvp);
826 Log("1 Volser: Clone: original update %u\n", error);
831 #ifdef AFS_DEMAND_ATTACH_FS
835 tt = (struct volser_trans *)0;
836 error = VOLSERTRELE_ERROR;
844 VDetachVolume(&code, purgevp);
846 VDetachVolume(&code, newvp);
853 #ifdef AFS_DEMAND_ATTACH_FS
854 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
856 VRequestSalvage_r(&salv_error, salv_vp, FSYNC_SALVAGE, 0);
858 #endif /* AFS_DEMAND_ATTACH_FS */
862 /* reclone this volume into the specified id */
864 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
868 code = VolReClone(acid, atrans, cloneId);
869 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
875 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
877 struct Volume *originalvp, *clonevp;
880 struct volser_trans *tt, *ttc;
881 char caller[MAXKTCNAMELEN];
883 /*not a super user */
884 if (!afsconf_SuperUser(tdir, acid, caller))
885 return VOLSERBAD_ACCESS;
887 Log("%s is executing Reclone Volume %u\n", caller, cloneId);
889 clonevp = originalvp = (Volume *) 0;
890 tt = (struct volser_trans *)0;
892 tt = FindTrans(atrans);
895 if (tt->vflags & VTDeleted) {
896 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
900 ttc = NewTrans(cloneId, tt->partition);
901 if (!ttc) { /* someone is messing with the clone already */
903 return VOLSERVOLBUSY;
905 TSetRxCall(tt, acid, "ReClone");
907 originalvp = tt->volume;
908 if ((V_type(originalvp) == backupVolume)
909 || (V_type(originalvp) == readonlyVolume)) {
910 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
914 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
915 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
921 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
923 Log("1 Volser: can't attach clone %d\n", cloneId);
927 newType = V_type(clonevp); /* type of the new volume */
929 if (originalvp->device != clonevp->device) {
930 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
935 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
936 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
940 if (V_type(originalvp) == readonlyVolume
941 && V_parentId(originalvp) != V_parentId(clonevp)) {
942 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
946 if (V_type(originalvp) == readwriteVolume
947 && tt->volid != V_parentId(clonevp)) {
948 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
954 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
956 CloneVolume(&error, originalvp, clonevp, clonevp);
958 Log("1 Volser: Clone: reclone operation failed with code %d\n",
964 /* fix up volume name and type, CloneVolume just propagated RW's */
965 if (newType == readonlyVolume) {
966 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
967 V_type(clonevp) = readonlyVolume;
968 } else if (newType == backupVolume) {
969 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
970 V_type(clonevp) = backupVolume;
971 V_backupId(originalvp) = cloneId;
973 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
975 /* pretend recloned volume is a totally new instance */
976 V_copyDate(clonevp) = time(0);
977 V_creationDate(clonevp) = V_copyDate(clonevp);
978 ClearVolumeStats(&V_disk(clonevp));
979 V_destroyMe(clonevp) = 0;
980 V_inService(clonevp) = 0;
981 if (newType == backupVolume) {
982 V_backupDate(originalvp) = V_copyDate(clonevp);
983 V_backupDate(clonevp) = V_copyDate(clonevp);
985 V_inUse(clonevp) = 0;
986 VUpdateVolume(&error, clonevp);
988 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
992 /* VUpdateVolume succeeded. Mark it in service so there's no window
993 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
994 * specialStatus; this is a reclone and this volume started online
996 V_inService(clonevp) = 1;
997 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
999 VUpdateVolume(&error, originalvp);
1001 Log("1 Volser: Clone: original update %u\n", error);
1007 tt = (struct volser_trans *)0;
1008 error = VOLSERTRELE_ERROR;
1012 DeleteTrans(ttc, 1);
1015 struct DiskPartition64 *tpartp = originalvp->partition;
1016 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1022 VDetachVolume(&code, clonevp);
1028 DeleteTrans(ttc, 1);
1032 /* create a new transaction, associated with volume and partition. Type of
1033 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1034 * See volser.h for definition of iflags (the constants are named IT*).
1037 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1038 afs_int32 iflags, afs_int32 *ttid)
1042 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1043 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1049 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1050 afs_int32 iflags, afs_int32 *ttid)
1052 struct volser_trans *tt;
1057 char caller[MAXKTCNAMELEN];
1059 if (!afsconf_SuperUser(tdir, acid, caller))
1060 return VOLSERBAD_ACCESS; /*not a super user */
1061 if (iflags & ITCreate)
1063 else if (iflags & ITBusy)
1065 else if (iflags & ITReadOnly)
1067 else if (iflags & ITOffline)
1070 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1075 tt = NewTrans(volume, partition);
1077 /* can't create a transaction? put the volume back */
1078 Log("1 transcreate: can't create transaction\n");
1079 return VOLSERVOLBUSY;
1081 tv = XAttachVolume(&error, volume, partition, mode);
1085 VDetachVolume(&code, tv);
1089 VTRANS_OBJ_LOCK(tt);
1092 tt->iflags = iflags;
1094 TSetRxCall_r(tt, NULL, "TransCreate");
1095 VTRANS_OBJ_UNLOCK(tt);
1097 return VOLSERTRELE_ERROR;
1102 /* using aindex as a 0-based index, return the aindex'th volume on this server
1103 * Both the volume number and partition number (one-based) are returned.
1106 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1111 code = VolGetNthVolume(acid, aindex, avolume, apart);
1112 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1117 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1120 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1124 /* return the volume flags (VT* constants in volser.h) associated with this
1128 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1132 code = VolGetFlags(acid, atid, aflags);
1133 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1138 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1140 struct volser_trans *tt;
1142 tt = FindTrans(atid);
1145 if (tt->vflags & VTDeleted) {
1146 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1151 TSetRxCall(tt, acid, "GetFlags");
1152 *aflags = tt->vflags;
1155 return VOLSERTRELE_ERROR;
1160 /* Change the volume flags (VT* constants in volser.h) associated with this
1161 * transaction. Effects take place immediately on volume, although volume
1162 * remains attached as usual by the transaction.
1165 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1169 code = VolSetFlags(acid, atid, aflags);
1170 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1176 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1178 struct volser_trans *tt;
1181 char caller[MAXKTCNAMELEN];
1183 if (!afsconf_SuperUser(tdir, acid, caller))
1184 return VOLSERBAD_ACCESS; /*not a super user */
1185 /* find the trans */
1186 tt = FindTrans(atid);
1189 if (tt->vflags & VTDeleted) {
1190 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1195 TSetRxCall(tt, acid, "SetFlags");
1196 vp = tt->volume; /* pull volume out of transaction */
1198 /* check if we're allowed to make any updates */
1199 if (tt->iflags & ITReadOnly) {
1204 /* handle delete-on-salvage flag */
1205 if (aflags & VTDeleteOnSalvage) {
1206 V_destroyMe(tt->volume) = DESTROY_ME;
1208 V_destroyMe(tt->volume) = 0;
1211 if (aflags & VTOutOfService) {
1212 V_inService(vp) = 0;
1214 V_inService(vp) = 1;
1216 VUpdateVolume(&error, vp);
1217 VTRANS_OBJ_LOCK(tt);
1218 tt->vflags = aflags;
1220 VTRANS_OBJ_UNLOCK(tt);
1221 if (TRELE(tt) && !error)
1222 return VOLSERTRELE_ERROR;
1227 /* dumpS the volume associated with a particular transaction from a particular
1228 * date. Send the dump to a different transaction (destTrans) on the server
1229 * specified by the destServer structure.
1232 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1233 struct destServer *destination, afs_int32 destTrans,
1234 struct restoreCookie *cookie)
1239 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1240 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1241 destination->destHost, AUD_LONG, destTrans, AUD_END);
1246 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1247 struct destServer *destination, afs_int32 destTrans,
1248 struct restoreCookie *cookie)
1250 struct volser_trans *tt;
1252 struct rx_connection *tcon;
1253 struct rx_call *tcall;
1255 struct rx_securityClass *securityObject;
1256 afs_int32 securityIndex;
1257 char caller[MAXKTCNAMELEN];
1259 if (!afsconf_SuperUser(tdir, acid, caller))
1260 return VOLSERBAD_ACCESS; /*not a super user */
1261 /* initialize things */
1262 tcon = (struct rx_connection *)0;
1263 tt = (struct volser_trans *)0;
1265 /* find the local transaction */
1266 tt = FindTrans(fromTrans);
1269 if (tt->vflags & VTDeleted) {
1270 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1275 TSetRxCall(tt, NULL, "Forward");
1277 /* get auth info for the this connection (uses afs from ticket file) */
1278 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1284 /* make an rpc connection to the other server */
1286 rx_NewConnection(htonl(destination->destHost),
1287 htons(destination->destPort), VOLSERVICE_ID,
1288 securityObject, securityIndex);
1294 tcall = rx_NewCall(tcon);
1295 TSetRxCall(tt, tcall, "Forward");
1296 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1297 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1302 /* these next calls implictly call rx_Write when writing out data */
1303 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1306 EndAFSVolRestore(tcall); /* probably doesn't do much */
1308 code = rx_EndCall(tcall, 0);
1309 rx_DestroyConnection(tcon); /* done with the connection */
1314 return VOLSERTRELE_ERROR;
1320 (void)rx_EndCall(tcall, 0);
1321 rx_DestroyConnection(tcon);
1330 /* Start a dump and send it to multiple places simultaneously.
1331 * If this returns an error (eg, return ENOENT), it means that
1332 * none of the releases worked. If this returns 0, that means
1333 * that one or more of the releases worked, and the caller has
1334 * to examine the results array to see which one(s).
1335 * This will only do EITHER incremental or full, not both, so it's
1336 * the caller's responsibility to be sure that all the destinations
1337 * need just an incremental (and from the same time), if that's
1341 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1342 fromDate, manyDests *destinations, afs_int32 spare,
1343 struct restoreCookie *cookie, manyResults *results)
1345 afs_int32 securityIndex;
1346 struct rx_securityClass *securityObject;
1347 char caller[MAXKTCNAMELEN];
1348 struct volser_trans *tt;
1349 afs_int32 ec, code, *codes;
1350 struct rx_connection **tcons;
1351 struct rx_call **tcalls;
1353 int i, is_incremental;
1356 memset(results, 0, sizeof(manyResults));
1357 i = results->manyResults_len = destinations->manyDests_len;
1358 results->manyResults_val = codes =
1359 (afs_int32 *) malloc(i * sizeof(afs_int32));
1361 if (!results || !results->manyResults_val)
1364 if (!afsconf_SuperUser(tdir, acid, caller))
1365 return VOLSERBAD_ACCESS; /*not a super user */
1366 tt = FindTrans(fromTrans);
1369 if (tt->vflags & VTDeleted) {
1370 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1375 TSetRxCall(tt, NULL, "ForwardMulti");
1377 /* (fromDate == 0) ==> full dump */
1378 is_incremental = (fromDate ? 1 : 0);
1381 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1385 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1391 /* get auth info for this connection (uses afs from ticket file) */
1392 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1394 goto fail; /* in order to audit each failure */
1397 /* make connections to all the other servers */
1398 for (i = 0; i < destinations->manyDests_len; i++) {
1399 struct replica *dest = &(destinations->manyDests_val[i]);
1401 rx_NewConnection(htonl(dest->server.destHost),
1402 htons(dest->server.destPort), VOLSERVICE_ID,
1403 securityObject, securityIndex);
1405 codes[i] = ENOTCONN;
1407 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1408 codes[i] = ENOTCONN;
1411 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1414 (void)rx_EndCall(tcalls[i], 0);
1416 rx_DestroyConnection(tcons[i]);
1423 /* these next calls implictly call rx_Write when writing out data */
1424 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1428 for (i--; i >= 0; i--) {
1429 struct replica *dest = &(destinations->manyDests_val[i]);
1431 if (!code && tcalls[i] && !codes[i]) {
1432 EndAFSVolRestore(tcalls[i]);
1435 ec = rx_EndCall(tcalls[i], 0);
1440 rx_DestroyConnection(tcons[i]); /* done with the connection */
1443 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1444 fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG,
1445 dest->trans, AUD_END);
1452 if (TRELE(tt) && !code) /* return the first code if it's set */
1453 return VOLSERTRELE_ERROR;
1460 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1464 code = VolDump(acid, fromTrans, fromDate, 0);
1465 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1470 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1475 code = VolDump(acid, fromTrans, fromDate, flags);
1476 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1481 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1485 struct volser_trans *tt;
1486 char caller[MAXKTCNAMELEN];
1488 if (!afsconf_SuperUser(tdir, acid, caller))
1489 return VOLSERBAD_ACCESS; /*not a super user */
1490 tt = FindTrans(fromTrans);
1493 if (tt->vflags & VTDeleted) {
1494 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1498 TSetRxCall(tt, acid, "Dump");
1499 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1500 ? 0 : 1); /* squirt out the volume's data, too */
1509 return VOLSERTRELE_ERROR;
1515 * Ha! No more helper process!
1518 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1519 struct restoreCookie *cookie)
1523 code = VolRestore(acid, atrans, aflags, cookie);
1524 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1529 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1530 struct restoreCookie *cookie)
1532 struct volser_trans *tt;
1533 afs_int32 code, tcode;
1534 char caller[MAXKTCNAMELEN];
1536 if (!afsconf_SuperUser(tdir, acid, caller))
1537 return VOLSERBAD_ACCESS; /*not a super user */
1538 tt = FindTrans(atrans);
1541 if (tt->vflags & VTDeleted) {
1542 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1546 TSetRxCall(tt, acid, "Restore");
1548 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1550 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1551 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1555 return (code ? code : tcode);
1558 /* end a transaction, returning the transaction's final error code in rcode */
1560 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1564 code = VolEndTrans(acid, destTrans, rcode);
1565 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1570 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1572 struct volser_trans *tt;
1573 char caller[MAXKTCNAMELEN];
1575 if (!afsconf_SuperUser(tdir, acid, caller))
1576 return VOLSERBAD_ACCESS; /*not a super user */
1577 tt = FindTrans(destTrans);
1581 *rcode = tt->returnCode;
1582 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1588 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1592 code = VolSetForwarding(acid, atid, anewsite);
1593 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1599 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1601 struct volser_trans *tt;
1602 char caller[MAXKTCNAMELEN];
1605 if (!afsconf_SuperUser(tdir, acid, caller))
1606 return VOLSERBAD_ACCESS; /*not a super user */
1607 tt = FindTrans(atid);
1610 if (tt->vflags & VTDeleted) {
1611 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1616 TSetRxCall(tt, acid, "SetForwarding");
1617 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1620 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1623 return VOLSERTRELE_ERROR;
1629 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1630 struct volser_status *astatus)
1634 code = VolGetStatus(acid, atrans, astatus);
1635 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1640 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1641 struct volser_status *astatus)
1644 struct VolumeDiskData *td;
1645 struct volser_trans *tt;
1648 tt = FindTrans(atrans);
1651 if (tt->vflags & VTDeleted) {
1652 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1657 TSetRxCall(tt, acid, "GetStatus");
1665 td = &tv->header->diskstuff;
1666 astatus->volID = td->id;
1667 astatus->nextUnique = td->uniquifier;
1668 astatus->type = td->type;
1669 astatus->parentID = td->parentId;
1670 astatus->cloneID = td->cloneId;
1671 astatus->backupID = td->backupId;
1672 astatus->restoredFromID = td->restoredFromId;
1673 astatus->maxQuota = td->maxquota;
1674 astatus->minQuota = td->minquota;
1675 astatus->owner = td->owner;
1676 astatus->creationDate = td->creationDate;
1677 astatus->accessDate = td->accessDate;
1678 astatus->updateDate = td->updateDate;
1679 astatus->expirationDate = td->expirationDate;
1680 astatus->backupDate = td->backupDate;
1681 astatus->copyDate = td->copyDate;
1684 return VOLSERTRELE_ERROR;
1690 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1691 struct volintInfo *astatus)
1695 code = VolSetInfo(acid, atrans, astatus);
1696 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1701 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1702 struct volintInfo *astatus)
1705 struct VolumeDiskData *td;
1706 struct volser_trans *tt;
1707 char caller[MAXKTCNAMELEN];
1710 if (!afsconf_SuperUser(tdir, acid, caller))
1711 return VOLSERBAD_ACCESS; /*not a super user */
1712 tt = FindTrans(atrans);
1715 if (tt->vflags & VTDeleted) {
1716 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1720 TSetRxCall(tt, acid, "SetStatus");
1728 td = &tv->header->diskstuff;
1730 * Add more fields as necessary
1732 if (astatus->maxquota != -1)
1733 td->maxquota = astatus->maxquota;
1734 if (astatus->dayUse != -1)
1735 td->dayUse = astatus->dayUse;
1736 if (astatus->creationDate != -1)
1737 td->creationDate = astatus->creationDate;
1738 if (astatus->updateDate != -1)
1739 td->updateDate = astatus->updateDate;
1740 if (astatus->spare2 != -1)
1741 td->volUpdateCounter = (unsigned int)astatus->spare2;
1742 VUpdateVolume(&error, tv);
1745 return VOLSERTRELE_ERROR;
1751 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1755 code = VolGetName(acid, atrans, aname);
1756 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1761 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1764 struct VolumeDiskData *td;
1765 struct volser_trans *tt;
1768 /* We need to at least fill it in */
1769 *aname = (char *)malloc(1);
1772 tt = FindTrans(atrans);
1775 if (tt->vflags & VTDeleted) {
1776 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1780 TSetRxCall(tt, acid, "GetName");
1788 td = &tv->header->diskstuff;
1789 len = strlen(td->name) + 1; /* don't forget the null */
1795 *aname = (char *)realloc(*aname, len);
1796 strcpy(*aname, td->name);
1799 return VOLSERTRELE_ERROR;
1804 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1807 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1808 afs_uint32 parentId, afs_uint32 cloneId)
1814 /*return a list of all partitions on the server. The non mounted
1815 *partitions are returned as -1 in the corresponding slot in partIds*/
1817 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1821 code = VolListPartitions(acid, partIds);
1822 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1827 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1832 strcpy(namehead, "/vicep"); /*7 including null terminator */
1834 /* Just return attached partitions. */
1836 for (i = 0; i < 26; i++) {
1837 namehead[6] = i + 'a';
1838 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1844 /*return a list of all partitions on the server. The non mounted
1845 *partitions are returned as -1 in the corresponding slot in partIds*/
1847 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1851 code = XVolListPartitions(acid, pEntries);
1852 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1857 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1860 struct partList partList;
1861 struct DiskPartition64 *dp;
1864 strcpy(namehead, "/vicep"); /*7 including null terminator */
1866 /* Only report attached partitions */
1867 for (i = 0; i < VOLMAXPARTS; i++) {
1868 #ifdef AFS_DEMAND_ATTACH_FS
1869 dp = VGetPartitionById(i, 0);
1872 namehead[6] = i + 'a';
1878 namehead[6] = 'a' + (k / 26);
1879 namehead[7] = 'a' + (k % 26);
1882 dp = VGetPartition(namehead, 0);
1885 partList.partId[j++] = i;
1887 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1888 if (!pEntries->partEntries_val)
1890 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1892 pEntries->partEntries_len = j;
1897 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1899 ExtractVolId(char vname[])
1902 char name[VOLSER_MAXVOLNAME + 1];
1904 strcpy(name, vname);
1906 while (name[i] == 'V' || name[i] == '0')
1909 name[11] = '\0'; /* smash the "." */
1910 return (atol(&name[i]));
1913 /*return the name of the next volume header in the directory associated with dirp and dp.
1914 *the volume id is returned in volid, and volume header name is returned in volname*/
1916 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1920 dp = readdir(dirp); /*read next entry in the directory */
1922 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1923 *volid = ExtractVolId(dp->d_name);
1924 strcpy(volname, dp->d_name);
1925 return 0; /*return the name of the file representing a volume */
1927 strcpy(volname, "");
1928 return 0; /*volname doesnot represent a volume */
1931 strcpy(volname, "EOD");
1932 return 0; /*end of directory */
1938 * volint vol info structure type.
1941 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1942 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1943 } volint_info_type_t;
1946 * handle to various on-wire vol info types.
1949 volint_info_type_t volinfo_type;
1955 } volint_info_handle_t;
1958 * store value to a field at the appropriate location in on-wire structure.
1960 #define VOLINT_INFO_STORE(handle, name, val) \
1962 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1963 (handle)->volinfo_ptr.base->name = (val); \
1965 (handle)->volinfo_ptr.ext->name = (val); \
1970 * get pointer to appropriate offset of field in on-wire structure.
1972 #define VOLINT_INFO_PTR(handle, name) \
1973 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1974 &((handle)->volinfo_ptr.base->name) : \
1975 &((handle)->volinfo_ptr.ext->name))
1978 * fill in appropriate type of on-wire volume metadata structure.
1980 * @param vp pointer to volume object
1981 * @param handle pointer to wire format handle object
1983 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1984 * @pre handle object must have a valid pointer and enumeration value
1986 * @note passing a NULL value for vp means that the fileserver doesn't
1987 * know about this particular volume, thus implying it is offline.
1989 * @return operation status
1994 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1996 unsigned int numStatBytes, now;
1997 struct VolumeDiskData *hdr = &vp->header->diskstuff;
1999 /*read in the relevant info */
2000 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2001 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
2002 VOLINT_INFO_STORE(handle, volid, hdr->id);
2003 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2004 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2005 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2006 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2007 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2008 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2009 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2010 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2011 now = FT_ApproxTime();
2012 if ((now - hdr->dayUseDate) > OneDay) {
2013 VOLINT_INFO_STORE(handle, dayUse, 0);
2015 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2017 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2018 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2019 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2020 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2022 #ifdef AFS_DEMAND_ATTACH_FS
2024 * for DAFS, we "lie" about volume state --
2025 * instead of returning the raw state from the disk header,
2026 * we compute state based upon the fileserver's internal
2027 * in-core state enumeration value reported to us via fssync,
2028 * along with the blessed and inService flags from the header.
2029 * -- tkeiser 11/27/2007
2032 /* Conditions that offline status is based on:
2033 volume is unattached state
2034 volume state is in (one of several error states)
2035 volume not in service
2036 volume is not marked as blessed (not on hold)
2037 volume in salvage req. state
2038 volume needsSalvaged
2039 next op would set volume offline
2040 next op would not leave volume online (based on several conditions)
2043 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2044 VIsErrorState(V_attachState(vp)) ||
2047 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2048 hdr->needsSalvaged ||
2049 (vp->pending_vol_op &&
2050 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2051 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2054 VOLINT_INFO_STORE(handle, inUse, 0);
2056 VOLINT_INFO_STORE(handle, inUse, 1);
2059 /* offline status based on program type, where != fileServer enum (1) is offline */
2060 if (hdr->inUse == fileServer) {
2061 VOLINT_INFO_STORE(handle, inUse, 1);
2063 VOLINT_INFO_STORE(handle, inUse, 0);
2068 switch(handle->volinfo_type) {
2069 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2070 case VOLINT_INFO_TYPE_BASE:
2072 #ifdef AFS_DEMAND_ATTACH_FS
2073 /* see comment above where we set inUse bit */
2074 if (hdr->needsSalvaged ||
2075 (vp && VIsErrorState(V_attachState(vp)))) {
2076 handle->volinfo_ptr.base->needsSalvaged = 1;
2078 handle->volinfo_ptr.base->needsSalvaged = 0;
2081 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2083 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2084 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2085 handle->volinfo_ptr.base->spare1 =
2086 (long)hdr->weekUse[0] +
2087 (long)hdr->weekUse[1] +
2088 (long)hdr->weekUse[2] +
2089 (long)hdr->weekUse[3] +
2090 (long)hdr->weekUse[4] +
2091 (long)hdr->weekUse[5] +
2092 (long)hdr->weekUse[6];
2093 handle->volinfo_ptr.base->flags = 0;
2094 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2095 handle->volinfo_ptr.base->spare3 = 0;
2099 case VOLINT_INFO_TYPE_EXT:
2101 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2102 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2105 * Copy out the stat fields in a single operation.
2107 if ((now - hdr->dayUseDate) > OneDay) {
2108 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2111 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2112 (char *)&(hdr->stat_reads[0]),
2121 #ifdef AFS_DEMAND_ATTACH_FS
2124 * get struct Volume out of the fileserver.
2126 * @param[in] volumeId volumeId for which we want state information
2127 * @param[in] pname partition name string
2128 * @param[inout] vp pointer to pointer to Volume object which
2129 * will be populated (see note)
2131 * @return operation status
2133 * @retval non-zero failure
2135 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2140 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2145 res.hdr.response_len = sizeof(res.hdr);
2146 res.payload.buf = *vp;
2147 res.payload.len = sizeof(Volume);
2149 code = FSYNC_VolOp(volumeId,
2155 if (code != SYNC_OK) {
2156 switch (res.hdr.reason) {
2157 case FSYNC_WRONG_PART:
2158 case FSYNC_UNKNOWN_VOLID:
2171 * mode of volume list operation.
2174 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2175 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2176 } vol_info_list_mode_t;
2179 * abstract interface to populate wire-format volume metadata structures.
2181 * @param[in] partId partition id
2182 * @param[in] volumeId volume id
2183 * @param[in] pname partition name
2184 * @param[in] volname volume file name
2185 * @param[in] handle handle to on-wire volume metadata object
2186 * @param[in] mode listing mode
2188 * @return operation status
2190 * @retval -2 DESTROY_ME flag is set
2191 * @retval -1 general failure; some data filled in
2192 * @retval -3 couldn't create vtrans; some data filled in
2195 GetVolInfo(afs_uint32 partId,
2196 afs_uint32 volumeId,
2199 volint_info_handle_t * handle,
2200 vol_info_list_mode_t mode)
2204 struct volser_trans *ttc = NULL;
2205 struct Volume *fill_tv, *tv = NULL;
2206 #ifdef AFS_DEMAND_ATTACH_FS
2207 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2208 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2209 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2210 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2212 /* Set up response handle for pending_vol_op */
2213 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2214 fs_res.payload.buf = fs_res_buf;
2215 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2218 ttc = NewTrans(volumeId, partId);
2221 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2222 VOLINT_INFO_STORE(handle, volid, volumeId);
2226 /* Get volume from volserver */
2227 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2229 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2230 volumeId, pname, volname, error);
2235 * please note that destroyMe and needsSalvaged checks used to be ordered
2236 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2237 * more correct to check destroyMe before needsSalvaged.
2238 * -- tkeiser 11/28/2007
2241 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2243 case VOL_INFO_LIST_MULTIPLE:
2247 case VOL_INFO_LIST_SINGLE:
2248 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2249 volumeId, pname, volname);
2256 if (tv->header->diskstuff.needsSalvaged) {
2257 /*this volume will be salvaged */
2258 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2259 volumeId, pname, volname);
2262 #ifdef AFS_DEMAND_ATTACH_FS
2263 /* If using DAFS, get volume from fsserver */
2264 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2269 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2270 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2271 /* If we if the pending vol op */
2272 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2273 fs_tv->pending_vol_op=&pending_vol_op_res;
2275 fs_tv->pending_vol_op=NULL;
2278 /* populate the header from the volserver copy */
2279 fs_tv->header=tv->header;
2281 /* When using DAFS, use the fs volume info, populated with required structures */
2284 /* When not using DAFS, just use the local volume info */
2288 /* ok, we have all the data we need; fill in the on-wire struct */
2289 code = FillVolInfo(fill_tv, handle);
2293 VOLINT_INFO_STORE(handle, status, 0);
2294 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2295 VOLINT_INFO_STORE(handle, volid, volumeId);
2298 VDetachVolume(&error, tv);
2301 VOLINT_INFO_STORE(handle, status, 0);
2302 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2303 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2304 volumeId, pname, volname);
2308 DeleteTrans(ttc, 1);
2315 /*return the header information about the <volid> */
2317 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2318 afs_uint32 volumeId, volEntries *volumeInfo)
2322 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2323 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2328 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2329 afs_uint32 volumeId, volEntries *volumeInfo)
2331 struct DiskPartition64 *partP;
2332 char pname[9], volname[20];
2337 volint_info_handle_t handle;
2339 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2340 if (!volumeInfo->volEntries_val)
2342 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2344 volumeInfo->volEntries_len = 1;
2345 if (GetPartName(partid, pname))
2346 return VOLSERILLEGAL_PARTITION;
2347 if (!(partP = VGetPartition(pname, 0)))
2348 return VOLSERILLEGAL_PARTITION;
2349 dirp = opendir(VPartitionPath(partP));
2351 return VOLSERILLEGAL_PARTITION;
2353 strcpy(volname, "");
2355 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2357 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2358 GetNextVol(dirp, volname, &volid);
2359 continue; /*back to while loop */
2362 if (volid == volumeId) { /*copy other things too */
2367 GetNextVol(dirp, volname, &volid);
2371 #ifndef AFS_PTHREAD_ENV
2372 IOMGR_Poll(); /*make sure that the client does not time out */
2375 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2376 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2378 code = GetVolInfo(partid,
2383 VOL_INFO_LIST_SINGLE);
2387 return (found) ? 0 : ENODEV;
2390 /*------------------------------------------------------------------------
2391 * EXPORTED SAFSVolXListOneVolume
2394 * Returns extended info on volume a_volID on partition a_partID.
2397 * a_rxCidP : Pointer to the Rx call we're performing.
2398 * a_partID : Partition for which we want the extended list.
2399 * a_volID : Volume ID we wish to know about.
2400 * a_volumeXInfoP : Ptr to the extended info blob.
2403 * 0 Successful operation
2404 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2407 * Nothing interesting.
2411 *------------------------------------------------------------------------*/
2414 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2415 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2419 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2420 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2425 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2426 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2427 { /*SAFSVolXListOneVolume */
2429 struct DiskPartition64 *partP; /*Ptr to partition */
2430 char pname[9], volname[20]; /*Partition, volume names */
2431 DIR *dirp; /*Partition directory ptr */
2432 afs_uint32 currVolID; /*Current volume ID */
2433 int found = 0; /*Did we find the volume we need? */
2435 volint_info_handle_t handle;
2438 * Set up our pointers for action, marking our structure to hold exactly
2439 * one entry. Also, assume we'll fail in our quest.
2441 a_volumeXInfoP->volXEntries_val =
2442 (volintXInfo *) malloc(sizeof(volintXInfo));
2443 if (!a_volumeXInfoP->volXEntries_val)
2445 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2447 a_volumeXInfoP->volXEntries_len = 1;
2451 * If the partition name we've been given is bad, bogue out.
2453 if (GetPartName(a_partID, pname))
2454 return (VOLSERILLEGAL_PARTITION);
2457 * Open the directory representing the given AFS parttion. If we can't
2460 if (!(partP = VGetPartition(pname, 0)))
2461 return VOLSERILLEGAL_PARTITION;
2462 dirp = opendir(VPartitionPath(partP));
2464 return (VOLSERILLEGAL_PARTITION);
2466 strcpy(volname, "");
2469 * Sweep through the partition directory, looking for the desired entry.
2470 * First, of course, figure out how many stat bytes to copy out of each
2473 while (strcmp(volname, "EOD") && !found) {
2475 * If this is not a volume, move on to the next entry in the
2476 * partition's directory.
2478 if (!strcmp(volname, "")) {
2479 GetNextVol(dirp, volname, &currVolID);
2483 if (currVolID == a_volID) {
2485 * We found the volume entry we're interested. Pull out the
2486 * extended information, remembering to poll (so that the client
2487 * doesn't time out) and to set up a transaction on the volume.
2491 } /*Found desired volume */
2493 GetNextVol(dirp, volname, &currVolID);
2497 #ifndef AFS_PTHREAD_ENV
2501 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2502 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2504 code = GetVolInfo(a_partID,
2509 VOL_INFO_LIST_SINGLE);
2514 * Clean up before going to dinner: close the partition directory,
2515 * return the proper value.
2518 return (found) ? 0 : ENODEV;
2519 } /*SAFSVolXListOneVolume */
2521 /*returns all the volumes on partition partid. If flags = 1 then all the
2522 * relevant info about the volumes is also returned */
2524 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2525 volEntries *volumeInfo)
2529 code = VolListVolumes(acid, partid, flags, volumeInfo);
2530 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2535 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2536 volEntries *volumeInfo)
2539 struct DiskPartition64 *partP;
2540 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2541 char pname[9], volname[20];
2545 volint_info_handle_t handle;
2547 volumeInfo->volEntries_val =
2548 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2549 if (!volumeInfo->volEntries_val)
2551 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2553 pntr = volumeInfo->volEntries_val;
2554 volumeInfo->volEntries_len = 0;
2555 if (GetPartName(partid, pname))
2556 return VOLSERILLEGAL_PARTITION;
2557 if (!(partP = VGetPartition(pname, 0)))
2558 return VOLSERILLEGAL_PARTITION;
2559 dirp = opendir(VPartitionPath(partP));
2561 return VOLSERILLEGAL_PARTITION;
2562 strcpy(volname, "");
2564 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2566 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2567 GetNextVol(dirp, volname, &volid);
2568 continue; /*back to while loop */
2571 if (flags) { /*copy other things too */
2572 #ifndef AFS_PTHREAD_ENV
2573 IOMGR_Poll(); /*make sure that the client does not time out */
2576 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2577 handle.volinfo_ptr.base = pntr;
2580 code = GetVolInfo(partid,
2585 VOL_INFO_LIST_MULTIPLE);
2586 if (code == -2) { /* DESTROY_ME flag set */
2590 pntr->volid = volid;
2591 /*just volids are needed */
2595 volumeInfo->volEntries_len += 1;
2596 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2597 /*running out of space, allocate more space */
2598 allocSize = (allocSize * 3) / 2;
2600 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2601 allocSize * sizeof(volintInfo));
2604 return VOLSERNO_MEMORY;
2606 volumeInfo->volEntries_val = pntr; /* point to new block */
2607 /* set pntr to the right position */
2608 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2613 GetNextVol(dirp, volname, &volid);
2621 /*------------------------------------------------------------------------
2622 * EXPORTED SAFSVolXListVolumes
2625 * Returns all the volumes on partition a_partID. If a_flags
2626 * is set to 1, then all the relevant extended volume information
2630 * a_rxCidP : Pointer to the Rx call we're performing.
2631 * a_partID : Partition for which we want the extended list.
2632 * a_flags : Various flags.
2633 * a_volumeXInfoP : Ptr to the extended info blob.
2636 * 0 Successful operation
2637 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2638 * VOLSERNO_MEMORY if we ran out of memory allocating
2642 * Nothing interesting.
2646 *------------------------------------------------------------------------*/
2649 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2650 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2654 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2655 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2660 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2661 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2662 { /*SAFSVolXListVolumes */
2664 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2665 struct DiskPartition64 *partP; /*Ptr to partition */
2666 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2667 char pname[9], volname[20]; /*Partition, volume names */
2668 DIR *dirp; /*Partition directory ptr */
2669 afs_uint32 volid; /*Current volume ID */
2671 volint_info_handle_t handle;
2674 * Allocate a large array of extended volume info structures, then
2675 * set it up for action.
2677 a_volumeXInfoP->volXEntries_val =
2678 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2679 if (!a_volumeXInfoP->volXEntries_val)
2681 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2683 xInfoP = a_volumeXInfoP->volXEntries_val;
2684 a_volumeXInfoP->volXEntries_len = 0;
2687 * If the partition name we've been given is bad, bogue out.
2689 if (GetPartName(a_partID, pname))
2690 return (VOLSERILLEGAL_PARTITION);
2693 * Open the directory representing the given AFS parttion. If we can't
2696 if (!(partP = VGetPartition(pname, 0)))
2697 return VOLSERILLEGAL_PARTITION;
2698 dirp = opendir(VPartitionPath(partP));
2700 return (VOLSERILLEGAL_PARTITION);
2701 strcpy(volname, "");
2704 * Sweep through the partition directory, acting on each entry. First,
2705 * of course, figure out how many stat bytes to copy out of each volume.
2707 while (strcmp(volname, "EOD")) {
2710 * If this is not a volume, move on to the next entry in the
2711 * partition's directory.
2713 if (!strcmp(volname, "")) {
2714 GetNextVol(dirp, volname, &volid);
2720 * Full info about the volume desired. Poll to make sure the
2721 * client doesn't time out, then start up a new transaction.
2723 #ifndef AFS_PTHREAD_ENV
2727 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2728 handle.volinfo_ptr.ext = xInfoP;
2730 code = GetVolInfo(a_partID,
2735 VOL_INFO_LIST_MULTIPLE);
2736 if (code == -2) { /* DESTROY_ME flag set */
2741 * Just volume IDs are needed.
2743 xInfoP->volid = volid;
2747 * Bump the pointer in the data area we're building, along with
2748 * the count of the number of entries it contains.
2751 (a_volumeXInfoP->volXEntries_len)++;
2752 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2754 * We're running out of space in the area we've built. Grow it.
2756 allocSize = (allocSize * 3) / 2;
2757 xInfoP = (volintXInfo *)
2758 realloc((char *)a_volumeXInfoP->volXEntries_val,
2759 (allocSize * sizeof(volintXInfo)));
2760 if (xInfoP == NULL) {
2762 * Bummer, no memory. Bag it, tell our caller what went wrong.
2765 return (VOLSERNO_MEMORY);
2769 * Memory reallocation worked. Correct our pointers so they
2770 * now point to the new block and the current open position within
2773 a_volumeXInfoP->volXEntries_val = xInfoP;
2775 a_volumeXInfoP->volXEntries_val +
2776 a_volumeXInfoP->volXEntries_len;
2780 GetNextVol(dirp, volname, &volid);
2781 } /*Sweep through the partition directory */
2784 * We've examined all entries in the partition directory. Close it,
2785 * delete our transaction (if any), and go home happy.
2790 } /*SAFSVolXListVolumes */
2792 /*this call is used to monitor the status of volser for debugging purposes.
2793 *information about all the active transactions is returned in transInfo*/
2795 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2799 code = VolMonitor(acid, transInfo);
2800 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2805 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2807 transDebugInfo *pntr;
2808 afs_int32 allocSize = 50;
2809 struct volser_trans *tt, *nt, *allTrans;
2811 transInfo->transDebugEntries_val =
2812 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2813 if (!transInfo->transDebugEntries_val)
2815 pntr = transInfo->transDebugEntries_val;
2816 transInfo->transDebugEntries_len = 0;
2819 allTrans = TransList();
2820 if (allTrans == (struct volser_trans *)0)
2821 goto done; /*no active transactions */
2822 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2824 VTRANS_OBJ_LOCK(tt);
2825 pntr->tid = tt->tid;
2826 pntr->time = tt->time;
2827 pntr->creationTime = tt->creationTime;
2828 pntr->returnCode = tt->returnCode;
2829 pntr->volid = tt->volid;
2830 pntr->partition = tt->partition;
2831 pntr->iflags = tt->iflags;
2832 pntr->vflags = tt->vflags;
2833 pntr->tflags = tt->tflags;
2834 strcpy(pntr->lastProcName, tt->lastProcName);
2835 pntr->callValid = 0;
2836 if (tt->rxCallPtr) { /*record call related info */
2837 pntr->callValid = 1;
2838 pntr->readNext = tt->rxCallPtr->rnext;
2839 pntr->transmitNext = tt->rxCallPtr->tnext;
2840 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2841 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2843 VTRANS_OBJ_UNLOCK(tt);
2845 transInfo->transDebugEntries_len += 1;
2846 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2847 allocSize = (allocSize * 3) / 2;
2849 (transDebugInfo *) realloc((char *)transInfo->
2850 transDebugEntries_val,
2852 sizeof(transDebugInfo));
2853 transInfo->transDebugEntries_val = pntr;
2855 transInfo->transDebugEntries_val +
2856 transInfo->transDebugEntries_len;
2857 /*set pntr to right position */
2868 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2869 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2870 afs_uint32 backupId)
2874 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2875 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2876 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2882 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2883 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2884 afs_uint32 backupId)
2888 struct volser_trans *tt;
2889 char caller[MAXKTCNAMELEN];
2891 if (strlen(name) > 31)
2892 return VOLSERBADNAME;
2893 if (!afsconf_SuperUser(tdir, acid, caller))
2894 return VOLSERBAD_ACCESS; /*not a super user */
2895 /* find the trans */
2896 tt = FindTrans(atid);
2899 if (tt->vflags & VTDeleted) {
2900 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2904 TSetRxCall(tt, acid, "SetIdsTypes");
2908 V_backupId(tv) = backupId;
2909 V_cloneId(tv) = cloneId;
2910 V_parentId(tv) = pId;
2911 strcpy((&V_disk(tv))->name, name);
2912 VUpdateVolume(&error, tv);
2914 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2919 if (TRELE(tt) && !error)
2920 return VOLSERTRELE_ERROR;
2925 if (TRELE(tt) && !error)
2926 return VOLSERTRELE_ERROR;
2931 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2935 code = VolSetDate(acid, atid, cdate);
2936 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2942 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2946 struct volser_trans *tt;
2947 char caller[MAXKTCNAMELEN];
2949 if (!afsconf_SuperUser(tdir, acid, caller))
2950 return VOLSERBAD_ACCESS; /*not a super user */
2951 /* find the trans */
2952 tt = FindTrans(atid);
2955 if (tt->vflags & VTDeleted) {
2956 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2960 TSetRxCall(tt, acid, "SetDate");
2963 V_creationDate(tv) = cdate;
2964 VUpdateVolume(&error, tv);
2966 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2971 if (TRELE(tt) && !error)
2972 return VOLSERTRELE_ERROR;
2977 if (TRELE(tt) && !error)
2978 return VOLSERTRELE_ERROR;
2983 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2984 afs_uint32 volumeId)
2989 char caller[MAXKTCNAMELEN];
2991 struct volser_trans *ttc;
2992 char pname[16], volname[20];
2993 struct DiskPartition64 *partP;
2994 afs_int32 ret = ENODEV;
2997 if (!afsconf_SuperUser(tdir, acid, caller))
2998 return VOLSERBAD_ACCESS; /*not a super user */
2999 if (GetPartName(partId, pname))
3000 return VOLSERILLEGAL_PARTITION;
3001 if (!(partP = VGetPartition(pname, 0)))
3002 return VOLSERILLEGAL_PARTITION;
3003 dirp = opendir(VPartitionPath(partP));
3005 return VOLSERILLEGAL_PARTITION;
3006 strcpy(volname, "");
3007 ttc = (struct volser_trans *)0;
3009 while (strcmp(volname, "EOD")) {
3010 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3011 GetNextVol(dirp, volname, &volid);
3012 continue; /*back to while loop */
3015 if (volid == volumeId) { /*copy other things too */
3016 #ifndef AFS_PTHREAD_ENV
3017 IOMGR_Poll(); /*make sure that the client doesnot time out */
3019 ttc = NewTrans(volumeId, partId);
3021 return VOLSERVOLBUSY;
3023 #ifdef AFS_NAMEI_ENV
3024 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3026 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3030 GetNextVol(dirp, volname, &volid);
3034 DeleteTrans(ttc, 1);
3035 ttc = (struct volser_trans *)0;
3044 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3045 struct volintSize *size)
3048 struct volser_trans *tt;
3049 char caller[MAXKTCNAMELEN];
3051 if (!afsconf_SuperUser(tdir, acid, caller))
3052 return VOLSERBAD_ACCESS; /*not a super user */
3053 tt = FindTrans(fromTrans);
3056 if (tt->vflags & VTDeleted) {
3060 TSetRxCall(tt, acid, "GetSize");
3061 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3064 return VOLSERTRELE_ERROR;
3066 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3071 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3072 afs_uint32 where, afs_int32 verbose)
3074 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3076 Volume *vol=0, *newvol=0;
3077 struct volser_trans *tt = 0, *tt2 = 0;
3078 char caller[MAXKTCNAMELEN];
3081 if (!afsconf_SuperUser(tdir, acall, caller))
3084 vol = VAttachVolume(&code, vid, V_VOLUPD);
3090 newvol = VAttachVolume(&code, new, V_VOLUPD);
3092 VDetachVolume(&code2, vol);
3097 if (V_device(vol) != V_device(newvol)
3098 || V_uniquifier(newvol) != 2) {
3099 if (V_device(vol) != V_device(newvol)) {
3100 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3102 rx_Write(acall, line, strlen(line));
3104 if (V_uniquifier(newvol) != 2) {
3105 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3106 rx_Write(acall, line, strlen(line));
3109 rx_Write(acall, line, 1);
3110 VDetachVolume(&code2, vol);
3111 VDetachVolume(&code2, newvol);
3114 tt = NewTrans(vid, V_device(vol));
3116 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3117 rx_Write(acall, line, strlen(line));
3119 rx_Write(acall, line, 1);
3120 VDetachVolume(&code2, vol);
3121 VDetachVolume(&code2, newvol);
3122 return VOLSERVOLBUSY;
3124 VTRANS_OBJ_LOCK(tt);
3125 tt->iflags = ITBusy;
3127 TSetRxCall_r(tt, NULL, "SplitVolume");
3128 VTRANS_OBJ_UNLOCK(tt);
3130 tt2 = NewTrans(new, V_device(newvol));
3132 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3133 rx_Write(acall, line, strlen(line));
3135 rx_Write(acall, line, 1);
3137 VDetachVolume(&code2, vol);
3138 VDetachVolume(&code2, newvol);
3139 return VOLSERVOLBUSY;
3141 VTRANS_OBJ_LOCK(tt2);
3142 tt2->iflags = ITBusy;
3144 TSetRxCall_r(tt2, NULL, "SplitVolume");
3145 VTRANS_OBJ_UNLOCK(tt2);
3147 code = split_volume(acall, vol, newvol, where, verbose);
3149 VDetachVolume(&code2, vol);
3151 VDetachVolume(&code2, newvol);
3152 DeleteTrans(tt2, 1);
3159 /* GetPartName - map partid (a decimal number) into pname (a string)
3160 * Since for NT we actually want to return the drive name, we map through the
3164 GetPartName(afs_int32 partid, char *pname)
3169 strcpy(pname, "/vicep");
3170 pname[6] = 'a' + partid;
3173 } else if (partid < VOLMAXPARTS) {
3174 strcpy(pname, "/vicep");
3176 pname[6] = 'a' + (partid / 26);
3177 pname[7] = 'a' + (partid % 26);