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 if (newType != readonlyVolume && newType != backupVolume)
732 tt = FindTrans(atrans);
735 if (tt->vflags & VTDeleted) {
736 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
740 ttc = NewTrans(newId, tt->partition);
741 if (!ttc) { /* someone is messing with the clone already */
743 return VOLSERVOLBUSY;
745 TSetRxCall(tt, acid, "Clone");
749 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
751 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
757 originalvp = tt->volume;
758 if ((V_type(originalvp) == backupVolume)
759 || (V_type(originalvp) == readonlyVolume)) {
760 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
764 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
765 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
771 if (originalvp->device != purgevp->device) {
772 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
776 if (V_type(purgevp) != readonlyVolume) {
777 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
781 if (V_type(originalvp) == readonlyVolume
782 && V_parentId(originalvp) != V_parentId(purgevp)) {
783 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
787 if (V_type(originalvp) == readwriteVolume
788 && tt->volid != V_parentId(purgevp)) {
789 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
796 #ifdef AFS_DEMAND_ATTACH_FS
797 salv_vp = originalvp;
801 VCreateVolume(&error, originalvp->partition->name, newId,
802 V_parentId(originalvp));
804 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
805 newvp = (Volume *) 0;
808 if (newType == readonlyVolume)
809 V_cloneId(originalvp) = newId;
810 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
813 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
814 CloneVolume(&error, originalvp, newvp, purgevp);
815 purgevp = NULL; /* clone releases it, maybe even if error */
817 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
821 if (newType == readonlyVolume) {
822 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
823 V_type(newvp) = readonlyVolume;
824 } else if (newType == backupVolume) {
825 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
826 V_type(newvp) = backupVolume;
827 V_backupId(originalvp) = newId;
829 strcpy(newvp->header->diskstuff.name, newName);
830 V_creationDate(newvp) = V_copyDate(newvp);
831 ClearVolumeStats(&V_disk(newvp));
832 V_destroyMe(newvp) = DESTROY_ME;
833 V_inService(newvp) = 0;
834 if (newType == backupVolume) {
835 V_backupDate(originalvp) = V_copyDate(newvp);
836 V_backupDate(newvp) = V_copyDate(newvp);
839 VUpdateVolume(&error, newvp);
841 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
845 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
847 VUpdateVolume(&error, originalvp);
849 Log("1 Volser: Clone: original update %u\n", error);
854 #ifdef AFS_DEMAND_ATTACH_FS
858 tt = (struct volser_trans *)0;
859 error = VOLSERTRELE_ERROR;
867 VDetachVolume(&code, purgevp);
869 VDetachVolume(&code, newvp);
876 #ifdef AFS_DEMAND_ATTACH_FS
877 if (salv_vp && error != VVOLEXISTS && error != EXDEV) {
878 V_needsSalvaged(salv_vp) = 1;
880 #endif /* AFS_DEMAND_ATTACH_FS */
884 /* reclone this volume into the specified id */
886 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
890 code = VolReClone(acid, atrans, cloneId);
891 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
897 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
899 struct Volume *originalvp, *clonevp;
902 struct volser_trans *tt, *ttc;
903 char caller[MAXKTCNAMELEN];
905 /*not a super user */
906 if (!afsconf_SuperUser(tdir, acid, caller))
907 return VOLSERBAD_ACCESS;
910 Log("%s on %s is executing Reclone Volume %u\n", caller,
911 callerAddress(acid, buffer), cloneId);
914 clonevp = originalvp = (Volume *) 0;
915 tt = (struct volser_trans *)0;
917 tt = FindTrans(atrans);
920 if (tt->vflags & VTDeleted) {
921 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
925 ttc = NewTrans(cloneId, tt->partition);
926 if (!ttc) { /* someone is messing with the clone already */
928 return VOLSERVOLBUSY;
930 TSetRxCall(tt, acid, "ReClone");
932 originalvp = tt->volume;
933 if ((V_type(originalvp) == backupVolume)
934 || (V_type(originalvp) == readonlyVolume)) {
935 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
939 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
940 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
946 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
948 Log("1 Volser: can't attach clone %d\n", cloneId);
952 newType = V_type(clonevp); /* type of the new volume */
954 if (originalvp->device != clonevp->device) {
955 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
960 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
961 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
965 if (V_type(originalvp) == readonlyVolume
966 && V_parentId(originalvp) != V_parentId(clonevp)) {
967 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
971 if (V_type(originalvp) == readwriteVolume
972 && tt->volid != V_parentId(clonevp)) {
973 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
979 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
981 CloneVolume(&error, originalvp, clonevp, clonevp);
983 Log("1 Volser: Clone: reclone operation failed with code %d\n",
989 /* fix up volume name and type, CloneVolume just propagated RW's */
990 if (newType == readonlyVolume) {
991 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
992 V_type(clonevp) = readonlyVolume;
993 } else if (newType == backupVolume) {
994 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
995 V_type(clonevp) = backupVolume;
996 V_backupId(originalvp) = cloneId;
998 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
1000 /* pretend recloned volume is a totally new instance */
1001 V_copyDate(clonevp) = time(0);
1002 V_creationDate(clonevp) = V_copyDate(clonevp);
1003 ClearVolumeStats(&V_disk(clonevp));
1004 V_destroyMe(clonevp) = 0;
1005 V_inService(clonevp) = 0;
1006 if (newType == backupVolume) {
1007 V_backupDate(originalvp) = V_copyDate(clonevp);
1008 V_backupDate(clonevp) = V_copyDate(clonevp);
1010 V_inUse(clonevp) = 0;
1011 VUpdateVolume(&error, clonevp);
1013 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
1017 /* VUpdateVolume succeeded. Mark it in service so there's no window
1018 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
1019 * specialStatus; this is a reclone and this volume started online
1021 V_inService(clonevp) = 1;
1022 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
1024 VUpdateVolume(&error, originalvp);
1026 Log("1 Volser: Clone: original update %u\n", error);
1032 tt = (struct volser_trans *)0;
1033 error = VOLSERTRELE_ERROR;
1037 DeleteTrans(ttc, 1);
1040 struct DiskPartition64 *tpartp = originalvp->partition;
1041 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1047 VDetachVolume(&code, clonevp);
1053 DeleteTrans(ttc, 1);
1057 /* create a new transaction, associated with volume and partition. Type of
1058 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1059 * See volser.h for definition of iflags (the constants are named IT*).
1062 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1063 afs_int32 iflags, afs_int32 *ttid)
1067 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1068 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1074 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1075 afs_int32 iflags, afs_int32 *ttid)
1077 struct volser_trans *tt;
1082 char caller[MAXKTCNAMELEN];
1084 if (!afsconf_SuperUser(tdir, acid, caller))
1085 return VOLSERBAD_ACCESS; /*not a super user */
1086 if (iflags & ITCreate)
1088 else if (iflags & ITBusy)
1090 else if (iflags & ITReadOnly)
1092 else if (iflags & ITOffline)
1095 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1100 tt = NewTrans(volume, partition);
1102 /* can't create a transaction? put the volume back */
1103 Log("1 transcreate: can't create transaction\n");
1104 return VOLSERVOLBUSY;
1106 tv = XAttachVolume(&error, volume, partition, mode);
1110 VDetachVolume(&code, tv);
1114 VTRANS_OBJ_LOCK(tt);
1117 tt->iflags = iflags;
1119 TSetRxCall_r(tt, NULL, "TransCreate");
1120 VTRANS_OBJ_UNLOCK(tt);
1122 return VOLSERTRELE_ERROR;
1127 /* using aindex as a 0-based index, return the aindex'th volume on this server
1128 * Both the volume number and partition number (one-based) are returned.
1131 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1136 code = VolGetNthVolume(acid, aindex, avolume, apart);
1137 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1142 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1145 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1149 /* return the volume flags (VT* constants in volser.h) associated with this
1153 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1157 code = VolGetFlags(acid, atid, aflags);
1158 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1163 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1165 struct volser_trans *tt;
1167 tt = FindTrans(atid);
1170 if (tt->vflags & VTDeleted) {
1171 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1176 TSetRxCall(tt, acid, "GetFlags");
1177 *aflags = tt->vflags;
1180 return VOLSERTRELE_ERROR;
1185 /* Change the volume flags (VT* constants in volser.h) associated with this
1186 * transaction. Effects take place immediately on volume, although volume
1187 * remains attached as usual by the transaction.
1190 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1194 code = VolSetFlags(acid, atid, aflags);
1195 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1201 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1203 struct volser_trans *tt;
1206 char caller[MAXKTCNAMELEN];
1208 if (!afsconf_SuperUser(tdir, acid, caller))
1209 return VOLSERBAD_ACCESS; /*not a super user */
1210 /* find the trans */
1211 tt = FindTrans(atid);
1214 if (tt->vflags & VTDeleted) {
1215 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1220 TSetRxCall(tt, acid, "SetFlags");
1221 vp = tt->volume; /* pull volume out of transaction */
1223 /* check if we're allowed to make any updates */
1224 if (tt->iflags & ITReadOnly) {
1229 /* handle delete-on-salvage flag */
1230 if (aflags & VTDeleteOnSalvage) {
1231 V_destroyMe(tt->volume) = DESTROY_ME;
1233 V_destroyMe(tt->volume) = 0;
1236 if (aflags & VTOutOfService) {
1237 V_inService(vp) = 0;
1239 V_inService(vp) = 1;
1241 VUpdateVolume(&error, vp);
1242 VTRANS_OBJ_LOCK(tt);
1243 tt->vflags = aflags;
1245 VTRANS_OBJ_UNLOCK(tt);
1246 if (TRELE(tt) && !error)
1247 return VOLSERTRELE_ERROR;
1252 /* dumpS the volume associated with a particular transaction from a particular
1253 * date. Send the dump to a different transaction (destTrans) on the server
1254 * specified by the destServer structure.
1257 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1258 struct destServer *destination, afs_int32 destTrans,
1259 struct restoreCookie *cookie)
1264 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1265 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1266 htonl(destination->destHost), AUD_LONG, destTrans, AUD_END);
1271 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1272 struct destServer *destination, afs_int32 destTrans,
1273 struct restoreCookie *cookie)
1275 struct volser_trans *tt;
1277 struct rx_connection *tcon;
1278 struct rx_call *tcall;
1280 struct rx_securityClass *securityObject;
1281 afs_int32 securityIndex;
1282 char caller[MAXKTCNAMELEN];
1284 if (!afsconf_SuperUser(tdir, acid, caller))
1285 return VOLSERBAD_ACCESS; /*not a super user */
1286 /* initialize things */
1287 tcon = (struct rx_connection *)0;
1288 tt = (struct volser_trans *)0;
1290 /* find the local transaction */
1291 tt = FindTrans(fromTrans);
1294 if (tt->vflags & VTDeleted) {
1295 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1300 TSetRxCall(tt, NULL, "Forward");
1302 /* get auth info for the this connection (uses afs from ticket file) */
1303 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1309 /* make an rpc connection to the other server */
1311 rx_NewConnection(htonl(destination->destHost),
1312 htons(destination->destPort), VOLSERVICE_ID,
1313 securityObject, securityIndex);
1319 tcall = rx_NewCall(tcon);
1320 TSetRxCall(tt, tcall, "Forward");
1321 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1322 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1327 /* these next calls implictly call rx_Write when writing out data */
1328 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1331 EndAFSVolRestore(tcall); /* probably doesn't do much */
1333 code = rx_EndCall(tcall, 0);
1334 rx_DestroyConnection(tcon); /* done with the connection */
1339 return VOLSERTRELE_ERROR;
1345 (void)rx_EndCall(tcall, 0);
1346 rx_DestroyConnection(tcon);
1355 /* Start a dump and send it to multiple places simultaneously.
1356 * If this returns an error (eg, return ENOENT), it means that
1357 * none of the releases worked. If this returns 0, that means
1358 * that one or more of the releases worked, and the caller has
1359 * to examine the results array to see which one(s).
1360 * This will only do EITHER incremental or full, not both, so it's
1361 * the caller's responsibility to be sure that all the destinations
1362 * need just an incremental (and from the same time), if that's
1366 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1367 fromDate, manyDests *destinations, afs_int32 spare,
1368 struct restoreCookie *cookie, manyResults *results)
1370 afs_int32 securityIndex;
1371 struct rx_securityClass *securityObject;
1372 char caller[MAXKTCNAMELEN];
1373 struct volser_trans *tt;
1374 afs_int32 ec, code, *codes;
1375 struct rx_connection **tcons;
1376 struct rx_call **tcalls;
1378 int i, is_incremental;
1381 memset(results, 0, sizeof(manyResults));
1382 i = results->manyResults_len = destinations->manyDests_len;
1383 results->manyResults_val = codes =
1384 (afs_int32 *) malloc(i * sizeof(afs_int32));
1386 if (!results || !results->manyResults_val)
1389 if (!afsconf_SuperUser(tdir, acid, caller))
1390 return VOLSERBAD_ACCESS; /*not a super user */
1391 tt = FindTrans(fromTrans);
1394 if (tt->vflags & VTDeleted) {
1395 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1400 TSetRxCall(tt, NULL, "ForwardMulti");
1402 /* (fromDate == 0) ==> full dump */
1403 is_incremental = (fromDate ? 1 : 0);
1406 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1410 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1416 /* get auth info for this connection (uses afs from ticket file) */
1417 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1419 goto fail; /* in order to audit each failure */
1422 /* make connections to all the other servers */
1423 for (i = 0; i < destinations->manyDests_len; i++) {
1424 struct replica *dest = &(destinations->manyDests_val[i]);
1426 rx_NewConnection(htonl(dest->server.destHost),
1427 htons(dest->server.destPort), VOLSERVICE_ID,
1428 securityObject, securityIndex);
1430 codes[i] = ENOTCONN;
1432 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1433 codes[i] = ENOTCONN;
1436 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1439 (void)rx_EndCall(tcalls[i], 0);
1441 rx_DestroyConnection(tcons[i]);
1448 /* these next calls implictly call rx_Write when writing out data */
1449 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1453 for (i--; i >= 0; i--) {
1454 struct replica *dest = &(destinations->manyDests_val[i]);
1456 if (!code && tcalls[i] && !codes[i]) {
1457 EndAFSVolRestore(tcalls[i]);
1460 ec = rx_EndCall(tcalls[i], 0);
1465 rx_DestroyConnection(tcons[i]); /* done with the connection */
1468 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1469 fromTrans, AUD_HOST, htonl(dest->server.destHost), AUD_LONG,
1470 dest->trans, AUD_END);
1477 if (TRELE(tt) && !code) /* return the first code if it's set */
1478 return VOLSERTRELE_ERROR;
1485 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1489 code = VolDump(acid, fromTrans, fromDate, 0);
1490 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1495 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1500 code = VolDump(acid, fromTrans, fromDate, flags);
1501 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1506 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1510 struct volser_trans *tt;
1511 char caller[MAXKTCNAMELEN];
1513 if (!afsconf_SuperUser(tdir, acid, caller))
1514 return VOLSERBAD_ACCESS; /*not a super user */
1515 tt = FindTrans(fromTrans);
1518 if (tt->vflags & VTDeleted) {
1519 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1523 TSetRxCall(tt, acid, "Dump");
1524 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1525 ? 0 : 1); /* squirt out the volume's data, too */
1534 return VOLSERTRELE_ERROR;
1540 * Ha! No more helper process!
1543 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1544 struct restoreCookie *cookie)
1548 code = VolRestore(acid, atrans, aflags, cookie);
1549 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1554 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1555 struct restoreCookie *cookie)
1557 struct volser_trans *tt;
1558 afs_int32 code, tcode;
1559 char caller[MAXKTCNAMELEN];
1561 if (!afsconf_SuperUser(tdir, acid, caller))
1562 return VOLSERBAD_ACCESS; /*not a super user */
1563 tt = FindTrans(atrans);
1566 if (tt->vflags & VTDeleted) {
1567 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1571 TSetRxCall(tt, acid, "Restore");
1573 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1575 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1576 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1580 return (code ? code : tcode);
1583 /* end a transaction, returning the transaction's final error code in rcode */
1585 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1589 code = VolEndTrans(acid, destTrans, rcode);
1590 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1595 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1597 struct volser_trans *tt;
1598 char caller[MAXKTCNAMELEN];
1600 if (!afsconf_SuperUser(tdir, acid, caller))
1601 return VOLSERBAD_ACCESS; /*not a super user */
1602 tt = FindTrans(destTrans);
1606 *rcode = tt->returnCode;
1607 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1613 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1617 code = VolSetForwarding(acid, atid, anewsite);
1618 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1619 htonl(anewsite), AUD_END);
1624 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1626 struct volser_trans *tt;
1627 char caller[MAXKTCNAMELEN];
1630 if (!afsconf_SuperUser(tdir, acid, caller))
1631 return VOLSERBAD_ACCESS; /*not a super user */
1632 tt = FindTrans(atid);
1635 if (tt->vflags & VTDeleted) {
1636 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1641 TSetRxCall(tt, acid, "SetForwarding");
1642 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1645 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1648 return VOLSERTRELE_ERROR;
1654 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1655 struct volser_status *astatus)
1659 code = VolGetStatus(acid, atrans, astatus);
1660 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1665 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1666 struct volser_status *astatus)
1669 struct VolumeDiskData *td;
1670 struct volser_trans *tt;
1673 tt = FindTrans(atrans);
1676 if (tt->vflags & VTDeleted) {
1677 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1682 TSetRxCall(tt, acid, "GetStatus");
1690 td = &tv->header->diskstuff;
1691 astatus->volID = td->id;
1692 astatus->nextUnique = td->uniquifier;
1693 astatus->type = td->type;
1694 astatus->parentID = td->parentId;
1695 astatus->cloneID = td->cloneId;
1696 astatus->backupID = td->backupId;
1697 astatus->restoredFromID = td->restoredFromId;
1698 astatus->maxQuota = td->maxquota;
1699 astatus->minQuota = td->minquota;
1700 astatus->owner = td->owner;
1701 astatus->creationDate = td->creationDate;
1702 astatus->accessDate = td->accessDate;
1703 astatus->updateDate = td->updateDate;
1704 astatus->expirationDate = td->expirationDate;
1705 astatus->backupDate = td->backupDate;
1706 astatus->copyDate = td->copyDate;
1709 return VOLSERTRELE_ERROR;
1715 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1716 struct volintInfo *astatus)
1720 code = VolSetInfo(acid, atrans, astatus);
1721 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1726 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1727 struct volintInfo *astatus)
1730 struct VolumeDiskData *td;
1731 struct volser_trans *tt;
1732 char caller[MAXKTCNAMELEN];
1735 if (!afsconf_SuperUser(tdir, acid, caller))
1736 return VOLSERBAD_ACCESS; /*not a super user */
1737 tt = FindTrans(atrans);
1740 if (tt->vflags & VTDeleted) {
1741 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1745 TSetRxCall(tt, acid, "SetStatus");
1753 td = &tv->header->diskstuff;
1755 * Add more fields as necessary
1757 if (astatus->maxquota != -1)
1758 td->maxquota = astatus->maxquota;
1759 if (astatus->dayUse != -1)
1760 td->dayUse = astatus->dayUse;
1761 if (astatus->creationDate != -1)
1762 td->creationDate = astatus->creationDate;
1763 if (astatus->updateDate != -1)
1764 td->updateDate = astatus->updateDate;
1765 if (astatus->spare2 != -1)
1766 td->volUpdateCounter = (unsigned int)astatus->spare2;
1767 VUpdateVolume(&error, tv);
1770 return VOLSERTRELE_ERROR;
1776 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1780 code = VolGetName(acid, atrans, aname);
1781 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1786 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1789 struct VolumeDiskData *td;
1790 struct volser_trans *tt;
1793 /* We need to at least fill it in */
1794 *aname = (char *)malloc(1);
1797 tt = FindTrans(atrans);
1800 if (tt->vflags & VTDeleted) {
1801 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1805 TSetRxCall(tt, acid, "GetName");
1813 td = &tv->header->diskstuff;
1814 len = strlen(td->name) + 1; /* don't forget the null */
1820 *aname = (char *)realloc(*aname, len);
1821 strcpy(*aname, td->name);
1824 return VOLSERTRELE_ERROR;
1829 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1832 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1833 afs_uint32 parentId, afs_uint32 cloneId)
1839 /*return a list of all partitions on the server. The non mounted
1840 *partitions are returned as -1 in the corresponding slot in partIds*/
1842 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1846 code = VolListPartitions(acid, partIds);
1847 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1852 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1857 strcpy(namehead, "/vicep"); /*7 including null terminator */
1859 /* Just return attached partitions. */
1861 for (i = 0; i < 26; i++) {
1862 namehead[6] = i + 'a';
1863 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1869 /*return a list of all partitions on the server. The non mounted
1870 *partitions are returned as -1 in the corresponding slot in partIds*/
1872 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1876 code = XVolListPartitions(acid, pEntries);
1877 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1882 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1885 struct partList partList;
1886 struct DiskPartition64 *dp;
1889 strcpy(namehead, "/vicep"); /*7 including null terminator */
1891 /* Only report attached partitions */
1892 for (i = 0; i < VOLMAXPARTS; i++) {
1893 #ifdef AFS_DEMAND_ATTACH_FS
1894 dp = VGetPartitionById(i, 0);
1897 namehead[6] = i + 'a';
1903 namehead[6] = 'a' + (k / 26);
1904 namehead[7] = 'a' + (k % 26);
1907 dp = VGetPartition(namehead, 0);
1910 partList.partId[j++] = i;
1913 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1914 if (!pEntries->partEntries_val)
1916 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1918 pEntries->partEntries_len = j;
1920 pEntries->partEntries_val = NULL;
1921 pEntries->partEntries_len = 0;
1927 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1929 ExtractVolId(char vname[])
1932 char name[VOLSER_MAXVOLNAME + 1];
1934 strcpy(name, vname);
1936 while (name[i] == 'V' || name[i] == '0')
1939 name[11] = '\0'; /* smash the "." */
1940 return (atol(&name[i]));
1943 /*return the name of the next volume header in the directory associated with dirp and dp.
1944 *the volume id is returned in volid, and volume header name is returned in volname*/
1946 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1950 dp = readdir(dirp); /*read next entry in the directory */
1952 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1953 *volid = ExtractVolId(dp->d_name);
1954 strcpy(volname, dp->d_name);
1955 return 0; /*return the name of the file representing a volume */
1957 strcpy(volname, "");
1958 return 0; /*volname doesnot represent a volume */
1961 strcpy(volname, "EOD");
1962 return 0; /*end of directory */
1968 * volint vol info structure type.
1971 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1972 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1973 } volint_info_type_t;
1976 * handle to various on-wire vol info types.
1979 volint_info_type_t volinfo_type;
1985 } volint_info_handle_t;
1988 * store value to a field at the appropriate location in on-wire structure.
1990 #define VOLINT_INFO_STORE(handle, name, val) \
1992 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1993 (handle)->volinfo_ptr.base->name = (val); \
1995 (handle)->volinfo_ptr.ext->name = (val); \
2000 * get pointer to appropriate offset of field in on-wire structure.
2002 #define VOLINT_INFO_PTR(handle, name) \
2003 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
2004 &((handle)->volinfo_ptr.base->name) : \
2005 &((handle)->volinfo_ptr.ext->name))
2008 * fill in appropriate type of on-wire volume metadata structure.
2010 * @param vp pointer to volume object
2011 * @param handle pointer to wire format handle object
2013 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
2014 * @pre handle object must have a valid pointer and enumeration value
2016 * @note passing a NULL value for vp means that the fileserver doesn't
2017 * know about this particular volume, thus implying it is offline.
2019 * @return operation status
2024 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
2026 unsigned int numStatBytes, now;
2027 struct VolumeDiskData *hdr = &vp->header->diskstuff;
2029 /*read in the relevant info */
2030 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
2031 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
2032 VOLINT_INFO_STORE(handle, volid, hdr->id);
2033 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
2034 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
2035 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
2036 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
2037 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
2038 VOLINT_INFO_STORE(handle, size, hdr->diskused);
2039 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
2040 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
2041 now = FT_ApproxTime();
2042 if ((now - hdr->dayUseDate) > OneDay) {
2043 VOLINT_INFO_STORE(handle, dayUse, 0);
2045 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
2047 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
2048 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
2049 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
2050 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
2052 #ifdef AFS_DEMAND_ATTACH_FS
2054 * for DAFS, we "lie" about volume state --
2055 * instead of returning the raw state from the disk header,
2056 * we compute state based upon the fileserver's internal
2057 * in-core state enumeration value reported to us via fssync,
2058 * along with the blessed and inService flags from the header.
2059 * -- tkeiser 11/27/2007
2062 /* Conditions that offline status is based on:
2063 volume is unattached state
2064 volume state is in (one of several error states)
2065 volume not in service
2066 volume is not marked as blessed (not on hold)
2067 volume in salvage req. state
2068 volume needsSalvaged
2069 next op would set volume offline
2070 next op would not leave volume online (based on several conditions)
2073 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2074 VIsErrorState(V_attachState(vp)) ||
2077 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
2078 hdr->needsSalvaged ||
2079 (vp->pending_vol_op &&
2080 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
2081 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
2084 VOLINT_INFO_STORE(handle, inUse, 0);
2086 VOLINT_INFO_STORE(handle, inUse, 1);
2089 /* offline status based on program type, where != fileServer enum (1) is offline */
2090 if (hdr->inUse == fileServer) {
2091 VOLINT_INFO_STORE(handle, inUse, 1);
2093 VOLINT_INFO_STORE(handle, inUse, 0);
2098 switch(handle->volinfo_type) {
2099 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2100 case VOLINT_INFO_TYPE_BASE:
2102 #ifdef AFS_DEMAND_ATTACH_FS
2103 /* see comment above where we set inUse bit */
2104 if (hdr->needsSalvaged ||
2105 (vp && VIsErrorState(V_attachState(vp)))) {
2106 handle->volinfo_ptr.base->needsSalvaged = 1;
2108 handle->volinfo_ptr.base->needsSalvaged = 0;
2111 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2113 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
2114 handle->volinfo_ptr.base->spare0 = hdr->minquota;
2115 handle->volinfo_ptr.base->spare1 =
2116 (long)hdr->weekUse[0] +
2117 (long)hdr->weekUse[1] +
2118 (long)hdr->weekUse[2] +
2119 (long)hdr->weekUse[3] +
2120 (long)hdr->weekUse[4] +
2121 (long)hdr->weekUse[5] +
2122 (long)hdr->weekUse[6];
2123 handle->volinfo_ptr.base->flags = 0;
2124 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
2125 handle->volinfo_ptr.base->spare3 = 0;
2129 case VOLINT_INFO_TYPE_EXT:
2131 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
2132 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
2135 * Copy out the stat fields in a single operation.
2137 if ((now - hdr->dayUseDate) > OneDay) {
2138 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2141 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2142 (char *)&(hdr->stat_reads[0]),
2151 #ifdef AFS_DEMAND_ATTACH_FS
2154 * get struct Volume out of the fileserver.
2156 * @param[in] volumeId volumeId for which we want state information
2157 * @param[in] pname partition name string
2158 * @param[inout] vp pointer to pointer to Volume object which
2159 * will be populated (see note)
2161 * @return operation status
2163 * @retval non-zero failure
2165 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2170 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2175 res.hdr.response_len = sizeof(res.hdr);
2176 res.payload.buf = *vp;
2177 res.payload.len = sizeof(Volume);
2179 code = FSYNC_VolOp(volumeId,
2185 if (code != SYNC_OK) {
2186 switch (res.hdr.reason) {
2187 case FSYNC_WRONG_PART:
2188 case FSYNC_UNKNOWN_VOLID:
2201 * mode of volume list operation.
2204 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2205 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2206 } vol_info_list_mode_t;
2209 * abstract interface to populate wire-format volume metadata structures.
2211 * @param[in] partId partition id
2212 * @param[in] volumeId volume id
2213 * @param[in] pname partition name
2214 * @param[in] volname volume file name
2215 * @param[in] handle handle to on-wire volume metadata object
2216 * @param[in] mode listing mode
2218 * @return operation status
2220 * @retval -2 DESTROY_ME flag is set
2221 * @retval -1 general failure; some data filled in
2222 * @retval -3 couldn't create vtrans; some data filled in
2225 GetVolInfo(afs_uint32 partId,
2226 afs_uint32 volumeId,
2229 volint_info_handle_t * handle,
2230 vol_info_list_mode_t mode)
2234 struct volser_trans *ttc = NULL;
2235 struct Volume *fill_tv, *tv = NULL;
2236 #ifdef AFS_DEMAND_ATTACH_FS
2237 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2238 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2239 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2240 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2242 /* Set up response handle for pending_vol_op */
2243 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2244 fs_res.payload.buf = fs_res_buf;
2245 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2248 ttc = NewTrans(volumeId, partId);
2251 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2252 VOLINT_INFO_STORE(handle, volid, volumeId);
2256 /* Get volume from volserver */
2257 if (mode == VOL_INFO_LIST_MULTIPLE)
2258 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2260 tv = VAttachVolumeByName_retry(&error, pname, volname, V_PEEK);
2262 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2263 volumeId, pname, volname, error);
2268 * please note that destroyMe and needsSalvaged checks used to be ordered
2269 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2270 * more correct to check destroyMe before needsSalvaged.
2271 * -- tkeiser 11/28/2007
2274 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2276 case VOL_INFO_LIST_MULTIPLE:
2280 case VOL_INFO_LIST_SINGLE:
2281 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2282 volumeId, pname, volname);
2289 if (tv->header->diskstuff.needsSalvaged) {
2290 /*this volume will be salvaged */
2291 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2292 volumeId, pname, volname);
2295 #ifdef AFS_DEMAND_ATTACH_FS
2296 /* If using DAFS, get volume from fsserver */
2297 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2302 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2303 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2304 /* If we if the pending vol op */
2305 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2306 fs_tv->pending_vol_op=&pending_vol_op_res;
2308 fs_tv->pending_vol_op=NULL;
2311 /* populate the header from the volserver copy */
2312 fs_tv->header=tv->header;
2314 /* When using DAFS, use the fs volume info, populated with required structures */
2317 /* When not using DAFS, just use the local volume info */
2321 /* ok, we have all the data we need; fill in the on-wire struct */
2322 code = FillVolInfo(fill_tv, handle);
2326 VOLINT_INFO_STORE(handle, status, 0);
2327 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2328 VOLINT_INFO_STORE(handle, volid, volumeId);
2331 VDetachVolume(&error, tv);
2334 VOLINT_INFO_STORE(handle, status, 0);
2335 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2336 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2337 volumeId, pname, volname);
2341 DeleteTrans(ttc, 1);
2348 /*return the header information about the <volid> */
2350 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2351 afs_uint32 volumeId, volEntries *volumeInfo)
2355 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2356 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2361 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2362 afs_uint32 volumeId, volEntries *volumeInfo)
2364 struct DiskPartition64 *partP;
2365 char pname[9], volname[20];
2370 volint_info_handle_t handle;
2372 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2373 if (!volumeInfo->volEntries_val)
2375 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2377 volumeInfo->volEntries_len = 1;
2378 if (GetPartName(partid, pname))
2379 return VOLSERILLEGAL_PARTITION;
2380 if (!(partP = VGetPartition(pname, 0)))
2381 return VOLSERILLEGAL_PARTITION;
2382 dirp = opendir(VPartitionPath(partP));
2384 return VOLSERILLEGAL_PARTITION;
2386 strcpy(volname, "");
2388 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2390 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2391 GetNextVol(dirp, volname, &volid);
2392 continue; /*back to while loop */
2395 if (volid == volumeId) { /*copy other things too */
2400 GetNextVol(dirp, volname, &volid);
2404 #ifndef AFS_PTHREAD_ENV
2405 IOMGR_Poll(); /*make sure that the client does not time out */
2408 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2409 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2411 code = GetVolInfo(partid,
2416 VOL_INFO_LIST_SINGLE);
2421 return code ? ENODEV: 0;
2426 /*------------------------------------------------------------------------
2427 * EXPORTED SAFSVolXListOneVolume
2430 * Returns extended info on volume a_volID on partition a_partID.
2433 * a_rxCidP : Pointer to the Rx call we're performing.
2434 * a_partID : Partition for which we want the extended list.
2435 * a_volID : Volume ID we wish to know about.
2436 * a_volumeXInfoP : Ptr to the extended info blob.
2439 * 0 Successful operation
2440 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2443 * Nothing interesting.
2447 *------------------------------------------------------------------------*/
2450 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2451 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2455 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2456 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2461 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2462 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2463 { /*SAFSVolXListOneVolume */
2465 struct DiskPartition64 *partP; /*Ptr to partition */
2466 char pname[9], volname[20]; /*Partition, volume names */
2467 DIR *dirp; /*Partition directory ptr */
2468 afs_uint32 currVolID; /*Current volume ID */
2469 int found = 0; /*Did we find the volume we need? */
2471 volint_info_handle_t handle;
2474 * Set up our pointers for action, marking our structure to hold exactly
2475 * one entry. Also, assume we'll fail in our quest.
2477 a_volumeXInfoP->volXEntries_val =
2478 (volintXInfo *) malloc(sizeof(volintXInfo));
2479 if (!a_volumeXInfoP->volXEntries_val)
2481 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2483 a_volumeXInfoP->volXEntries_len = 1;
2487 * If the partition name we've been given is bad, bogue out.
2489 if (GetPartName(a_partID, pname))
2490 return (VOLSERILLEGAL_PARTITION);
2493 * Open the directory representing the given AFS parttion. If we can't
2496 if (!(partP = VGetPartition(pname, 0)))
2497 return VOLSERILLEGAL_PARTITION;
2498 dirp = opendir(VPartitionPath(partP));
2500 return (VOLSERILLEGAL_PARTITION);
2502 strcpy(volname, "");
2505 * Sweep through the partition directory, looking for the desired entry.
2506 * First, of course, figure out how many stat bytes to copy out of each
2509 while (strcmp(volname, "EOD") && !found) {
2511 * If this is not a volume, move on to the next entry in the
2512 * partition's directory.
2514 if (!strcmp(volname, "")) {
2515 GetNextVol(dirp, volname, &currVolID);
2519 if (currVolID == a_volID) {
2521 * We found the volume entry we're interested. Pull out the
2522 * extended information, remembering to poll (so that the client
2523 * doesn't time out) and to set up a transaction on the volume.
2527 } /*Found desired volume */
2529 GetNextVol(dirp, volname, &currVolID);
2533 #ifndef AFS_PTHREAD_ENV
2537 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2538 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2540 code = GetVolInfo(a_partID,
2545 VOL_INFO_LIST_SINGLE);
2550 * Clean up before going to dinner: close the partition directory,
2551 * return the proper value.
2555 return code ? ENODEV: 0;
2558 } /*SAFSVolXListOneVolume */
2560 /*returns all the volumes on partition partid. If flags = 1 then all the
2561 * relevant info about the volumes is also returned */
2563 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2564 volEntries *volumeInfo)
2568 code = VolListVolumes(acid, partid, flags, volumeInfo);
2569 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2574 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2575 volEntries *volumeInfo)
2578 struct DiskPartition64 *partP;
2579 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2580 char pname[9], volname[20];
2584 volint_info_handle_t handle;
2586 volumeInfo->volEntries_val =
2587 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2588 if (!volumeInfo->volEntries_val)
2590 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2592 pntr = volumeInfo->volEntries_val;
2593 volumeInfo->volEntries_len = 0;
2594 if (GetPartName(partid, pname))
2595 return VOLSERILLEGAL_PARTITION;
2596 if (!(partP = VGetPartition(pname, 0)))
2597 return VOLSERILLEGAL_PARTITION;
2598 dirp = opendir(VPartitionPath(partP));
2600 return VOLSERILLEGAL_PARTITION;
2601 strcpy(volname, "");
2603 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2605 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2606 GetNextVol(dirp, volname, &volid);
2607 continue; /*back to while loop */
2610 if (flags) { /*copy other things too */
2611 #ifndef AFS_PTHREAD_ENV
2612 IOMGR_Poll(); /*make sure that the client does not time out */
2615 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2616 handle.volinfo_ptr.base = pntr;
2619 code = GetVolInfo(partid,
2624 VOL_INFO_LIST_MULTIPLE);
2625 if (code == -2) { /* DESTROY_ME flag set */
2629 pntr->volid = volid;
2630 /*just volids are needed */
2634 volumeInfo->volEntries_len += 1;
2635 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2636 /*running out of space, allocate more space */
2637 allocSize = (allocSize * 3) / 2;
2639 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2640 allocSize * sizeof(volintInfo));
2643 return VOLSERNO_MEMORY;
2645 volumeInfo->volEntries_val = pntr; /* point to new block */
2646 /* set pntr to the right position */
2647 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2652 GetNextVol(dirp, volname, &volid);
2660 /*------------------------------------------------------------------------
2661 * EXPORTED SAFSVolXListVolumes
2664 * Returns all the volumes on partition a_partID. If a_flags
2665 * is set to 1, then all the relevant extended volume information
2669 * a_rxCidP : Pointer to the Rx call we're performing.
2670 * a_partID : Partition for which we want the extended list.
2671 * a_flags : Various flags.
2672 * a_volumeXInfoP : Ptr to the extended info blob.
2675 * 0 Successful operation
2676 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2677 * VOLSERNO_MEMORY if we ran out of memory allocating
2681 * Nothing interesting.
2685 *------------------------------------------------------------------------*/
2688 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2689 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2693 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2694 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2699 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2700 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2701 { /*SAFSVolXListVolumes */
2703 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2704 struct DiskPartition64 *partP; /*Ptr to partition */
2705 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2706 char pname[9], volname[20]; /*Partition, volume names */
2707 DIR *dirp; /*Partition directory ptr */
2708 afs_uint32 volid; /*Current volume ID */
2710 volint_info_handle_t handle;
2713 * Allocate a large array of extended volume info structures, then
2714 * set it up for action.
2716 a_volumeXInfoP->volXEntries_val =
2717 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2718 if (!a_volumeXInfoP->volXEntries_val)
2720 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2722 xInfoP = a_volumeXInfoP->volXEntries_val;
2723 a_volumeXInfoP->volXEntries_len = 0;
2726 * If the partition name we've been given is bad, bogue out.
2728 if (GetPartName(a_partID, pname))
2729 return (VOLSERILLEGAL_PARTITION);
2732 * Open the directory representing the given AFS parttion. If we can't
2735 if (!(partP = VGetPartition(pname, 0)))
2736 return VOLSERILLEGAL_PARTITION;
2737 dirp = opendir(VPartitionPath(partP));
2739 return (VOLSERILLEGAL_PARTITION);
2740 strcpy(volname, "");
2743 * Sweep through the partition directory, acting on each entry. First,
2744 * of course, figure out how many stat bytes to copy out of each volume.
2746 while (strcmp(volname, "EOD")) {
2749 * If this is not a volume, move on to the next entry in the
2750 * partition's directory.
2752 if (!strcmp(volname, "")) {
2753 GetNextVol(dirp, volname, &volid);
2759 * Full info about the volume desired. Poll to make sure the
2760 * client doesn't time out, then start up a new transaction.
2762 #ifndef AFS_PTHREAD_ENV
2766 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2767 handle.volinfo_ptr.ext = xInfoP;
2769 code = GetVolInfo(a_partID,
2774 VOL_INFO_LIST_MULTIPLE);
2775 if (code == -2) { /* DESTROY_ME flag set */
2780 * Just volume IDs are needed.
2782 xInfoP->volid = volid;
2786 * Bump the pointer in the data area we're building, along with
2787 * the count of the number of entries it contains.
2790 (a_volumeXInfoP->volXEntries_len)++;
2791 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2793 * We're running out of space in the area we've built. Grow it.
2795 allocSize = (allocSize * 3) / 2;
2796 xInfoP = (volintXInfo *)
2797 realloc((char *)a_volumeXInfoP->volXEntries_val,
2798 (allocSize * sizeof(volintXInfo)));
2799 if (xInfoP == NULL) {
2801 * Bummer, no memory. Bag it, tell our caller what went wrong.
2804 return (VOLSERNO_MEMORY);
2808 * Memory reallocation worked. Correct our pointers so they
2809 * now point to the new block and the current open position within
2812 a_volumeXInfoP->volXEntries_val = xInfoP;
2814 a_volumeXInfoP->volXEntries_val +
2815 a_volumeXInfoP->volXEntries_len;
2819 GetNextVol(dirp, volname, &volid);
2820 } /*Sweep through the partition directory */
2823 * We've examined all entries in the partition directory. Close it,
2824 * delete our transaction (if any), and go home happy.
2829 } /*SAFSVolXListVolumes */
2831 /*this call is used to monitor the status of volser for debugging purposes.
2832 *information about all the active transactions is returned in transInfo*/
2834 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2838 code = VolMonitor(acid, transInfo);
2839 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2844 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2846 transDebugInfo *pntr;
2847 afs_int32 allocSize = 50;
2848 struct volser_trans *tt, *nt, *allTrans;
2850 transInfo->transDebugEntries_val =
2851 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2852 if (!transInfo->transDebugEntries_val)
2854 pntr = transInfo->transDebugEntries_val;
2855 transInfo->transDebugEntries_len = 0;
2858 allTrans = TransList();
2859 if (allTrans == (struct volser_trans *)0)
2860 goto done; /*no active transactions */
2861 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2863 VTRANS_OBJ_LOCK(tt);
2864 pntr->tid = tt->tid;
2865 pntr->time = tt->time;
2866 pntr->creationTime = tt->creationTime;
2867 pntr->returnCode = tt->returnCode;
2868 pntr->volid = tt->volid;
2869 pntr->partition = tt->partition;
2870 pntr->iflags = tt->iflags;
2871 pntr->vflags = tt->vflags;
2872 pntr->tflags = tt->tflags;
2873 strcpy(pntr->lastProcName, tt->lastProcName);
2874 pntr->callValid = 0;
2875 if (tt->rxCallPtr) { /*record call related info */
2876 pntr->callValid = 1;
2877 pntr->readNext = tt->rxCallPtr->rnext;
2878 pntr->transmitNext = tt->rxCallPtr->tnext;
2879 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2880 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2882 VTRANS_OBJ_UNLOCK(tt);
2884 transInfo->transDebugEntries_len += 1;
2885 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2886 allocSize = (allocSize * 3) / 2;
2888 (transDebugInfo *) realloc((char *)transInfo->
2889 transDebugEntries_val,
2891 sizeof(transDebugInfo));
2892 transInfo->transDebugEntries_val = pntr;
2894 transInfo->transDebugEntries_val +
2895 transInfo->transDebugEntries_len;
2896 /*set pntr to right position */
2907 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2908 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2909 afs_uint32 backupId)
2913 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2914 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2915 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2921 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2922 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2923 afs_uint32 backupId)
2927 struct volser_trans *tt;
2928 char caller[MAXKTCNAMELEN];
2930 if (strlen(name) > 31)
2931 return VOLSERBADNAME;
2932 if (!afsconf_SuperUser(tdir, acid, caller))
2933 return VOLSERBAD_ACCESS; /*not a super user */
2934 /* find the trans */
2935 tt = FindTrans(atid);
2938 if (tt->vflags & VTDeleted) {
2939 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2943 TSetRxCall(tt, acid, "SetIdsTypes");
2947 V_backupId(tv) = backupId;
2948 V_cloneId(tv) = cloneId;
2949 V_parentId(tv) = pId;
2950 strcpy((&V_disk(tv))->name, name);
2951 VUpdateVolume(&error, tv);
2953 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2958 if (TRELE(tt) && !error)
2959 return VOLSERTRELE_ERROR;
2964 if (TRELE(tt) && !error)
2965 return VOLSERTRELE_ERROR;
2970 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2974 code = VolSetDate(acid, atid, cdate);
2975 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2981 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
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 /* find the trans */
2991 tt = FindTrans(atid);
2994 if (tt->vflags & VTDeleted) {
2995 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2999 TSetRxCall(tt, acid, "SetDate");
3002 V_creationDate(tv) = cdate;
3003 VUpdateVolume(&error, tv);
3005 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
3010 if (TRELE(tt) && !error)
3011 return VOLSERTRELE_ERROR;
3016 if (TRELE(tt) && !error)
3017 return VOLSERTRELE_ERROR;
3022 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
3023 afs_uint32 volumeId)
3028 char caller[MAXKTCNAMELEN];
3030 struct volser_trans *ttc;
3031 char pname[16], volname[20];
3032 struct DiskPartition64 *partP;
3033 afs_int32 ret = ENODEV;
3036 if (!afsconf_SuperUser(tdir, acid, caller))
3037 return VOLSERBAD_ACCESS; /*not a super user */
3038 if (GetPartName(partId, pname))
3039 return VOLSERILLEGAL_PARTITION;
3040 if (!(partP = VGetPartition(pname, 0)))
3041 return VOLSERILLEGAL_PARTITION;
3042 dirp = opendir(VPartitionPath(partP));
3044 return VOLSERILLEGAL_PARTITION;
3045 strcpy(volname, "");
3046 ttc = (struct volser_trans *)0;
3048 while (strcmp(volname, "EOD")) {
3049 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
3050 GetNextVol(dirp, volname, &volid);
3051 continue; /*back to while loop */
3054 if (volid == volumeId) { /*copy other things too */
3055 #ifndef AFS_PTHREAD_ENV
3056 IOMGR_Poll(); /*make sure that the client doesnot time out */
3058 ttc = NewTrans(volumeId, partId);
3060 return VOLSERVOLBUSY;
3062 #ifdef AFS_NAMEI_ENV
3063 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3065 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3069 GetNextVol(dirp, volname, &volid);
3073 DeleteTrans(ttc, 1);
3074 ttc = (struct volser_trans *)0;
3083 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3084 struct volintSize *size)
3087 struct volser_trans *tt;
3088 char caller[MAXKTCNAMELEN];
3090 if (!afsconf_SuperUser(tdir, acid, caller))
3091 return VOLSERBAD_ACCESS; /*not a super user */
3092 tt = FindTrans(fromTrans);
3095 if (tt->vflags & VTDeleted) {
3099 TSetRxCall(tt, acid, "GetSize");
3100 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3103 return VOLSERTRELE_ERROR;
3105 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3110 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
3111 afs_uint32 where, afs_int32 verbose)
3113 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3115 Volume *vol=0, *newvol=0;
3116 struct volser_trans *tt = 0, *tt2 = 0;
3117 char caller[MAXKTCNAMELEN];
3120 if (!afsconf_SuperUser(tdir, acall, caller))
3123 vol = VAttachVolume(&code, vid, V_VOLUPD);
3129 newvol = VAttachVolume(&code, new, V_VOLUPD);
3131 VDetachVolume(&code2, vol);
3136 if (V_device(vol) != V_device(newvol)
3137 || V_uniquifier(newvol) != 2) {
3138 if (V_device(vol) != V_device(newvol)) {
3139 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3141 rx_Write(acall, line, strlen(line));
3143 if (V_uniquifier(newvol) != 2) {
3144 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3145 rx_Write(acall, line, strlen(line));
3148 rx_Write(acall, line, 1);
3149 VDetachVolume(&code2, vol);
3150 VDetachVolume(&code2, newvol);
3153 tt = NewTrans(vid, V_device(vol));
3155 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3156 rx_Write(acall, line, strlen(line));
3158 rx_Write(acall, line, 1);
3159 VDetachVolume(&code2, vol);
3160 VDetachVolume(&code2, newvol);
3161 return VOLSERVOLBUSY;
3163 VTRANS_OBJ_LOCK(tt);
3164 tt->iflags = ITBusy;
3166 TSetRxCall_r(tt, NULL, "SplitVolume");
3167 VTRANS_OBJ_UNLOCK(tt);
3169 tt2 = NewTrans(new, V_device(newvol));
3171 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3172 rx_Write(acall, line, strlen(line));
3174 rx_Write(acall, line, 1);
3176 VDetachVolume(&code2, vol);
3177 VDetachVolume(&code2, newvol);
3178 return VOLSERVOLBUSY;
3180 VTRANS_OBJ_LOCK(tt2);
3181 tt2->iflags = ITBusy;
3183 TSetRxCall_r(tt2, NULL, "SplitVolume");
3184 VTRANS_OBJ_UNLOCK(tt2);
3186 code = split_volume(acall, vol, newvol, where, verbose);
3188 VDetachVolume(&code2, vol);
3190 VDetachVolume(&code2, newvol);
3191 DeleteTrans(tt2, 1);
3198 /* GetPartName - map partid (a decimal number) into pname (a string)
3199 * Since for NT we actually want to return the drive name, we map through the
3203 GetPartName(afs_int32 partid, char *pname)
3208 strcpy(pname, "/vicep");
3209 pname[6] = 'a' + partid;
3212 } else if (partid < VOLMAXPARTS) {
3213 strcpy(pname, "/vicep");
3215 pname[6] = 'a' + (partid / 26);
3216 pname[7] = 'a' + (partid % 26);