2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
9 * Portions Copyright (c) 2007-2008 Sine Nomine Associates
12 #include <afsconfig.h>
13 #include <afs/param.h>
17 #include <sys/types.h>
26 #include <netinet/in.h>
35 #include <afs/afsint.h>
37 #ifdef AFS_PTHREAD_ENV
39 #else /* AFS_PTHREAD_ENV */
40 #include <afs/assert.h>
41 #endif /* AFS_PTHREAD_ENV */
42 #include <afs/prs_fs.h>
46 #include <afs/cellconfig.h>
49 #include <afs/ihandle.h>
51 #include <afs/ntops.h>
53 #include <afs/vnode.h>
54 #include <afs/volume.h>
55 #include <afs/volume_inline.h>
56 #include <afs/partition.h>
58 #include <afs/daemon_com.h>
59 #include <afs/fssync.h>
61 #include "afs/audit.h"
63 #include <afs/afsutil.h>
64 #include <afs/vol_prototypes.h>
67 #include "voltrans_inline.h"
70 #include "volser_internal.h"
72 #include "dumpstuff.h"
75 extern struct afsconf_dir *tdir;
77 extern void LogError(afs_int32 errcode);
79 /* Forward declarations */
80 static int GetPartName(afs_int32 partid, char *pname);
82 #define OneDay (24*60*60)
88 afs_int32 localTid = 1;
90 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
91 struct diskPartition64 *);
92 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
93 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
94 afs_int32, afs_uint32, afs_uint32 *,
96 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
97 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
98 afs_int32, char *, afs_uint32 *);
99 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
100 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
101 afs_int32, afs_int32 *);
102 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
104 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
105 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
106 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
107 struct destServer *destination, afs_int32,
108 struct restoreCookie *cookie);
109 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
110 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
111 struct restoreCookie *);
112 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
113 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
114 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
115 struct volser_status *);
116 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
117 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
118 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
119 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
120 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
122 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
124 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
126 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
128 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
129 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
130 afs_int32, afs_uint32, afs_uint32,
132 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
134 /* this call unlocks all of the partition locks we've set */
138 register struct DiskPartition64 *tp;
139 for (tp = DiskPartitionList; tp; tp = tp->next) {
140 if (tp->lock_fd != INVALID_FD) {
141 close(tp->lock_fd); /* releases flock held on this partition */
142 tp->lock_fd = INVALID_FD;
148 /* get partition id from a name */
150 PartitionID(char *aname)
153 register int code = 0;
158 return -1; /* unknown */
160 /* otherwise check for vicepa or /vicepa, or just plain "a" */
162 if (!strncmp(aname, "/vicep", 6)) {
163 strncpy(ascii, aname + 6, 2);
165 return -1; /* bad partition name */
166 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
167 * from 0. Do the appropriate conversion */
169 /* one char name, 0..25 */
170 if (ascii[0] < 'a' || ascii[0] > 'z')
171 return -1; /* wrongo */
172 return ascii[0] - 'a';
174 /* two char name, 26 .. <whatever> */
175 if (ascii[0] < 'a' || ascii[0] > 'z')
176 return -1; /* wrongo */
177 if (ascii[1] < 'a' || ascii[1] > 'z')
178 return -1; /* just as bad */
179 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
180 if (code > VOLMAXPARTS)
187 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
191 /* 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 */
192 (void)afs_snprintf(aname, asize, VFORMAT, (unsigned long)avol);
197 ConvertPartition(int apartno, char *aname, int asize)
203 strcpy(aname, "/vicep");
205 aname[6] = 'a' + apartno;
209 aname[6] = 'a' + (apartno / 26);
210 aname[7] = 'a' + (apartno % 26);
216 /* the only attach function that takes a partition is "...ByName", so we use it */
218 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
220 char pbuf[30], vbuf[20];
221 register struct Volume *tv;
223 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
227 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
231 tv = VAttachVolumeByName((Error *)error, pbuf, vbuf, amode);
235 /* Adapted from the file server; create a root directory for this volume */
237 ViceCreateRoot(Volume *vp)
240 struct acl_accessList *ACL;
242 Inode inodeNumber, nearInode;
243 struct VnodeDiskObject *vnode;
244 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
250 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
253 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
255 V_pref(vp, nearInode);
257 IH_CREATE(V_linkHandle(vp), V_device(vp),
258 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
260 assert(VALID_INO(inodeNumber));
262 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
263 did.Volume = V_id(vp);
264 did.Vnode = (VnodeId) 1;
267 assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
268 DFlush(); /* flush all modified dir buffers out */
269 DZap((afs_int32 *)&dir); /* Remove all buffers for this dir */
270 length = Length(&dir); /* Remember size of this directory */
272 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
274 /* build a single entry ACL that gives all rights to system:administrators */
275 /* this section of code assumes that access list format is not going to
278 ACL = VVnodeDiskACL(vnode);
279 ACL->size = sizeof(struct acl_accessList);
280 ACL->version = ACL_ACLVERSION;
284 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
285 ACL->entries[0].rights =
286 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
287 | PRSFS_LOCK | PRSFS_ADMINISTER;
289 vnode->type = vDirectory;
291 vnode->modeBits = 0777;
292 vnode->linkCount = 2;
293 VNDISK_SET_LEN(vnode, length);
294 vnode->uniquifier = 1;
295 V_uniquifier(vp) = vnode->uniquifier + 1;
296 vnode->dataVersion = 1;
297 VNDISK_SET_INO(vnode, inodeNumber);
298 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
302 vnode->vnodeMagic = vcp->magic;
304 IH_INIT(h, vp->device, V_parentId(vp),
305 vp->vnodeIndex[vLarge].handle->ih_ino);
308 code = FDH_SEEK(fdP, vnodeIndexOffset(vcp, 1), SEEK_SET);
310 code = FDH_WRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE);
311 assert(code == SIZEOF_LARGEDISKVNODE);
312 FDH_REALLYCLOSE(fdP);
314 VNDISK_GET_LEN(length, vnode);
315 V_diskused(vp) = nBlocks(length);
322 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
326 struct diskPartition64 *dp = (struct diskPartition64 *)
327 malloc(sizeof(struct diskPartition64));
329 code = VolPartitionInfo(acid, pname, dp);
331 strncpy(partition->name, dp->name, 32);
332 strncpy(partition->devName, dp->devName, 32);
333 partition->lock_fd = dp->lock_fd;
334 partition->free=RoundInt64ToInt32(dp->free);
335 partition->minFree=RoundInt64ToInt32(dp->minFree);
338 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
343 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
348 code = VolPartitionInfo(acid, pname, partition);
349 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
354 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
357 register struct DiskPartition64 *dp;
360 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
363 dp = VGetPartition(pname, 0);
365 strncpy(partition->name, dp->name, 32);
366 strncpy(partition->devName, dp->devName, 32);
367 partition->lock_fd = (int)dp->lock_fd;
368 partition->free = dp->free;
369 partition->minFree = dp->totalUsable;
372 return VOLSERILLEGAL_PARTITION;
375 /* obliterate a volume completely, and slowly. */
377 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
381 code = VolNukeVolume(acid, apartID, avolID);
382 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
387 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
392 register afs_int32 code;
394 char caller[MAXKTCNAMELEN];
396 /* check for access */
397 if (!afsconf_SuperUser(tdir, acid, caller))
398 return VOLSERBAD_ACCESS;
400 Log("%s is executing VolNukeVolume %u\n", caller, avolID);
402 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
404 /* we first try to attach the volume in update mode, so that the file
405 * server doesn't try to use it (and abort) while (or after) we delete it.
406 * If we don't get the volume, that's fine, too. We just won't put it back.
408 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
409 code = nuke(partName, avolID);
411 VDetachVolume(&verror, tvp);
415 /* create a new volume, with name aname, on the specified partition (1..n)
416 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
417 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
418 * for the volume id (useful for things like volume restore).
419 * Return the new volume id in *avolid.
422 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
423 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
429 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
430 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
431 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
437 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
438 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
443 Error junk; /* discardable error code */
445 afs_int32 doCreateRoot = 1;
446 register struct volser_trans *tt;
448 char caller[MAXKTCNAMELEN];
450 if (strlen(aname) > 31)
451 return VOLSERBADNAME;
452 if (!afsconf_SuperUser(tdir, acid, caller))
453 return VOLSERBAD_ACCESS;
455 Log("%s is executing CreateVolume '%s'\n", caller, aname);
456 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
457 return error; /*a standard unix error */
458 if (atype != readwriteVolume && atype != readonlyVolume
459 && atype != backupVolume)
461 if ((volumeID = *avolid) == 0) {
463 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
467 if ((aparent == volumeID) && (atype == readwriteVolume)) {
472 tt = NewTrans(volumeID, apart);
474 Log("1 createvolume: failed to create trans\n");
475 return VOLSERVOLBUSY; /* volume already busy! */
477 vp = VCreateVolume(&error, ppath, volumeID, aparent);
479 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
484 V_uniquifier(vp) = 1;
485 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
486 V_inService(vp) = V_blessed(vp) = 1;
488 AssignVolumeName(&V_disk(vp), aname, 0);
491 V_destroyMe(vp) = DESTROY_ME;
493 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
494 VUpdateVolume(&error, vp);
496 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
499 VDetachVolume(&junk, vp); /* rather return the real error code */
505 TSetRxCall_r(tt, acid, "CreateVolume");
506 VTRANS_OBJ_UNLOCK(tt);
507 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
510 return VOLSERTRELE_ERROR;
514 /* delete the volume associated with this transaction */
516 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
520 code = VolDeleteVolume(acid, atrans);
521 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
526 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
528 register struct volser_trans *tt;
530 char caller[MAXKTCNAMELEN];
532 if (!afsconf_SuperUser(tdir, acid, caller))
533 return VOLSERBAD_ACCESS;
534 tt = FindTrans(atrans);
537 if (tt->vflags & VTDeleted) {
538 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
543 Log("%s is executing Delete Volume %u\n", caller, tt->volid);
544 TSetRxCall(tt, acid, "DeleteVolume");
545 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
546 V_destroyMe(tt->volume) = DESTROY_ME; /* so endtrans does the right fssync opcode */
548 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
550 VTRANS_OBJ_UNLOCK(tt);
552 return VOLSERTRELE_ERROR;
554 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
555 return 0; /* vpurgevolume doesn't set an error code */
558 /* make a clone of the volume associated with atrans, possibly giving it a new
559 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
560 * for the clone's id). The new clone is given the name newName. Finally,
561 * due to efficiency considerations, if purgeId is non-zero, we purge that
562 * volume when doing the clone operation. This may be useful when making
563 * new backup volumes, for instance since the net result of a clone and a
564 * purge generally leaves many inode ref counts the same, while doing them
565 * separately would result in far more iincs and idecs being peformed
566 * (and they are slow operations).
568 /* for efficiency reasons, sometimes faster to piggyback a purge here */
570 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
571 afs_int32 newType, char *newName, afs_uint32 *newNumber)
575 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
576 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
577 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
583 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
584 afs_int32 newType, char *newName, afs_uint32 *newNumber)
587 register struct Volume *originalvp, *purgevp, *newvp;
589 register struct volser_trans *tt, *ttc;
590 char caller[MAXKTCNAMELEN];
592 if (strlen(newName) > 31)
593 return VOLSERBADNAME;
594 if (!afsconf_SuperUser(tdir, acid, caller))
595 return VOLSERBAD_ACCESS; /*not a super user */
597 Log("%s is executing Clone Volume new name=%s\n", caller, newName);
599 originalvp = (Volume *) 0;
600 purgevp = (Volume *) 0;
601 newvp = (Volume *) 0;
602 tt = ttc = (struct volser_trans *)0;
604 if (!newNumber || !*newNumber) {
605 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
610 if (newType != readonlyVolume && newType != backupVolume)
612 tt = FindTrans(atrans);
615 if (tt->vflags & VTDeleted) {
616 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
620 ttc = NewTrans(newId, tt->partition);
621 if (!ttc) { /* someone is messing with the clone already */
623 return VOLSERVOLBUSY;
625 TSetRxCall(tt, acid, "Clone");
629 purgevp = VAttachVolume(&error, purgeId, V_VOLUPD);
631 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
637 originalvp = tt->volume;
638 if ((V_type(originalvp) == backupVolume)
639 || (V_type(originalvp) == readonlyVolume)) {
640 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
644 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
645 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
651 if (originalvp->device != purgevp->device) {
652 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
656 if (V_type(purgevp) != readonlyVolume) {
657 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
661 if (V_type(originalvp) == readonlyVolume
662 && V_parentId(originalvp) != V_parentId(purgevp)) {
663 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
667 if (V_type(originalvp) == readwriteVolume
668 && tt->volid != V_parentId(purgevp)) {
669 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
678 VCreateVolume(&error, originalvp->partition->name, newId,
679 V_parentId(originalvp));
681 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
682 newvp = (Volume *) 0;
685 if (newType == readonlyVolume)
686 V_cloneId(originalvp) = newId;
687 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
690 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
691 CloneVolume(&error, originalvp, newvp, purgevp);
692 purgevp = NULL; /* clone releases it, maybe even if error */
694 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
698 if (newType == readonlyVolume) {
699 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
700 V_type(newvp) = readonlyVolume;
701 } else if (newType == backupVolume) {
702 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
703 V_type(newvp) = backupVolume;
704 V_backupId(originalvp) = newId;
706 strcpy(newvp->header->diskstuff.name, newName);
707 V_creationDate(newvp) = V_copyDate(newvp);
708 ClearVolumeStats(&V_disk(newvp));
709 V_destroyMe(newvp) = DESTROY_ME;
710 V_inService(newvp) = 0;
711 if (newType == backupVolume) {
712 V_backupDate(originalvp) = V_copyDate(newvp);
713 V_backupDate(newvp) = V_copyDate(newvp);
716 VUpdateVolume(&error, newvp);
718 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
722 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
724 VUpdateVolume(&error, originalvp);
726 Log("1 Volser: Clone: original update %u\n", error);
732 tt = (struct volser_trans *)0;
733 error = VOLSERTRELE_ERROR;
741 VDetachVolume(&code, purgevp);
743 VDetachVolume(&code, newvp);
753 /* reclone this volume into the specified id */
755 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
759 code = VolReClone(acid, atrans, cloneId);
760 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
766 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
768 register struct Volume *originalvp, *clonevp;
771 register struct volser_trans *tt, *ttc;
772 char caller[MAXKTCNAMELEN];
774 /*not a super user */
775 if (!afsconf_SuperUser(tdir, acid, caller))
776 return VOLSERBAD_ACCESS;
778 Log("%s is executing Reclone Volume %u\n", caller, cloneId);
780 clonevp = originalvp = (Volume *) 0;
781 tt = (struct volser_trans *)0;
783 tt = FindTrans(atrans);
786 if (tt->vflags & VTDeleted) {
787 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
791 ttc = NewTrans(cloneId, tt->partition);
792 if (!ttc) { /* someone is messing with the clone already */
794 return VOLSERVOLBUSY;
796 TSetRxCall(tt, acid, "ReClone");
798 originalvp = tt->volume;
799 if ((V_type(originalvp) == backupVolume)
800 || (V_type(originalvp) == readonlyVolume)) {
801 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
805 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
806 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
812 clonevp = VAttachVolume(&error, cloneId, V_VOLUPD);
814 Log("1 Volser: can't attach clone %d\n", cloneId);
818 newType = V_type(clonevp); /* type of the new volume */
820 if (originalvp->device != clonevp->device) {
821 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
826 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
827 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
831 if (V_type(originalvp) == readonlyVolume
832 && V_parentId(originalvp) != V_parentId(clonevp)) {
833 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
837 if (V_type(originalvp) == readwriteVolume
838 && tt->volid != V_parentId(clonevp)) {
839 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
845 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
847 CloneVolume(&error, originalvp, clonevp, clonevp);
849 Log("1 Volser: Clone: reclone operation failed with code %d\n",
855 /* fix up volume name and type, CloneVolume just propagated RW's */
856 if (newType == readonlyVolume) {
857 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
858 V_type(clonevp) = readonlyVolume;
859 } else if (newType == backupVolume) {
860 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
861 V_type(clonevp) = backupVolume;
862 V_backupId(originalvp) = cloneId;
864 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
866 /* pretend recloned volume is a totally new instance */
867 V_copyDate(clonevp) = time(0);
868 V_creationDate(clonevp) = V_copyDate(clonevp);
869 ClearVolumeStats(&V_disk(clonevp));
870 V_destroyMe(clonevp) = 0;
871 V_inService(clonevp) = 0;
872 if (newType == backupVolume) {
873 V_backupDate(originalvp) = V_copyDate(clonevp);
874 V_backupDate(clonevp) = V_copyDate(clonevp);
876 V_inUse(clonevp) = 0;
877 VUpdateVolume(&error, clonevp);
879 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
883 /* VUpdateVolume succeeded. Mark it in service so there's no window
884 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
885 * specialStatus; this is a reclone and this volume started online
887 V_inService(clonevp) = 1;
888 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
890 VUpdateVolume(&error, originalvp);
892 Log("1 Volser: Clone: original update %u\n", error);
898 tt = (struct volser_trans *)0;
899 error = VOLSERTRELE_ERROR;
906 struct DiskPartition64 *tpartp = originalvp->partition;
907 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
913 VDetachVolume(&code, clonevp);
923 /* create a new transaction, associated with volume and partition. Type of
924 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
925 * See volser.h for definition of iflags (the constants are named IT*).
928 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
929 afs_int32 iflags, afs_int32 *ttid)
933 code = VolTransCreate(acid, volume, partition, iflags, ttid);
934 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
940 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
941 afs_int32 iflags, afs_int32 *ttid)
943 register struct volser_trans *tt;
948 char caller[MAXKTCNAMELEN];
950 if (!afsconf_SuperUser(tdir, acid, caller))
951 return VOLSERBAD_ACCESS; /*not a super user */
952 if (iflags & ITCreate)
954 else if (iflags & ITBusy)
956 else if (iflags & ITReadOnly)
958 else if (iflags & ITOffline)
961 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
966 tt = NewTrans(volume, partition);
968 /* can't create a transaction? put the volume back */
969 Log("1 transcreate: can't create transaction\n");
970 return VOLSERVOLBUSY;
972 tv = XAttachVolume(&error, volume, partition, mode);
976 VDetachVolume(&code, tv);
985 TSetRxCall_r(tt, NULL, "TransCreate");
986 VTRANS_OBJ_UNLOCK(tt);
988 return VOLSERTRELE_ERROR;
993 /* using aindex as a 0-based index, return the aindex'th volume on this server
994 * Both the volume number and partition number (one-based) are returned.
997 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1002 code = VolGetNthVolume(acid, aindex, avolume, apart);
1003 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1008 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1011 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1015 /* return the volume flags (VT* constants in volser.h) associated with this
1019 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1023 code = VolGetFlags(acid, atid, aflags);
1024 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1029 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1031 register struct volser_trans *tt;
1033 tt = FindTrans(atid);
1036 if (tt->vflags & VTDeleted) {
1037 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1042 TSetRxCall(tt, acid, "GetFlags");
1043 *aflags = tt->vflags;
1046 return VOLSERTRELE_ERROR;
1051 /* Change the volume flags (VT* constants in volser.h) associated with this
1052 * transaction. Effects take place immediately on volume, although volume
1053 * remains attached as usual by the transaction.
1056 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1060 code = VolSetFlags(acid, atid, aflags);
1061 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1067 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1069 register struct volser_trans *tt;
1070 register struct Volume *vp;
1072 char caller[MAXKTCNAMELEN];
1074 if (!afsconf_SuperUser(tdir, acid, caller))
1075 return VOLSERBAD_ACCESS; /*not a super user */
1076 /* find the trans */
1077 tt = FindTrans(atid);
1080 if (tt->vflags & VTDeleted) {
1081 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1086 TSetRxCall(tt, acid, "SetFlags");
1087 vp = tt->volume; /* pull volume out of transaction */
1089 /* check if we're allowed to make any updates */
1090 if (tt->iflags & ITReadOnly) {
1095 /* handle delete-on-salvage flag */
1096 if (aflags & VTDeleteOnSalvage) {
1097 V_destroyMe(tt->volume) = DESTROY_ME;
1099 V_destroyMe(tt->volume) = 0;
1102 if (aflags & VTOutOfService) {
1103 V_inService(vp) = 0;
1105 V_inService(vp) = 1;
1107 VUpdateVolume(&error, vp);
1108 VTRANS_OBJ_LOCK(tt);
1109 tt->vflags = aflags;
1111 VTRANS_OBJ_UNLOCK(tt);
1112 if (TRELE(tt) && !error)
1113 return VOLSERTRELE_ERROR;
1118 /* dumpS the volume associated with a particular transaction from a particular
1119 * date. Send the dump to a different transaction (destTrans) on the server
1120 * specified by the destServer structure.
1123 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1124 struct destServer *destination, afs_int32 destTrans,
1125 struct restoreCookie *cookie)
1130 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1131 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1132 destination->destHost, AUD_LONG, destTrans, AUD_END);
1137 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1138 struct destServer *destination, afs_int32 destTrans,
1139 struct restoreCookie *cookie)
1141 register struct volser_trans *tt;
1142 register afs_int32 code;
1143 register struct rx_connection *tcon;
1144 struct rx_call *tcall;
1145 register struct Volume *vp;
1146 struct rx_securityClass *securityObject;
1147 afs_int32 securityIndex;
1148 char caller[MAXKTCNAMELEN];
1150 if (!afsconf_SuperUser(tdir, acid, caller))
1151 return VOLSERBAD_ACCESS; /*not a super user */
1152 /* initialize things */
1153 tcon = (struct rx_connection *)0;
1154 tt = (struct volser_trans *)0;
1156 /* find the local transaction */
1157 tt = FindTrans(fromTrans);
1160 if (tt->vflags & VTDeleted) {
1161 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1166 TSetRxCall(tt, NULL, "Forward");
1168 /* get auth info for the this connection (uses afs from ticket file) */
1169 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1175 /* make an rpc connection to the other server */
1177 rx_NewConnection(htonl(destination->destHost),
1178 htons(destination->destPort), VOLSERVICE_ID,
1179 securityObject, securityIndex);
1185 tcall = rx_NewCall(tcon);
1186 TSetRxCall(tt, tcall, "Forward");
1187 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1188 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1193 /* these next calls implictly call rx_Write when writing out data */
1194 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1197 EndAFSVolRestore(tcall); /* probably doesn't do much */
1199 code = rx_EndCall(tcall, 0);
1200 rx_DestroyConnection(tcon); /* done with the connection */
1205 return VOLSERTRELE_ERROR;
1211 (void)rx_EndCall(tcall, 0);
1212 rx_DestroyConnection(tcon);
1221 /* Start a dump and send it to multiple places simultaneously.
1222 * If this returns an error (eg, return ENOENT), it means that
1223 * none of the releases worked. If this returns 0, that means
1224 * that one or more of the releases worked, and the caller has
1225 * to examine the results array to see which one(s).
1226 * This will only do EITHER incremental or full, not both, so it's
1227 * the caller's responsibility to be sure that all the destinations
1228 * need just an incremental (and from the same time), if that's
1232 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1233 fromDate, manyDests *destinations, afs_int32 spare,
1234 struct restoreCookie *cookie, manyResults *results)
1236 afs_int32 securityIndex;
1237 struct rx_securityClass *securityObject;
1238 char caller[MAXKTCNAMELEN];
1239 struct volser_trans *tt;
1240 afs_int32 ec, code, *codes;
1241 struct rx_connection **tcons;
1242 struct rx_call **tcalls;
1244 int i, is_incremental;
1247 memset(results, 0, sizeof(manyResults));
1248 i = results->manyResults_len = destinations->manyDests_len;
1249 results->manyResults_val = codes =
1250 (afs_int32 *) malloc(i * sizeof(afs_int32));
1252 if (!results || !results->manyResults_val)
1255 if (!afsconf_SuperUser(tdir, acid, caller))
1256 return VOLSERBAD_ACCESS; /*not a super user */
1257 tt = FindTrans(fromTrans);
1260 if (tt->vflags & VTDeleted) {
1261 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1266 TSetRxCall(tt, NULL, "ForwardMulti");
1268 /* (fromDate == 0) ==> full dump */
1269 is_incremental = (fromDate ? 1 : 0);
1272 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1276 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1282 /* get auth info for this connection (uses afs from ticket file) */
1283 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1285 goto fail; /* in order to audit each failure */
1288 /* make connections to all the other servers */
1289 for (i = 0; i < destinations->manyDests_len; i++) {
1290 struct replica *dest = &(destinations->manyDests_val[i]);
1292 rx_NewConnection(htonl(dest->server.destHost),
1293 htons(dest->server.destPort), VOLSERVICE_ID,
1294 securityObject, securityIndex);
1296 codes[i] = ENOTCONN;
1298 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1299 codes[i] = ENOTCONN;
1302 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1305 (void)rx_EndCall(tcalls[i], 0);
1307 rx_DestroyConnection(tcons[i]);
1314 /* these next calls implictly call rx_Write when writing out data */
1315 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1319 for (i--; i >= 0; i--) {
1320 struct replica *dest = &(destinations->manyDests_val[i]);
1322 if (!code && tcalls[i] && !codes[i]) {
1323 EndAFSVolRestore(tcalls[i]);
1326 ec = rx_EndCall(tcalls[i], 0);
1331 rx_DestroyConnection(tcons[i]); /* done with the connection */
1334 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1335 fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG,
1336 dest->trans, AUD_END);
1343 if (TRELE(tt) && !code) /* return the first code if it's set */
1344 return VOLSERTRELE_ERROR;
1351 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1355 code = VolDump(acid, fromTrans, fromDate, 0);
1356 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1361 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1366 code = VolDump(acid, fromTrans, fromDate, flags);
1367 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1372 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1376 register struct volser_trans *tt;
1377 char caller[MAXKTCNAMELEN];
1379 if (!afsconf_SuperUser(tdir, acid, caller))
1380 return VOLSERBAD_ACCESS; /*not a super user */
1381 tt = FindTrans(fromTrans);
1384 if (tt->vflags & VTDeleted) {
1385 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1389 TSetRxCall(tt, acid, "Dump");
1390 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1391 ? 0 : 1); /* squirt out the volume's data, too */
1400 return VOLSERTRELE_ERROR;
1406 * Ha! No more helper process!
1409 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1410 struct restoreCookie *cookie)
1414 code = VolRestore(acid, atrans, aflags, cookie);
1415 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1420 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1421 struct restoreCookie *cookie)
1423 register struct volser_trans *tt;
1424 register afs_int32 code, tcode;
1425 char caller[MAXKTCNAMELEN];
1427 if (!afsconf_SuperUser(tdir, acid, caller))
1428 return VOLSERBAD_ACCESS; /*not a super user */
1429 tt = FindTrans(atrans);
1432 if (tt->vflags & VTDeleted) {
1433 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1437 TSetRxCall(tt, acid, "Restore");
1439 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1441 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1442 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1446 return (code ? code : tcode);
1449 /* end a transaction, returning the transaction's final error code in rcode */
1451 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1455 code = VolEndTrans(acid, destTrans, rcode);
1456 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1461 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1463 register struct volser_trans *tt;
1464 char caller[MAXKTCNAMELEN];
1466 if (!afsconf_SuperUser(tdir, acid, caller))
1467 return VOLSERBAD_ACCESS; /*not a super user */
1468 tt = FindTrans(destTrans);
1472 *rcode = tt->returnCode;
1473 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1479 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1483 code = VolSetForwarding(acid, atid, anewsite);
1484 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1490 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1492 register struct volser_trans *tt;
1493 char caller[MAXKTCNAMELEN];
1496 if (!afsconf_SuperUser(tdir, acid, caller))
1497 return VOLSERBAD_ACCESS; /*not a super user */
1498 tt = FindTrans(atid);
1501 if (tt->vflags & VTDeleted) {
1502 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1507 TSetRxCall(tt, acid, "SetForwarding");
1508 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1511 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1514 return VOLSERTRELE_ERROR;
1520 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1521 register struct volser_status *astatus)
1525 code = VolGetStatus(acid, atrans, astatus);
1526 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1531 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1532 register struct volser_status *astatus)
1534 register struct Volume *tv;
1535 register struct VolumeDiskData *td;
1536 struct volser_trans *tt;
1539 tt = FindTrans(atrans);
1542 if (tt->vflags & VTDeleted) {
1543 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1548 TSetRxCall(tt, acid, "GetStatus");
1556 td = &tv->header->diskstuff;
1557 astatus->volID = td->id;
1558 astatus->nextUnique = td->uniquifier;
1559 astatus->type = td->type;
1560 astatus->parentID = td->parentId;
1561 astatus->cloneID = td->cloneId;
1562 astatus->backupID = td->backupId;
1563 astatus->restoredFromID = td->restoredFromId;
1564 astatus->maxQuota = td->maxquota;
1565 astatus->minQuota = td->minquota;
1566 astatus->owner = td->owner;
1567 astatus->creationDate = td->creationDate;
1568 astatus->accessDate = td->accessDate;
1569 astatus->updateDate = td->updateDate;
1570 astatus->expirationDate = td->expirationDate;
1571 astatus->backupDate = td->backupDate;
1572 astatus->copyDate = td->copyDate;
1575 return VOLSERTRELE_ERROR;
1581 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1582 register struct volintInfo *astatus)
1586 code = VolSetInfo(acid, atrans, astatus);
1587 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1592 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1593 register struct volintInfo *astatus)
1595 register struct Volume *tv;
1596 register struct VolumeDiskData *td;
1597 struct volser_trans *tt;
1598 char caller[MAXKTCNAMELEN];
1601 if (!afsconf_SuperUser(tdir, acid, caller))
1602 return VOLSERBAD_ACCESS; /*not a super user */
1603 tt = FindTrans(atrans);
1606 if (tt->vflags & VTDeleted) {
1607 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1611 TSetRxCall(tt, acid, "SetStatus");
1619 td = &tv->header->diskstuff;
1621 * Add more fields as necessary
1623 if (astatus->maxquota != -1)
1624 td->maxquota = astatus->maxquota;
1625 if (astatus->dayUse != -1)
1626 td->dayUse = astatus->dayUse;
1627 if (astatus->creationDate != -1)
1628 td->creationDate = astatus->creationDate;
1629 if (astatus->updateDate != -1)
1630 td->updateDate = astatus->updateDate;
1631 if (astatus->spare2 != -1)
1632 td->volUpdateCounter = (unsigned int)astatus->spare2;
1633 VUpdateVolume(&error, tv);
1636 return VOLSERTRELE_ERROR;
1642 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1646 code = VolGetName(acid, atrans, aname);
1647 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1652 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1654 register struct Volume *tv;
1655 register struct VolumeDiskData *td;
1656 struct volser_trans *tt;
1659 /* We need to at least fill it in */
1660 *aname = (char *)malloc(1);
1663 tt = FindTrans(atrans);
1666 if (tt->vflags & VTDeleted) {
1667 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1671 TSetRxCall(tt, acid, "GetName");
1679 td = &tv->header->diskstuff;
1680 len = strlen(td->name) + 1; /* don't forget the null */
1686 *aname = (char *)realloc(*aname, len);
1687 strcpy(*aname, td->name);
1690 return VOLSERTRELE_ERROR;
1695 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1698 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1699 afs_uint32 parentId, afs_uint32 cloneId)
1705 /*return a list of all partitions on the server. The non mounted
1706 *partitions are returned as -1 in the corresponding slot in partIds*/
1708 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1712 code = VolListPartitions(acid, partIds);
1713 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1718 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1723 strcpy(namehead, "/vicep"); /*7 including null terminator */
1725 /* Just return attached partitions. */
1727 for (i = 0; i < 26; i++) {
1728 namehead[6] = i + 'a';
1729 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1735 /*return a list of all partitions on the server. The non mounted
1736 *partitions are returned as -1 in the corresponding slot in partIds*/
1738 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1742 code = XVolListPartitions(acid, pEntries);
1743 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1748 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1751 struct partList partList;
1752 struct DiskPartition64 *dp;
1755 strcpy(namehead, "/vicep"); /*7 including null terminator */
1757 /* Only report attached partitions */
1758 for (i = 0; i < VOLMAXPARTS; i++) {
1759 #ifdef AFS_DEMAND_ATTACH_FS
1760 dp = VGetPartitionById(i, 0);
1763 namehead[6] = i + 'a';
1769 namehead[6] = 'a' + (k / 26);
1770 namehead[7] = 'a' + (k % 26);
1773 dp = VGetPartition(namehead, 0);
1776 partList.partId[j++] = i;
1778 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1779 if (!pEntries->partEntries_val)
1781 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1783 pEntries->partEntries_len = j;
1788 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1790 ExtractVolId(char vname[])
1793 char name[VOLSER_MAXVOLNAME + 1];
1795 strcpy(name, vname);
1797 while (name[i] == 'V' || name[i] == '0')
1800 name[11] = '\0'; /* smash the "." */
1801 return (atol(&name[i]));
1804 /*return the name of the next volume header in the directory associated with dirp and dp.
1805 *the volume id is returned in volid, and volume header name is returned in volname*/
1807 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1811 dp = readdir(dirp); /*read next entry in the directory */
1813 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1814 *volid = ExtractVolId(dp->d_name);
1815 strcpy(volname, dp->d_name);
1816 return 0; /*return the name of the file representing a volume */
1818 strcpy(volname, "");
1819 return 0; /*volname doesnot represent a volume */
1822 strcpy(volname, "EOD");
1823 return 0; /*end of directory */
1829 * volint vol info structure type.
1832 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1833 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1834 } volint_info_type_t;
1837 * handle to various on-wire vol info types.
1840 volint_info_type_t volinfo_type;
1846 } volint_info_handle_t;
1849 * store value to a field at the appropriate location in on-wire structure.
1851 #define VOLINT_INFO_STORE(handle, name, val) \
1853 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1854 (handle)->volinfo_ptr.base->name = (val); \
1856 (handle)->volinfo_ptr.ext->name = (val); \
1861 * get pointer to appropriate offset of field in on-wire structure.
1863 #define VOLINT_INFO_PTR(handle, name) \
1864 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1865 &((handle)->volinfo_ptr.base->name) : \
1866 &((handle)->volinfo_ptr.ext->name))
1869 * fill in appropriate type of on-wire volume metadata structure.
1871 * @param vp pointer to volume object
1872 * @param handle pointer to wire format handle object
1874 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1875 * @pre handle object must have a valid pointer and enumeration value
1877 * @note passing a NULL value for vp means that the fileserver doesn't
1878 * know about this particular volume, thus implying it is offline.
1880 * @return operation status
1885 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1887 unsigned int numStatBytes, now;
1888 register struct VolumeDiskData *hdr = &vp->header->diskstuff;
1890 /*read in the relevant info */
1891 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1892 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1893 VOLINT_INFO_STORE(handle, volid, hdr->id);
1894 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1895 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
1896 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
1897 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
1898 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
1899 VOLINT_INFO_STORE(handle, size, hdr->diskused);
1900 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
1901 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
1902 now = FT_ApproxTime();
1903 if ((now - hdr->dayUseDate) > OneDay) {
1904 VOLINT_INFO_STORE(handle, dayUse, 0);
1906 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
1908 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
1909 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
1910 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
1911 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
1913 #ifdef AFS_DEMAND_ATTACH_FS
1915 * for DAFS, we "lie" about volume state --
1916 * instead of returning the raw state from the disk header,
1917 * we compute state based upon the fileserver's internal
1918 * in-core state enumeration value reported to us via fssync,
1919 * along with the blessed and inService flags from the header.
1920 * -- tkeiser 11/27/2007
1923 /* Conditions that offline status is based on:
1924 volume is unattached state
1925 volume state is in (one of several error states)
1926 volume not in service
1927 volume is not marked as blessed (not on hold)
1928 volume in salvage req. state
1929 volume needsSalvaged
1930 next op would set volume offline
1931 next op would not leave volume online (based on several conditions)
1934 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1935 VIsErrorState(V_attachState(vp)) ||
1938 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
1939 hdr->needsSalvaged ||
1940 (vp->pending_vol_op &&
1941 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
1942 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
1945 VOLINT_INFO_STORE(handle, inUse, 0);
1947 VOLINT_INFO_STORE(handle, inUse, 1);
1950 /* offline status based on program type, where != fileServer enum (1) is offline */
1951 if (hdr->inUse == fileServer) {
1952 VOLINT_INFO_STORE(handle, inUse, 1);
1954 VOLINT_INFO_STORE(handle, inUse, 0);
1959 switch(handle->volinfo_type) {
1960 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
1961 case VOLINT_INFO_TYPE_BASE:
1963 #ifdef AFS_DEMAND_ATTACH_FS
1964 /* see comment above where we set inUse bit */
1965 if (hdr->needsSalvaged ||
1966 (vp && VIsErrorState(V_attachState(vp)))) {
1967 handle->volinfo_ptr.base->needsSalvaged = 1;
1969 handle->volinfo_ptr.base->needsSalvaged = 0;
1972 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
1974 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
1975 handle->volinfo_ptr.base->spare0 = hdr->minquota;
1976 handle->volinfo_ptr.base->spare1 =
1977 (long)hdr->weekUse[0] +
1978 (long)hdr->weekUse[1] +
1979 (long)hdr->weekUse[2] +
1980 (long)hdr->weekUse[3] +
1981 (long)hdr->weekUse[4] +
1982 (long)hdr->weekUse[5] +
1983 (long)hdr->weekUse[6];
1984 handle->volinfo_ptr.base->flags = 0;
1985 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
1986 handle->volinfo_ptr.base->spare3 = 0;
1990 case VOLINT_INFO_TYPE_EXT:
1992 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
1993 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
1996 * Copy out the stat fields in a single operation.
1998 if ((now - hdr->dayUseDate) > OneDay) {
1999 memset(&(handle->volinfo_ptr.ext->stat_reads[0]),
2002 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2003 (char *)&(hdr->stat_reads[0]),
2012 #ifdef AFS_DEMAND_ATTACH_FS
2015 * get struct Volume out of the fileserver.
2017 * @param[in] volumeId volumeId for which we want state information
2018 * @param[in] pname partition name string
2019 * @param[inout] vp pointer to pointer to Volume object which
2020 * will be populated (see note)
2022 * @return operation status
2024 * @retval non-zero failure
2026 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2031 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2036 res.hdr.response_len = sizeof(res.hdr);
2037 res.payload.buf = *vp;
2038 res.payload.len = sizeof(Volume);
2040 code = FSYNC_VolOp(volumeId,
2046 if (code != SYNC_OK) {
2047 switch (res.hdr.reason) {
2048 case FSYNC_WRONG_PART:
2049 case FSYNC_UNKNOWN_VOLID:
2062 * mode of volume list operation.
2065 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2066 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2067 } vol_info_list_mode_t;
2070 * abstract interface to populate wire-format volume metadata structures.
2072 * @param[in] partId partition id
2073 * @param[in] volumeId volume id
2074 * @param[in] pname partition name
2075 * @param[in] volname volume file name
2076 * @param[in] handle handle to on-wire volume metadata object
2077 * @param[in] mode listing mode
2079 * @return operation status
2081 * @retval -2 DESTROY_ME flag is set
2082 * @retval -1 general failure; some data filled in
2083 * @retval -3 couldn't create vtrans; some data filled in
2086 GetVolInfo(afs_uint32 partId,
2087 afs_uint32 volumeId,
2090 volint_info_handle_t * handle,
2091 vol_info_list_mode_t mode)
2095 struct volser_trans *ttc = NULL;
2096 struct Volume *fill_tv, *tv = NULL;
2097 #ifdef AFS_DEMAND_ATTACH_FS
2098 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2099 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2100 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2101 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2103 /* Set up response handle for pending_vol_op */
2104 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2105 fs_res.payload.buf = fs_res_buf;
2106 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2109 ttc = NewTrans(volumeId, partId);
2112 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2113 VOLINT_INFO_STORE(handle, volid, volumeId);
2117 /* Get volume from volserver */
2118 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2120 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2121 volumeId, pname, volname, error);
2126 * please note that destroyMe and needsSalvaged checks used to be ordered
2127 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2128 * more correct to check destroyMe before needsSalvaged.
2129 * -- tkeiser 11/28/2007
2132 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2134 case VOL_INFO_LIST_MULTIPLE:
2138 case VOL_INFO_LIST_SINGLE:
2139 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2140 volumeId, pname, volname);
2147 if (tv->header->diskstuff.needsSalvaged) {
2148 /*this volume will be salvaged */
2149 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2150 volumeId, pname, volname);
2153 #ifdef AFS_DEMAND_ATTACH_FS
2154 /* If using DAFS, get volume from fsserver */
2155 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK || fs_tv == NULL) {
2160 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2161 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2162 /* If we if the pending vol op */
2163 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2164 fs_tv->pending_vol_op=&pending_vol_op_res;
2166 fs_tv->pending_vol_op=NULL;
2169 /* populate the header from the volserver copy */
2170 fs_tv->header=tv->header;
2172 /* When using DAFS, use the fs volume info, populated with required structures */
2175 /* When not using DAFS, just use the local volume info */
2179 /* ok, we have all the data we need; fill in the on-wire struct */
2180 code = FillVolInfo(fill_tv, handle);
2184 VOLINT_INFO_STORE(handle, status, 0);
2185 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2186 VOLINT_INFO_STORE(handle, volid, volumeId);
2189 VDetachVolume(&error, tv);
2192 VOLINT_INFO_STORE(handle, status, 0);
2193 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2194 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2195 volumeId, pname, volname);
2199 DeleteTrans(ttc, 1);
2206 /*return the header information about the <volid> */
2208 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2209 afs_uint32 volumeId, volEntries *volumeInfo)
2213 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2214 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2219 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2220 afs_uint32 volumeId, volEntries *volumeInfo)
2223 struct DiskPartition64 *partP;
2224 char pname[9], volname[20];
2229 volint_info_handle_t handle;
2231 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2232 if (!volumeInfo->volEntries_val)
2234 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2236 pntr = volumeInfo->volEntries_val;
2237 volumeInfo->volEntries_len = 1;
2238 if (GetPartName(partid, pname))
2239 return VOLSERILLEGAL_PARTITION;
2240 if (!(partP = VGetPartition(pname, 0)))
2241 return VOLSERILLEGAL_PARTITION;
2242 dirp = opendir(VPartitionPath(partP));
2244 return VOLSERILLEGAL_PARTITION;
2246 strcpy(volname, "");
2248 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2250 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2251 GetNextVol(dirp, volname, &volid);
2252 continue; /*back to while loop */
2255 if (volid == volumeId) { /*copy other things too */
2260 GetNextVol(dirp, volname, &volid);
2264 #ifndef AFS_PTHREAD_ENV
2265 IOMGR_Poll(); /*make sure that the client does not time out */
2268 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2269 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2271 code = GetVolInfo(partid,
2276 VOL_INFO_LIST_SINGLE);
2280 return (found) ? 0 : ENODEV;
2283 /*------------------------------------------------------------------------
2284 * EXPORTED SAFSVolXListOneVolume
2287 * Returns extended info on volume a_volID on partition a_partID.
2290 * a_rxCidP : Pointer to the Rx call we're performing.
2291 * a_partID : Partition for which we want the extended list.
2292 * a_volID : Volume ID we wish to know about.
2293 * a_volumeXInfoP : Ptr to the extended info blob.
2296 * 0 Successful operation
2297 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2300 * Nothing interesting.
2304 *------------------------------------------------------------------------*/
2307 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2308 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2312 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2313 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2318 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2319 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2320 { /*SAFSVolXListOneVolume */
2322 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2323 struct DiskPartition64 *partP; /*Ptr to partition */
2324 char pname[9], volname[20]; /*Partition, volume names */
2325 DIR *dirp; /*Partition directory ptr */
2326 afs_uint32 currVolID; /*Current volume ID */
2327 int found = 0; /*Did we find the volume we need? */
2329 volint_info_handle_t handle;
2332 * Set up our pointers for action, marking our structure to hold exactly
2333 * one entry. Also, assume we'll fail in our quest.
2335 a_volumeXInfoP->volXEntries_val =
2336 (volintXInfo *) malloc(sizeof(volintXInfo));
2337 if (!a_volumeXInfoP->volXEntries_val)
2339 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2341 xInfoP = a_volumeXInfoP->volXEntries_val;
2342 a_volumeXInfoP->volXEntries_len = 1;
2346 * If the partition name we've been given is bad, bogue out.
2348 if (GetPartName(a_partID, pname))
2349 return (VOLSERILLEGAL_PARTITION);
2352 * Open the directory representing the given AFS parttion. If we can't
2355 if (!(partP = VGetPartition(pname, 0)))
2356 return VOLSERILLEGAL_PARTITION;
2357 dirp = opendir(VPartitionPath(partP));
2359 return (VOLSERILLEGAL_PARTITION);
2361 strcpy(volname, "");
2364 * Sweep through the partition directory, looking for the desired entry.
2365 * First, of course, figure out how many stat bytes to copy out of each
2368 while (strcmp(volname, "EOD") && !found) {
2370 * If this is not a volume, move on to the next entry in the
2371 * partition's directory.
2373 if (!strcmp(volname, "")) {
2374 GetNextVol(dirp, volname, &currVolID);
2378 if (currVolID == a_volID) {
2380 * We found the volume entry we're interested. Pull out the
2381 * extended information, remembering to poll (so that the client
2382 * doesn't time out) and to set up a transaction on the volume.
2386 } /*Found desired volume */
2388 GetNextVol(dirp, volname, &currVolID);
2392 #ifndef AFS_PTHREAD_ENV
2396 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2397 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2399 code = GetVolInfo(a_partID,
2404 VOL_INFO_LIST_SINGLE);
2409 * Clean up before going to dinner: close the partition directory,
2410 * return the proper value.
2413 return (found) ? 0 : ENODEV;
2414 } /*SAFSVolXListOneVolume */
2416 /*returns all the volumes on partition partid. If flags = 1 then all the
2417 * relevant info about the volumes is also returned */
2419 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2420 volEntries *volumeInfo)
2424 code = VolListVolumes(acid, partid, flags, volumeInfo);
2425 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2430 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2431 volEntries *volumeInfo)
2434 struct DiskPartition64 *partP;
2435 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2436 char pname[9], volname[20];
2440 volint_info_handle_t handle;
2442 volumeInfo->volEntries_val =
2443 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2444 if (!volumeInfo->volEntries_val)
2446 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2448 pntr = volumeInfo->volEntries_val;
2449 volumeInfo->volEntries_len = 0;
2450 if (GetPartName(partid, pname))
2451 return VOLSERILLEGAL_PARTITION;
2452 if (!(partP = VGetPartition(pname, 0)))
2453 return VOLSERILLEGAL_PARTITION;
2454 dirp = opendir(VPartitionPath(partP));
2456 return VOLSERILLEGAL_PARTITION;
2457 strcpy(volname, "");
2459 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2461 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2462 GetNextVol(dirp, volname, &volid);
2463 continue; /*back to while loop */
2466 if (flags) { /*copy other things too */
2467 #ifndef AFS_PTHREAD_ENV
2468 IOMGR_Poll(); /*make sure that the client does not time out */
2471 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2472 handle.volinfo_ptr.base = pntr;
2475 code = GetVolInfo(partid,
2480 VOL_INFO_LIST_MULTIPLE);
2481 if (code == -2) { /* DESTROY_ME flag set */
2485 pntr->volid = volid;
2486 /*just volids are needed */
2490 volumeInfo->volEntries_len += 1;
2491 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2492 /*running out of space, allocate more space */
2493 allocSize = (allocSize * 3) / 2;
2495 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2496 allocSize * sizeof(volintInfo));
2499 return VOLSERNO_MEMORY;
2501 volumeInfo->volEntries_val = pntr; /* point to new block */
2502 /* set pntr to the right position */
2503 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2508 GetNextVol(dirp, volname, &volid);
2516 /*------------------------------------------------------------------------
2517 * EXPORTED SAFSVolXListVolumes
2520 * Returns all the volumes on partition a_partID. If a_flags
2521 * is set to 1, then all the relevant extended volume information
2525 * a_rxCidP : Pointer to the Rx call we're performing.
2526 * a_partID : Partition for which we want the extended list.
2527 * a_flags : Various flags.
2528 * a_volumeXInfoP : Ptr to the extended info blob.
2531 * 0 Successful operation
2532 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2533 * VOLSERNO_MEMORY if we ran out of memory allocating
2537 * Nothing interesting.
2541 *------------------------------------------------------------------------*/
2544 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2545 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2549 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2550 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2555 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2556 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2557 { /*SAFSVolXListVolumes */
2559 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2560 struct DiskPartition64 *partP; /*Ptr to partition */
2561 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2562 char pname[9], volname[20]; /*Partition, volume names */
2563 DIR *dirp; /*Partition directory ptr */
2564 afs_uint32 volid; /*Current volume ID */
2566 volint_info_handle_t handle;
2569 * Allocate a large array of extended volume info structures, then
2570 * set it up for action.
2572 a_volumeXInfoP->volXEntries_val =
2573 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2574 if (!a_volumeXInfoP->volXEntries_val)
2576 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2578 xInfoP = a_volumeXInfoP->volXEntries_val;
2579 a_volumeXInfoP->volXEntries_len = 0;
2582 * If the partition name we've been given is bad, bogue out.
2584 if (GetPartName(a_partID, pname))
2585 return (VOLSERILLEGAL_PARTITION);
2588 * Open the directory representing the given AFS parttion. If we can't
2591 if (!(partP = VGetPartition(pname, 0)))
2592 return VOLSERILLEGAL_PARTITION;
2593 dirp = opendir(VPartitionPath(partP));
2595 return (VOLSERILLEGAL_PARTITION);
2596 strcpy(volname, "");
2599 * Sweep through the partition directory, acting on each entry. First,
2600 * of course, figure out how many stat bytes to copy out of each volume.
2602 while (strcmp(volname, "EOD")) {
2605 * If this is not a volume, move on to the next entry in the
2606 * partition's directory.
2608 if (!strcmp(volname, "")) {
2609 GetNextVol(dirp, volname, &volid);
2615 * Full info about the volume desired. Poll to make sure the
2616 * client doesn't time out, then start up a new transaction.
2618 #ifndef AFS_PTHREAD_ENV
2622 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2623 handle.volinfo_ptr.ext = xInfoP;
2625 code = GetVolInfo(a_partID,
2630 VOL_INFO_LIST_MULTIPLE);
2631 if (code == -2) { /* DESTROY_ME flag set */
2636 * Just volume IDs are needed.
2638 xInfoP->volid = volid;
2642 * Bump the pointer in the data area we're building, along with
2643 * the count of the number of entries it contains.
2646 (a_volumeXInfoP->volXEntries_len)++;
2647 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2649 * We're running out of space in the area we've built. Grow it.
2651 allocSize = (allocSize * 3) / 2;
2652 xInfoP = (volintXInfo *)
2653 realloc((char *)a_volumeXInfoP->volXEntries_val,
2654 (allocSize * sizeof(volintXInfo)));
2655 if (xInfoP == NULL) {
2657 * Bummer, no memory. Bag it, tell our caller what went wrong.
2660 return (VOLSERNO_MEMORY);
2664 * Memory reallocation worked. Correct our pointers so they
2665 * now point to the new block and the current open position within
2668 a_volumeXInfoP->volXEntries_val = xInfoP;
2670 a_volumeXInfoP->volXEntries_val +
2671 a_volumeXInfoP->volXEntries_len;
2675 GetNextVol(dirp, volname, &volid);
2676 } /*Sweep through the partition directory */
2679 * We've examined all entries in the partition directory. Close it,
2680 * delete our transaction (if any), and go home happy.
2685 } /*SAFSVolXListVolumes */
2687 /*this call is used to monitor the status of volser for debugging purposes.
2688 *information about all the active transactions is returned in transInfo*/
2690 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2694 code = VolMonitor(acid, transInfo);
2695 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2700 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2702 transDebugInfo *pntr;
2703 afs_int32 allocSize = 50;
2704 struct volser_trans *tt, *nt, *allTrans;
2706 transInfo->transDebugEntries_val =
2707 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2708 if (!transInfo->transDebugEntries_val)
2710 pntr = transInfo->transDebugEntries_val;
2711 transInfo->transDebugEntries_len = 0;
2714 allTrans = TransList();
2715 if (allTrans == (struct volser_trans *)0)
2716 goto done; /*no active transactions */
2717 for (tt = allTrans; tt; tt = nt) { /*copy relevant info into pntr */
2718 THOLD(tt); /* do not delete tt while copying info */
2721 VTRANS_OBJ_LOCK(tt);
2722 pntr->tid = tt->tid;
2723 pntr->time = tt->time;
2724 pntr->creationTime = tt->creationTime;
2725 pntr->returnCode = tt->returnCode;
2726 pntr->volid = tt->volid;
2727 pntr->partition = tt->partition;
2728 pntr->iflags = tt->iflags;
2729 pntr->vflags = tt->vflags;
2730 pntr->tflags = tt->tflags;
2731 strcpy(pntr->lastProcName, tt->lastProcName);
2732 pntr->callValid = 0;
2733 if (tt->rxCallPtr) { /*record call related info */
2734 pntr->callValid = 1;
2735 pntr->readNext = tt->rxCallPtr->rnext;
2736 pntr->transmitNext = tt->rxCallPtr->tnext;
2737 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2738 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2740 VTRANS_OBJ_UNLOCK(tt);
2742 transInfo->transDebugEntries_len += 1;
2743 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2744 allocSize = (allocSize * 3) / 2;
2746 (transDebugInfo *) realloc((char *)transInfo->
2747 transDebugEntries_val,
2749 sizeof(transDebugInfo));
2750 transInfo->transDebugEntries_val = pntr;
2752 transInfo->transDebugEntries_val +
2753 transInfo->transDebugEntries_len;
2754 /*set pntr to right position */
2767 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2768 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2769 afs_uint32 backupId)
2773 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2774 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2775 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2781 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2782 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2783 afs_uint32 backupId)
2787 register struct volser_trans *tt;
2788 char caller[MAXKTCNAMELEN];
2790 if (strlen(name) > 31)
2791 return VOLSERBADNAME;
2792 if (!afsconf_SuperUser(tdir, acid, caller))
2793 return VOLSERBAD_ACCESS; /*not a super user */
2794 /* find the trans */
2795 tt = FindTrans(atid);
2798 if (tt->vflags & VTDeleted) {
2799 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2803 TSetRxCall(tt, acid, "SetIdsTypes");
2807 V_backupId(tv) = backupId;
2808 V_cloneId(tv) = cloneId;
2809 V_parentId(tv) = pId;
2810 strcpy((&V_disk(tv))->name, name);
2811 VUpdateVolume(&error, tv);
2813 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2818 if (TRELE(tt) && !error)
2819 return VOLSERTRELE_ERROR;
2824 if (TRELE(tt) && !error)
2825 return VOLSERTRELE_ERROR;
2830 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2834 code = VolSetDate(acid, atid, cdate);
2835 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2841 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2845 register struct volser_trans *tt;
2846 char caller[MAXKTCNAMELEN];
2848 if (!afsconf_SuperUser(tdir, acid, caller))
2849 return VOLSERBAD_ACCESS; /*not a super user */
2850 /* find the trans */
2851 tt = FindTrans(atid);
2854 if (tt->vflags & VTDeleted) {
2855 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2859 TSetRxCall(tt, acid, "SetDate");
2862 V_creationDate(tv) = cdate;
2863 VUpdateVolume(&error, tv);
2865 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2870 if (TRELE(tt) && !error)
2871 return VOLSERTRELE_ERROR;
2876 if (TRELE(tt) && !error)
2877 return VOLSERTRELE_ERROR;
2882 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2883 afs_uint32 volumeId)
2888 char caller[MAXKTCNAMELEN];
2890 register struct volser_trans *ttc;
2891 char pname[16], volname[20];
2892 struct DiskPartition64 *partP;
2893 afs_int32 ret = ENODEV;
2896 if (!afsconf_SuperUser(tdir, acid, caller))
2897 return VOLSERBAD_ACCESS; /*not a super user */
2898 if (GetPartName(partId, pname))
2899 return VOLSERILLEGAL_PARTITION;
2900 if (!(partP = VGetPartition(pname, 0)))
2901 return VOLSERILLEGAL_PARTITION;
2902 dirp = opendir(VPartitionPath(partP));
2904 return VOLSERILLEGAL_PARTITION;
2905 strcpy(volname, "");
2906 ttc = (struct volser_trans *)0;
2908 while (strcmp(volname, "EOD")) {
2909 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2910 GetNextVol(dirp, volname, &volid);
2911 continue; /*back to while loop */
2914 if (volid == volumeId) { /*copy other things too */
2915 #ifndef AFS_PTHREAD_ENV
2916 IOMGR_Poll(); /*make sure that the client doesnot time out */
2918 ttc = NewTrans(volumeId, partId);
2920 return VOLSERVOLBUSY;
2922 #ifdef AFS_NAMEI_ENV
2923 ret = namei_ConvertROtoRWvolume(pname, volumeId);
2925 ret = inode_ConvertROtoRWvolume(pname, volumeId);
2929 GetNextVol(dirp, volname, &volid);
2933 DeleteTrans(ttc, 1);
2934 ttc = (struct volser_trans *)0;
2943 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
2944 register struct volintSize *size)
2947 register struct volser_trans *tt;
2948 char caller[MAXKTCNAMELEN];
2950 if (!afsconf_SuperUser(tdir, acid, caller))
2951 return VOLSERBAD_ACCESS; /*not a super user */
2952 tt = FindTrans(fromTrans);
2955 if (tt->vflags & VTDeleted) {
2959 TSetRxCall(tt, acid, "GetSize");
2960 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
2963 return VOLSERTRELE_ERROR;
2965 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
2970 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
2971 afs_uint32 where, afs_int32 verbose)
2973 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
2975 Volume *vol=0, *newvol=0;
2976 struct volser_trans *tt = 0, *tt2 = 0;
2977 char caller[MAXKTCNAMELEN];
2980 if (!afsconf_SuperUser(tdir, acall, caller))
2983 vol = VAttachVolume(&code, vid, V_VOLUPD);
2989 newvol = VAttachVolume(&code, new, V_VOLUPD);
2991 VDetachVolume(&code2, vol);
2996 if (V_device(vol) != V_device(newvol)
2997 || V_uniquifier(newvol) != 2) {
2998 if (V_device(vol) != V_device(newvol)) {
2999 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
3001 rx_Write(acall, line, strlen(line));
3003 if (V_uniquifier(newvol) != 2) {
3004 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
3005 rx_Write(acall, line, strlen(line));
3008 rx_Write(acall, line, 1);
3009 VDetachVolume(&code2, vol);
3010 VDetachVolume(&code2, newvol);
3013 tt = NewTrans(vid, V_device(vol));
3015 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3016 rx_Write(acall, line, strlen(line));
3018 rx_Write(acall, line, 1);
3019 VDetachVolume(&code2, vol);
3020 VDetachVolume(&code2, newvol);
3021 return VOLSERVOLBUSY;
3023 VTRANS_OBJ_LOCK(tt);
3024 tt->iflags = ITBusy;
3026 TSetRxCall_r(tt, NULL, "SplitVolume");
3027 VTRANS_OBJ_UNLOCK(tt);
3029 tt2 = NewTrans(new, V_device(newvol));
3031 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3032 rx_Write(acall, line, strlen(line));
3034 rx_Write(acall, line, 1);
3036 VDetachVolume(&code2, vol);
3037 VDetachVolume(&code2, newvol);
3038 return VOLSERVOLBUSY;
3040 VTRANS_OBJ_LOCK(tt2);
3041 tt2->iflags = ITBusy;
3043 TSetRxCall_r(tt2, NULL, "SplitVolume");
3044 VTRANS_OBJ_UNLOCK(tt2);
3046 code = split_volume(acall, vol, newvol, where, verbose);
3048 VDetachVolume(&code2, vol);
3050 VDetachVolume(&code2, newvol);
3051 DeleteTrans(tt2, 1);
3058 /* GetPartName - map partid (a decimal number) into pname (a string)
3059 * Since for NT we actually want to return the drive name, we map through the
3063 GetPartName(afs_int32 partid, char *pname)
3068 strcpy(pname, "/vicep");
3069 pname[6] = 'a' + partid;
3072 } else if (partid < VOLMAXPARTS) {
3073 strcpy(pname, "/vicep");
3075 pname[6] = 'a' + (partid / 26);
3076 pname[7] = 'a' + (partid % 26);