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>
18 #ifdef AFS_PTHREAD_ENV
19 # include <opr/lock.h>
24 #include <rx/rx_queue.h>
25 #include <afs/afsint.h>
26 #include <afs/prs_fs.h>
30 #include <afs/cellconfig.h>
33 #include <afs/ihandle.h>
35 #include <afs/ntops.h>
37 #include <afs/vnode.h>
38 #include <afs/volume.h>
39 #include <afs/volume_inline.h>
40 #include <afs/partition.h>
42 #include <afs/daemon_com.h>
43 #include <afs/fssync.h>
45 #include "afs/audit.h"
47 #include <afs/afsutil.h>
48 #include <afs/com_err.h>
49 #include <afs/vol_prototypes.h>
50 #include <afs/errors.h>
53 #include "voltrans_inline.h"
56 #include "volser_internal.h"
58 #include "dumpstuff.h"
61 extern struct afsconf_dir *tdir;
62 extern int DoPreserveVolumeStats;
64 extern void LogError(afs_int32 errcode);
66 /* Forward declarations */
67 static int GetPartName(afs_int32 partid, char *pname);
69 #define OneDay (24*60*60)
75 afs_int32 localTid = 1;
77 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
78 struct diskPartition64 *);
79 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
80 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
81 afs_int32, afs_uint32, afs_uint32 *,
83 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
84 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
85 afs_int32, char *, afs_uint32 *);
86 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
87 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
88 afs_int32, afs_int32 *);
89 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
91 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
92 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
93 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
94 struct destServer *destination, afs_int32,
95 struct restoreCookie *cookie);
96 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
97 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
98 struct restoreCookie *);
99 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
100 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
101 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
102 struct volser_status *);
103 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
104 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
105 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
106 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
107 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
109 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
111 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
113 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
115 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
116 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
117 afs_int32, afs_uint32, afs_uint32,
119 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
122 * Return the host address of the caller as a string.
124 * @param[in] acid incoming rx call
125 * @param[out] buffer buffer to be filled with the addess string
127 * @return address as formatted by inet_ntoa
130 callerAddress(struct rx_call *acid, char *buffer)
132 afs_uint32 ip = rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid)));
133 return afs_inet_ntoa_r(ip, buffer);
136 /* this call unlocks all of the partition locks we've set */
140 struct DiskPartition64 *tp;
141 for (tp = DiskPartitionList; tp; tp = tp->next) {
142 if (tp->lock_fd != INVALID_FD) {
143 OS_CLOSE(tp->lock_fd);
144 tp->lock_fd = INVALID_FD;
155 code = VPFullUnlock_r();
160 /* get partition id from a name */
162 PartitionID(char *aname)
170 return -1; /* unknown */
172 /* otherwise check for vicepa or /vicepa, or just plain "a" */
174 if (!strncmp(aname, "/vicep", 6)) {
175 strncpy(ascii, aname + 6, 2);
177 return -1; /* bad partition name */
178 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
179 * from 0. Do the appropriate conversion */
181 /* one char name, 0..25 */
182 if (ascii[0] < 'a' || ascii[0] > 'z')
183 return -1; /* wrongo */
184 return ascii[0] - 'a';
186 /* two char name, 26 .. <whatever> */
187 if (ascii[0] < 'a' || ascii[0] > 'z')
188 return -1; /* wrongo */
189 if (ascii[1] < 'a' || ascii[1] > 'z')
190 return -1; /* just as bad */
191 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
192 if (code > VOLMAXPARTS)
199 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
203 /* 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 */
204 snprintf(aname, asize, VFORMAT, (unsigned long)avol);
209 ConvertPartition(int apartno, char *aname, int asize)
215 strcpy(aname, "/vicep");
217 aname[6] = 'a' + apartno;
221 aname[6] = 'a' + (apartno / 26);
222 aname[7] = 'a' + (apartno % 26);
228 #ifdef AFS_DEMAND_ATTACH_FS
229 /* normally we should use the regular salvaging functions from the volume
230 * package, but this is a special case where we have a volume ID, but no
231 * volume structure to give the volume package */
233 SalvageUnknownVolume(VolumeId volid, char *part)
237 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
238 afs_printable_uint32_lu(volid), part);
240 code = FSYNC_VolOp(volid, part, FSYNC_VOL_FORCE_ERROR,
241 FSYNC_SALVAGE, NULL);
243 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
244 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
248 #endif /* AFS_DEMAND_ATTACH_FS */
250 static struct Volume *
251 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
256 vp = VAttachVolumeByName(ec, partition, name, mode);
258 #ifdef AFS_DEMAND_ATTACH_FS
262 * The fileserver will take care of keeping track of how many
263 * demand-salvages have been performed, and will force the volume to
264 * ERROR if we've done too many. The limit on This loop is just a
265 * failsafe to prevent trying to salvage forever. We want to attempt
266 * attachment at least SALVAGE_COUNT_MAX times, since we want to
267 * avoid prematurely exiting this loop, if we can.
269 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
270 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
271 vp = VAttachVolumeByName(ec, partition, name, mode);
274 if (*ec == VSALVAGING) {
278 #endif /* AFS_DEMAND_ATTACH_FS */
283 static struct Volume *
284 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
289 vp = VAttachVolume(ec, avolid, amode);
291 #ifdef AFS_DEMAND_ATTACH_FS
294 /* see comment above in VAttachVolumeByName_retry */
295 for (i = 0; i < SALVAGE_COUNT_MAX*2 && *ec == VSALVAGING; i++) {
296 sleep(SALVAGE_PRIO_UPDATE_INTERVAL);
297 vp = VAttachVolume(ec, avolid, amode);
300 if (*ec == VSALVAGING) {
304 #endif /* AFS_DEMAND_ATTACH_FS */
309 /* the only attach function that takes a partition is "...ByName", so we use it */
310 static struct Volume *
311 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
313 char pbuf[30], vbuf[20];
315 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
319 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
324 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
327 /* Adapted from the file server; create a root directory for this volume */
329 ViceCreateRoot(Volume *vp)
332 struct acl_accessList *ACL;
334 Inode inodeNumber, AFS_UNUSED nearInode;
335 struct VnodeDiskObject *vnode;
336 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
342 vnode = calloc(1, SIZEOF_LARGEDISKVNODE);
346 V_pref(vp, nearInode);
348 IH_CREATE(V_linkHandle(vp), V_device(vp),
349 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
351 if (!VALID_INO(inodeNumber)) {
352 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
357 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
358 did.Volume = V_id(vp);
359 did.Vnode = (VnodeId) 1;
362 opr_Verify(!(afs_dir_MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
363 DFlush(); /* flush all modified dir buffers out */
364 DZap(&dir); /* Remove all buffers for this dir */
365 length = afs_dir_Length(&dir); /* Remember size of this directory */
367 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
369 /* build a single entry ACL that gives all rights to system:administrators */
370 /* this section of code assumes that access list format is not going to
373 ACL = VVnodeDiskACL(vnode);
374 ACL->size = sizeof(struct acl_accessList);
375 ACL->version = ACL_ACLVERSION;
379 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
380 ACL->entries[0].rights =
381 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
382 | PRSFS_LOCK | PRSFS_ADMINISTER;
384 vnode->type = vDirectory;
386 vnode->modeBits = 0777;
387 vnode->linkCount = 2;
388 VNDISK_SET_LEN(vnode, length);
389 vnode->uniquifier = 1;
390 V_uniquifier(vp) = vnode->uniquifier + 1;
391 vnode->dataVersion = 1;
392 VNDISK_SET_INO(vnode, inodeNumber);
393 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
397 vnode->vnodeMagic = vcp->magic;
399 IH_INIT(h, vp->device, V_parentId(vp),
400 vp->vnodeIndex[vLarge].handle->ih_ino);
402 opr_Assert(fdP != NULL);
403 nBytes = FDH_PWRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE, vnodeIndexOffset(vcp, 1));
404 opr_Assert(nBytes == SIZEOF_LARGEDISKVNODE);
405 FDH_REALLYCLOSE(fdP);
407 VNDISK_GET_LEN(length, vnode);
408 V_diskused(vp) = nBlocks(length);
415 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
419 struct diskPartition64 *dp = malloc(sizeof(struct diskPartition64));
421 code = VolPartitionInfo(acid, pname, dp);
423 strncpy(partition->name, dp->name, 32);
424 strncpy(partition->devName, dp->devName, 32);
425 partition->lock_fd = dp->lock_fd;
426 partition->free=RoundInt64ToInt32(dp->free);
427 partition->minFree=RoundInt64ToInt32(dp->minFree);
430 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
435 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
440 code = VolPartitionInfo(acid, pname, partition);
441 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
446 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
449 struct DiskPartition64 *dp;
452 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
455 dp = VGetPartition(pname, 0);
457 strncpy(partition->name, dp->name, 32);
458 strncpy(partition->devName, dp->devName, 32);
459 partition->lock_fd = (int)dp->lock_fd;
460 partition->free = dp->free;
461 partition->minFree = dp->totalUsable;
464 return VOLSERILLEGAL_PARTITION;
467 /* obliterate a volume completely, and slowly. */
469 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
473 code = VolNukeVolume(acid, apartID, avolID);
474 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
479 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
486 char caller[MAXKTCNAMELEN];
488 /* check for access */
489 if (!afsconf_SuperUser(tdir, acid, caller))
490 return VOLSERBAD_ACCESS;
493 Log("%s on %s is executing VolNukeVolume %u\n", caller,
494 callerAddress(acid, buffer), avolID);
497 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
499 /* we first try to attach the volume in update mode, so that the file
500 * server doesn't try to use it (and abort) while (or after) we delete it.
501 * If we don't get the volume, that's fine, too. We just won't put it back.
503 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
504 code = nuke(partName, avolID);
506 VDetachVolume(&verror, tvp);
510 /* create a new volume, with name aname, on the specified partition (1..n)
511 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
512 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
513 * for the volume id (useful for things like volume restore).
514 * Return the new volume id in *avolid.
517 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
518 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
524 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
525 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
526 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
532 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
533 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
538 Error junk; /* discardable error code */
540 afs_int32 doCreateRoot = 1;
541 struct volser_trans *tt;
543 char caller[MAXKTCNAMELEN];
545 if (strlen(aname) > 31)
546 return VOLSERBADNAME;
547 if (!afsconf_SuperUser(tdir, acid, caller))
548 return VOLSERBAD_ACCESS;
551 Log("%s on %s is executing CreateVolume '%s'\n", caller,
552 callerAddress(acid, buffer), aname);
554 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
555 return error; /*a standard unix error */
556 if (atype != readwriteVolume && atype != readonlyVolume
557 && atype != backupVolume)
559 if ((volumeID = *avolid) == 0) {
561 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
565 if ((aparent == volumeID) && (atype == readwriteVolume)) {
570 tt = NewTrans(volumeID, apart);
572 Log("1 createvolume: failed to create trans\n");
573 return VOLSERVOLBUSY; /* volume already busy! */
575 vp = VCreateVolume(&error, ppath, volumeID, aparent);
577 #ifdef AFS_DEMAND_ATTACH_FS
578 if (error != VVOLEXISTS && error != EXDEV) {
579 SalvageUnknownVolume(volumeID, ppath);
582 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
587 V_uniquifier(vp) = 1;
588 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
589 V_inService(vp) = V_blessed(vp) = 1;
591 AssignVolumeName(&V_disk(vp), aname, 0);
593 error = ViceCreateRoot(vp);
595 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
596 "error code %u\n", (unsigned)error);
598 V_needsSalvaged(vp) = 1;
599 VDetachVolume(&junk, vp);
603 V_destroyMe(vp) = DESTROY_ME;
605 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
606 VUpdateVolume(&error, vp);
608 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
611 VDetachVolume(&junk, vp); /* rather return the real error code */
617 TSetRxCall_r(tt, acid, "CreateVolume");
618 VTRANS_OBJ_UNLOCK(tt);
619 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
622 return VOLSERTRELE_ERROR;
626 /* delete the volume associated with this transaction */
628 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
632 code = VolDeleteVolume(acid, atrans);
633 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
638 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
640 struct volser_trans *tt;
642 char caller[MAXKTCNAMELEN];
644 if (!afsconf_SuperUser(tdir, acid, caller))
645 return VOLSERBAD_ACCESS;
646 tt = FindTrans(atrans);
649 if (tt->vflags & VTDeleted) {
650 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
656 Log("%s on %s is executing Delete Volume %u\n", caller,
657 callerAddress(acid, buffer), tt->volid);
659 TSetRxCall(tt, acid, "DeleteVolume");
660 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
661 V_destroyMe(tt->volume) = DESTROY_ME;
662 if (tt->volume->needsPutBack) {
663 tt->volume->needsPutBack = VOL_PUTBACK_DELETE; /* so endtrans does the right fssync opcode */
666 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
668 VTRANS_OBJ_UNLOCK(tt);
670 return VOLSERTRELE_ERROR;
672 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
673 return 0; /* vpurgevolume doesn't set an error code */
676 /* make a clone of the volume associated with atrans, possibly giving it a new
677 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
678 * for the clone's id). The new clone is given the name newName. Finally,
679 * due to efficiency considerations, if purgeId is non-zero, we purge that
680 * volume when doing the clone operation. This may be useful when making
681 * new backup volumes, for instance since the net result of a clone and a
682 * purge generally leaves many inode ref counts the same, while doing them
683 * separately would result in far more iincs and idecs being peformed
684 * (and they are slow operations).
686 /* for efficiency reasons, sometimes faster to piggyback a purge here */
688 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
689 afs_int32 newType, char *newName, afs_uint32 *newNumber)
693 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
694 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
695 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
701 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
702 afs_int32 newType, char *newName, afs_uint32 *newNumber)
705 struct Volume *originalvp, *purgevp, *newvp;
707 struct volser_trans *tt, *ttc;
708 char caller[MAXKTCNAMELEN];
709 #ifdef AFS_DEMAND_ATTACH_FS
710 struct Volume *salv_vp = NULL;
713 if (strlen(newName) > 31)
714 return VOLSERBADNAME;
715 if (!afsconf_SuperUser(tdir, acid, caller))
716 return VOLSERBAD_ACCESS; /*not a super user */
719 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
720 callerAddress(acid, buffer), newName);
723 originalvp = (Volume *) 0;
724 purgevp = (Volume *) 0;
725 newvp = (Volume *) 0;
726 tt = ttc = (struct volser_trans *)0;
728 if (!newNumber || !*newNumber) {
729 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
734 tt = FindTrans(atrans);
737 if (tt->vflags & VTDeleted) {
738 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
742 ttc = NewTrans(newId, tt->partition);
743 if (!ttc) { /* someone is messing with the clone already */
745 return VOLSERVOLBUSY;
747 TSetRxCall(tt, acid, "Clone");
751 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
753 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
759 originalvp = tt->volume;
760 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
761 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
767 if (originalvp->device != purgevp->device) {
768 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
772 if (V_type(purgevp) != readonlyVolume) {
773 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
777 if (V_parentId(originalvp) != V_parentId(purgevp)) {
778 Log("1 Volser: Clone: Volume %u and volume %u were not originally cloned from the same parent; aborted\n", purgeId, tt->volid);
785 #ifdef AFS_DEMAND_ATTACH_FS
786 salv_vp = originalvp;
789 if (purgeId == newId) {
793 VCreateVolume(&error, originalvp->partition->name, newId,
794 V_parentId(originalvp));
796 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
797 newvp = (Volume *) 0;
801 if (newType == readonlyVolume)
802 V_cloneId(originalvp) = newId;
803 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
806 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
807 CloneVolume(&error, originalvp, newvp, purgevp);
808 purgevp = NULL; /* clone releases it, maybe even if error */
810 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
814 if (newType == readonlyVolume) {
815 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
816 V_type(newvp) = readonlyVolume;
817 } else if (newType == backupVolume) {
818 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
819 V_type(newvp) = backupVolume;
820 V_backupId(originalvp) = newId;
822 strcpy(newvp->header->diskstuff.name, newName);
823 V_creationDate(newvp) = V_copyDate(newvp);
824 ClearVolumeStats(&V_disk(newvp));
825 V_destroyMe(newvp) = DESTROY_ME;
826 V_inService(newvp) = 0;
827 if (newType == backupVolume) {
828 V_backupDate(originalvp) = V_copyDate(newvp);
829 V_backupDate(newvp) = V_copyDate(newvp);
832 VUpdateVolume(&error, newvp);
834 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
838 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
840 VUpdateVolume(&error, originalvp);
842 Log("1 Volser: Clone: original update %u\n", error);
847 #ifdef AFS_DEMAND_ATTACH_FS
851 tt = (struct volser_trans *)0;
852 error = VOLSERTRELE_ERROR;
860 VDetachVolume(&code, purgevp);
862 VDetachVolume(&code, newvp);
869 #ifdef AFS_DEMAND_ATTACH_FS
870 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
871 V_needsSalvaged(salv_vp) = 1;
873 #endif /* AFS_DEMAND_ATTACH_FS */
877 /* reclone this volume into the specified id */
879 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
883 code = VolReClone(acid, atrans, cloneId);
884 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
890 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
892 struct Volume *originalvp, *clonevp;
895 struct volser_trans *tt, *ttc;
896 char caller[MAXKTCNAMELEN];
897 VolumeDiskData saved_header;
899 /*not a super user */
900 if (!afsconf_SuperUser(tdir, acid, caller))
901 return VOLSERBAD_ACCESS;
904 Log("%s on %s is executing Reclone Volume %u\n", caller,
905 callerAddress(acid, buffer), cloneId);
908 clonevp = originalvp = (Volume *) 0;
909 tt = (struct volser_trans *)0;
911 tt = FindTrans(atrans);
914 if (tt->vflags & VTDeleted) {
915 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
919 ttc = NewTrans(cloneId, tt->partition);
920 if (!ttc) { /* someone is messing with the clone already */
922 return VOLSERVOLBUSY;
924 TSetRxCall(tt, acid, "ReClone");
926 originalvp = tt->volume;
927 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
928 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
934 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
936 Log("1 Volser: can't attach clone %d\n", cloneId);
940 newType = V_type(clonevp); /* type of the new volume */
942 if (originalvp->device != clonevp->device) {
943 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
948 if (V_parentId(originalvp) != V_parentId(clonevp)) {
949 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
954 if (DoPreserveVolumeStats) {
955 CopyVolumeStats(&V_disk(clonevp), &saved_header);
959 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
961 CloneVolume(&error, originalvp, clonevp, clonevp);
963 Log("1 Volser: Clone: reclone operation failed with code %d\n",
969 /* fix up volume name and type, CloneVolume just propagated RW's */
970 if (newType == readonlyVolume) {
971 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
972 V_type(clonevp) = readonlyVolume;
973 } else if (newType == backupVolume) {
974 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
975 V_type(clonevp) = backupVolume;
976 V_backupId(originalvp) = cloneId;
978 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
980 /* update the creationDate, since this represents the last cloning date
981 * for ROs. But do not update copyDate; let it stay so we can identify
982 * when the clone was first created. */
983 V_creationDate(clonevp) = time(0);
984 if (DoPreserveVolumeStats) {
985 CopyVolumeStats(&saved_header, &V_disk(clonevp));
987 ClearVolumeStats(&V_disk(clonevp));
989 V_destroyMe(clonevp) = 0;
990 V_inService(clonevp) = 0;
991 if (newType == backupVolume) {
992 V_backupDate(originalvp) = V_creationDate(clonevp);
993 V_backupDate(clonevp) = V_creationDate(clonevp);
995 V_inUse(clonevp) = 0;
996 VUpdateVolume(&error, clonevp);
998 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
1002 /* VUpdateVolume succeeded. Mark it in service so there's no window
1003 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
1004 * specialStatus; this is a reclone and this volume started online
1006 V_inService(clonevp) = 1;
1007 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
1009 VUpdateVolume(&error, originalvp);
1011 Log("1 Volser: Clone: original update %u\n", error);
1017 tt = (struct volser_trans *)0;
1018 error = VOLSERTRELE_ERROR;
1022 DeleteTrans(ttc, 1);
1025 struct DiskPartition64 *tpartp = originalvp->partition;
1026 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1032 VDetachVolume(&code, clonevp);
1038 DeleteTrans(ttc, 1);
1042 /* create a new transaction, associated with volume and partition. Type of
1043 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1044 * See volser.h for definition of iflags (the constants are named IT*).
1047 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1048 afs_int32 iflags, afs_int32 *ttid)
1052 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1053 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1059 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1060 afs_int32 iflags, afs_int32 *ttid)
1062 struct volser_trans *tt;
1067 char caller[MAXKTCNAMELEN];
1069 if (!afsconf_SuperUser(tdir, acid, caller))
1070 return VOLSERBAD_ACCESS; /*not a super user */
1071 if (iflags & ITCreate)
1073 else if (iflags & ITBusy)
1075 else if (iflags & ITReadOnly)
1077 else if (iflags & ITOffline)
1080 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1085 tt = NewTrans(volume, partition);
1087 /* can't create a transaction? put the volume back */
1088 Log("1 transcreate: can't create transaction\n");
1089 return VOLSERVOLBUSY;
1091 tv = XAttachVolume(&error, volume, partition, mode);
1095 VDetachVolume(&code, tv);
1099 VTRANS_OBJ_LOCK(tt);
1102 tt->iflags = iflags;
1104 TSetRxCall_r(tt, NULL, "TransCreate");
1105 VTRANS_OBJ_UNLOCK(tt);
1107 return VOLSERTRELE_ERROR;
1112 /* using aindex as a 0-based index, return the aindex'th volume on this server
1113 * Both the volume number and partition number (one-based) are returned.
1116 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1121 code = VolGetNthVolume(acid, aindex, avolume, apart);
1122 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1127 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1130 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1134 /* return the volume flags (VT* constants in volser.h) associated with this
1138 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1142 code = VolGetFlags(acid, atid, aflags);
1143 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1148 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1150 struct volser_trans *tt;
1152 tt = FindTrans(atid);
1155 if (tt->vflags & VTDeleted) {
1156 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1161 TSetRxCall(tt, acid, "GetFlags");
1162 *aflags = tt->vflags;
1165 return VOLSERTRELE_ERROR;
1170 /* Change the volume flags (VT* constants in volser.h) associated with this
1171 * transaction. Effects take place immediately on volume, although volume
1172 * remains attached as usual by the transaction.
1175 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1179 code = VolSetFlags(acid, atid, aflags);
1180 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1186 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1188 struct volser_trans *tt;
1191 char caller[MAXKTCNAMELEN];
1193 if (!afsconf_SuperUser(tdir, acid, caller))
1194 return VOLSERBAD_ACCESS; /*not a super user */
1195 /* find the trans */
1196 tt = FindTrans(atid);
1199 if (tt->vflags & VTDeleted) {
1200 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1205 TSetRxCall(tt, acid, "SetFlags");
1206 vp = tt->volume; /* pull volume out of transaction */
1208 /* check if we're allowed to make any updates */
1209 if (tt->iflags & ITReadOnly) {
1214 /* handle delete-on-salvage flag */
1215 if (aflags & VTDeleteOnSalvage) {
1216 V_destroyMe(tt->volume) = DESTROY_ME;
1218 V_destroyMe(tt->volume) = 0;
1221 if (aflags & VTOutOfService) {
1222 V_inService(vp) = 0;
1224 V_inService(vp) = 1;
1226 VUpdateVolume(&error, vp);
1227 VTRANS_OBJ_LOCK(tt);
1228 tt->vflags = aflags;
1230 VTRANS_OBJ_UNLOCK(tt);
1231 if (TRELE(tt) && !error)
1232 return VOLSERTRELE_ERROR;
1237 /* dumpS the volume associated with a particular transaction from a particular
1238 * date. Send the dump to a different transaction (destTrans) on the server
1239 * specified by the destServer structure.
1242 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1243 struct destServer *destination, afs_int32 destTrans,
1244 struct restoreCookie *cookie)
1249 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1250 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1251 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1256 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1257 struct destServer *destination, afs_int32 destTrans,
1258 struct restoreCookie *cookie)
1260 struct volser_trans *tt;
1262 struct rx_connection *tcon;
1263 struct rx_call *tcall;
1265 struct rx_securityClass *securityObject;
1266 afs_int32 securityIndex;
1267 char caller[MAXKTCNAMELEN];
1269 if (!afsconf_SuperUser(tdir, acid, caller))
1270 return VOLSERBAD_ACCESS; /*not a super user */
1271 /* initialize things */
1272 tcon = (struct rx_connection *)0;
1273 tt = (struct volser_trans *)0;
1275 /* find the local transaction */
1276 tt = FindTrans(fromTrans);
1279 if (tt->vflags & VTDeleted) {
1280 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1285 TSetRxCall(tt, NULL, "Forward");
1287 /* get auth info for the this connection (uses afs from ticket file) */
1288 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1294 /* make an rpc connection to the other server */
1296 rx_NewConnection(htonl(destination->destHost),
1297 htons(destination->destPort), VOLSERVICE_ID,
1298 securityObject, securityIndex);
1304 tcall = rx_NewCall(tcon);
1305 TSetRxCall(tt, tcall, "Forward");
1306 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1307 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1312 /* these next calls implictly call rx_Write when writing out data */
1313 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1316 EndAFSVolRestore(tcall); /* probably doesn't do much */
1318 code = rx_EndCall(tcall, 0);
1319 rx_DestroyConnection(tcon); /* done with the connection */
1324 return VOLSERTRELE_ERROR;
1330 (void)rx_EndCall(tcall, 0);
1331 rx_DestroyConnection(tcon);
1340 /* Start a dump and send it to multiple places simultaneously.
1341 * If this returns an error (eg, return ENOENT), it means that
1342 * none of the releases worked. If this returns 0, that means
1343 * that one or more of the releases worked, and the caller has
1344 * to examine the results array to see which one(s).
1345 * This will only do EITHER incremental or full, not both, so it's
1346 * the caller's responsibility to be sure that all the destinations
1347 * need just an incremental (and from the same time), if that's
1351 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1352 fromDate, manyDests *destinations, afs_int32 spare,
1353 struct restoreCookie *cookie, manyResults *results)
1355 afs_int32 securityIndex;
1356 struct rx_securityClass *securityObject;
1357 char caller[MAXKTCNAMELEN];
1358 struct volser_trans *tt;
1359 afs_int32 ec, code, *codes;
1360 struct rx_connection **tcons;
1361 struct rx_call **tcalls;
1363 int i, is_incremental;
1366 memset(results, 0, sizeof(manyResults));
1367 i = results->manyResults_len = destinations->manyDests_len;
1368 results->manyResults_val = codes = malloc(i * sizeof(afs_int32));
1370 if (!results || !results->manyResults_val)
1373 if (!afsconf_SuperUser(tdir, acid, caller))
1374 return VOLSERBAD_ACCESS; /*not a super user */
1375 tt = FindTrans(fromTrans);
1378 if (tt->vflags & VTDeleted) {
1379 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1384 TSetRxCall(tt, NULL, "ForwardMulti");
1386 /* (fromDate == 0) ==> full dump */
1387 is_incremental = (fromDate ? 1 : 0);
1389 tcons = malloc(i * sizeof(struct rx_connection *));
1393 tcalls = malloc(i * sizeof(struct rx_call *));
1399 /* get auth info for this connection (uses afs from ticket file) */
1400 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1402 goto fail; /* in order to audit each failure */
1405 /* make connections to all the other servers */
1406 for (i = 0; i < destinations->manyDests_len; i++) {
1407 struct replica *dest = &(destinations->manyDests_val[i]);
1409 rx_NewConnection(htonl(dest->server.destHost),
1410 htons(dest->server.destPort), VOLSERVICE_ID,
1411 securityObject, securityIndex);
1413 codes[i] = ENOTCONN;
1415 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1416 codes[i] = ENOTCONN;
1419 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1422 (void)rx_EndCall(tcalls[i], 0);
1424 rx_DestroyConnection(tcons[i]);
1431 /* these next calls implictly call rx_Write when writing out data */
1432 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1436 for (i--; i >= 0; i--) {
1437 struct replica *dest = &(destinations->manyDests_val[i]);
1439 if (!code && tcalls[i] && !codes[i]) {
1440 EndAFSVolRestore(tcalls[i]);
1443 ec = rx_EndCall(tcalls[i], 0);
1448 rx_DestroyConnection(tcons[i]); /* done with the connection */
1451 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1452 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1453 dest->trans, AUD_END);
1460 if (TRELE(tt) && !code) /* return the first code if it's set */
1461 return VOLSERTRELE_ERROR;
1468 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1472 code = VolDump(acid, fromTrans, fromDate, 0);
1473 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1478 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1483 code = VolDump(acid, fromTrans, fromDate, flags);
1484 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1489 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1493 struct volser_trans *tt;
1494 char caller[MAXKTCNAMELEN];
1496 if (!afsconf_SuperUser(tdir, acid, caller))
1497 return VOLSERBAD_ACCESS; /*not a super user */
1498 tt = FindTrans(fromTrans);
1501 if (tt->vflags & VTDeleted) {
1502 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1506 TSetRxCall(tt, acid, "Dump");
1507 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1508 ? 0 : 1); /* squirt out the volume's data, too */
1517 return VOLSERTRELE_ERROR;
1523 * Ha! No more helper process!
1526 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1527 struct restoreCookie *cookie)
1531 code = VolRestore(acid, atrans, aflags, cookie);
1532 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1537 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1538 struct restoreCookie *cookie)
1540 struct volser_trans *tt;
1541 afs_int32 code, tcode;
1542 char caller[MAXKTCNAMELEN];
1544 if (!afsconf_SuperUser(tdir, acid, caller))
1545 return VOLSERBAD_ACCESS; /*not a super user */
1546 tt = FindTrans(atrans);
1549 if (tt->vflags & VTDeleted) {
1550 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1554 TSetRxCall(tt, acid, "Restore");
1556 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1558 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1559 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1563 return (code ? code : tcode);
1566 /* end a transaction, returning the transaction's final error code in rcode */
1568 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1572 code = VolEndTrans(acid, destTrans, rcode);
1573 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1578 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1580 struct volser_trans *tt;
1581 char caller[MAXKTCNAMELEN];
1583 if (!afsconf_SuperUser(tdir, acid, caller))
1584 return VOLSERBAD_ACCESS; /*not a super user */
1585 tt = FindTrans(destTrans);
1589 *rcode = tt->returnCode;
1590 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1596 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1600 code = VolSetForwarding(acid, atid, anewsite);
1601 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1602 htonl(anewsite), AUD_END);
1607 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1609 struct volser_trans *tt;
1610 char caller[MAXKTCNAMELEN];
1613 if (!afsconf_SuperUser(tdir, acid, caller))
1614 return VOLSERBAD_ACCESS; /*not a super user */
1615 tt = FindTrans(atid);
1618 if (tt->vflags & VTDeleted) {
1619 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1624 TSetRxCall(tt, acid, "SetForwarding");
1625 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1628 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1631 return VOLSERTRELE_ERROR;
1637 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1638 struct volser_status *astatus)
1642 code = VolGetStatus(acid, atrans, astatus);
1643 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1648 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1649 struct volser_status *astatus)
1652 struct VolumeDiskData *td;
1653 struct volser_trans *tt;
1656 tt = FindTrans(atrans);
1659 if (tt->vflags & VTDeleted) {
1660 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1665 TSetRxCall(tt, acid, "GetStatus");
1673 td = &tv->header->diskstuff;
1674 astatus->volID = td->id;
1675 astatus->nextUnique = td->uniquifier;
1676 astatus->type = td->type;
1677 astatus->parentID = td->parentId;
1678 astatus->cloneID = td->cloneId;
1679 astatus->backupID = td->backupId;
1680 astatus->restoredFromID = td->restoredFromId;
1681 astatus->maxQuota = td->maxquota;
1682 astatus->minQuota = td->minquota;
1683 astatus->owner = td->owner;
1684 astatus->creationDate = td->creationDate;
1685 astatus->accessDate = td->accessDate;
1686 astatus->updateDate = td->updateDate;
1687 astatus->expirationDate = td->expirationDate;
1688 astatus->backupDate = td->backupDate;
1689 astatus->copyDate = td->copyDate;
1692 return VOLSERTRELE_ERROR;
1698 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1699 struct volintInfo *astatus)
1703 code = VolSetInfo(acid, atrans, astatus);
1704 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1709 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1710 struct volintInfo *astatus)
1713 struct VolumeDiskData *td;
1714 struct volser_trans *tt;
1715 char caller[MAXKTCNAMELEN];
1718 if (!afsconf_SuperUser(tdir, acid, caller))
1719 return VOLSERBAD_ACCESS; /*not a super user */
1720 tt = FindTrans(atrans);
1723 if (tt->vflags & VTDeleted) {
1724 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1728 TSetRxCall(tt, acid, "SetStatus");
1736 td = &tv->header->diskstuff;
1738 * Add more fields as necessary
1740 if (astatus->maxquota != -1)
1741 td->maxquota = astatus->maxquota;
1742 if (astatus->dayUse != -1)
1743 td->dayUse = astatus->dayUse;
1744 if (astatus->creationDate != -1)
1745 td->creationDate = astatus->creationDate;
1746 if (astatus->updateDate != -1)
1747 td->updateDate = astatus->updateDate;
1748 if (astatus->spare2 != -1)
1749 td->volUpdateCounter = (unsigned int)astatus->spare2;
1750 VUpdateVolume(&error, tv);
1753 return VOLSERTRELE_ERROR;
1759 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1763 code = VolGetName(acid, atrans, aname);
1764 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1769 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1772 struct VolumeDiskData *td;
1773 struct volser_trans *tt;
1776 /* We need to at least fill it in */
1780 tt = FindTrans(atrans);
1783 if (tt->vflags & VTDeleted) {
1784 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1788 TSetRxCall(tt, acid, "GetName");
1796 td = &tv->header->diskstuff;
1797 len = strlen(td->name) + 1; /* don't forget the null */
1803 *aname = realloc(*aname, len);
1804 strcpy(*aname, td->name);
1807 return VOLSERTRELE_ERROR;
1812 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1815 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1816 afs_uint32 parentId, afs_uint32 cloneId)
1822 /*return a list of all partitions on the server. The non mounted
1823 *partitions are returned as -1 in the corresponding slot in partIds*/
1825 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1829 code = VolListPartitions(acid, partIds);
1830 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1835 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1840 strcpy(namehead, "/vicep"); /*7 including null terminator */
1842 /* Just return attached partitions. */
1844 for (i = 0; i < 26; i++) {
1845 namehead[6] = i + 'a';
1846 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1852 /*return a list of all partitions on the server. The non mounted
1853 *partitions are returned as -1 in the corresponding slot in partIds*/
1855 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1859 code = XVolListPartitions(acid, pEntries);
1860 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1865 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1868 struct partList partList;
1869 struct DiskPartition64 *dp;
1872 strcpy(namehead, "/vicep"); /*7 including null terminator */
1874 /* Only report attached partitions */
1875 for (i = 0; i < VOLMAXPARTS; i++) {
1876 #ifdef AFS_DEMAND_ATTACH_FS
1877 dp = VGetPartitionById(i, 0);
1880 namehead[6] = i + 'a';
1886 namehead[6] = 'a' + (k / 26);
1887 namehead[7] = 'a' + (k % 26);
1890 dp = VGetPartition(namehead, 0);
1893 partList.partId[j++] = i;
1896 pEntries->partEntries_val = malloc(j * sizeof(int));
1897 if (!pEntries->partEntries_val)
1899 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1901 pEntries->partEntries_len = j;
1903 pEntries->partEntries_val = NULL;
1904 pEntries->partEntries_len = 0;
1911 * Scan a directory for possible volume headers.
1912 * in: DIR *dirp -- a directory handle from opendir()
1913 * out: char *volname -- set to name of directory entry
1914 * afs_uint32 *volid -- set to volume ID parsed from name
1916 * true if volname and volid have been set to valid values
1917 * false if we got to the end of the directory
1920 GetNextVol(DIR *dirp, char *volname, afs_uint32 *volid)
1924 while ((dp = readdir(dirp)) != NULL) {
1925 /* could be optimized on platforms with dp->d_namlen */
1926 if (dp->d_name[0] == 'V' && strlen(dp->d_name) == VHDRNAMELEN
1927 && strcmp(&(dp->d_name[11]), VHDREXT) == 0) {
1928 *volid = VolumeNumber(dp->d_name);
1929 strcpy(volname, dp->d_name);
1937 * volint vol info structure type.
1940 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1941 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1942 } volint_info_type_t;
1945 * handle to various on-wire vol info types.
1948 volint_info_type_t volinfo_type;
1954 } volint_info_handle_t;
1957 * store value to a field at the appropriate location in on-wire structure.
1959 #define VOLINT_INFO_STORE(handle, name, val) \
1961 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1962 (handle)->volinfo_ptr.base->name = (val); \
1964 (handle)->volinfo_ptr.ext->name = (val); \
1969 * get pointer to appropriate offset of field in on-wire structure.
1971 #define VOLINT_INFO_PTR(handle, name) \
1972 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1973 &((handle)->volinfo_ptr.base->name) : \
1974 &((handle)->volinfo_ptr.ext->name))
1977 * fill in appropriate type of on-wire volume metadata structure.
1979 * @param vp pointer to volume object
1980 * @param handle pointer to wire format handle object
1982 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1983 * @pre handle object must have a valid pointer and enumeration value
1985 * @note passing a NULL value for vp means that the fileserver doesn't
1986 * know about this particular volume, thus implying it is offline.
1988 * @return operation status
1993 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1995 unsigned int numStatBytes, now;
1996 struct VolumeDiskData *hdr = &vp->header->diskstuff;
1998 /*read in the relevant info */
1999 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2000 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
2001 VOLINT_INFO_STORE(handle, volid, hdr->id);
2002 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2003 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2004 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2005 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2006 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2007 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2008 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2009 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2010 now = FT_ApproxTime();
2011 if ((now - hdr->dayUseDate) > OneDay) {
2012 VOLINT_INFO_STORE(handle, dayUse, 0);
2014 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2016 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2017 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2018 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2019 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2021 #ifdef AFS_DEMAND_ATTACH_FS
2023 * for DAFS, we "lie" about volume state --
2024 * instead of returning the raw state from the disk header,
2025 * we compute state based upon the fileserver's internal
2026 * in-core state enumeration value reported to us via fssync,
2027 * along with the blessed and inService flags from the header.
2028 * -- tkeiser 11/27/2007
2031 /* Conditions that offline status is based on:
2032 volume is unattached state
2033 volume state is in (one of several error states)
2034 volume not in service
2035 volume is not marked as blessed (not on hold)
2036 volume in salvage req. state
2037 volume needsSalvaged
2038 next op would set volume offline
2039 next op would not leave volume online (based on several conditions)
2042 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2043 VIsErrorState(V_attachState(vp)) ||
2046 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2047 hdr->needsSalvaged ||
2048 (vp->pending_vol_op &&
2049 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2050 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2053 VOLINT_INFO_STORE(handle, inUse, 0);
2055 VOLINT_INFO_STORE(handle, inUse, 1);
2058 /* offline status based on program type, where != fileServer enum (1) is offline */
2059 if (hdr->inUse == fileServer) {
2060 VOLINT_INFO_STORE(handle, inUse, 1);
2062 VOLINT_INFO_STORE(handle, inUse, 0);
2067 switch(handle->volinfo_type) {
2068 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2069 case VOLINT_INFO_TYPE_BASE:
2071 #ifdef AFS_DEMAND_ATTACH_FS
2072 /* see comment above where we set inUse bit */
2073 if (hdr->needsSalvaged ||
2074 (vp && VIsErrorState(V_attachState(vp)))) {
2075 handle->volinfo_ptr.base->needsSalvaged = 1;
2077 handle->volinfo_ptr.base->needsSalvaged = 0;
2080 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2082 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2083 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2084 handle->volinfo_ptr.base->spare1 =
2085 (long)hdr->weekUse[0] +
2086 (long)hdr->weekUse[1] +
2087 (long)hdr->weekUse[2] +
2088 (long)hdr->weekUse[3] +
2089 (long)hdr->weekUse[4] +
2090 (long)hdr->weekUse[5] +
2091 (long)hdr->weekUse[6];
2092 handle->volinfo_ptr.base->flags = 0;
2093 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2094 handle->volinfo_ptr.base->spare3 = 0;
2098 case VOLINT_INFO_TYPE_EXT:
2100 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2101 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2104 * Copy out the stat fields in a single operation.
2106 if ((now - hdr->dayUseDate) > OneDay) {
2107 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2110 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2111 (char *)&(hdr->stat_reads[0]),
2120 #ifdef AFS_DEMAND_ATTACH_FS
2123 * get struct Volume out of the fileserver.
2125 * @param[in] volumeId volumeId for which we want state information
2126 * @param[in] pname partition name string
2127 * @param[inout] vp pointer to pointer to Volume object which
2128 * will be populated (see note)
2130 * @return operation status
2132 * @retval non-zero failure
2134 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2139 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2144 res.hdr.response_len = sizeof(res.hdr);
2145 res.payload.buf = *vp;
2146 res.payload.len = sizeof(Volume);
2148 code = FSYNC_VolOp(volumeId,
2154 if (code != SYNC_OK) {
2155 switch (res.hdr.reason) {
2156 case FSYNC_WRONG_PART:
2157 case FSYNC_UNKNOWN_VOLID:
2170 * mode of volume list operation.
2173 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2174 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2175 } vol_info_list_mode_t;
2178 * abstract interface to populate wire-format volume metadata structures.
2180 * @param[in] partId partition id
2181 * @param[in] volumeId volume id
2182 * @param[in] pname partition name
2183 * @param[in] volname volume file name
2184 * @param[in] handle handle to on-wire volume metadata object
2185 * @param[in] mode listing mode
2187 * @return operation status
2189 * @retval -2 DESTROY_ME flag is set
2190 * @retval -1 general failure; some data filled in
2191 * @retval -3 couldn't create vtrans; some data filled in
2194 GetVolInfo(afs_uint32 partId,
2195 afs_uint32 volumeId,
2198 volint_info_handle_t * handle,
2199 vol_info_list_mode_t mode)
2203 struct volser_trans *ttc = NULL;
2204 struct Volume *fill_tv, *tv = NULL;
2205 #ifdef AFS_DEMAND_ATTACH_FS
2206 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2207 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2208 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2209 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2211 /* Set up response handle for pending_vol_op */
2212 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2213 fs_res.payload.buf = fs_res_buf;
2214 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2217 ttc = NewTrans(volumeId, partId);
2220 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2221 VOLINT_INFO_STORE(handle, volid, volumeId);
2225 /* Get volume from volserver */
2226 if (mode == VOL_INFO_LIST_MULTIPLE)
2227 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2229 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2231 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2232 volumeId, pname, volname, error);
2237 * please note that destroyMe and needsSalvaged checks used to be ordered
2238 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2239 * more correct to check destroyMe before needsSalvaged.
2240 * -- tkeiser 11/28/2007
2243 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2245 case VOL_INFO_LIST_MULTIPLE:
2249 case VOL_INFO_LIST_SINGLE:
2250 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2251 volumeId, pname, volname);
2258 if (tv->header->diskstuff.needsSalvaged) {
2259 /*this volume will be salvaged */
2260 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2261 volumeId, pname, volname);
2264 #ifdef AFS_DEMAND_ATTACH_FS
2265 /* If using DAFS, get volume from fsserver */
2266 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2271 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2272 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2273 /* If we if the pending vol op */
2274 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2275 fs_tv->pending_vol_op=&pending_vol_op_res;
2277 fs_tv->pending_vol_op=NULL;
2280 /* populate the header from the volserver copy */
2281 fs_tv->header=tv->header;
2283 /* When using DAFS, use the fs volume info, populated with required structures */
2286 /* When not using DAFS, just use the local volume info */
2290 /* ok, we have all the data we need; fill in the on-wire struct */
2291 code = FillVolInfo(fill_tv, handle);
2295 VOLINT_INFO_STORE(handle, status, 0);
2296 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2297 VOLINT_INFO_STORE(handle, volid, volumeId);
2300 VDetachVolume(&error, tv);
2303 VOLINT_INFO_STORE(handle, status, 0);
2304 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2305 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2306 volumeId, pname, volname);
2310 DeleteTrans(ttc, 1);
2317 /*return the header information about the <volid> */
2319 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2320 afs_uint32 volumeId, volEntries *volumeInfo)
2324 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2325 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2330 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2331 afs_uint32 volumeId, volEntries *volumeInfo)
2333 struct DiskPartition64 *partP;
2334 char pname[9], volname[20];
2339 volint_info_handle_t handle;
2341 volumeInfo->volEntries_val = calloc(1, sizeof(volintInfo));
2342 if (!volumeInfo->volEntries_val)
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 while (GetNextVol(dirp, volname, &volid)) {
2355 if (volid == volumeId) { /*copy other things too */
2362 #ifndef AFS_PTHREAD_ENV
2363 IOMGR_Poll(); /*make sure that the client does not time out */
2366 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2367 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2369 code = GetVolInfo(partid,
2374 VOL_INFO_LIST_SINGLE);
2379 return code ? ENODEV: 0;
2384 /*------------------------------------------------------------------------
2385 * EXPORTED SAFSVolXListOneVolume
2388 * Returns extended info on volume a_volID on partition a_partID.
2391 * a_rxCidP : Pointer to the Rx call we're performing.
2392 * a_partID : Partition for which we want the extended list.
2393 * a_volID : Volume ID we wish to know about.
2394 * a_volumeXInfoP : Ptr to the extended info blob.
2397 * 0 Successful operation
2398 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2401 * Nothing interesting.
2405 *------------------------------------------------------------------------*/
2408 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2409 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2413 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2414 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2419 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2420 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2421 { /*SAFSVolXListOneVolume */
2423 struct DiskPartition64 *partP; /*Ptr to partition */
2424 char pname[9], volname[20]; /*Partition, volume names */
2425 DIR *dirp; /*Partition directory ptr */
2426 afs_uint32 currVolID; /*Current volume ID */
2427 int found = 0; /*Did we find the volume we need? */
2429 volint_info_handle_t handle;
2432 * Set up our pointers for action, marking our structure to hold exactly
2433 * one entry. Also, assume we'll fail in our quest.
2435 a_volumeXInfoP->volXEntries_val = calloc(1, sizeof(volintXInfo));
2436 if (!a_volumeXInfoP->volXEntries_val)
2439 a_volumeXInfoP->volXEntries_len = 1;
2443 * If the partition name we've been given is bad, bogue out.
2445 if (GetPartName(a_partID, pname))
2446 return (VOLSERILLEGAL_PARTITION);
2449 * Open the directory representing the given AFS parttion. If we can't
2452 if (!(partP = VGetPartition(pname, 0)))
2453 return VOLSERILLEGAL_PARTITION;
2454 dirp = opendir(VPartitionPath(partP));
2456 return (VOLSERILLEGAL_PARTITION);
2460 * Sweep through the partition directory, looking for the desired entry.
2461 * First, of course, figure out how many stat bytes to copy out of each
2464 while (GetNextVol(dirp, volname, &currVolID)) {
2465 if (currVolID == a_volID) {
2467 * We found the volume entry we're interested. Pull out the
2468 * extended information, remembering to poll (so that the client
2469 * doesn't time out) and to set up a transaction on the volume.
2473 } /*Found desired volume */
2477 #ifndef AFS_PTHREAD_ENV
2481 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2482 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2484 code = GetVolInfo(a_partID,
2489 VOL_INFO_LIST_SINGLE);
2494 * Clean up before going to dinner: close the partition directory,
2495 * return the proper value.
2499 return code ? ENODEV: 0;
2502 } /*SAFSVolXListOneVolume */
2504 /*returns all the volumes on partition partid. If flags = 1 then all the
2505 * relevant info about the volumes is also returned */
2507 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2508 volEntries *volumeInfo)
2512 code = VolListVolumes(acid, partid, flags, volumeInfo);
2513 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2518 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2519 volEntries *volumeInfo)
2522 struct DiskPartition64 *partP;
2523 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2524 char pname[9], volname[20];
2528 volint_info_handle_t handle;
2530 volumeInfo->volEntries_val = calloc(allocSize, sizeof(volintInfo));
2531 if (!volumeInfo->volEntries_val)
2534 pntr = volumeInfo->volEntries_val;
2535 volumeInfo->volEntries_len = 0;
2536 if (GetPartName(partid, pname))
2537 return VOLSERILLEGAL_PARTITION;
2538 if (!(partP = VGetPartition(pname, 0)))
2539 return VOLSERILLEGAL_PARTITION;
2540 dirp = opendir(VPartitionPath(partP));
2542 return VOLSERILLEGAL_PARTITION;
2544 while (GetNextVol(dirp, volname, &volid)) {
2545 if (flags) { /*copy other things too */
2546 #ifndef AFS_PTHREAD_ENV
2547 IOMGR_Poll(); /*make sure that the client does not time out */
2550 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2551 handle.volinfo_ptr.base = pntr;
2554 code = GetVolInfo(partid,
2559 VOL_INFO_LIST_MULTIPLE);
2560 if (code == -2) /* DESTROY_ME flag set */
2563 pntr->volid = volid;
2564 /*just volids are needed */
2568 volumeInfo->volEntries_len += 1;
2569 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2570 /*running out of space, allocate more space */
2571 allocSize = (allocSize * 3) / 2;
2572 pntr = realloc(volumeInfo->volEntries_val,
2573 allocSize * sizeof(volintInfo));
2576 return VOLSERNO_MEMORY;
2578 volumeInfo->volEntries_val = pntr; /* point to new block */
2579 /* set pntr to the right position */
2580 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2588 /*------------------------------------------------------------------------
2589 * EXPORTED SAFSVolXListVolumes
2592 * Returns all the volumes on partition a_partID. If a_flags
2593 * is set to 1, then all the relevant extended volume information
2597 * a_rxCidP : Pointer to the Rx call we're performing.
2598 * a_partID : Partition for which we want the extended list.
2599 * a_flags : Various flags.
2600 * a_volumeXInfoP : Ptr to the extended info blob.
2603 * 0 Successful operation
2604 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2605 * VOLSERNO_MEMORY if we ran out of memory allocating
2609 * Nothing interesting.
2613 *------------------------------------------------------------------------*/
2616 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2617 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2621 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2622 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2627 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2628 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2629 { /*SAFSVolXListVolumes */
2631 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2632 struct DiskPartition64 *partP; /*Ptr to partition */
2633 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2634 char pname[9], volname[20]; /*Partition, volume names */
2635 DIR *dirp; /*Partition directory ptr */
2636 afs_uint32 volid; /*Current volume ID */
2638 volint_info_handle_t handle;
2641 * Allocate a large array of extended volume info structures, then
2642 * set it up for action.
2644 a_volumeXInfoP->volXEntries_val = calloc(allocSize, sizeof(volintXInfo));
2645 if (!a_volumeXInfoP->volXEntries_val)
2648 xInfoP = a_volumeXInfoP->volXEntries_val;
2649 a_volumeXInfoP->volXEntries_len = 0;
2652 * If the partition name we've been given is bad, bogue out.
2654 if (GetPartName(a_partID, pname))
2655 return (VOLSERILLEGAL_PARTITION);
2658 * Open the directory representing the given AFS parttion. If we can't
2661 if (!(partP = VGetPartition(pname, 0)))
2662 return VOLSERILLEGAL_PARTITION;
2663 dirp = opendir(VPartitionPath(partP));
2665 return (VOLSERILLEGAL_PARTITION);
2666 while (GetNextVol(dirp, volname, &volid)) {
2669 * Full info about the volume desired. Poll to make sure the
2670 * client doesn't time out, then start up a new transaction.
2672 #ifndef AFS_PTHREAD_ENV
2676 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2677 handle.volinfo_ptr.ext = xInfoP;
2679 code = GetVolInfo(a_partID,
2684 VOL_INFO_LIST_MULTIPLE);
2685 if (code == -2) /* DESTROY_ME flag set */
2689 * Just volume IDs are needed.
2691 xInfoP->volid = volid;
2695 * Bump the pointer in the data area we're building, along with
2696 * the count of the number of entries it contains.
2699 (a_volumeXInfoP->volXEntries_len)++;
2700 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2702 * We're running out of space in the area we've built. Grow it.
2704 allocSize = (allocSize * 3) / 2;
2705 xInfoP = (volintXInfo *)
2706 realloc((char *)a_volumeXInfoP->volXEntries_val,
2707 (allocSize * sizeof(volintXInfo)));
2708 if (xInfoP == NULL) {
2710 * Bummer, no memory. Bag it, tell our caller what went wrong.
2713 return (VOLSERNO_MEMORY);
2717 * Memory reallocation worked. Correct our pointers so they
2718 * now point to the new block and the current open position within
2721 a_volumeXInfoP->volXEntries_val = xInfoP;
2723 a_volumeXInfoP->volXEntries_val +
2724 a_volumeXInfoP->volXEntries_len;
2729 * We've examined all entries in the partition directory. Close it,
2730 * delete our transaction (if any), and go home happy.
2735 } /*SAFSVolXListVolumes */
2737 /*this call is used to monitor the status of volser for debugging purposes.
2738 *information about all the active transactions is returned in transInfo*/
2740 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2744 code = VolMonitor(acid, transInfo);
2745 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2750 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2752 transDebugInfo *pntr;
2753 afs_int32 allocSize = 50;
2754 struct volser_trans *tt, *nt, *allTrans;
2756 transInfo->transDebugEntries_val =
2757 malloc(allocSize * sizeof(transDebugInfo));
2758 if (!transInfo->transDebugEntries_val)
2760 pntr = transInfo->transDebugEntries_val;
2761 transInfo->transDebugEntries_len = 0;
2764 allTrans = TransList();
2765 if (allTrans == (struct volser_trans *)0)
2766 goto done; /*no active transactions */
2767 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2769 VTRANS_OBJ_LOCK(tt);
2770 pntr->tid = tt->tid;
2771 pntr->time = tt->time;
2772 pntr->creationTime = tt->creationTime;
2773 pntr->returnCode = tt->returnCode;
2774 pntr->volid = tt->volid;
2775 pntr->partition = tt->partition;
2776 pntr->iflags = tt->iflags;
2777 pntr->vflags = tt->vflags;
2778 pntr->tflags = tt->tflags;
2779 strcpy(pntr->lastProcName, tt->lastProcName);
2780 pntr->callValid = 0;
2781 if (tt->rxCallPtr) { /*record call related info */
2782 pntr->callValid = 1;
2784 pntr->readNext = tt->rxCallPtr->rnext;
2785 pntr->transmitNext = tt->rxCallPtr->tnext;
2786 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2787 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2790 VTRANS_OBJ_UNLOCK(tt);
2792 transInfo->transDebugEntries_len += 1;
2793 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2794 allocSize = (allocSize * 3) / 2;
2795 pntr = realloc(transInfo->transDebugEntries_val,
2796 allocSize * sizeof(transDebugInfo));
2797 transInfo->transDebugEntries_val = pntr;
2799 transInfo->transDebugEntries_val +
2800 transInfo->transDebugEntries_len;
2801 /*set pntr to right position */
2812 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2813 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2814 afs_uint32 backupId)
2818 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2819 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2820 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2826 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2827 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2828 afs_uint32 backupId)
2832 struct volser_trans *tt;
2833 char caller[MAXKTCNAMELEN];
2835 if (strlen(name) > 31)
2836 return VOLSERBADNAME;
2837 if (!afsconf_SuperUser(tdir, acid, caller))
2838 return VOLSERBAD_ACCESS; /*not a super user */
2839 /* find the trans */
2840 tt = FindTrans(atid);
2843 if (tt->vflags & VTDeleted) {
2844 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2848 TSetRxCall(tt, acid, "SetIdsTypes");
2852 V_backupId(tv) = backupId;
2853 V_cloneId(tv) = cloneId;
2854 V_parentId(tv) = pId;
2855 strcpy((&V_disk(tv))->name, name);
2856 VUpdateVolume(&error, tv);
2858 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2863 if (TRELE(tt) && !error)
2864 return VOLSERTRELE_ERROR;
2869 if (TRELE(tt) && !error)
2870 return VOLSERTRELE_ERROR;
2875 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2879 code = VolSetDate(acid, atid, cdate);
2880 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2886 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2890 struct volser_trans *tt;
2891 char caller[MAXKTCNAMELEN];
2893 if (!afsconf_SuperUser(tdir, acid, caller))
2894 return VOLSERBAD_ACCESS; /*not a super user */
2895 /* find the trans */
2896 tt = FindTrans(atid);
2899 if (tt->vflags & VTDeleted) {
2900 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2904 TSetRxCall(tt, acid, "SetDate");
2907 V_creationDate(tv) = cdate;
2908 VUpdateVolume(&error, tv);
2910 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2915 if (TRELE(tt) && !error)
2916 return VOLSERTRELE_ERROR;
2921 if (TRELE(tt) && !error)
2922 return VOLSERTRELE_ERROR;
2927 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2928 afs_uint32 volumeId)
2933 char caller[MAXKTCNAMELEN];
2935 struct volser_trans *ttc;
2936 char pname[16], volname[20];
2937 struct DiskPartition64 *partP;
2938 afs_int32 ret = ENODEV;
2941 if (!afsconf_SuperUser(tdir, acid, caller))
2942 return VOLSERBAD_ACCESS; /*not a super user */
2943 if (GetPartName(partId, pname))
2944 return VOLSERILLEGAL_PARTITION;
2945 if (!(partP = VGetPartition(pname, 0)))
2946 return VOLSERILLEGAL_PARTITION;
2947 dirp = opendir(VPartitionPath(partP));
2949 return VOLSERILLEGAL_PARTITION;
2950 ttc = (struct volser_trans *)0;
2952 while (GetNextVol(dirp, volname, &volid)) {
2953 if (volid == volumeId) { /*copy other things too */
2954 #ifndef AFS_PTHREAD_ENV
2955 IOMGR_Poll(); /*make sure that the client doesnot time out */
2957 ttc = NewTrans(volumeId, partId);
2959 return VOLSERVOLBUSY;
2961 #ifdef AFS_NAMEI_ENV
2962 ret = namei_ConvertROtoRWvolume(pname, volumeId);
2964 ret = inode_ConvertROtoRWvolume(pname, volumeId);
2971 DeleteTrans(ttc, 1);
2972 ttc = (struct volser_trans *)0;
2981 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
2982 struct volintSize *size)
2985 struct volser_trans *tt;
2986 char caller[MAXKTCNAMELEN];
2988 if (!afsconf_SuperUser(tdir, acid, caller))
2989 return VOLSERBAD_ACCESS; /*not a super user */
2990 tt = FindTrans(fromTrans);
2993 if (tt->vflags & VTDeleted) {
2997 TSetRxCall(tt, acid, "GetSize");
2998 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3001 return VOLSERTRELE_ERROR;
3003 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3008 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3009 afs_uint32 where, afs_int32 verbose)
3011 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3013 Volume *vol=0, *newvol=0;
3014 struct volser_trans *tt = 0, *tt2 = 0;
3015 char caller[MAXKTCNAMELEN];
3018 if (!afsconf_SuperUser(tdir, acall, caller))
3021 vol = VAttachVolume(&code, vid, V_VOLUPD);
3027 newvol = VAttachVolume(&code, new, V_VOLUPD);
3029 VDetachVolume(&code2, vol);
3034 if (V_device(vol) != V_device(newvol)
3035 || V_uniquifier(newvol) != 2) {
3036 if (V_device(vol) != V_device(newvol)) {
3037 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3039 rx_Write(acall, line, strlen(line));
3041 if (V_uniquifier(newvol) != 2) {
3042 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3043 rx_Write(acall, line, strlen(line));
3046 rx_Write(acall, line, 1);
3047 VDetachVolume(&code2, vol);
3048 VDetachVolume(&code2, newvol);
3051 tt = NewTrans(vid, V_device(vol));
3053 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3054 rx_Write(acall, line, strlen(line));
3056 rx_Write(acall, line, 1);
3057 VDetachVolume(&code2, vol);
3058 VDetachVolume(&code2, newvol);
3059 return VOLSERVOLBUSY;
3061 VTRANS_OBJ_LOCK(tt);
3062 tt->iflags = ITBusy;
3064 TSetRxCall_r(tt, NULL, "SplitVolume");
3065 VTRANS_OBJ_UNLOCK(tt);
3067 tt2 = NewTrans(new, V_device(newvol));
3069 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3070 rx_Write(acall, line, strlen(line));
3072 rx_Write(acall, line, 1);
3074 VDetachVolume(&code2, vol);
3075 VDetachVolume(&code2, newvol);
3076 return VOLSERVOLBUSY;
3078 VTRANS_OBJ_LOCK(tt2);
3079 tt2->iflags = ITBusy;
3081 TSetRxCall_r(tt2, NULL, "SplitVolume");
3082 VTRANS_OBJ_UNLOCK(tt2);
3084 code = split_volume(acall, vol, newvol, where, verbose);
3086 VDetachVolume(&code2, vol);
3088 VDetachVolume(&code2, newvol);
3089 DeleteTrans(tt2, 1);
3096 /* GetPartName - map partid (a decimal number) into pname (a string)
3097 * Since for NT we actually want to return the drive name, we map through the
3101 GetPartName(afs_int32 partid, char *pname)
3106 strcpy(pname, "/vicep");
3107 pname[6] = 'a' + partid;
3110 } else if (partid < VOLMAXPARTS) {
3111 strcpy(pname, "/vicep");
3113 pname[6] = 'a' + (partid / 26);
3114 pname[7] = 'a' + (partid % 26);