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 #include <afs/afs_assert.h>
38 #include <afs/prs_fs.h>
42 #include <afs/cellconfig.h>
45 #include <afs/ihandle.h>
47 #include <afs/ntops.h>
49 #include <afs/vnode.h>
50 #include <afs/volume.h>
51 #include <afs/volume_inline.h>
52 #include <afs/partition.h>
54 #include <afs/daemon_com.h>
55 #include <afs/fssync.h>
57 #include "afs/audit.h"
59 #include <afs/afsutil.h>
60 #include <afs/vol_prototypes.h>
61 #include <afs/errors.h>
64 #include "voltrans_inline.h"
67 #include "volser_internal.h"
69 #include "dumpstuff.h"
72 extern struct afsconf_dir *tdir;
74 extern void LogError(afs_int32 errcode);
76 /* Forward declarations */
77 static int GetPartName(afs_int32 partid, char *pname);
79 #define OneDay (24*60*60)
85 afs_int32 localTid = 1;
87 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
88 struct diskPartition64 *);
89 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
90 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
91 afs_int32, afs_uint32, afs_uint32 *,
93 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
94 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
95 afs_int32, char *, afs_uint32 *);
96 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
97 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
98 afs_int32, afs_int32 *);
99 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
101 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
102 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
103 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
104 struct destServer *destination, afs_int32,
105 struct restoreCookie *cookie);
106 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
107 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
108 struct restoreCookie *);
109 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
110 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
111 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
112 struct volser_status *);
113 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
114 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
115 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
116 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
117 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
119 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
121 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
123 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
125 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
126 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
127 afs_int32, afs_uint32, afs_uint32,
129 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
131 /* this call unlocks all of the partition locks we've set */
135 struct DiskPartition64 *tp;
136 for (tp = DiskPartitionList; tp; tp = tp->next) {
137 if (tp->lock_fd != INVALID_FD) {
138 close(tp->lock_fd); /* releases flock held on this partition */
139 tp->lock_fd = INVALID_FD;
150 code = VPFullUnlock_r();
155 /* get partition id from a name */
157 PartitionID(char *aname)
165 return -1; /* unknown */
167 /* otherwise check for vicepa or /vicepa, or just plain "a" */
169 if (!strncmp(aname, "/vicep", 6)) {
170 strncpy(ascii, aname + 6, 2);
172 return -1; /* bad partition name */
173 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
174 * from 0. Do the appropriate conversion */
176 /* one char name, 0..25 */
177 if (ascii[0] < 'a' || ascii[0] > 'z')
178 return -1; /* wrongo */
179 return ascii[0] - 'a';
181 /* two char name, 26 .. <whatever> */
182 if (ascii[0] < 'a' || ascii[0] > 'z')
183 return -1; /* wrongo */
184 if (ascii[1] < 'a' || ascii[1] > 'z')
185 return -1; /* just as bad */
186 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
187 if (code > VOLMAXPARTS)
194 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
198 /* 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 */
199 (void)afs_snprintf(aname, asize, VFORMAT, (unsigned long)avol);
204 ConvertPartition(int apartno, char *aname, int asize)
210 strcpy(aname, "/vicep");
212 aname[6] = 'a' + apartno;
216 aname[6] = 'a' + (apartno / 26);
217 aname[7] = 'a' + (apartno % 26);
223 #ifdef AFS_DEMAND_ATTACH_FS
224 /* normally we should use the regular salvaging functions from the volume
225 * package, but this is a special case where we have a volume ID, but no
226 * volume structure to give the volume package */
228 SalvageUnknownVolume(VolumeId volid, char *part)
232 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
233 afs_printable_uint32_lu(volid), part);
235 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
236 FSYNC_SALVAGE, NULL);
238 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
239 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
243 #endif /* AFS_DEMAND_ATTACH_FS */
245 static struct Volume *
246 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
251 vp = VAttachVolumeByName(ec, partition, name, mode);
253 #ifdef AFS_DEMAND_ATTACH_FS
257 * The fileserver will take care of keeping track of how many
258 * demand-salvages have been performed, and will force the volume to
259 * ERROR if we've done too many. The limit on This loop is just a
260 * failsafe to prevent trying to salvage forever. We want to attempt
261 * attachment at least SALVAGE_COUNT_MAX times, since we want to
262 * avoid prematurely exiting this loop, if we can.
264 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
265 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
266 vp = VAttachVolumeByName(ec, partition, name, mode);
269 if (*ec == VSALVAGING) {
273 #endif /* AFS_DEMAND_ATTACH_FS */
278 static struct Volume *
279 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
284 vp = VAttachVolume(ec, avolid, amode);
286 #ifdef AFS_DEMAND_ATTACH_FS
289 /* see comment above in VAttachVolumeByName_retry */
290 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
291 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
292 vp = VAttachVolume(ec, avolid, amode);
295 if (*ec == VSALVAGING) {
299 #endif /* AFS_DEMAND_ATTACH_FS */
304 /* the only attach function that takes a partition is "...ByName", so we use it */
305 static struct Volume *
306 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
308 char pbuf[30], vbuf[20];
310 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
314 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
319 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
322 /* Adapted from the file server; create a root directory for this volume */
324 ViceCreateRoot(Volume *vp)
327 struct acl_accessList *ACL;
329 Inode inodeNumber, nearInode;
330 struct VnodeDiskObject *vnode;
331 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
337 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
340 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
342 V_pref(vp, nearInode);
344 IH_CREATE(V_linkHandle(vp), V_device(vp),
345 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
347 osi_Assert(VALID_INO(inodeNumber));
349 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
350 did.Volume = V_id(vp);
351 did.Vnode = (VnodeId) 1;
354 osi_Assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
355 DFlush(); /* flush all modified dir buffers out */
356 DZap((afs_int32 *)&dir); /* Remove all buffers for this dir */
357 length = Length(&dir); /* Remember size of this directory */
359 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
361 /* build a single entry ACL that gives all rights to system:administrators */
362 /* this section of code assumes that access list format is not going to
365 ACL = VVnodeDiskACL(vnode);
366 ACL->size = sizeof(struct acl_accessList);
367 ACL->version = ACL_ACLVERSION;
371 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
372 ACL->entries[0].rights =
373 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
374 | PRSFS_LOCK | PRSFS_ADMINISTER;
376 vnode->type = vDirectory;
378 vnode->modeBits = 0777;
379 vnode->linkCount = 2;
380 VNDISK_SET_LEN(vnode, length);
381 vnode->uniquifier = 1;
382 V_uniquifier(vp) = vnode->uniquifier + 1;
383 vnode->dataVersion = 1;
384 VNDISK_SET_INO(vnode, inodeNumber);
385 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
389 vnode->vnodeMagic = vcp->magic;
391 IH_INIT(h, vp->device, V_parentId(vp),
392 vp->vnodeIndex[vLarge].handle->ih_ino);
394 osi_Assert(fdP != NULL);
395 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
396 osi_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
397 FDH_REALLYCLOSE(fdP);
399 VNDISK_GET_LEN(length, vnode);
400 V_diskused(vp) = nBlocks(length);
407 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
411 struct diskPartition64 *dp = (struct diskPartition64 *)
412 malloc(sizeof(struct diskPartition64));
414 code = VolPartitionInfo(acid, pname, dp);
416 strncpy(partition->name, dp->name, 32);
417 strncpy(partition->devName, dp->devName, 32);
418 partition->lock_fd = dp->lock_fd;
419 partition->free=RoundInt64ToInt32(dp->free);
420 partition->minFree=RoundInt64ToInt32(dp->minFree);
423 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
428 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
433 code = VolPartitionInfo(acid, pname, partition);
434 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
439 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
442 struct DiskPartition64 *dp;
445 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
448 dp = VGetPartition(pname, 0);
450 strncpy(partition->name, dp->name, 32);
451 strncpy(partition->devName, dp->devName, 32);
452 partition->lock_fd = (int)dp->lock_fd;
453 partition->free = dp->free;
454 partition->minFree = dp->totalUsable;
457 return VOLSERILLEGAL_PARTITION;
460 /* obliterate a volume completely, and slowly. */
462 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
466 code = VolNukeVolume(acid, apartID, avolID);
467 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
472 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
479 char caller[MAXKTCNAMELEN];
481 /* check for access */
482 if (!afsconf_SuperUser(tdir, acid, caller))
483 return VOLSERBAD_ACCESS;
485 Log("%s is executing VolNukeVolume %u\n", caller, avolID);
487 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
489 /* we first try to attach the volume in update mode, so that the file
490 * server doesn't try to use it (and abort) while (or after) we delete it.
491 * If we don't get the volume, that's fine, too. We just won't put it back.
493 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
494 code = nuke(partName, avolID);
496 VDetachVolume(&verror, tvp);
500 /* create a new volume, with name aname, on the specified partition (1..n)
501 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
502 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
503 * for the volume id (useful for things like volume restore).
504 * Return the new volume id in *avolid.
507 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
508 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
514 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
515 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
516 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
522 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
523 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
528 Error junk; /* discardable error code */
530 afs_int32 doCreateRoot = 1;
531 struct volser_trans *tt;
533 char caller[MAXKTCNAMELEN];
535 if (strlen(aname) > 31)
536 return VOLSERBADNAME;
537 if (!afsconf_SuperUser(tdir, acid, caller))
538 return VOLSERBAD_ACCESS;
540 Log("%s is executing CreateVolume '%s'\n", caller, aname);
541 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
542 return error; /*a standard unix error */
543 if (atype != readwriteVolume && atype != readonlyVolume
544 && atype != backupVolume)
546 if ((volumeID = *avolid) == 0) {
548 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
552 if ((aparent == volumeID) && (atype == readwriteVolume)) {
557 tt = NewTrans(volumeID, apart);
559 Log("1 createvolume: failed to create trans\n");
560 return VOLSERVOLBUSY; /* volume already busy! */
562 vp = VCreateVolume(&error, ppath, volumeID, aparent);
564 #ifdef AFS_DEMAND_ATTACH_FS
565 if (error != VVOLEXISTS && error != EXDEV) {
566 SalvageUnknownVolume(volumeID, ppath);
569 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
574 V_uniquifier(vp) = 1;
575 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
576 V_inService(vp) = V_blessed(vp) = 1;
578 AssignVolumeName(&V_disk(vp), aname, 0);
581 V_destroyMe(vp) = DESTROY_ME;
583 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
584 VUpdateVolume(&error, vp);
586 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
589 VDetachVolume(&junk, vp); /* rather return the real error code */
595 TSetRxCall_r(tt, acid, "CreateVolume");
596 VTRANS_OBJ_UNLOCK(tt);
597 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
600 return VOLSERTRELE_ERROR;
604 /* delete the volume associated with this transaction */
606 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
610 code = VolDeleteVolume(acid, atrans);
611 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
616 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
618 struct volser_trans *tt;
620 char caller[MAXKTCNAMELEN];
622 if (!afsconf_SuperUser(tdir, acid, caller))
623 return VOLSERBAD_ACCESS;
624 tt = FindTrans(atrans);
627 if (tt->vflags & VTDeleted) {
628 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
633 Log("%s is executing Delete Volume %u\n", caller, tt->volid);
634 TSetRxCall(tt, acid, "DeleteVolume");
635 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
636 V_destroyMe(tt->volume) = DESTROY_ME; /* so endtrans does the right fssync opcode */
638 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
640 VTRANS_OBJ_UNLOCK(tt);
642 return VOLSERTRELE_ERROR;
644 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
645 return 0; /* vpurgevolume doesn't set an error code */
648 /* make a clone of the volume associated with atrans, possibly giving it a new
649 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
650 * for the clone's id). The new clone is given the name newName. Finally,
651 * due to efficiency considerations, if purgeId is non-zero, we purge that
652 * volume when doing the clone operation. This may be useful when making
653 * new backup volumes, for instance since the net result of a clone and a
654 * purge generally leaves many inode ref counts the same, while doing them
655 * separately would result in far more iincs and idecs being peformed
656 * (and they are slow operations).
658 /* for efficiency reasons, sometimes faster to piggyback a purge here */
660 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
661 afs_int32 newType, char *newName, afs_uint32 *newNumber)
665 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
666 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
667 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
673 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
674 afs_int32 newType, char *newName, afs_uint32 *newNumber)
677 struct Volume *originalvp, *purgevp, *newvp;
679 struct volser_trans *tt, *ttc;
680 char caller[MAXKTCNAMELEN];
681 #ifdef AFS_DEMAND_ATTACH_FS
682 struct Volume *salv_vp = NULL;
685 if (strlen(newName) > 31)
686 return VOLSERBADNAME;
687 if (!afsconf_SuperUser(tdir, acid, caller))
688 return VOLSERBAD_ACCESS; /*not a super user */
690 Log("%s is executing Clone Volume new name=%s\n", caller, newName);
692 originalvp = (Volume *) 0;
693 purgevp = (Volume *) 0;
694 newvp = (Volume *) 0;
695 tt = ttc = (struct volser_trans *)0;
697 if (!newNumber || !*newNumber) {
698 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
703 if (newType != readonlyVolume && newType != backupVolume)
705 tt = FindTrans(atrans);
708 if (tt->vflags & VTDeleted) {
709 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
713 ttc = NewTrans(newId, tt->partition);
714 if (!ttc) { /* someone is messing with the clone already */
716 return VOLSERVOLBUSY;
718 TSetRxCall(tt, acid, "Clone");
722 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
724 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
730 originalvp = tt->volume;
731 if ((V_type(originalvp) == backupVolume)
732 || (V_type(originalvp) == readonlyVolume)) {
733 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
737 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
738 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
744 if (originalvp->device != purgevp->device) {
745 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
749 if (V_type(purgevp) != readonlyVolume) {
750 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
754 if (V_type(originalvp) == readonlyVolume
755 && V_parentId(originalvp) != V_parentId(purgevp)) {
756 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
760 if (V_type(originalvp) == readwriteVolume
761 && tt->volid != V_parentId(purgevp)) {
762 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
769 #ifdef AFS_DEMAND_ATTACH_FS
770 salv_vp = originalvp;
774 VCreateVolume(&error, originalvp->partition->name, newId,
775 V_parentId(originalvp));
777 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
778 newvp = (Volume *) 0;
781 if (newType == readonlyVolume)
782 V_cloneId(originalvp) = newId;
783 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
786 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
787 CloneVolume(&error, originalvp, newvp, purgevp);
788 purgevp = NULL; /* clone releases it, maybe even if error */
790 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
794 if (newType == readonlyVolume) {
795 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
796 V_type(newvp) = readonlyVolume;
797 } else if (newType == backupVolume) {
798 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
799 V_type(newvp) = backupVolume;
800 V_backupId(originalvp) = newId;
802 strcpy(newvp->header->diskstuff.name, newName);
803 V_creationDate(newvp) = V_copyDate(newvp);
804 ClearVolumeStats(&V_disk(newvp));
805 V_destroyMe(newvp) = DESTROY_ME;
806 V_inService(newvp) = 0;
807 if (newType == backupVolume) {
808 V_backupDate(originalvp) = V_copyDate(newvp);
809 V_backupDate(newvp) = V_copyDate(newvp);
812 VUpdateVolume(&error, newvp);
814 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
818 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
820 VUpdateVolume(&error, originalvp);
822 Log("1 Volser: Clone: original update %u\n", error);
827 #ifdef AFS_DEMAND_ATTACH_FS
831 tt = (struct volser_trans *)0;
832 error = VOLSERTRELE_ERROR;
840 VDetachVolume(&code, purgevp);
842 VDetachVolume(&code, newvp);
849 #ifdef AFS_DEMAND_ATTACH_FS
850 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
852 VRequestSalvage_r(&salv_error, salv_vp, FSYNC_SALVAGE, 0);
854 #endif /* AFS_DEMAND_ATTACH_FS */
858 /* reclone this volume into the specified id */
860 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
864 code = VolReClone(acid, atrans, cloneId);
865 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
871 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
873 struct Volume *originalvp, *clonevp;
876 struct volser_trans *tt, *ttc;
877 char caller[MAXKTCNAMELEN];
879 /*not a super user */
880 if (!afsconf_SuperUser(tdir, acid, caller))
881 return VOLSERBAD_ACCESS;
883 Log("%s is executing Reclone Volume %u\n", caller, cloneId);
885 clonevp = originalvp = (Volume *) 0;
886 tt = (struct volser_trans *)0;
888 tt = FindTrans(atrans);
891 if (tt->vflags & VTDeleted) {
892 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
896 ttc = NewTrans(cloneId, tt->partition);
897 if (!ttc) { /* someone is messing with the clone already */
899 return VOLSERVOLBUSY;
901 TSetRxCall(tt, acid, "ReClone");
903 originalvp = tt->volume;
904 if ((V_type(originalvp) == backupVolume)
905 || (V_type(originalvp) == readonlyVolume)) {
906 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
910 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
911 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
917 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
919 Log("1 Volser: can't attach clone %d\n", cloneId);
923 newType = V_type(clonevp); /* type of the new volume */
925 if (originalvp->device != clonevp->device) {
926 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
931 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
932 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
936 if (V_type(originalvp) == readonlyVolume
937 && V_parentId(originalvp) != V_parentId(clonevp)) {
938 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
942 if (V_type(originalvp) == readwriteVolume
943 && tt->volid != V_parentId(clonevp)) {
944 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
950 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
952 CloneVolume(&error, originalvp, clonevp, clonevp);
954 Log("1 Volser: Clone: reclone operation failed with code %d\n",
960 /* fix up volume name and type, CloneVolume just propagated RW's */
961 if (newType == readonlyVolume) {
962 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
963 V_type(clonevp) = readonlyVolume;
964 } else if (newType == backupVolume) {
965 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
966 V_type(clonevp) = backupVolume;
967 V_backupId(originalvp) = cloneId;
969 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
971 /* pretend recloned volume is a totally new instance */
972 V_copyDate(clonevp) = time(0);
973 V_creationDate(clonevp) = V_copyDate(clonevp);
974 ClearVolumeStats(&V_disk(clonevp));
975 V_destroyMe(clonevp) = 0;
976 V_inService(clonevp) = 0;
977 if (newType == backupVolume) {
978 V_backupDate(originalvp) = V_copyDate(clonevp);
979 V_backupDate(clonevp) = V_copyDate(clonevp);
981 V_inUse(clonevp) = 0;
982 VUpdateVolume(&error, clonevp);
984 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
988 /* VUpdateVolume succeeded. Mark it in service so there's no window
989 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
990 * specialStatus; this is a reclone and this volume started online
992 V_inService(clonevp) = 1;
993 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
995 VUpdateVolume(&error, originalvp);
997 Log("1 Volser: Clone: original update %u\n", error);
1003 tt = (struct volser_trans *)0;
1004 error = VOLSERTRELE_ERROR;
1008 DeleteTrans(ttc, 1);
1011 struct DiskPartition64 *tpartp = originalvp->partition;
1012 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1018 VDetachVolume(&code, clonevp);
1024 DeleteTrans(ttc, 1);
1028 /* create a new transaction, associated with volume and partition. Type of
1029 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1030 * See volser.h for definition of iflags (the constants are named IT*).
1033 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1034 afs_int32 iflags, afs_int32 *ttid)
1038 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1039 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1045 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1046 afs_int32 iflags, afs_int32 *ttid)
1048 struct volser_trans *tt;
1053 char caller[MAXKTCNAMELEN];
1055 if (!afsconf_SuperUser(tdir, acid, caller))
1056 return VOLSERBAD_ACCESS; /*not a super user */
1057 if (iflags & ITCreate)
1059 else if (iflags & ITBusy)
1061 else if (iflags & ITReadOnly)
1063 else if (iflags & ITOffline)
1066 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1071 tt = NewTrans(volume, partition);
1073 /* can't create a transaction? put the volume back */
1074 Log("1 transcreate: can't create transaction\n");
1075 return VOLSERVOLBUSY;
1077 tv = XAttachVolume(&error, volume, partition, mode);
1081 VDetachVolume(&code, tv);
1085 VTRANS_OBJ_LOCK(tt);
1088 tt->iflags = iflags;
1090 TSetRxCall_r(tt, NULL, "TransCreate");
1091 VTRANS_OBJ_UNLOCK(tt);
1093 return VOLSERTRELE_ERROR;
1098 /* using aindex as a 0-based index, return the aindex'th volume on this server
1099 * Both the volume number and partition number (one-based) are returned.
1102 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1107 code = VolGetNthVolume(acid, aindex, avolume, apart);
1108 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1113 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1116 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1120 /* return the volume flags (VT* constants in volser.h) associated with this
1124 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1128 code = VolGetFlags(acid, atid, aflags);
1129 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1134 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1136 struct volser_trans *tt;
1138 tt = FindTrans(atid);
1141 if (tt->vflags & VTDeleted) {
1142 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1147 TSetRxCall(tt, acid, "GetFlags");
1148 *aflags = tt->vflags;
1151 return VOLSERTRELE_ERROR;
1156 /* Change the volume flags (VT* constants in volser.h) associated with this
1157 * transaction. Effects take place immediately on volume, although volume
1158 * remains attached as usual by the transaction.
1161 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1165 code = VolSetFlags(acid, atid, aflags);
1166 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1172 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1174 struct volser_trans *tt;
1177 char caller[MAXKTCNAMELEN];
1179 if (!afsconf_SuperUser(tdir, acid, caller))
1180 return VOLSERBAD_ACCESS; /*not a super user */
1181 /* find the trans */
1182 tt = FindTrans(atid);
1185 if (tt->vflags & VTDeleted) {
1186 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1191 TSetRxCall(tt, acid, "SetFlags");
1192 vp = tt->volume; /* pull volume out of transaction */
1194 /* check if we're allowed to make any updates */
1195 if (tt->iflags & ITReadOnly) {
1200 /* handle delete-on-salvage flag */
1201 if (aflags & VTDeleteOnSalvage) {
1202 V_destroyMe(tt->volume) = DESTROY_ME;
1204 V_destroyMe(tt->volume) = 0;
1207 if (aflags & VTOutOfService) {
1208 V_inService(vp) = 0;
1210 V_inService(vp) = 1;
1212 VUpdateVolume(&error, vp);
1213 VTRANS_OBJ_LOCK(tt);
1214 tt->vflags = aflags;
1216 VTRANS_OBJ_UNLOCK(tt);
1217 if (TRELE(tt) && !error)
1218 return VOLSERTRELE_ERROR;
1223 /* dumpS the volume associated with a particular transaction from a particular
1224 * date. Send the dump to a different transaction (destTrans) on the server
1225 * specified by the destServer structure.
1228 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1229 struct destServer *destination, afs_int32 destTrans,
1230 struct restoreCookie *cookie)
1235 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1236 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1237 destination->destHost, AUD_LONG, destTrans, AUD_END);
1242 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1243 struct destServer *destination, afs_int32 destTrans,
1244 struct restoreCookie *cookie)
1246 struct volser_trans *tt;
1248 struct rx_connection *tcon;
1249 struct rx_call *tcall;
1251 struct rx_securityClass *securityObject;
1252 afs_int32 securityIndex;
1253 char caller[MAXKTCNAMELEN];
1255 if (!afsconf_SuperUser(tdir, acid, caller))
1256 return VOLSERBAD_ACCESS; /*not a super user */
1257 /* initialize things */
1258 tcon = (struct rx_connection *)0;
1259 tt = (struct volser_trans *)0;
1261 /* find the local transaction */
1262 tt = FindTrans(fromTrans);
1265 if (tt->vflags & VTDeleted) {
1266 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1271 TSetRxCall(tt, NULL, "Forward");
1273 /* get auth info for the this connection (uses afs from ticket file) */
1274 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1280 /* make an rpc connection to the other server */
1282 rx_NewConnection(htonl(destination->destHost),
1283 htons(destination->destPort), VOLSERVICE_ID,
1284 securityObject, securityIndex);
1290 tcall = rx_NewCall(tcon);
1291 TSetRxCall(tt, tcall, "Forward");
1292 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1293 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1298 /* these next calls implictly call rx_Write when writing out data */
1299 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1302 EndAFSVolRestore(tcall); /* probably doesn't do much */
1304 code = rx_EndCall(tcall, 0);
1305 rx_DestroyConnection(tcon); /* done with the connection */
1310 return VOLSERTRELE_ERROR;
1316 (void)rx_EndCall(tcall, 0);
1317 rx_DestroyConnection(tcon);
1326 /* Start a dump and send it to multiple places simultaneously.
1327 * If this returns an error (eg, return ENOENT), it means that
1328 * none of the releases worked. If this returns 0, that means
1329 * that one or more of the releases worked, and the caller has
1330 * to examine the results array to see which one(s).
1331 * This will only do EITHER incremental or full, not both, so it's
1332 * the caller's responsibility to be sure that all the destinations
1333 * need just an incremental (and from the same time), if that's
1337 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1338 fromDate, manyDests *destinations, afs_int32 spare,
1339 struct restoreCookie *cookie, manyResults *results)
1341 afs_int32 securityIndex;
1342 struct rx_securityClass *securityObject;
1343 char caller[MAXKTCNAMELEN];
1344 struct volser_trans *tt;
1345 afs_int32 ec, code, *codes;
1346 struct rx_connection **tcons;
1347 struct rx_call **tcalls;
1349 int i, is_incremental;
1352 memset(results, 0, sizeof(manyResults));
1353 i = results->manyResults_len = destinations->manyDests_len;
1354 results->manyResults_val = codes =
1355 (afs_int32 *) malloc(i * sizeof(afs_int32));
1357 if (!results || !results->manyResults_val)
1360 if (!afsconf_SuperUser(tdir, acid, caller))
1361 return VOLSERBAD_ACCESS; /*not a super user */
1362 tt = FindTrans(fromTrans);
1365 if (tt->vflags & VTDeleted) {
1366 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1371 TSetRxCall(tt, NULL, "ForwardMulti");
1373 /* (fromDate == 0) ==> full dump */
1374 is_incremental = (fromDate ? 1 : 0);
1377 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1381 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1387 /* get auth info for this connection (uses afs from ticket file) */
1388 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1390 goto fail; /* in order to audit each failure */
1393 /* make connections to all the other servers */
1394 for (i = 0; i < destinations->manyDests_len; i++) {
1395 struct replica *dest = &(destinations->manyDests_val[i]);
1397 rx_NewConnection(htonl(dest->server.destHost),
1398 htons(dest->server.destPort), VOLSERVICE_ID,
1399 securityObject, securityIndex);
1401 codes[i] = ENOTCONN;
1403 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1404 codes[i] = ENOTCONN;
1407 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1410 (void)rx_EndCall(tcalls[i], 0);
1412 rx_DestroyConnection(tcons[i]);
1419 /* these next calls implictly call rx_Write when writing out data */
1420 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1424 for (i--; i >= 0; i--) {
1425 struct replica *dest = &(destinations->manyDests_val[i]);
1427 if (!code && tcalls[i] && !codes[i]) {
1428 EndAFSVolRestore(tcalls[i]);
1431 ec = rx_EndCall(tcalls[i], 0);
1436 rx_DestroyConnection(tcons[i]); /* done with the connection */
1439 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1440 fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG,
1441 dest->trans, AUD_END);
1448 if (TRELE(tt) && !code) /* return the first code if it's set */
1449 return VOLSERTRELE_ERROR;
1456 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1460 code = VolDump(acid, fromTrans, fromDate, 0);
1461 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1466 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1471 code = VolDump(acid, fromTrans, fromDate, flags);
1472 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1477 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1481 struct volser_trans *tt;
1482 char caller[MAXKTCNAMELEN];
1484 if (!afsconf_SuperUser(tdir, acid, caller))
1485 return VOLSERBAD_ACCESS; /*not a super user */
1486 tt = FindTrans(fromTrans);
1489 if (tt->vflags & VTDeleted) {
1490 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1494 TSetRxCall(tt, acid, "Dump");
1495 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1496 ? 0 : 1); /* squirt out the volume's data, too */
1505 return VOLSERTRELE_ERROR;
1511 * Ha! No more helper process!
1514 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1515 struct restoreCookie *cookie)
1519 code = VolRestore(acid, atrans, aflags, cookie);
1520 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1525 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1526 struct restoreCookie *cookie)
1528 struct volser_trans *tt;
1529 afs_int32 code, tcode;
1530 char caller[MAXKTCNAMELEN];
1532 if (!afsconf_SuperUser(tdir, acid, caller))
1533 return VOLSERBAD_ACCESS; /*not a super user */
1534 tt = FindTrans(atrans);
1537 if (tt->vflags & VTDeleted) {
1538 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1542 TSetRxCall(tt, acid, "Restore");
1544 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1546 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1547 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1551 return (code ? code : tcode);
1554 /* end a transaction, returning the transaction's final error code in rcode */
1556 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1560 code = VolEndTrans(acid, destTrans, rcode);
1561 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1566 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1568 struct volser_trans *tt;
1569 char caller[MAXKTCNAMELEN];
1571 if (!afsconf_SuperUser(tdir, acid, caller))
1572 return VOLSERBAD_ACCESS; /*not a super user */
1573 tt = FindTrans(destTrans);
1577 *rcode = tt->returnCode;
1578 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1584 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1588 code = VolSetForwarding(acid, atid, anewsite);
1589 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1595 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1597 struct volser_trans *tt;
1598 char caller[MAXKTCNAMELEN];
1601 if (!afsconf_SuperUser(tdir, acid, caller))
1602 return VOLSERBAD_ACCESS; /*not a super user */
1603 tt = FindTrans(atid);
1606 if (tt->vflags & VTDeleted) {
1607 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1612 TSetRxCall(tt, acid, "SetForwarding");
1613 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1616 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1619 return VOLSERTRELE_ERROR;
1625 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1626 struct volser_status *astatus)
1630 code = VolGetStatus(acid, atrans, astatus);
1631 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1636 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1637 struct volser_status *astatus)
1640 struct VolumeDiskData *td;
1641 struct volser_trans *tt;
1644 tt = FindTrans(atrans);
1647 if (tt->vflags & VTDeleted) {
1648 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1653 TSetRxCall(tt, acid, "GetStatus");
1661 td = &tv->header->diskstuff;
1662 astatus->volID = td->id;
1663 astatus->nextUnique = td->uniquifier;
1664 astatus->type = td->type;
1665 astatus->parentID = td->parentId;
1666 astatus->cloneID = td->cloneId;
1667 astatus->backupID = td->backupId;
1668 astatus->restoredFromID = td->restoredFromId;
1669 astatus->maxQuota = td->maxquota;
1670 astatus->minQuota = td->minquota;
1671 astatus->owner = td->owner;
1672 astatus->creationDate = td->creationDate;
1673 astatus->accessDate = td->accessDate;
1674 astatus->updateDate = td->updateDate;
1675 astatus->expirationDate = td->expirationDate;
1676 astatus->backupDate = td->backupDate;
1677 astatus->copyDate = td->copyDate;
1680 return VOLSERTRELE_ERROR;
1686 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1687 struct volintInfo *astatus)
1691 code = VolSetInfo(acid, atrans, astatus);
1692 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1697 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1698 struct volintInfo *astatus)
1701 struct VolumeDiskData *td;
1702 struct volser_trans *tt;
1703 char caller[MAXKTCNAMELEN];
1706 if (!afsconf_SuperUser(tdir, acid, caller))
1707 return VOLSERBAD_ACCESS; /*not a super user */
1708 tt = FindTrans(atrans);
1711 if (tt->vflags & VTDeleted) {
1712 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1716 TSetRxCall(tt, acid, "SetStatus");
1724 td = &tv->header->diskstuff;
1726 * Add more fields as necessary
1728 if (astatus->maxquota != -1)
1729 td->maxquota = astatus->maxquota;
1730 if (astatus->dayUse != -1)
1731 td->dayUse = astatus->dayUse;
1732 if (astatus->creationDate != -1)
1733 td->creationDate = astatus->creationDate;
1734 if (astatus->updateDate != -1)
1735 td->updateDate = astatus->updateDate;
1736 if (astatus->spare2 != -1)
1737 td->volUpdateCounter = (unsigned int)astatus->spare2;
1738 VUpdateVolume(&error, tv);
1741 return VOLSERTRELE_ERROR;
1747 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1751 code = VolGetName(acid, atrans, aname);
1752 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1757 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1760 struct VolumeDiskData *td;
1761 struct volser_trans *tt;
1764 /* We need to at least fill it in */
1765 *aname = (char *)malloc(1);
1768 tt = FindTrans(atrans);
1771 if (tt->vflags & VTDeleted) {
1772 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1776 TSetRxCall(tt, acid, "GetName");
1784 td = &tv->header->diskstuff;
1785 len = strlen(td->name) + 1; /* don't forget the null */
1791 *aname = (char *)realloc(*aname, len);
1792 strcpy(*aname, td->name);
1795 return VOLSERTRELE_ERROR;
1800 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1803 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1804 afs_uint32 parentId, afs_uint32 cloneId)
1810 /*return a list of all partitions on the server. The non mounted
1811 *partitions are returned as -1 in the corresponding slot in partIds*/
1813 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1817 code = VolListPartitions(acid, partIds);
1818 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1823 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1828 strcpy(namehead, "/vicep"); /*7 including null terminator */
1830 /* Just return attached partitions. */
1832 for (i = 0; i < 26; i++) {
1833 namehead[6] = i + 'a';
1834 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1840 /*return a list of all partitions on the server. The non mounted
1841 *partitions are returned as -1 in the corresponding slot in partIds*/
1843 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1847 code = XVolListPartitions(acid, pEntries);
1848 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1853 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1856 struct partList partList;
1857 struct DiskPartition64 *dp;
1860 strcpy(namehead, "/vicep"); /*7 including null terminator */
1862 /* Only report attached partitions */
1863 for (i = 0; i < VOLMAXPARTS; i++) {
1864 #ifdef AFS_DEMAND_ATTACH_FS
1865 dp = VGetPartitionById(i, 0);
1868 namehead[6] = i + 'a';
1874 namehead[6] = 'a' + (k / 26);
1875 namehead[7] = 'a' + (k % 26);
1878 dp = VGetPartition(namehead, 0);
1881 partList.partId[j++] = i;
1884 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1885 if (!pEntries->partEntries_val)
1887 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1889 pEntries->partEntries_len = j;
1891 pEntries->partEntries_val = NULL;
1892 pEntries->partEntries_len = 0;
1898 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1900 ExtractVolId(char vname[])
1903 char name[VOLSER_MAXVOLNAME + 1];
1905 strcpy(name, vname);
1907 while (name[i] == 'V' || name[i] == '0')
1910 name[11] = '\0'; /* smash the "." */
1911 return (atol(&name[i]));
1914 /*return the name of the next volume header in the directory associated with dirp and dp.
1915 *the volume id is returned in volid, and volume header name is returned in volname*/
1917 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1921 dp = readdir(dirp); /*read next entry in the directory */
1923 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1924 *volid = ExtractVolId(dp->d_name);
1925 strcpy(volname, dp->d_name);
1926 return 0; /*return the name of the file representing a volume */
1928 strcpy(volname, "");
1929 return 0; /*volname doesnot represent a volume */
1932 strcpy(volname, "EOD");
1933 return 0; /*end of directory */
1939 * volint vol info structure type.
1942 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1943 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1944 } volint_info_type_t;
1947 * handle to various on-wire vol info types.
1950 volint_info_type_t volinfo_type;
1956 } volint_info_handle_t;
1959 * store value to a field at the appropriate location in on-wire structure.
1961 #define VOLINT_INFO_STORE(handle, name, val) \
1963 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1964 (handle)->volinfo_ptr.base->name = (val); \
1966 (handle)->volinfo_ptr.ext->name = (val); \
1971 * get pointer to appropriate offset of field in on-wire structure.
1973 #define VOLINT_INFO_PTR(handle, name) \
1974 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1975 &((handle)->volinfo_ptr.base->name) : \
1976 &((handle)->volinfo_ptr.ext->name))
1979 * fill in appropriate type of on-wire volume metadata structure.
1981 * @param vp pointer to volume object
1982 * @param handle pointer to wire format handle object
1984 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1985 * @pre handle object must have a valid pointer and enumeration value
1987 * @note passing a NULL value for vp means that the fileserver doesn't
1988 * know about this particular volume, thus implying it is offline.
1990 * @return operation status
1995 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1997 unsigned int numStatBytes, now;
1998 struct VolumeDiskData *hdr = &vp->header->diskstuff;
2000 /*read in the relevant info */
2001 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2002 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
2003 VOLINT_INFO_STORE(handle, volid, hdr->id);
2004 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2005 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2006 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2007 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2008 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2009 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2010 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2011 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2012 now = FT_ApproxTime();
2013 if ((now - hdr->dayUseDate) > OneDay) {
2014 VOLINT_INFO_STORE(handle, dayUse, 0);
2016 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2018 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2019 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2020 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2021 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2023 #ifdef AFS_DEMAND_ATTACH_FS
2025 * for DAFS, we "lie" about volume state --
2026 * instead of returning the raw state from the disk header,
2027 * we compute state based upon the fileserver's internal
2028 * in-core state enumeration value reported to us via fssync,
2029 * along with the blessed and inService flags from the header.
2030 * -- tkeiser 11/27/2007
2033 /* Conditions that offline status is based on:
2034 volume is unattached state
2035 volume state is in (one of several error states)
2036 volume not in service
2037 volume is not marked as blessed (not on hold)
2038 volume in salvage req. state
2039 volume needsSalvaged
2040 next op would set volume offline
2041 next op would not leave volume online (based on several conditions)
2044 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2045 VIsErrorState(V_attachState(vp)) ||
2048 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2049 hdr->needsSalvaged ||
2050 (vp->pending_vol_op &&
2051 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2052 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2055 VOLINT_INFO_STORE(handle, inUse, 0);
2057 VOLINT_INFO_STORE(handle, inUse, 1);
2060 /* offline status based on program type, where != fileServer enum (1) is offline */
2061 if (hdr->inUse == fileServer) {
2062 VOLINT_INFO_STORE(handle, inUse, 1);
2064 VOLINT_INFO_STORE(handle, inUse, 0);
2069 switch(handle->volinfo_type) {
2070 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2071 case VOLINT_INFO_TYPE_BASE:
2073 #ifdef AFS_DEMAND_ATTACH_FS
2074 /* see comment above where we set inUse bit */
2075 if (hdr->needsSalvaged ||
2076 (vp && VIsErrorState(V_attachState(vp)))) {
2077 handle->volinfo_ptr.base->needsSalvaged = 1;
2079 handle->volinfo_ptr.base->needsSalvaged = 0;
2082 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2084 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2085 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2086 handle->volinfo_ptr.base->spare1 =
2087 (long)hdr->weekUse[0] +
2088 (long)hdr->weekUse[1] +
2089 (long)hdr->weekUse[2] +
2090 (long)hdr->weekUse[3] +
2091 (long)hdr->weekUse[4] +
2092 (long)hdr->weekUse[5] +
2093 (long)hdr->weekUse[6];
2094 handle->volinfo_ptr.base->flags = 0;
2095 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2096 handle->volinfo_ptr.base->spare3 = 0;
2100 case VOLINT_INFO_TYPE_EXT:
2102 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2103 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2106 * Copy out the stat fields in a single operation.
2108 if ((now - hdr->dayUseDate) > OneDay) {
2109 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2112 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2113 (char *)&(hdr->stat_reads[0]),
2122 #ifdef AFS_DEMAND_ATTACH_FS
2125 * get struct Volume out of the fileserver.
2127 * @param[in] volumeId volumeId for which we want state information
2128 * @param[in] pname partition name string
2129 * @param[inout] vp pointer to pointer to Volume object which
2130 * will be populated (see note)
2132 * @return operation status
2134 * @retval non-zero failure
2136 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2141 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2146 res.hdr.response_len = sizeof(res.hdr);
2147 res.payload.buf = *vp;
2148 res.payload.len = sizeof(Volume);
2150 code = FSYNC_VolOp(volumeId,
2156 if (code != SYNC_OK) {
2157 switch (res.hdr.reason) {
2158 case FSYNC_WRONG_PART:
2159 case FSYNC_UNKNOWN_VOLID:
2172 * mode of volume list operation.
2175 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2176 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2177 } vol_info_list_mode_t;
2180 * abstract interface to populate wire-format volume metadata structures.
2182 * @param[in] partId partition id
2183 * @param[in] volumeId volume id
2184 * @param[in] pname partition name
2185 * @param[in] volname volume file name
2186 * @param[in] handle handle to on-wire volume metadata object
2187 * @param[in] mode listing mode
2189 * @return operation status
2191 * @retval -2 DESTROY_ME flag is set
2192 * @retval -1 general failure; some data filled in
2193 * @retval -3 couldn't create vtrans; some data filled in
2196 GetVolInfo(afs_uint32 partId,
2197 afs_uint32 volumeId,
2200 volint_info_handle_t * handle,
2201 vol_info_list_mode_t mode)
2205 struct volser_trans *ttc = NULL;
2206 struct Volume *fill_tv, *tv = NULL;
2207 #ifdef AFS_DEMAND_ATTACH_FS
2208 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2209 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2210 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2211 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2213 /* Set up response handle for pending_vol_op */
2214 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2215 fs_res.payload.buf = fs_res_buf;
2216 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2219 ttc = NewTrans(volumeId, partId);
2222 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2223 VOLINT_INFO_STORE(handle, volid, volumeId);
2227 /* Get volume from volserver */
2228 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2230 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2231 volumeId, pname, volname, error);
2236 * please note that destroyMe and needsSalvaged checks used to be ordered
2237 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2238 * more correct to check destroyMe before needsSalvaged.
2239 * -- tkeiser 11/28/2007
2242 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2244 case VOL_INFO_LIST_MULTIPLE:
2248 case VOL_INFO_LIST_SINGLE:
2249 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2250 volumeId, pname, volname);
2257 if (tv->header->diskstuff.needsSalvaged) {
2258 /*this volume will be salvaged */
2259 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2260 volumeId, pname, volname);
2263 #ifdef AFS_DEMAND_ATTACH_FS
2264 /* If using DAFS, get volume from fsserver */
2265 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2270 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2271 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2272 /* If we if the pending vol op */
2273 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2274 fs_tv->pending_vol_op=&pending_vol_op_res;
2276 fs_tv->pending_vol_op=NULL;
2279 /* populate the header from the volserver copy */
2280 fs_tv->header=tv->header;
2282 /* When using DAFS, use the fs volume info, populated with required structures */
2285 /* When not using DAFS, just use the local volume info */
2289 /* ok, we have all the data we need; fill in the on-wire struct */
2290 code = FillVolInfo(fill_tv, handle);
2294 VOLINT_INFO_STORE(handle, status, 0);
2295 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2296 VOLINT_INFO_STORE(handle, volid, volumeId);
2299 VDetachVolume(&error, tv);
2302 VOLINT_INFO_STORE(handle, status, 0);
2303 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2304 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2305 volumeId, pname, volname);
2309 DeleteTrans(ttc, 1);
2316 /*return the header information about the <volid> */
2318 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2319 afs_uint32 volumeId, volEntries *volumeInfo)
2323 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2324 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2329 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2330 afs_uint32 volumeId, volEntries *volumeInfo)
2332 struct DiskPartition64 *partP;
2333 char pname[9], volname[20];
2338 volint_info_handle_t handle;
2340 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2341 if (!volumeInfo->volEntries_val)
2343 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2345 volumeInfo->volEntries_len = 1;
2346 if (GetPartName(partid, pname))
2347 return VOLSERILLEGAL_PARTITION;
2348 if (!(partP = VGetPartition(pname, 0)))
2349 return VOLSERILLEGAL_PARTITION;
2350 dirp = opendir(VPartitionPath(partP));
2352 return VOLSERILLEGAL_PARTITION;
2354 strcpy(volname, "");
2356 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2358 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2359 GetNextVol(dirp, volname, &volid);
2360 continue; /*back to while loop */
2363 if (volid == volumeId) { /*copy other things too */
2368 GetNextVol(dirp, volname, &volid);
2372 #ifndef AFS_PTHREAD_ENV
2373 IOMGR_Poll(); /*make sure that the client does not time out */
2376 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2377 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2379 code = GetVolInfo(partid,
2384 VOL_INFO_LIST_SINGLE);
2388 return (found) ? 0 : ENODEV;
2391 /*------------------------------------------------------------------------
2392 * EXPORTED SAFSVolXListOneVolume
2395 * Returns extended info on volume a_volID on partition a_partID.
2398 * a_rxCidP : Pointer to the Rx call we're performing.
2399 * a_partID : Partition for which we want the extended list.
2400 * a_volID : Volume ID we wish to know about.
2401 * a_volumeXInfoP : Ptr to the extended info blob.
2404 * 0 Successful operation
2405 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2408 * Nothing interesting.
2412 *------------------------------------------------------------------------*/
2415 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2416 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2420 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2421 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2426 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2427 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2428 { /*SAFSVolXListOneVolume */
2430 struct DiskPartition64 *partP; /*Ptr to partition */
2431 char pname[9], volname[20]; /*Partition, volume names */
2432 DIR *dirp; /*Partition directory ptr */
2433 afs_uint32 currVolID; /*Current volume ID */
2434 int found = 0; /*Did we find the volume we need? */
2436 volint_info_handle_t handle;
2439 * Set up our pointers for action, marking our structure to hold exactly
2440 * one entry. Also, assume we'll fail in our quest.
2442 a_volumeXInfoP->volXEntries_val =
2443 (volintXInfo *) malloc(sizeof(volintXInfo));
2444 if (!a_volumeXInfoP->volXEntries_val)
2446 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2448 a_volumeXInfoP->volXEntries_len = 1;
2452 * If the partition name we've been given is bad, bogue out.
2454 if (GetPartName(a_partID, pname))
2455 return (VOLSERILLEGAL_PARTITION);
2458 * Open the directory representing the given AFS parttion. If we can't
2461 if (!(partP = VGetPartition(pname, 0)))
2462 return VOLSERILLEGAL_PARTITION;
2463 dirp = opendir(VPartitionPath(partP));
2465 return (VOLSERILLEGAL_PARTITION);
2467 strcpy(volname, "");
2470 * Sweep through the partition directory, looking for the desired entry.
2471 * First, of course, figure out how many stat bytes to copy out of each
2474 while (strcmp(volname, "EOD") && !found) {
2476 * If this is not a volume, move on to the next entry in the
2477 * partition's directory.
2479 if (!strcmp(volname, "")) {
2480 GetNextVol(dirp, volname, &currVolID);
2484 if (currVolID == a_volID) {
2486 * We found the volume entry we're interested. Pull out the
2487 * extended information, remembering to poll (so that the client
2488 * doesn't time out) and to set up a transaction on the volume.
2492 } /*Found desired volume */
2494 GetNextVol(dirp, volname, &currVolID);
2498 #ifndef AFS_PTHREAD_ENV
2502 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2503 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2505 code = GetVolInfo(a_partID,
2510 VOL_INFO_LIST_SINGLE);
2515 * Clean up before going to dinner: close the partition directory,
2516 * return the proper value.
2519 return (found) ? 0 : ENODEV;
2520 } /*SAFSVolXListOneVolume */
2522 /*returns all the volumes on partition partid. If flags = 1 then all the
2523 * relevant info about the volumes is also returned */
2525 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2526 volEntries *volumeInfo)
2530 code = VolListVolumes(acid, partid, flags, volumeInfo);
2531 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2536 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2537 volEntries *volumeInfo)
2540 struct DiskPartition64 *partP;
2541 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2542 char pname[9], volname[20];
2546 volint_info_handle_t handle;
2548 volumeInfo->volEntries_val =
2549 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2550 if (!volumeInfo->volEntries_val)
2552 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2554 pntr = volumeInfo->volEntries_val;
2555 volumeInfo->volEntries_len = 0;
2556 if (GetPartName(partid, pname))
2557 return VOLSERILLEGAL_PARTITION;
2558 if (!(partP = VGetPartition(pname, 0)))
2559 return VOLSERILLEGAL_PARTITION;
2560 dirp = opendir(VPartitionPath(partP));
2562 return VOLSERILLEGAL_PARTITION;
2563 strcpy(volname, "");
2565 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2567 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2568 GetNextVol(dirp, volname, &volid);
2569 continue; /*back to while loop */
2572 if (flags) { /*copy other things too */
2573 #ifndef AFS_PTHREAD_ENV
2574 IOMGR_Poll(); /*make sure that the client does not time out */
2577 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2578 handle.volinfo_ptr.base = pntr;
2581 code = GetVolInfo(partid,
2586 VOL_INFO_LIST_MULTIPLE);
2587 if (code == -2) { /* DESTROY_ME flag set */
2591 pntr->volid = volid;
2592 /*just volids are needed */
2596 volumeInfo->volEntries_len += 1;
2597 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2598 /*running out of space, allocate more space */
2599 allocSize = (allocSize * 3) / 2;
2601 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2602 allocSize * sizeof(volintInfo));
2605 return VOLSERNO_MEMORY;
2607 volumeInfo->volEntries_val = pntr; /* point to new block */
2608 /* set pntr to the right position */
2609 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2614 GetNextVol(dirp, volname, &volid);
2622 /*------------------------------------------------------------------------
2623 * EXPORTED SAFSVolXListVolumes
2626 * Returns all the volumes on partition a_partID. If a_flags
2627 * is set to 1, then all the relevant extended volume information
2631 * a_rxCidP : Pointer to the Rx call we're performing.
2632 * a_partID : Partition for which we want the extended list.
2633 * a_flags : Various flags.
2634 * a_volumeXInfoP : Ptr to the extended info blob.
2637 * 0 Successful operation
2638 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2639 * VOLSERNO_MEMORY if we ran out of memory allocating
2643 * Nothing interesting.
2647 *------------------------------------------------------------------------*/
2650 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2651 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2655 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2656 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2661 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2662 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2663 { /*SAFSVolXListVolumes */
2665 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2666 struct DiskPartition64 *partP; /*Ptr to partition */
2667 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2668 char pname[9], volname[20]; /*Partition, volume names */
2669 DIR *dirp; /*Partition directory ptr */
2670 afs_uint32 volid; /*Current volume ID */
2672 volint_info_handle_t handle;
2675 * Allocate a large array of extended volume info structures, then
2676 * set it up for action.
2678 a_volumeXInfoP->volXEntries_val =
2679 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2680 if (!a_volumeXInfoP->volXEntries_val)
2682 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2684 xInfoP = a_volumeXInfoP->volXEntries_val;
2685 a_volumeXInfoP->volXEntries_len = 0;
2688 * If the partition name we've been given is bad, bogue out.
2690 if (GetPartName(a_partID, pname))
2691 return (VOLSERILLEGAL_PARTITION);
2694 * Open the directory representing the given AFS parttion. If we can't
2697 if (!(partP = VGetPartition(pname, 0)))
2698 return VOLSERILLEGAL_PARTITION;
2699 dirp = opendir(VPartitionPath(partP));
2701 return (VOLSERILLEGAL_PARTITION);
2702 strcpy(volname, "");
2705 * Sweep through the partition directory, acting on each entry. First,
2706 * of course, figure out how many stat bytes to copy out of each volume.
2708 while (strcmp(volname, "EOD")) {
2711 * If this is not a volume, move on to the next entry in the
2712 * partition's directory.
2714 if (!strcmp(volname, "")) {
2715 GetNextVol(dirp, volname, &volid);
2721 * Full info about the volume desired. Poll to make sure the
2722 * client doesn't time out, then start up a new transaction.
2724 #ifndef AFS_PTHREAD_ENV
2728 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2729 handle.volinfo_ptr.ext = xInfoP;
2731 code = GetVolInfo(a_partID,
2736 VOL_INFO_LIST_MULTIPLE);
2737 if (code == -2) { /* DESTROY_ME flag set */
2742 * Just volume IDs are needed.
2744 xInfoP->volid = volid;
2748 * Bump the pointer in the data area we're building, along with
2749 * the count of the number of entries it contains.
2752 (a_volumeXInfoP->volXEntries_len)++;
2753 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2755 * We're running out of space in the area we've built. Grow it.
2757 allocSize = (allocSize * 3) / 2;
2758 xInfoP = (volintXInfo *)
2759 realloc((char *)a_volumeXInfoP->volXEntries_val,
2760 (allocSize * sizeof(volintXInfo)));
2761 if (xInfoP == NULL) {
2763 * Bummer, no memory. Bag it, tell our caller what went wrong.
2766 return (VOLSERNO_MEMORY);
2770 * Memory reallocation worked. Correct our pointers so they
2771 * now point to the new block and the current open position within
2774 a_volumeXInfoP->volXEntries_val = xInfoP;
2776 a_volumeXInfoP->volXEntries_val +
2777 a_volumeXInfoP->volXEntries_len;
2781 GetNextVol(dirp, volname, &volid);
2782 } /*Sweep through the partition directory */
2785 * We've examined all entries in the partition directory. Close it,
2786 * delete our transaction (if any), and go home happy.
2791 } /*SAFSVolXListVolumes */
2793 /*this call is used to monitor the status of volser for debugging purposes.
2794 *information about all the active transactions is returned in transInfo*/
2796 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2800 code = VolMonitor(acid, transInfo);
2801 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2806 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2808 transDebugInfo *pntr;
2809 afs_int32 allocSize = 50;
2810 struct volser_trans *tt, *nt, *allTrans;
2812 transInfo->transDebugEntries_val =
2813 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2814 if (!transInfo->transDebugEntries_val)
2816 pntr = transInfo->transDebugEntries_val;
2817 transInfo->transDebugEntries_len = 0;
2820 allTrans = TransList();
2821 if (allTrans == (struct volser_trans *)0)
2822 goto done; /*no active transactions */
2823 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2825 VTRANS_OBJ_LOCK(tt);
2826 pntr->tid = tt->tid;
2827 pntr->time = tt->time;
2828 pntr->creationTime = tt->creationTime;
2829 pntr->returnCode = tt->returnCode;
2830 pntr->volid = tt->volid;
2831 pntr->partition = tt->partition;
2832 pntr->iflags = tt->iflags;
2833 pntr->vflags = tt->vflags;
2834 pntr->tflags = tt->tflags;
2835 strcpy(pntr->lastProcName, tt->lastProcName);
2836 pntr->callValid = 0;
2837 if (tt->rxCallPtr) { /*record call related info */
2838 pntr->callValid = 1;
2839 pntr->readNext = tt->rxCallPtr->rnext;
2840 pntr->transmitNext = tt->rxCallPtr->tnext;
2841 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2842 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2844 VTRANS_OBJ_UNLOCK(tt);
2846 transInfo->transDebugEntries_len += 1;
2847 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2848 allocSize = (allocSize * 3) / 2;
2850 (transDebugInfo *) realloc((char *)transInfo->
2851 transDebugEntries_val,
2853 sizeof(transDebugInfo));
2854 transInfo->transDebugEntries_val = pntr;
2856 transInfo->transDebugEntries_val +
2857 transInfo->transDebugEntries_len;
2858 /*set pntr to right position */
2869 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2870 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2871 afs_uint32 backupId)
2875 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2876 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2877 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2883 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2884 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2885 afs_uint32 backupId)
2889 struct volser_trans *tt;
2890 char caller[MAXKTCNAMELEN];
2892 if (strlen(name) > 31)
2893 return VOLSERBADNAME;
2894 if (!afsconf_SuperUser(tdir, acid, caller))
2895 return VOLSERBAD_ACCESS; /*not a super user */
2896 /* find the trans */
2897 tt = FindTrans(atid);
2900 if (tt->vflags & VTDeleted) {
2901 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2905 TSetRxCall(tt, acid, "SetIdsTypes");
2909 V_backupId(tv) = backupId;
2910 V_cloneId(tv) = cloneId;
2911 V_parentId(tv) = pId;
2912 strcpy((&V_disk(tv))->name, name);
2913 VUpdateVolume(&error, tv);
2915 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2920 if (TRELE(tt) && !error)
2921 return VOLSERTRELE_ERROR;
2926 if (TRELE(tt) && !error)
2927 return VOLSERTRELE_ERROR;
2932 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2936 code = VolSetDate(acid, atid, cdate);
2937 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2943 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2947 struct volser_trans *tt;
2948 char caller[MAXKTCNAMELEN];
2950 if (!afsconf_SuperUser(tdir, acid, caller))
2951 return VOLSERBAD_ACCESS; /*not a super user */
2952 /* find the trans */
2953 tt = FindTrans(atid);
2956 if (tt->vflags & VTDeleted) {
2957 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2961 TSetRxCall(tt, acid, "SetDate");
2964 V_creationDate(tv) = cdate;
2965 VUpdateVolume(&error, tv);
2967 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2972 if (TRELE(tt) && !error)
2973 return VOLSERTRELE_ERROR;
2978 if (TRELE(tt) && !error)
2979 return VOLSERTRELE_ERROR;
2984 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2985 afs_uint32 volumeId)
2990 char caller[MAXKTCNAMELEN];
2992 struct volser_trans *ttc;
2993 char pname[16], volname[20];
2994 struct DiskPartition64 *partP;
2995 afs_int32 ret = ENODEV;
2998 if (!afsconf_SuperUser(tdir, acid, caller))
2999 return VOLSERBAD_ACCESS; /*not a super user */
3000 if (GetPartName(partId, pname))
3001 return VOLSERILLEGAL_PARTITION;
3002 if (!(partP = VGetPartition(pname, 0)))
3003 return VOLSERILLEGAL_PARTITION;
3004 dirp = opendir(VPartitionPath(partP));
3006 return VOLSERILLEGAL_PARTITION;
3007 strcpy(volname, "");
3008 ttc = (struct volser_trans *)0;
3010 while (strcmp(volname, "EOD")) {
3011 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3012 GetNextVol(dirp, volname, &volid);
3013 continue; /*back to while loop */
3016 if (volid == volumeId) { /*copy other things too */
3017 #ifndef AFS_PTHREAD_ENV
3018 IOMGR_Poll(); /*make sure that the client doesnot time out */
3020 ttc = NewTrans(volumeId, partId);
3022 return VOLSERVOLBUSY;
3024 #ifdef AFS_NAMEI_ENV
3025 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3027 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3031 GetNextVol(dirp, volname, &volid);
3035 DeleteTrans(ttc, 1);
3036 ttc = (struct volser_trans *)0;
3045 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3046 struct volintSize *size)
3049 struct volser_trans *tt;
3050 char caller[MAXKTCNAMELEN];
3052 if (!afsconf_SuperUser(tdir, acid, caller))
3053 return VOLSERBAD_ACCESS; /*not a super user */
3054 tt = FindTrans(fromTrans);
3057 if (tt->vflags & VTDeleted) {
3061 TSetRxCall(tt, acid, "GetSize");
3062 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3065 return VOLSERTRELE_ERROR;
3067 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3072 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3073 afs_uint32 where, afs_int32 verbose)
3075 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3077 Volume *vol=0, *newvol=0;
3078 struct volser_trans *tt = 0, *tt2 = 0;
3079 char caller[MAXKTCNAMELEN];
3082 if (!afsconf_SuperUser(tdir, acall, caller))
3085 vol = VAttachVolume(&code, vid, V_VOLUPD);
3091 newvol = VAttachVolume(&code, new, V_VOLUPD);
3093 VDetachVolume(&code2, vol);
3098 if (V_device(vol) != V_device(newvol)
3099 || V_uniquifier(newvol) != 2) {
3100 if (V_device(vol) != V_device(newvol)) {
3101 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3103 rx_Write(acall, line, strlen(line));
3105 if (V_uniquifier(newvol) != 2) {
3106 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3107 rx_Write(acall, line, strlen(line));
3110 rx_Write(acall, line, 1);
3111 VDetachVolume(&code2, vol);
3112 VDetachVolume(&code2, newvol);
3115 tt = NewTrans(vid, V_device(vol));
3117 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3118 rx_Write(acall, line, strlen(line));
3120 rx_Write(acall, line, 1);
3121 VDetachVolume(&code2, vol);
3122 VDetachVolume(&code2, newvol);
3123 return VOLSERVOLBUSY;
3125 VTRANS_OBJ_LOCK(tt);
3126 tt->iflags = ITBusy;
3128 TSetRxCall_r(tt, NULL, "SplitVolume");
3129 VTRANS_OBJ_UNLOCK(tt);
3131 tt2 = NewTrans(new, V_device(newvol));
3133 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3134 rx_Write(acall, line, strlen(line));
3136 rx_Write(acall, line, 1);
3138 VDetachVolume(&code2, vol);
3139 VDetachVolume(&code2, newvol);
3140 return VOLSERVOLBUSY;
3142 VTRANS_OBJ_LOCK(tt2);
3143 tt2->iflags = ITBusy;
3145 TSetRxCall_r(tt2, NULL, "SplitVolume");
3146 VTRANS_OBJ_UNLOCK(tt2);
3148 code = split_volume(acall, vol, newvol, where, verbose);
3150 VDetachVolume(&code2, vol);
3152 VDetachVolume(&code2, newvol);
3153 DeleteTrans(tt2, 1);
3160 /* GetPartName - map partid (a decimal number) into pname (a string)
3161 * Since for NT we actually want to return the drive name, we map through the
3165 GetPartName(afs_int32 partid, char *pname)
3170 strcpy(pname, "/vicep");
3171 pname[6] = 'a' + partid;
3174 } else if (partid < VOLMAXPARTS) {
3175 strcpy(pname, "/vicep");
3177 pname[6] = 'a' + (partid / 26);
3178 pname[7] = 'a' + (partid % 26);