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>
20 #include <afs/afsint.h>
21 #include <afs/prs_fs.h>
25 #include <afs/cellconfig.h>
28 #include <afs/ihandle.h>
30 #include <afs/ntops.h>
32 #include <afs/vnode.h>
33 #include <afs/volume.h>
34 #include <afs/volume_inline.h>
35 #include <afs/partition.h>
37 #include <afs/daemon_com.h>
38 #include <afs/fssync.h>
40 #include "afs/audit.h"
42 #include <afs/afsutil.h>
43 #include <afs/com_err.h>
44 #include <afs/vol_prototypes.h>
45 #include <afs/errors.h>
48 #include "voltrans_inline.h"
51 #include "volser_internal.h"
53 #include "dumpstuff.h"
56 extern struct afsconf_dir *tdir;
58 extern void LogError(afs_int32 errcode);
60 /* Forward declarations */
61 static int GetPartName(afs_int32 partid, char *pname);
63 #define OneDay (24*60*60)
69 afs_int32 localTid = 1;
71 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
72 struct diskPartition64 *);
73 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
74 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
75 afs_int32, afs_uint32, afs_uint32 *,
77 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
78 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
79 afs_int32, char *, afs_uint32 *);
80 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
81 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
82 afs_int32, afs_int32 *);
83 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
85 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
86 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
87 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
88 struct destServer *destination, afs_int32,
89 struct restoreCookie *cookie);
90 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
91 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
92 struct restoreCookie *);
93 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
94 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
95 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
96 struct volser_status *);
97 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
98 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
99 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
100 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
101 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
103 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
105 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
107 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
109 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
110 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
111 afs_int32, afs_uint32, afs_uint32,
113 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
116 * Return the host address of the caller as a string.
118 * @param[in] acid incoming rx call
119 * @param[out] buffer buffer to be filled with the addess string
121 * @return address as formatted by inet_ntoa
124 callerAddress(struct rx_call *acid, char *buffer)
126 afs_uint32 ip = rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid)));
127 return afs_inet_ntoa_r(ip, buffer);
130 /* this call unlocks all of the partition locks we've set */
134 struct DiskPartition64 *tp;
135 for (tp = DiskPartitionList; tp; tp = tp->next) {
136 if (tp->lock_fd != INVALID_FD) {
137 OS_CLOSE(tp->lock_fd);
138 tp->lock_fd = INVALID_FD;
149 code = VPFullUnlock_r();
154 /* get partition id from a name */
156 PartitionID(char *aname)
164 return -1; /* unknown */
166 /* otherwise check for vicepa or /vicepa, or just plain "a" */
168 if (!strncmp(aname, "/vicep", 6)) {
169 strncpy(ascii, aname + 6, 2);
171 return -1; /* bad partition name */
172 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
173 * from 0. Do the appropriate conversion */
175 /* one char name, 0..25 */
176 if (ascii[0] < 'a' || ascii[0] > 'z')
177 return -1; /* wrongo */
178 return ascii[0] - 'a';
180 /* two char name, 26 .. <whatever> */
181 if (ascii[0] < 'a' || ascii[0] > 'z')
182 return -1; /* wrongo */
183 if (ascii[1] < 'a' || ascii[1] > 'z')
184 return -1; /* just as bad */
185 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
186 if (code > VOLMAXPARTS)
193 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
197 /* 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 */
198 snprintf(aname, asize, VFORMAT, (unsigned long)avol);
203 ConvertPartition(int apartno, char *aname, int asize)
209 strcpy(aname, "/vicep");
211 aname[6] = 'a' + apartno;
215 aname[6] = 'a' + (apartno / 26);
216 aname[7] = 'a' + (apartno % 26);
222 #ifdef AFS_DEMAND_ATTACH_FS
223 /* normally we should use the regular salvaging functions from the volume
224 * package, but this is a special case where we have a volume ID, but no
225 * volume structure to give the volume package */
227 SalvageUnknownVolume(VolumeId volid, char *part)
231 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
232 afs_printable_uint32_lu(volid), part);
234 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
235 FSYNC_SALVAGE, NULL);
237 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
238 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
242 #endif /* AFS_DEMAND_ATTACH_FS */
244 static struct Volume *
245 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
250 vp = VAttachVolumeByName(ec, partition, name, mode);
252 #ifdef AFS_DEMAND_ATTACH_FS
256 * The fileserver will take care of keeping track of how many
257 * demand-salvages have been performed, and will force the volume to
258 * ERROR if we've done too many. The limit on This loop is just a
259 * failsafe to prevent trying to salvage forever. We want to attempt
260 * attachment at least SALVAGE_COUNT_MAX times, since we want to
261 * avoid prematurely exiting this loop, if we can.
263 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
264 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
265 vp = VAttachVolumeByName(ec, partition, name, mode);
268 if (*ec == VSALVAGING) {
272 #endif /* AFS_DEMAND_ATTACH_FS */
277 static struct Volume *
278 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
283 vp = VAttachVolume(ec, avolid, amode);
285 #ifdef AFS_DEMAND_ATTACH_FS
288 /* see comment above in VAttachVolumeByName_retry */
289 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
290 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
291 vp = VAttachVolume(ec, avolid, amode);
294 if (*ec == VSALVAGING) {
298 #endif /* AFS_DEMAND_ATTACH_FS */
303 /* the only attach function that takes a partition is "...ByName", so we use it */
304 static struct Volume *
305 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
307 char pbuf[30], vbuf[20];
309 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
313 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
318 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
321 /* Adapted from the file server; create a root directory for this volume */
323 ViceCreateRoot(Volume *vp)
326 struct acl_accessList *ACL;
328 Inode inodeNumber, AFS_UNUSED nearInode;
329 struct VnodeDiskObject *vnode;
330 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
336 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
339 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
341 V_pref(vp, nearInode);
343 IH_CREATE(V_linkHandle(vp), V_device(vp),
344 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
346 if (!VALID_INO(inodeNumber)) {
347 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
352 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
353 did.Volume = V_id(vp);
354 did.Vnode = (VnodeId) 1;
357 osi_Assert(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
358 DFlush(); /* flush all modified dir buffers out */
359 DZap(&dir); /* Remove all buffers for this dir */
360 length = afs_dir_Length(&dir); /* Remember size of this directory */
362 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
364 /* build a single entry ACL that gives all rights to system:administrators */
365 /* this section of code assumes that access list format is not going to
368 ACL = VVnodeDiskACL(vnode);
369 ACL->size = sizeof(struct acl_accessList);
370 ACL->version = ACL_ACLVERSION;
374 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
375 ACL->entries[0].rights =
376 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
377 | PRSFS_LOCK | PRSFS_ADMINISTER;
379 vnode->type = vDirectory;
381 vnode->modeBits = 0777;
382 vnode->linkCount = 2;
383 VNDISK_SET_LEN(vnode, length);
384 vnode->uniquifier = 1;
385 V_uniquifier(vp) = vnode->uniquifier + 1;
386 vnode->dataVersion = 1;
387 VNDISK_SET_INO(vnode, inodeNumber);
388 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
392 vnode->vnodeMagic = vcp->magic;
394 IH_INIT(h, vp->device, V_parentId(vp),
395 vp->vnodeIndex[vLarge].handle->ih_ino);
397 osi_Assert(fdP != NULL);
398 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
399 osi_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
400 FDH_REALLYCLOSE(fdP);
402 VNDISK_GET_LEN(length, vnode);
403 V_diskused(vp) = nBlocks(length);
410 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
414 struct diskPartition64 *dp = (struct diskPartition64 *)
415 malloc(sizeof(struct diskPartition64));
417 code = VolPartitionInfo(acid, pname, dp);
419 strncpy(partition->name, dp->name, 32);
420 strncpy(partition->devName, dp->devName, 32);
421 partition->lock_fd = dp->lock_fd;
422 partition->free=RoundInt64ToInt32(dp->free);
423 partition->minFree=RoundInt64ToInt32(dp->minFree);
426 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
431 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
436 code = VolPartitionInfo(acid, pname, partition);
437 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
442 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
445 struct DiskPartition64 *dp;
448 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
451 dp = VGetPartition(pname, 0);
453 strncpy(partition->name, dp->name, 32);
454 strncpy(partition->devName, dp->devName, 32);
455 partition->lock_fd = (int)dp->lock_fd;
456 partition->free = dp->free;
457 partition->minFree = dp->totalUsable;
460 return VOLSERILLEGAL_PARTITION;
463 /* obliterate a volume completely, and slowly. */
465 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
469 code = VolNukeVolume(acid, apartID, avolID);
470 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
475 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
482 char caller[MAXKTCNAMELEN];
484 /* check for access */
485 if (!afsconf_SuperUser(tdir, acid, caller))
486 return VOLSERBAD_ACCESS;
489 Log("%s on %s is executing VolNukeVolume %u\n", caller,
490 callerAddress(acid, buffer), avolID);
493 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
495 /* we first try to attach the volume in update mode, so that the file
496 * server doesn't try to use it (and abort) while (or after) we delete it.
497 * If we don't get the volume, that's fine, too. We just won't put it back.
499 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
500 code = nuke(partName, avolID);
502 VDetachVolume(&verror, tvp);
506 /* create a new volume, with name aname, on the specified partition (1..n)
507 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
508 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
509 * for the volume id (useful for things like volume restore).
510 * Return the new volume id in *avolid.
513 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
514 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
520 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
521 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
522 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
528 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
529 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
534 Error junk; /* discardable error code */
536 afs_int32 doCreateRoot = 1;
537 struct volser_trans *tt;
539 char caller[MAXKTCNAMELEN];
541 if (strlen(aname) > 31)
542 return VOLSERBADNAME;
543 if (!afsconf_SuperUser(tdir, acid, caller))
544 return VOLSERBAD_ACCESS;
547 Log("%s on %s is executing CreateVolume '%s'\n", caller,
548 callerAddress(acid, buffer), aname);
550 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
551 return error; /*a standard unix error */
552 if (atype != readwriteVolume && atype != readonlyVolume
553 && atype != backupVolume)
555 if ((volumeID = *avolid) == 0) {
557 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
561 if ((aparent == volumeID) && (atype == readwriteVolume)) {
566 tt = NewTrans(volumeID, apart);
568 Log("1 createvolume: failed to create trans\n");
569 return VOLSERVOLBUSY; /* volume already busy! */
571 vp = VCreateVolume(&error, ppath, volumeID, aparent);
573 #ifdef AFS_DEMAND_ATTACH_FS
574 if (error != VVOLEXISTS && error != EXDEV) {
575 SalvageUnknownVolume(volumeID, ppath);
578 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
583 V_uniquifier(vp) = 1;
584 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
585 V_inService(vp) = V_blessed(vp) = 1;
587 AssignVolumeName(&V_disk(vp), aname, 0);
589 error = ViceCreateRoot(vp);
591 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
592 "error code %u\n", (unsigned)error);
594 V_needsSalvaged(vp) = 1;
595 VDetachVolume(&junk, vp);
599 V_destroyMe(vp) = DESTROY_ME;
601 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
602 VUpdateVolume(&error, vp);
604 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
607 VDetachVolume(&junk, vp); /* rather return the real error code */
613 TSetRxCall_r(tt, acid, "CreateVolume");
614 VTRANS_OBJ_UNLOCK(tt);
615 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
618 return VOLSERTRELE_ERROR;
622 /* delete the volume associated with this transaction */
624 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
628 code = VolDeleteVolume(acid, atrans);
629 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
634 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
636 struct volser_trans *tt;
638 char caller[MAXKTCNAMELEN];
640 if (!afsconf_SuperUser(tdir, acid, caller))
641 return VOLSERBAD_ACCESS;
642 tt = FindTrans(atrans);
645 if (tt->vflags & VTDeleted) {
646 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
652 Log("%s on %s is executing Delete Volume %u\n", caller,
653 callerAddress(acid, buffer), tt->volid);
655 TSetRxCall(tt, acid, "DeleteVolume");
656 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
657 V_destroyMe(tt->volume) = DESTROY_ME;
658 if (tt->volume->needsPutBack) {
659 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
662 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
664 VTRANS_OBJ_UNLOCK(tt);
666 return VOLSERTRELE_ERROR;
668 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
669 return 0; /* vpurgevolume doesn't set an error code */
672 /* make a clone of the volume associated with atrans, possibly giving it a new
673 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
674 * for the clone's id). The new clone is given the name newName. Finally,
675 * due to efficiency considerations, if purgeId is non-zero, we purge that
676 * volume when doing the clone operation. This may be useful when making
677 * new backup volumes, for instance since the net result of a clone and a
678 * purge generally leaves many inode ref counts the same, while doing them
679 * separately would result in far more iincs and idecs being peformed
680 * (and they are slow operations).
682 /* for efficiency reasons, sometimes faster to piggyback a purge here */
684 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
685 afs_int32 newType, char *newName, afs_uint32 *newNumber)
689 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
690 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
691 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
697 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
698 afs_int32 newType, char *newName, afs_uint32 *newNumber)
701 struct Volume *originalvp, *purgevp, *newvp;
703 struct volser_trans *tt, *ttc;
704 char caller[MAXKTCNAMELEN];
705 #ifdef AFS_DEMAND_ATTACH_FS
706 struct Volume *salv_vp = NULL;
709 if (strlen(newName) > 31)
710 return VOLSERBADNAME;
711 if (!afsconf_SuperUser(tdir, acid, caller))
712 return VOLSERBAD_ACCESS; /*not a super user */
715 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
716 callerAddress(acid, buffer), newName);
719 originalvp = (Volume *) 0;
720 purgevp = (Volume *) 0;
721 newvp = (Volume *) 0;
722 tt = ttc = (struct volser_trans *)0;
724 if (!newNumber || !*newNumber) {
725 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
730 tt = FindTrans(atrans);
733 if (tt->vflags & VTDeleted) {
734 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
738 ttc = NewTrans(newId, tt->partition);
739 if (!ttc) { /* someone is messing with the clone already */
741 return VOLSERVOLBUSY;
743 TSetRxCall(tt, acid, "Clone");
747 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
749 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
755 originalvp = tt->volume;
756 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
757 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
763 if (originalvp->device != purgevp->device) {
764 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
768 if (V_type(purgevp) != readonlyVolume) {
769 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
773 if (V_parentId(originalvp) != V_parentId(purgevp)) {
774 Log("1 Volser: Clone: Volume %u and volume %u were not originally cloned from the same parent; aborted\n", purgeId, tt->volid);
781 #ifdef AFS_DEMAND_ATTACH_FS
782 salv_vp = originalvp;
786 VCreateVolume(&error, originalvp->partition->name, newId,
787 V_parentId(originalvp));
789 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
790 newvp = (Volume *) 0;
793 if (newType == readonlyVolume)
794 V_cloneId(originalvp) = newId;
795 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
798 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
799 CloneVolume(&error, originalvp, newvp, purgevp);
800 purgevp = NULL; /* clone releases it, maybe even if error */
802 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
806 if (newType == readonlyVolume) {
807 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
808 V_type(newvp) = readonlyVolume;
809 } else if (newType == backupVolume) {
810 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
811 V_type(newvp) = backupVolume;
812 V_backupId(originalvp) = newId;
814 strcpy(newvp->header->diskstuff.name, newName);
815 V_creationDate(newvp) = V_copyDate(newvp);
816 ClearVolumeStats(&V_disk(newvp));
817 V_destroyMe(newvp) = DESTROY_ME;
818 V_inService(newvp) = 0;
819 if (newType == backupVolume) {
820 V_backupDate(originalvp) = V_copyDate(newvp);
821 V_backupDate(newvp) = V_copyDate(newvp);
824 VUpdateVolume(&error, newvp);
826 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
830 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
832 VUpdateVolume(&error, originalvp);
834 Log("1 Volser: Clone: original update %u\n", error);
839 #ifdef AFS_DEMAND_ATTACH_FS
843 tt = (struct volser_trans *)0;
844 error = VOLSERTRELE_ERROR;
852 VDetachVolume(&code, purgevp);
854 VDetachVolume(&code, newvp);
861 #ifdef AFS_DEMAND_ATTACH_FS
862 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
863 V_needsSalvaged(salv_vp) = 1;
865 #endif /* AFS_DEMAND_ATTACH_FS */
869 /* reclone this volume into the specified id */
871 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
875 code = VolReClone(acid, atrans, cloneId);
876 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
882 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
884 struct Volume *originalvp, *clonevp;
887 struct volser_trans *tt, *ttc;
888 char caller[MAXKTCNAMELEN];
890 /*not a super user */
891 if (!afsconf_SuperUser(tdir, acid, caller))
892 return VOLSERBAD_ACCESS;
895 Log("%s on %s is executing Reclone Volume %u\n", caller,
896 callerAddress(acid, buffer), cloneId);
899 clonevp = originalvp = (Volume *) 0;
900 tt = (struct volser_trans *)0;
902 tt = FindTrans(atrans);
905 if (tt->vflags & VTDeleted) {
906 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
910 ttc = NewTrans(cloneId, tt->partition);
911 if (!ttc) { /* someone is messing with the clone already */
913 return VOLSERVOLBUSY;
915 TSetRxCall(tt, acid, "ReClone");
917 originalvp = tt->volume;
918 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
919 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
925 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
927 Log("1 Volser: can't attach clone %d\n", cloneId);
931 newType = V_type(clonevp); /* type of the new volume */
933 if (originalvp->device != clonevp->device) {
934 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
939 if (V_parentId(originalvp) != V_parentId(clonevp)) {
940 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
946 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
948 CloneVolume(&error, originalvp, clonevp, clonevp);
950 Log("1 Volser: Clone: reclone operation failed with code %d\n",
956 /* fix up volume name and type, CloneVolume just propagated RW's */
957 if (newType == readonlyVolume) {
958 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
959 V_type(clonevp) = readonlyVolume;
960 } else if (newType == backupVolume) {
961 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
962 V_type(clonevp) = backupVolume;
963 V_backupId(originalvp) = cloneId;
965 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
967 /* update the creationDate, since this represents the last cloning date
968 * for ROs. But do not update copyDate; let it stay so we can identify
969 * when the clone was first created. */
970 V_creationDate(clonevp) = time(0);
971 ClearVolumeStats(&V_disk(clonevp));
972 V_destroyMe(clonevp) = 0;
973 V_inService(clonevp) = 0;
974 if (newType == backupVolume) {
975 V_backupDate(originalvp) = V_creationDate(clonevp);
976 V_backupDate(clonevp) = V_creationDate(clonevp);
978 V_inUse(clonevp) = 0;
979 VUpdateVolume(&error, clonevp);
981 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
985 /* VUpdateVolume succeeded. Mark it in service so there's no window
986 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
987 * specialStatus; this is a reclone and this volume started online
989 V_inService(clonevp) = 1;
990 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
992 VUpdateVolume(&error, originalvp);
994 Log("1 Volser: Clone: original update %u\n", error);
1000 tt = (struct volser_trans *)0;
1001 error = VOLSERTRELE_ERROR;
1005 DeleteTrans(ttc, 1);
1008 struct DiskPartition64 *tpartp = originalvp->partition;
1009 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1015 VDetachVolume(&code, clonevp);
1021 DeleteTrans(ttc, 1);
1025 /* create a new transaction, associated with volume and partition. Type of
1026 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1027 * See volser.h for definition of iflags (the constants are named IT*).
1030 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1031 afs_int32 iflags, afs_int32 *ttid)
1035 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1036 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1042 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1043 afs_int32 iflags, afs_int32 *ttid)
1045 struct volser_trans *tt;
1050 char caller[MAXKTCNAMELEN];
1052 if (!afsconf_SuperUser(tdir, acid, caller))
1053 return VOLSERBAD_ACCESS; /*not a super user */
1054 if (iflags & ITCreate)
1056 else if (iflags & ITBusy)
1058 else if (iflags & ITReadOnly)
1060 else if (iflags & ITOffline)
1063 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1068 tt = NewTrans(volume, partition);
1070 /* can't create a transaction? put the volume back */
1071 Log("1 transcreate: can't create transaction\n");
1072 return VOLSERVOLBUSY;
1074 tv = XAttachVolume(&error, volume, partition, mode);
1078 VDetachVolume(&code, tv);
1082 VTRANS_OBJ_LOCK(tt);
1085 tt->iflags = iflags;
1087 TSetRxCall_r(tt, NULL, "TransCreate");
1088 VTRANS_OBJ_UNLOCK(tt);
1090 return VOLSERTRELE_ERROR;
1095 /* using aindex as a 0-based index, return the aindex'th volume on this server
1096 * Both the volume number and partition number (one-based) are returned.
1099 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1104 code = VolGetNthVolume(acid, aindex, avolume, apart);
1105 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1110 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1113 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1117 /* return the volume flags (VT* constants in volser.h) associated with this
1121 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1125 code = VolGetFlags(acid, atid, aflags);
1126 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1131 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1133 struct volser_trans *tt;
1135 tt = FindTrans(atid);
1138 if (tt->vflags & VTDeleted) {
1139 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1144 TSetRxCall(tt, acid, "GetFlags");
1145 *aflags = tt->vflags;
1148 return VOLSERTRELE_ERROR;
1153 /* Change the volume flags (VT* constants in volser.h) associated with this
1154 * transaction. Effects take place immediately on volume, although volume
1155 * remains attached as usual by the transaction.
1158 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1162 code = VolSetFlags(acid, atid, aflags);
1163 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1169 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1171 struct volser_trans *tt;
1174 char caller[MAXKTCNAMELEN];
1176 if (!afsconf_SuperUser(tdir, acid, caller))
1177 return VOLSERBAD_ACCESS; /*not a super user */
1178 /* find the trans */
1179 tt = FindTrans(atid);
1182 if (tt->vflags & VTDeleted) {
1183 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1188 TSetRxCall(tt, acid, "SetFlags");
1189 vp = tt->volume; /* pull volume out of transaction */
1191 /* check if we're allowed to make any updates */
1192 if (tt->iflags & ITReadOnly) {
1197 /* handle delete-on-salvage flag */
1198 if (aflags & VTDeleteOnSalvage) {
1199 V_destroyMe(tt->volume) = DESTROY_ME;
1201 V_destroyMe(tt->volume) = 0;
1204 if (aflags & VTOutOfService) {
1205 V_inService(vp) = 0;
1207 V_inService(vp) = 1;
1209 VUpdateVolume(&error, vp);
1210 VTRANS_OBJ_LOCK(tt);
1211 tt->vflags = aflags;
1213 VTRANS_OBJ_UNLOCK(tt);
1214 if (TRELE(tt) && !error)
1215 return VOLSERTRELE_ERROR;
1220 /* dumpS the volume associated with a particular transaction from a particular
1221 * date. Send the dump to a different transaction (destTrans) on the server
1222 * specified by the destServer structure.
1225 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1226 struct destServer *destination, afs_int32 destTrans,
1227 struct restoreCookie *cookie)
1232 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1233 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1234 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1239 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1240 struct destServer *destination, afs_int32 destTrans,
1241 struct restoreCookie *cookie)
1243 struct volser_trans *tt;
1245 struct rx_connection *tcon;
1246 struct rx_call *tcall;
1248 struct rx_securityClass *securityObject;
1249 afs_int32 securityIndex;
1250 char caller[MAXKTCNAMELEN];
1252 if (!afsconf_SuperUser(tdir, acid, caller))
1253 return VOLSERBAD_ACCESS; /*not a super user */
1254 /* initialize things */
1255 tcon = (struct rx_connection *)0;
1256 tt = (struct volser_trans *)0;
1258 /* find the local transaction */
1259 tt = FindTrans(fromTrans);
1262 if (tt->vflags & VTDeleted) {
1263 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1268 TSetRxCall(tt, NULL, "Forward");
1270 /* get auth info for the this connection (uses afs from ticket file) */
1271 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1277 /* make an rpc connection to the other server */
1279 rx_NewConnection(htonl(destination->destHost),
1280 htons(destination->destPort), VOLSERVICE_ID,
1281 securityObject, securityIndex);
1287 tcall = rx_NewCall(tcon);
1288 TSetRxCall(tt, tcall, "Forward");
1289 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1290 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1295 /* these next calls implictly call rx_Write when writing out data */
1296 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1299 EndAFSVolRestore(tcall); /* probably doesn't do much */
1301 code = rx_EndCall(tcall, 0);
1302 rx_DestroyConnection(tcon); /* done with the connection */
1307 return VOLSERTRELE_ERROR;
1313 (void)rx_EndCall(tcall, 0);
1314 rx_DestroyConnection(tcon);
1323 /* Start a dump and send it to multiple places simultaneously.
1324 * If this returns an error (eg, return ENOENT), it means that
1325 * none of the releases worked. If this returns 0, that means
1326 * that one or more of the releases worked, and the caller has
1327 * to examine the results array to see which one(s).
1328 * This will only do EITHER incremental or full, not both, so it's
1329 * the caller's responsibility to be sure that all the destinations
1330 * need just an incremental (and from the same time), if that's
1334 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1335 fromDate, manyDests *destinations, afs_int32 spare,
1336 struct restoreCookie *cookie, manyResults *results)
1338 afs_int32 securityIndex;
1339 struct rx_securityClass *securityObject;
1340 char caller[MAXKTCNAMELEN];
1341 struct volser_trans *tt;
1342 afs_int32 ec, code, *codes;
1343 struct rx_connection **tcons;
1344 struct rx_call **tcalls;
1346 int i, is_incremental;
1349 memset(results, 0, sizeof(manyResults));
1350 i = results->manyResults_len = destinations->manyDests_len;
1351 results->manyResults_val = codes =
1352 (afs_int32 *) malloc(i * sizeof(afs_int32));
1354 if (!results || !results->manyResults_val)
1357 if (!afsconf_SuperUser(tdir, acid, caller))
1358 return VOLSERBAD_ACCESS; /*not a super user */
1359 tt = FindTrans(fromTrans);
1362 if (tt->vflags & VTDeleted) {
1363 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1368 TSetRxCall(tt, NULL, "ForwardMulti");
1370 /* (fromDate == 0) ==> full dump */
1371 is_incremental = (fromDate ? 1 : 0);
1374 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1378 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1384 /* get auth info for this connection (uses afs from ticket file) */
1385 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1387 goto fail; /* in order to audit each failure */
1390 /* make connections to all the other servers */
1391 for (i = 0; i < destinations->manyDests_len; i++) {
1392 struct replica *dest = &(destinations->manyDests_val[i]);
1394 rx_NewConnection(htonl(dest->server.destHost),
1395 htons(dest->server.destPort), VOLSERVICE_ID,
1396 securityObject, securityIndex);
1398 codes[i] = ENOTCONN;
1400 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1401 codes[i] = ENOTCONN;
1404 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1407 (void)rx_EndCall(tcalls[i], 0);
1409 rx_DestroyConnection(tcons[i]);
1416 /* these next calls implictly call rx_Write when writing out data */
1417 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1421 for (i--; i >= 0; i--) {
1422 struct replica *dest = &(destinations->manyDests_val[i]);
1424 if (!code && tcalls[i] && !codes[i]) {
1425 EndAFSVolRestore(tcalls[i]);
1428 ec = rx_EndCall(tcalls[i], 0);
1433 rx_DestroyConnection(tcons[i]); /* done with the connection */
1436 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1437 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1438 dest->trans, AUD_END);
1445 if (TRELE(tt) && !code) /* return the first code if it's set */
1446 return VOLSERTRELE_ERROR;
1453 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1457 code = VolDump(acid, fromTrans, fromDate, 0);
1458 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1463 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1468 code = VolDump(acid, fromTrans, fromDate, flags);
1469 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1474 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1478 struct volser_trans *tt;
1479 char caller[MAXKTCNAMELEN];
1481 if (!afsconf_SuperUser(tdir, acid, caller))
1482 return VOLSERBAD_ACCESS; /*not a super user */
1483 tt = FindTrans(fromTrans);
1486 if (tt->vflags & VTDeleted) {
1487 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1491 TSetRxCall(tt, acid, "Dump");
1492 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1493 ? 0 : 1); /* squirt out the volume's data, too */
1502 return VOLSERTRELE_ERROR;
1508 * Ha! No more helper process!
1511 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1512 struct restoreCookie *cookie)
1516 code = VolRestore(acid, atrans, aflags, cookie);
1517 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1522 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1523 struct restoreCookie *cookie)
1525 struct volser_trans *tt;
1526 afs_int32 code, tcode;
1527 char caller[MAXKTCNAMELEN];
1529 if (!afsconf_SuperUser(tdir, acid, caller))
1530 return VOLSERBAD_ACCESS; /*not a super user */
1531 tt = FindTrans(atrans);
1534 if (tt->vflags & VTDeleted) {
1535 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1539 TSetRxCall(tt, acid, "Restore");
1541 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1543 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1544 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1548 return (code ? code : tcode);
1551 /* end a transaction, returning the transaction's final error code in rcode */
1553 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1557 code = VolEndTrans(acid, destTrans, rcode);
1558 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1563 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1565 struct volser_trans *tt;
1566 char caller[MAXKTCNAMELEN];
1568 if (!afsconf_SuperUser(tdir, acid, caller))
1569 return VOLSERBAD_ACCESS; /*not a super user */
1570 tt = FindTrans(destTrans);
1574 *rcode = tt->returnCode;
1575 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1581 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1585 code = VolSetForwarding(acid, atid, anewsite);
1586 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1587 htonl(anewsite), AUD_END);
1592 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1594 struct volser_trans *tt;
1595 char caller[MAXKTCNAMELEN];
1598 if (!afsconf_SuperUser(tdir, acid, caller))
1599 return VOLSERBAD_ACCESS; /*not a super user */
1600 tt = FindTrans(atid);
1603 if (tt->vflags & VTDeleted) {
1604 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1609 TSetRxCall(tt, acid, "SetForwarding");
1610 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1613 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1616 return VOLSERTRELE_ERROR;
1622 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1623 struct volser_status *astatus)
1627 code = VolGetStatus(acid, atrans, astatus);
1628 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1633 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1634 struct volser_status *astatus)
1637 struct VolumeDiskData *td;
1638 struct volser_trans *tt;
1641 tt = FindTrans(atrans);
1644 if (tt->vflags & VTDeleted) {
1645 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1650 TSetRxCall(tt, acid, "GetStatus");
1658 td = &tv->header->diskstuff;
1659 astatus->volID = td->id;
1660 astatus->nextUnique = td->uniquifier;
1661 astatus->type = td->type;
1662 astatus->parentID = td->parentId;
1663 astatus->cloneID = td->cloneId;
1664 astatus->backupID = td->backupId;
1665 astatus->restoredFromID = td->restoredFromId;
1666 astatus->maxQuota = td->maxquota;
1667 astatus->minQuota = td->minquota;
1668 astatus->owner = td->owner;
1669 astatus->creationDate = td->creationDate;
1670 astatus->accessDate = td->accessDate;
1671 astatus->updateDate = td->updateDate;
1672 astatus->expirationDate = td->expirationDate;
1673 astatus->backupDate = td->backupDate;
1674 astatus->copyDate = td->copyDate;
1677 return VOLSERTRELE_ERROR;
1683 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1684 struct volintInfo *astatus)
1688 code = VolSetInfo(acid, atrans, astatus);
1689 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1694 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1695 struct volintInfo *astatus)
1698 struct VolumeDiskData *td;
1699 struct volser_trans *tt;
1700 char caller[MAXKTCNAMELEN];
1703 if (!afsconf_SuperUser(tdir, acid, caller))
1704 return VOLSERBAD_ACCESS; /*not a super user */
1705 tt = FindTrans(atrans);
1708 if (tt->vflags & VTDeleted) {
1709 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1713 TSetRxCall(tt, acid, "SetStatus");
1721 td = &tv->header->diskstuff;
1723 * Add more fields as necessary
1725 if (astatus->maxquota != -1)
1726 td->maxquota = astatus->maxquota;
1727 if (astatus->dayUse != -1)
1728 td->dayUse = astatus->dayUse;
1729 if (astatus->creationDate != -1)
1730 td->creationDate = astatus->creationDate;
1731 if (astatus->updateDate != -1)
1732 td->updateDate = astatus->updateDate;
1733 if (astatus->spare2 != -1)
1734 td->volUpdateCounter = (unsigned int)astatus->spare2;
1735 VUpdateVolume(&error, tv);
1738 return VOLSERTRELE_ERROR;
1744 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1748 code = VolGetName(acid, atrans, aname);
1749 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1754 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1757 struct VolumeDiskData *td;
1758 struct volser_trans *tt;
1761 /* We need to at least fill it in */
1762 *aname = (char *)malloc(1);
1765 tt = FindTrans(atrans);
1768 if (tt->vflags & VTDeleted) {
1769 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1773 TSetRxCall(tt, acid, "GetName");
1781 td = &tv->header->diskstuff;
1782 len = strlen(td->name) + 1; /* don't forget the null */
1788 *aname = (char *)realloc(*aname, len);
1789 strcpy(*aname, td->name);
1792 return VOLSERTRELE_ERROR;
1797 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1800 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1801 afs_uint32 parentId, afs_uint32 cloneId)
1807 /*return a list of all partitions on the server. The non mounted
1808 *partitions are returned as -1 in the corresponding slot in partIds*/
1810 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1814 code = VolListPartitions(acid, partIds);
1815 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1820 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1825 strcpy(namehead, "/vicep"); /*7 including null terminator */
1827 /* Just return attached partitions. */
1829 for (i = 0; i < 26; i++) {
1830 namehead[6] = i + 'a';
1831 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1837 /*return a list of all partitions on the server. The non mounted
1838 *partitions are returned as -1 in the corresponding slot in partIds*/
1840 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1844 code = XVolListPartitions(acid, pEntries);
1845 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1850 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1853 struct partList partList;
1854 struct DiskPartition64 *dp;
1857 strcpy(namehead, "/vicep"); /*7 including null terminator */
1859 /* Only report attached partitions */
1860 for (i = 0; i < VOLMAXPARTS; i++) {
1861 #ifdef AFS_DEMAND_ATTACH_FS
1862 dp = VGetPartitionById(i, 0);
1865 namehead[6] = i + 'a';
1871 namehead[6] = 'a' + (k / 26);
1872 namehead[7] = 'a' + (k % 26);
1875 dp = VGetPartition(namehead, 0);
1878 partList.partId[j++] = i;
1881 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1882 if (!pEntries->partEntries_val)
1884 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1886 pEntries->partEntries_len = j;
1888 pEntries->partEntries_val = NULL;
1889 pEntries->partEntries_len = 0;
1895 /*return the name of the next volume header in the directory associated with dirp and dp.
1896 *the volume id is returned in volid, and volume header name is returned in volname*/
1898 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1902 dp = readdir(dirp); /*read next entry in the directory */
1904 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1905 *volid = VolumeNumber(dp->d_name);
1906 strcpy(volname, dp->d_name);
1907 return 0; /*return the name of the file representing a volume */
1909 strcpy(volname, "");
1910 return 0; /*volname doesnot represent a volume */
1913 strcpy(volname, "EOD");
1914 return 0; /*end of directory */
1920 * volint vol info structure type.
1923 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1924 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1925 } volint_info_type_t;
1928 * handle to various on-wire vol info types.
1931 volint_info_type_t volinfo_type;
1937 } volint_info_handle_t;
1940 * store value to a field at the appropriate location in on-wire structure.
1942 #define VOLINT_INFO_STORE(handle, name, val) \
1944 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1945 (handle)->volinfo_ptr.base->name = (val); \
1947 (handle)->volinfo_ptr.ext->name = (val); \
1952 * get pointer to appropriate offset of field in on-wire structure.
1954 #define VOLINT_INFO_PTR(handle, name) \
1955 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1956 &((handle)->volinfo_ptr.base->name) : \
1957 &((handle)->volinfo_ptr.ext->name))
1960 * fill in appropriate type of on-wire volume metadata structure.
1962 * @param vp pointer to volume object
1963 * @param handle pointer to wire format handle object
1965 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1966 * @pre handle object must have a valid pointer and enumeration value
1968 * @note passing a NULL value for vp means that the fileserver doesn't
1969 * know about this particular volume, thus implying it is offline.
1971 * @return operation status
1976 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1978 unsigned int numStatBytes, now;
1979 struct VolumeDiskData *hdr = &vp->header->diskstuff;
1981 /*read in the relevant info */
1982 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1983 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1984 VOLINT_INFO_STORE(handle, volid, hdr->id);
1985 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1986 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
1987 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
1988 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
1989 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
1990 VOLINT_INFO_STORE(handle, size, hdr->diskused);
1991 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
1992 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
1993 now = FT_ApproxTime();
1994 if ((now - hdr->dayUseDate) > OneDay) {
1995 VOLINT_INFO_STORE(handle, dayUse, 0);
1997 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
1999 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2000 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2001 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2002 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2004 #ifdef AFS_DEMAND_ATTACH_FS
2006 * for DAFS, we "lie" about volume state --
2007 * instead of returning the raw state from the disk header,
2008 * we compute state based upon the fileserver's internal
2009 * in-core state enumeration value reported to us via fssync,
2010 * along with the blessed and inService flags from the header.
2011 * -- tkeiser 11/27/2007
2014 /* Conditions that offline status is based on:
2015 volume is unattached state
2016 volume state is in (one of several error states)
2017 volume not in service
2018 volume is not marked as blessed (not on hold)
2019 volume in salvage req. state
2020 volume needsSalvaged
2021 next op would set volume offline
2022 next op would not leave volume online (based on several conditions)
2025 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2026 VIsErrorState(V_attachState(vp)) ||
2029 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2030 hdr->needsSalvaged ||
2031 (vp->pending_vol_op &&
2032 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2033 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2036 VOLINT_INFO_STORE(handle, inUse, 0);
2038 VOLINT_INFO_STORE(handle, inUse, 1);
2041 /* offline status based on program type, where != fileServer enum (1) is offline */
2042 if (hdr->inUse == fileServer) {
2043 VOLINT_INFO_STORE(handle, inUse, 1);
2045 VOLINT_INFO_STORE(handle, inUse, 0);
2050 switch(handle->volinfo_type) {
2051 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2052 case VOLINT_INFO_TYPE_BASE:
2054 #ifdef AFS_DEMAND_ATTACH_FS
2055 /* see comment above where we set inUse bit */
2056 if (hdr->needsSalvaged ||
2057 (vp && VIsErrorState(V_attachState(vp)))) {
2058 handle->volinfo_ptr.base->needsSalvaged = 1;
2060 handle->volinfo_ptr.base->needsSalvaged = 0;
2063 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2065 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2066 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2067 handle->volinfo_ptr.base->spare1 =
2068 (long)hdr->weekUse[0] +
2069 (long)hdr->weekUse[1] +
2070 (long)hdr->weekUse[2] +
2071 (long)hdr->weekUse[3] +
2072 (long)hdr->weekUse[4] +
2073 (long)hdr->weekUse[5] +
2074 (long)hdr->weekUse[6];
2075 handle->volinfo_ptr.base->flags = 0;
2076 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2077 handle->volinfo_ptr.base->spare3 = 0;
2081 case VOLINT_INFO_TYPE_EXT:
2083 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2084 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2087 * Copy out the stat fields in a single operation.
2089 if ((now - hdr->dayUseDate) > OneDay) {
2090 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2093 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2094 (char *)&(hdr->stat_reads[0]),
2103 #ifdef AFS_DEMAND_ATTACH_FS
2106 * get struct Volume out of the fileserver.
2108 * @param[in] volumeId volumeId for which we want state information
2109 * @param[in] pname partition name string
2110 * @param[inout] vp pointer to pointer to Volume object which
2111 * will be populated (see note)
2113 * @return operation status
2115 * @retval non-zero failure
2117 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2122 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2127 res.hdr.response_len = sizeof(res.hdr);
2128 res.payload.buf = *vp;
2129 res.payload.len = sizeof(Volume);
2131 code = FSYNC_VolOp(volumeId,
2137 if (code != SYNC_OK) {
2138 switch (res.hdr.reason) {
2139 case FSYNC_WRONG_PART:
2140 case FSYNC_UNKNOWN_VOLID:
2153 * mode of volume list operation.
2156 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2157 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2158 } vol_info_list_mode_t;
2161 * abstract interface to populate wire-format volume metadata structures.
2163 * @param[in] partId partition id
2164 * @param[in] volumeId volume id
2165 * @param[in] pname partition name
2166 * @param[in] volname volume file name
2167 * @param[in] handle handle to on-wire volume metadata object
2168 * @param[in] mode listing mode
2170 * @return operation status
2172 * @retval -2 DESTROY_ME flag is set
2173 * @retval -1 general failure; some data filled in
2174 * @retval -3 couldn't create vtrans; some data filled in
2177 GetVolInfo(afs_uint32 partId,
2178 afs_uint32 volumeId,
2181 volint_info_handle_t * handle,
2182 vol_info_list_mode_t mode)
2186 struct volser_trans *ttc = NULL;
2187 struct Volume *fill_tv, *tv = NULL;
2188 #ifdef AFS_DEMAND_ATTACH_FS
2189 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2190 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2191 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2192 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2194 /* Set up response handle for pending_vol_op */
2195 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2196 fs_res.payload.buf = fs_res_buf;
2197 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2200 ttc = NewTrans(volumeId, partId);
2203 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2204 VOLINT_INFO_STORE(handle, volid, volumeId);
2208 /* Get volume from volserver */
2209 if (mode == VOL_INFO_LIST_MULTIPLE)
2210 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2212 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2214 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2215 volumeId, pname, volname, error);
2220 * please note that destroyMe and needsSalvaged checks used to be ordered
2221 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2222 * more correct to check destroyMe before needsSalvaged.
2223 * -- tkeiser 11/28/2007
2226 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2228 case VOL_INFO_LIST_MULTIPLE:
2232 case VOL_INFO_LIST_SINGLE:
2233 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2234 volumeId, pname, volname);
2241 if (tv->header->diskstuff.needsSalvaged) {
2242 /*this volume will be salvaged */
2243 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2244 volumeId, pname, volname);
2247 #ifdef AFS_DEMAND_ATTACH_FS
2248 /* If using DAFS, get volume from fsserver */
2249 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2254 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2255 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2256 /* If we if the pending vol op */
2257 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2258 fs_tv->pending_vol_op=&pending_vol_op_res;
2260 fs_tv->pending_vol_op=NULL;
2263 /* populate the header from the volserver copy */
2264 fs_tv->header=tv->header;
2266 /* When using DAFS, use the fs volume info, populated with required structures */
2269 /* When not using DAFS, just use the local volume info */
2273 /* ok, we have all the data we need; fill in the on-wire struct */
2274 code = FillVolInfo(fill_tv, handle);
2278 VOLINT_INFO_STORE(handle, status, 0);
2279 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2280 VOLINT_INFO_STORE(handle, volid, volumeId);
2283 VDetachVolume(&error, tv);
2286 VOLINT_INFO_STORE(handle, status, 0);
2287 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2288 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2289 volumeId, pname, volname);
2293 DeleteTrans(ttc, 1);
2300 /*return the header information about the <volid> */
2302 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2303 afs_uint32 volumeId, volEntries *volumeInfo)
2307 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2308 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2313 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2314 afs_uint32 volumeId, volEntries *volumeInfo)
2316 struct DiskPartition64 *partP;
2317 char pname[9], volname[20];
2322 volint_info_handle_t handle;
2324 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2325 if (!volumeInfo->volEntries_val)
2327 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2329 volumeInfo->volEntries_len = 1;
2330 if (GetPartName(partid, pname))
2331 return VOLSERILLEGAL_PARTITION;
2332 if (!(partP = VGetPartition(pname, 0)))
2333 return VOLSERILLEGAL_PARTITION;
2334 dirp = opendir(VPartitionPath(partP));
2336 return VOLSERILLEGAL_PARTITION;
2338 strcpy(volname, "");
2340 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2342 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2343 GetNextVol(dirp, volname, &volid);
2344 continue; /*back to while loop */
2347 if (volid == volumeId) { /*copy other things too */
2352 GetNextVol(dirp, volname, &volid);
2356 #ifndef AFS_PTHREAD_ENV
2357 IOMGR_Poll(); /*make sure that the client does not time out */
2360 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2361 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2363 code = GetVolInfo(partid,
2368 VOL_INFO_LIST_SINGLE);
2373 return code ? ENODEV: 0;
2378 /*------------------------------------------------------------------------
2379 * EXPORTED SAFSVolXListOneVolume
2382 * Returns extended info on volume a_volID on partition a_partID.
2385 * a_rxCidP : Pointer to the Rx call we're performing.
2386 * a_partID : Partition for which we want the extended list.
2387 * a_volID : Volume ID we wish to know about.
2388 * a_volumeXInfoP : Ptr to the extended info blob.
2391 * 0 Successful operation
2392 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2395 * Nothing interesting.
2399 *------------------------------------------------------------------------*/
2402 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2403 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2407 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2408 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2413 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2414 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2415 { /*SAFSVolXListOneVolume */
2417 struct DiskPartition64 *partP; /*Ptr to partition */
2418 char pname[9], volname[20]; /*Partition, volume names */
2419 DIR *dirp; /*Partition directory ptr */
2420 afs_uint32 currVolID; /*Current volume ID */
2421 int found = 0; /*Did we find the volume we need? */
2423 volint_info_handle_t handle;
2426 * Set up our pointers for action, marking our structure to hold exactly
2427 * one entry. Also, assume we'll fail in our quest.
2429 a_volumeXInfoP->volXEntries_val =
2430 (volintXInfo *) malloc(sizeof(volintXInfo));
2431 if (!a_volumeXInfoP->volXEntries_val)
2433 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2435 a_volumeXInfoP->volXEntries_len = 1;
2439 * If the partition name we've been given is bad, bogue out.
2441 if (GetPartName(a_partID, pname))
2442 return (VOLSERILLEGAL_PARTITION);
2445 * Open the directory representing the given AFS parttion. If we can't
2448 if (!(partP = VGetPartition(pname, 0)))
2449 return VOLSERILLEGAL_PARTITION;
2450 dirp = opendir(VPartitionPath(partP));
2452 return (VOLSERILLEGAL_PARTITION);
2454 strcpy(volname, "");
2457 * Sweep through the partition directory, looking for the desired entry.
2458 * First, of course, figure out how many stat bytes to copy out of each
2461 while (strcmp(volname, "EOD") && !found) {
2463 * If this is not a volume, move on to the next entry in the
2464 * partition's directory.
2466 if (!strcmp(volname, "")) {
2467 GetNextVol(dirp, volname, &currVolID);
2471 if (currVolID == a_volID) {
2473 * We found the volume entry we're interested. Pull out the
2474 * extended information, remembering to poll (so that the client
2475 * doesn't time out) and to set up a transaction on the volume.
2479 } /*Found desired volume */
2481 GetNextVol(dirp, volname, &currVolID);
2485 #ifndef AFS_PTHREAD_ENV
2489 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2490 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2492 code = GetVolInfo(a_partID,
2497 VOL_INFO_LIST_SINGLE);
2502 * Clean up before going to dinner: close the partition directory,
2503 * return the proper value.
2507 return code ? ENODEV: 0;
2510 } /*SAFSVolXListOneVolume */
2512 /*returns all the volumes on partition partid. If flags = 1 then all the
2513 * relevant info about the volumes is also returned */
2515 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2516 volEntries *volumeInfo)
2520 code = VolListVolumes(acid, partid, flags, volumeInfo);
2521 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2526 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2527 volEntries *volumeInfo)
2530 struct DiskPartition64 *partP;
2531 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2532 char pname[9], volname[20];
2536 volint_info_handle_t handle;
2538 volumeInfo->volEntries_val =
2539 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2540 if (!volumeInfo->volEntries_val)
2542 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2544 pntr = volumeInfo->volEntries_val;
2545 volumeInfo->volEntries_len = 0;
2546 if (GetPartName(partid, pname))
2547 return VOLSERILLEGAL_PARTITION;
2548 if (!(partP = VGetPartition(pname, 0)))
2549 return VOLSERILLEGAL_PARTITION;
2550 dirp = opendir(VPartitionPath(partP));
2552 return VOLSERILLEGAL_PARTITION;
2553 strcpy(volname, "");
2555 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2557 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2558 GetNextVol(dirp, volname, &volid);
2559 continue; /*back to while loop */
2562 if (flags) { /*copy other things too */
2563 #ifndef AFS_PTHREAD_ENV
2564 IOMGR_Poll(); /*make sure that the client does not time out */
2567 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2568 handle.volinfo_ptr.base = pntr;
2571 code = GetVolInfo(partid,
2576 VOL_INFO_LIST_MULTIPLE);
2577 if (code == -2) { /* DESTROY_ME flag set */
2581 pntr->volid = volid;
2582 /*just volids are needed */
2586 volumeInfo->volEntries_len += 1;
2587 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2588 /*running out of space, allocate more space */
2589 allocSize = (allocSize * 3) / 2;
2591 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2592 allocSize * sizeof(volintInfo));
2595 return VOLSERNO_MEMORY;
2597 volumeInfo->volEntries_val = pntr; /* point to new block */
2598 /* set pntr to the right position */
2599 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2604 GetNextVol(dirp, volname, &volid);
2612 /*------------------------------------------------------------------------
2613 * EXPORTED SAFSVolXListVolumes
2616 * Returns all the volumes on partition a_partID. If a_flags
2617 * is set to 1, then all the relevant extended volume information
2621 * a_rxCidP : Pointer to the Rx call we're performing.
2622 * a_partID : Partition for which we want the extended list.
2623 * a_flags : Various flags.
2624 * a_volumeXInfoP : Ptr to the extended info blob.
2627 * 0 Successful operation
2628 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2629 * VOLSERNO_MEMORY if we ran out of memory allocating
2633 * Nothing interesting.
2637 *------------------------------------------------------------------------*/
2640 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2641 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2645 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2646 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2651 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2652 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2653 { /*SAFSVolXListVolumes */
2655 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2656 struct DiskPartition64 *partP; /*Ptr to partition */
2657 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2658 char pname[9], volname[20]; /*Partition, volume names */
2659 DIR *dirp; /*Partition directory ptr */
2660 afs_uint32 volid; /*Current volume ID */
2662 volint_info_handle_t handle;
2665 * Allocate a large array of extended volume info structures, then
2666 * set it up for action.
2668 a_volumeXInfoP->volXEntries_val =
2669 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2670 if (!a_volumeXInfoP->volXEntries_val)
2672 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2674 xInfoP = a_volumeXInfoP->volXEntries_val;
2675 a_volumeXInfoP->volXEntries_len = 0;
2678 * If the partition name we've been given is bad, bogue out.
2680 if (GetPartName(a_partID, pname))
2681 return (VOLSERILLEGAL_PARTITION);
2684 * Open the directory representing the given AFS parttion. If we can't
2687 if (!(partP = VGetPartition(pname, 0)))
2688 return VOLSERILLEGAL_PARTITION;
2689 dirp = opendir(VPartitionPath(partP));
2691 return (VOLSERILLEGAL_PARTITION);
2692 strcpy(volname, "");
2695 * Sweep through the partition directory, acting on each entry. First,
2696 * of course, figure out how many stat bytes to copy out of each volume.
2698 while (strcmp(volname, "EOD")) {
2701 * If this is not a volume, move on to the next entry in the
2702 * partition's directory.
2704 if (!strcmp(volname, "")) {
2705 GetNextVol(dirp, volname, &volid);
2711 * Full info about the volume desired. Poll to make sure the
2712 * client doesn't time out, then start up a new transaction.
2714 #ifndef AFS_PTHREAD_ENV
2718 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2719 handle.volinfo_ptr.ext = xInfoP;
2721 code = GetVolInfo(a_partID,
2726 VOL_INFO_LIST_MULTIPLE);
2727 if (code == -2) { /* DESTROY_ME flag set */
2732 * Just volume IDs are needed.
2734 xInfoP->volid = volid;
2738 * Bump the pointer in the data area we're building, along with
2739 * the count of the number of entries it contains.
2742 (a_volumeXInfoP->volXEntries_len)++;
2743 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2745 * We're running out of space in the area we've built. Grow it.
2747 allocSize = (allocSize * 3) / 2;
2748 xInfoP = (volintXInfo *)
2749 realloc((char *)a_volumeXInfoP->volXEntries_val,
2750 (allocSize * sizeof(volintXInfo)));
2751 if (xInfoP == NULL) {
2753 * Bummer, no memory. Bag it, tell our caller what went wrong.
2756 return (VOLSERNO_MEMORY);
2760 * Memory reallocation worked. Correct our pointers so they
2761 * now point to the new block and the current open position within
2764 a_volumeXInfoP->volXEntries_val = xInfoP;
2766 a_volumeXInfoP->volXEntries_val +
2767 a_volumeXInfoP->volXEntries_len;
2771 GetNextVol(dirp, volname, &volid);
2772 } /*Sweep through the partition directory */
2775 * We've examined all entries in the partition directory. Close it,
2776 * delete our transaction (if any), and go home happy.
2781 } /*SAFSVolXListVolumes */
2783 /*this call is used to monitor the status of volser for debugging purposes.
2784 *information about all the active transactions is returned in transInfo*/
2786 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2790 code = VolMonitor(acid, transInfo);
2791 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2796 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2798 transDebugInfo *pntr;
2799 afs_int32 allocSize = 50;
2800 struct volser_trans *tt, *nt, *allTrans;
2802 transInfo->transDebugEntries_val =
2803 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2804 if (!transInfo->transDebugEntries_val)
2806 pntr = transInfo->transDebugEntries_val;
2807 transInfo->transDebugEntries_len = 0;
2810 allTrans = TransList();
2811 if (allTrans == (struct volser_trans *)0)
2812 goto done; /*no active transactions */
2813 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2815 VTRANS_OBJ_LOCK(tt);
2816 pntr->tid = tt->tid;
2817 pntr->time = tt->time;
2818 pntr->creationTime = tt->creationTime;
2819 pntr->returnCode = tt->returnCode;
2820 pntr->volid = tt->volid;
2821 pntr->partition = tt->partition;
2822 pntr->iflags = tt->iflags;
2823 pntr->vflags = tt->vflags;
2824 pntr->tflags = tt->tflags;
2825 strcpy(pntr->lastProcName, tt->lastProcName);
2826 pntr->callValid = 0;
2827 if (tt->rxCallPtr) { /*record call related info */
2828 pntr->callValid = 1;
2830 pntr->readNext = tt->rxCallPtr->rnext;
2831 pntr->transmitNext = tt->rxCallPtr->tnext;
2832 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2833 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2836 VTRANS_OBJ_UNLOCK(tt);
2838 transInfo->transDebugEntries_len += 1;
2839 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2840 allocSize = (allocSize * 3) / 2;
2842 (transDebugInfo *) realloc((char *)transInfo->
2843 transDebugEntries_val,
2845 sizeof(transDebugInfo));
2846 transInfo->transDebugEntries_val = pntr;
2848 transInfo->transDebugEntries_val +
2849 transInfo->transDebugEntries_len;
2850 /*set pntr to right position */
2861 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2862 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2863 afs_uint32 backupId)
2867 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2868 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2869 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2875 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2876 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2877 afs_uint32 backupId)
2881 struct volser_trans *tt;
2882 char caller[MAXKTCNAMELEN];
2884 if (strlen(name) > 31)
2885 return VOLSERBADNAME;
2886 if (!afsconf_SuperUser(tdir, acid, caller))
2887 return VOLSERBAD_ACCESS; /*not a super user */
2888 /* find the trans */
2889 tt = FindTrans(atid);
2892 if (tt->vflags & VTDeleted) {
2893 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2897 TSetRxCall(tt, acid, "SetIdsTypes");
2901 V_backupId(tv) = backupId;
2902 V_cloneId(tv) = cloneId;
2903 V_parentId(tv) = pId;
2904 strcpy((&V_disk(tv))->name, name);
2905 VUpdateVolume(&error, tv);
2907 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2912 if (TRELE(tt) && !error)
2913 return VOLSERTRELE_ERROR;
2918 if (TRELE(tt) && !error)
2919 return VOLSERTRELE_ERROR;
2924 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2928 code = VolSetDate(acid, atid, cdate);
2929 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2935 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2939 struct volser_trans *tt;
2940 char caller[MAXKTCNAMELEN];
2942 if (!afsconf_SuperUser(tdir, acid, caller))
2943 return VOLSERBAD_ACCESS; /*not a super user */
2944 /* find the trans */
2945 tt = FindTrans(atid);
2948 if (tt->vflags & VTDeleted) {
2949 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2953 TSetRxCall(tt, acid, "SetDate");
2956 V_creationDate(tv) = cdate;
2957 VUpdateVolume(&error, tv);
2959 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2964 if (TRELE(tt) && !error)
2965 return VOLSERTRELE_ERROR;
2970 if (TRELE(tt) && !error)
2971 return VOLSERTRELE_ERROR;
2976 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2977 afs_uint32 volumeId)
2982 char caller[MAXKTCNAMELEN];
2984 struct volser_trans *ttc;
2985 char pname[16], volname[20];
2986 struct DiskPartition64 *partP;
2987 afs_int32 ret = ENODEV;
2990 if (!afsconf_SuperUser(tdir, acid, caller))
2991 return VOLSERBAD_ACCESS; /*not a super user */
2992 if (GetPartName(partId, pname))
2993 return VOLSERILLEGAL_PARTITION;
2994 if (!(partP = VGetPartition(pname, 0)))
2995 return VOLSERILLEGAL_PARTITION;
2996 dirp = opendir(VPartitionPath(partP));
2998 return VOLSERILLEGAL_PARTITION;
2999 strcpy(volname, "");
3000 ttc = (struct volser_trans *)0;
3002 while (strcmp(volname, "EOD")) {
3003 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3004 GetNextVol(dirp, volname, &volid);
3005 continue; /*back to while loop */
3008 if (volid == volumeId) { /*copy other things too */
3009 #ifndef AFS_PTHREAD_ENV
3010 IOMGR_Poll(); /*make sure that the client doesnot time out */
3012 ttc = NewTrans(volumeId, partId);
3014 return VOLSERVOLBUSY;
3016 #ifdef AFS_NAMEI_ENV
3017 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3019 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3023 GetNextVol(dirp, volname, &volid);
3027 DeleteTrans(ttc, 1);
3028 ttc = (struct volser_trans *)0;
3037 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3038 struct volintSize *size)
3041 struct volser_trans *tt;
3042 char caller[MAXKTCNAMELEN];
3044 if (!afsconf_SuperUser(tdir, acid, caller))
3045 return VOLSERBAD_ACCESS; /*not a super user */
3046 tt = FindTrans(fromTrans);
3049 if (tt->vflags & VTDeleted) {
3053 TSetRxCall(tt, acid, "GetSize");
3054 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3057 return VOLSERTRELE_ERROR;
3059 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3064 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3065 afs_uint32 where, afs_int32 verbose)
3067 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3069 Volume *vol=0, *newvol=0;
3070 struct volser_trans *tt = 0, *tt2 = 0;
3071 char caller[MAXKTCNAMELEN];
3074 if (!afsconf_SuperUser(tdir, acall, caller))
3077 vol = VAttachVolume(&code, vid, V_VOLUPD);
3083 newvol = VAttachVolume(&code, new, V_VOLUPD);
3085 VDetachVolume(&code2, vol);
3090 if (V_device(vol) != V_device(newvol)
3091 || V_uniquifier(newvol) != 2) {
3092 if (V_device(vol) != V_device(newvol)) {
3093 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3095 rx_Write(acall, line, strlen(line));
3097 if (V_uniquifier(newvol) != 2) {
3098 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3099 rx_Write(acall, line, strlen(line));
3102 rx_Write(acall, line, 1);
3103 VDetachVolume(&code2, vol);
3104 VDetachVolume(&code2, newvol);
3107 tt = NewTrans(vid, V_device(vol));
3109 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3110 rx_Write(acall, line, strlen(line));
3112 rx_Write(acall, line, 1);
3113 VDetachVolume(&code2, vol);
3114 VDetachVolume(&code2, newvol);
3115 return VOLSERVOLBUSY;
3117 VTRANS_OBJ_LOCK(tt);
3118 tt->iflags = ITBusy;
3120 TSetRxCall_r(tt, NULL, "SplitVolume");
3121 VTRANS_OBJ_UNLOCK(tt);
3123 tt2 = NewTrans(new, V_device(newvol));
3125 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3126 rx_Write(acall, line, strlen(line));
3128 rx_Write(acall, line, 1);
3130 VDetachVolume(&code2, vol);
3131 VDetachVolume(&code2, newvol);
3132 return VOLSERVOLBUSY;
3134 VTRANS_OBJ_LOCK(tt2);
3135 tt2->iflags = ITBusy;
3137 TSetRxCall_r(tt2, NULL, "SplitVolume");
3138 VTRANS_OBJ_UNLOCK(tt2);
3140 code = split_volume(acall, vol, newvol, where, verbose);
3142 VDetachVolume(&code2, vol);
3144 VDetachVolume(&code2, newvol);
3145 DeleteTrans(tt2, 1);
3152 /* GetPartName - map partid (a decimal number) into pname (a string)
3153 * Since for NT we actually want to return the drive name, we map through the
3157 GetPartName(afs_int32 partid, char *pname)
3162 strcpy(pname, "/vicep");
3163 pname[6] = 'a' + partid;
3166 } else if (partid < VOLMAXPARTS) {
3167 strcpy(pname, "/vicep");
3169 pname[6] = 'a' + (partid / 26);
3170 pname[7] = 'a' + (partid % 26);