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>
69 #include "volser_prototypes.h"
71 #include "dumpstuff.h"
74 extern struct afsconf_dir *tdir;
76 extern void LogError(afs_int32 errcode);
78 /* Forward declarations */
79 static int GetPartName(afs_int32 partid, char *pname);
81 #define OneDay (24*60*60)
87 afs_int32 localTid = 1;
89 static afs_int32 VolPartitionInfo(struct rx_call *, char *pname,
90 struct diskPartition64 *);
91 static afs_int32 VolNukeVolume(struct rx_call *, afs_int32, afs_uint32);
92 static afs_int32 VolCreateVolume(struct rx_call *, afs_int32, char *,
93 afs_int32, afs_uint32, afs_uint32 *,
95 static afs_int32 VolDeleteVolume(struct rx_call *, afs_int32);
96 static afs_int32 VolClone(struct rx_call *, afs_int32, afs_uint32,
97 afs_int32, char *, afs_uint32 *);
98 static afs_int32 VolReClone(struct rx_call *, afs_int32, afs_int32);
99 static afs_int32 VolTransCreate(struct rx_call *, afs_uint32, afs_int32,
100 afs_int32, afs_int32 *);
101 static afs_int32 VolGetNthVolume(struct rx_call *, afs_int32, afs_uint32 *,
103 static afs_int32 VolGetFlags(struct rx_call *, afs_int32, afs_int32 *);
104 static afs_int32 VolSetFlags(struct rx_call *, afs_int32, afs_int32 );
105 static afs_int32 VolForward(struct rx_call *, afs_int32, afs_int32,
106 struct destServer *destination, afs_int32,
107 struct restoreCookie *cookie);
108 static afs_int32 VolDump(struct rx_call *, afs_int32, afs_int32, afs_int32);
109 static afs_int32 VolRestore(struct rx_call *, afs_int32, afs_int32,
110 struct restoreCookie *);
111 static afs_int32 VolEndTrans(struct rx_call *, afs_int32, afs_int32 *);
112 static afs_int32 VolSetForwarding(struct rx_call *, afs_int32, afs_int32);
113 static afs_int32 VolGetStatus(struct rx_call *, afs_int32,
114 struct volser_status *);
115 static afs_int32 VolSetInfo(struct rx_call *, afs_int32, struct volintInfo *);
116 static afs_int32 VolGetName(struct rx_call *, afs_int32, char **);
117 static afs_int32 VolListPartitions(struct rx_call *, struct pIDs *);
118 static afs_int32 XVolListPartitions(struct rx_call *, struct partEntries *);
119 static afs_int32 VolListOneVolume(struct rx_call *, afs_int32, afs_uint32,
121 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
123 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
125 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
127 static afs_int32 VolMonitor(struct rx_call *, transDebugEntries *);
128 static afs_int32 VolSetIdsTypes(struct rx_call *, afs_int32, char [],
129 afs_int32, afs_uint32, afs_uint32,
131 static afs_int32 VolSetDate(struct rx_call *, afs_int32, afs_int32);
133 /* this call unlocks all of the partition locks we've set */
137 register struct DiskPartition64 *tp;
138 for (tp = DiskPartitionList; tp; tp = tp->next) {
139 if (tp->lock_fd != INVALID_FD) {
140 close(tp->lock_fd); /* releases flock held on this partition */
141 tp->lock_fd = INVALID_FD;
147 /* get partition id from a name */
149 PartitionID(char *aname)
152 register int code = 0;
157 return -1; /* unknown */
159 /* otherwise check for vicepa or /vicepa, or just plain "a" */
161 if (!strncmp(aname, "/vicep", 6)) {
162 strncpy(ascii, aname + 6, 2);
164 return -1; /* bad partition name */
165 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
166 * from 0. Do the appropriate conversion */
168 /* one char name, 0..25 */
169 if (ascii[0] < 'a' || ascii[0] > 'z')
170 return -1; /* wrongo */
171 return ascii[0] - 'a';
173 /* two char name, 26 .. <whatever> */
174 if (ascii[0] < 'a' || ascii[0] > 'z')
175 return -1; /* wrongo */
176 if (ascii[1] < 'a' || ascii[1] > 'z')
177 return -1; /* just as bad */
178 code = (ascii[0] - 'a') * 26 + (ascii[1] - 'a') + 26;
179 if (code > VOLMAXPARTS)
186 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
190 /* 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 */
191 (void)afs_snprintf(aname, asize, VFORMAT, (unsigned long)avol);
196 ConvertPartition(int apartno, char *aname, int asize)
202 strcpy(aname, "/vicep");
204 aname[6] = 'a' + apartno;
208 aname[6] = 'a' + (apartno / 26);
209 aname[7] = 'a' + (apartno % 26);
215 /* the only attach function that takes a partition is "...ByName", so we use it */
217 XAttachVolume(afs_int32 *error, afs_uint32 avolid, afs_int32 apartid, int amode)
219 char pbuf[30], vbuf[20];
220 register struct Volume *tv;
222 if (ConvertPartition(apartid, pbuf, sizeof(pbuf))) {
226 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
230 tv = VAttachVolumeByName((Error *)error, pbuf, vbuf, amode);
234 /* Adapted from the file server; create a root directory for this volume */
236 ViceCreateRoot(Volume *vp)
239 struct acl_accessList *ACL;
241 Inode inodeNumber, nearInode;
242 struct VnodeDiskObject *vnode;
243 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
249 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
252 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
254 V_pref(vp, nearInode);
256 IH_CREATE(V_linkHandle(vp), V_device(vp),
257 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
259 assert(VALID_INO(inodeNumber));
261 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
262 did.Volume = V_id(vp);
263 did.Vnode = (VnodeId) 1;
266 assert(!(MakeDir(&dir, (afs_int32 *)&did, (afs_int32 *)&did)));
267 DFlush(); /* flush all modified dir buffers out */
268 DZap((afs_int32 *)&dir); /* Remove all buffers for this dir */
269 length = Length(&dir); /* Remember size of this directory */
271 FidZap(&dir); /* Done with the dir handle obtained via SetSalvageDirHandle() */
273 /* build a single entry ACL that gives all rights to system:administrators */
274 /* this section of code assumes that access list format is not going to
277 ACL = VVnodeDiskACL(vnode);
278 ACL->size = sizeof(struct acl_accessList);
279 ACL->version = ACL_ACLVERSION;
283 ACL->entries[0].id = -204; /* this assumes System:administrators is group -204 */
284 ACL->entries[0].rights =
285 PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | PRSFS_LOOKUP | PRSFS_DELETE
286 | PRSFS_LOCK | PRSFS_ADMINISTER;
288 vnode->type = vDirectory;
290 vnode->modeBits = 0777;
291 vnode->linkCount = 2;
292 VNDISK_SET_LEN(vnode, length);
293 vnode->uniquifier = 1;
294 V_uniquifier(vp) = vnode->uniquifier + 1;
295 vnode->dataVersion = 1;
296 VNDISK_SET_INO(vnode, inodeNumber);
297 vnode->unixModifyTime = vnode->serverModifyTime = V_creationDate(vp);
301 vnode->vnodeMagic = vcp->magic;
303 IH_INIT(h, vp->device, V_parentId(vp),
304 vp->vnodeIndex[vLarge].handle->ih_ino);
307 code = FDH_SEEK(fdP, vnodeIndexOffset(vcp, 1), SEEK_SET);
309 code = FDH_WRITE(fdP, vnode, SIZEOF_LARGEDISKVNODE);
310 assert(code == SIZEOF_LARGEDISKVNODE);
311 FDH_REALLYCLOSE(fdP);
313 VNDISK_GET_LEN(length, vnode);
314 V_diskused(vp) = nBlocks(length);
321 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
325 struct diskPartition64 *dp = (struct diskPartition64 *)
326 malloc(sizeof(struct diskPartition64));
328 code = VolPartitionInfo(acid, pname, dp);
330 strncpy(partition->name, dp->name, 32);
331 strncpy(partition->devName, dp->devName, 32);
332 partition->lock_fd = dp->lock_fd;
333 partition->free=RoundInt64ToInt32(dp->free);
334 partition->minFree=RoundInt64ToInt32(dp->minFree);
337 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
342 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
347 code = VolPartitionInfo(acid, pname, partition);
348 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
353 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
356 register struct DiskPartition64 *dp;
359 if (!afsconf_SuperUser(tdir, acid, caller)) return VOLSERBAD_ACCESS;
362 dp = VGetPartition(pname, 0);
364 strncpy(partition->name, dp->name, 32);
365 strncpy(partition->devName, dp->devName, 32);
366 partition->lock_fd = (int)dp->lock_fd;
367 partition->free = dp->free;
368 partition->minFree = dp->totalUsable;
371 return VOLSERILLEGAL_PARTITION;
374 /* obliterate a volume completely, and slowly. */
376 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
380 code = VolNukeVolume(acid, apartID, avolID);
381 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
386 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
391 register afs_int32 code;
393 char caller[MAXKTCNAMELEN];
395 /* check for access */
396 if (!afsconf_SuperUser(tdir, acid, caller))
397 return VOLSERBAD_ACCESS;
399 Log("%s is executing VolNukeVolume %u\n", caller, avolID);
401 if (volutil_PartitionName2_r(apartID, partName, sizeof(partName)) != 0)
403 /* we first try to attach the volume in update mode, so that the file
404 * server doesn't try to use it (and abort) while (or after) we delete it.
405 * If we don't get the volume, that's fine, too. We just won't put it back.
407 tvp = XAttachVolume(&error, avolID, apartID, V_VOLUPD);
408 code = nuke(partName, avolID);
410 VDetachVolume(&verror, tvp);
414 /* create a new volume, with name aname, on the specified partition (1..n)
415 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
416 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
417 * for the volume id (useful for things like volume restore).
418 * Return the new volume id in *avolid.
421 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
422 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
428 VolCreateVolume(acid, apart, aname, atype, aparent, avolid, atrans);
429 osi_auditU(acid, VS_CrVolEvent, code, AUD_LONG, *atrans, AUD_LONG,
430 *avolid, AUD_STR, aname, AUD_LONG, atype, AUD_LONG, aparent,
436 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
437 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
442 Error junk; /* discardable error code */
444 afs_int32 doCreateRoot = 1;
445 register struct volser_trans *tt;
447 char caller[MAXKTCNAMELEN];
449 if (strlen(aname) > 31)
450 return VOLSERBADNAME;
451 if (!afsconf_SuperUser(tdir, acid, caller))
452 return VOLSERBAD_ACCESS;
454 Log("%s is executing CreateVolume '%s'\n", caller, aname);
455 if ((error = ConvertPartition(apart, ppath, sizeof(ppath))))
456 return error; /*a standard unix error */
457 if (atype != readwriteVolume && atype != readonlyVolume
458 && atype != backupVolume)
460 if ((volumeID = *avolid) == 0) {
462 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
466 if ((aparent == volumeID) && (atype == readwriteVolume)) {
471 tt = NewTrans(volumeID, apart);
473 Log("1 createvolume: failed to create trans\n");
474 return VOLSERVOLBUSY; /* volume already busy! */
476 vp = VCreateVolume(&error, ppath, volumeID, aparent);
478 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
483 V_uniquifier(vp) = 1;
484 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
485 V_inService(vp) = V_blessed(vp) = 1;
487 AssignVolumeName(&V_disk(vp), aname, 0);
490 V_destroyMe(vp) = DESTROY_ME;
492 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
493 VUpdateVolume(&error, vp);
495 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
498 VDetachVolume(&junk, vp); /* rather return the real error code */
503 strcpy(tt->lastProcName, "CreateVolume");
504 tt->rxCallPtr = acid;
505 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
506 tt->rxCallPtr = (struct rx_call *)0;
508 return VOLSERTRELE_ERROR;
512 /* delete the volume associated with this transaction */
514 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
518 code = VolDeleteVolume(acid, atrans);
519 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
524 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
526 register struct volser_trans *tt;
528 char caller[MAXKTCNAMELEN];
530 if (!afsconf_SuperUser(tdir, acid, caller))
531 return VOLSERBAD_ACCESS;
532 tt = FindTrans(atrans);
535 if (tt->vflags & VTDeleted) {
536 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
541 Log("%s is executing Delete Volume %u\n", caller, tt->volid);
542 strcpy(tt->lastProcName, "DeleteVolume");
543 tt->rxCallPtr = acid;
544 VPurgeVolume(&error, tt->volume); /* don't check error code, it is not set! */
545 V_destroyMe(tt->volume) = DESTROY_ME; /* so endtrans does the right fssync opcode */
546 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
547 tt->rxCallPtr = (struct rx_call *)0;
549 return VOLSERTRELE_ERROR;
551 Log("1 Volser: Delete: volume %u deleted \n", tt->volid);
552 return 0; /* vpurgevolume doesn't set an error code */
555 /* make a clone of the volume associated with atrans, possibly giving it a new
556 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
557 * for the clone's id). The new clone is given the name newName. Finally,
558 * due to efficiency considerations, if purgeId is non-zero, we purge that
559 * volume when doing the clone operation. This may be useful when making
560 * new backup volumes, for instance since the net result of a clone and a
561 * purge generally leaves many inode ref counts the same, while doing them
562 * separately would result in far more iincs and idecs being peformed
563 * (and they are slow operations).
565 /* for efficiency reasons, sometimes faster to piggyback a purge here */
567 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
568 afs_int32 newType, char *newName, afs_uint32 *newNumber)
572 code = VolClone(acid, atrans, purgeId, newType, newName, newNumber);
573 osi_auditU(acid, VS_CloneEvent, code, AUD_LONG, atrans, AUD_LONG, purgeId,
574 AUD_STR, newName, AUD_LONG, newType, AUD_LONG, *newNumber,
580 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
581 afs_int32 newType, char *newName, afs_uint32 *newNumber)
584 register struct Volume *originalvp, *purgevp, *newvp;
586 register struct volser_trans *tt, *ttc;
587 char caller[MAXKTCNAMELEN];
589 if (strlen(newName) > 31)
590 return VOLSERBADNAME;
591 if (!afsconf_SuperUser(tdir, acid, caller))
592 return VOLSERBAD_ACCESS; /*not a super user */
594 Log("%s is executing Clone Volume new name=%s\n", caller, newName);
596 originalvp = (Volume *) 0;
597 purgevp = (Volume *) 0;
598 newvp = (Volume *) 0;
599 tt = ttc = (struct volser_trans *)0;
601 if (!newNumber || !*newNumber) {
602 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
607 if (newType != readonlyVolume && newType != backupVolume)
609 tt = FindTrans(atrans);
612 if (tt->vflags & VTDeleted) {
613 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
617 ttc = NewTrans(newId, tt->partition);
618 if (!ttc) { /* someone is messing with the clone already */
620 return VOLSERVOLBUSY;
622 strcpy(tt->lastProcName, "Clone");
623 tt->rxCallPtr = acid;
627 purgevp = VAttachVolume(&error, purgeId, V_VOLUPD);
629 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
635 originalvp = tt->volume;
636 if ((V_type(originalvp) == backupVolume)
637 || (V_type(originalvp) == readonlyVolume)) {
638 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
642 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
643 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
649 if (originalvp->device != purgevp->device) {
650 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
654 if (V_type(purgevp) != readonlyVolume) {
655 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
659 if (V_type(originalvp) == readonlyVolume
660 && V_parentId(originalvp) != V_parentId(purgevp)) {
661 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, purgeId);
665 if (V_type(originalvp) == readwriteVolume
666 && tt->volid != V_parentId(purgevp)) {
667 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", purgeId, tt->volid);
676 VCreateVolume(&error, originalvp->partition->name, newId,
677 V_parentId(originalvp));
679 Log("1 Volser: Clone: Couldn't create new volume; clone aborted\n");
680 newvp = (Volume *) 0;
683 if (newType == readonlyVolume)
684 V_cloneId(originalvp) = newId;
685 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
688 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId);
689 CloneVolume(&error, originalvp, newvp, purgevp);
690 purgevp = NULL; /* clone releases it, maybe even if error */
692 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
696 if (newType == readonlyVolume) {
697 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".readonly");
698 V_type(newvp) = readonlyVolume;
699 } else if (newType == backupVolume) {
700 AssignVolumeName(&V_disk(newvp), V_name(originalvp), ".backup");
701 V_type(newvp) = backupVolume;
702 V_backupId(originalvp) = newId;
704 strcpy(newvp->header->diskstuff.name, newName);
705 V_creationDate(newvp) = V_copyDate(newvp);
706 ClearVolumeStats(&V_disk(newvp));
707 V_destroyMe(newvp) = DESTROY_ME;
708 V_inService(newvp) = 0;
709 if (newType == backupVolume) {
710 V_backupDate(originalvp) = V_copyDate(newvp);
711 V_backupDate(newvp) = V_copyDate(newvp);
714 VUpdateVolume(&error, newvp);
716 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
720 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
722 VUpdateVolume(&error, originalvp);
724 Log("1 Volser: Clone: original update %u\n", error);
728 tt->rxCallPtr = (struct rx_call *)0;
730 tt = (struct volser_trans *)0;
731 error = VOLSERTRELE_ERROR;
739 VDetachVolume(&code, purgevp);
741 VDetachVolume(&code, newvp);
743 tt->rxCallPtr = (struct rx_call *)0;
751 /* reclone this volume into the specified id */
753 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
757 code = VolReClone(acid, atrans, cloneId);
758 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
764 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
766 register struct Volume *originalvp, *clonevp;
769 register struct volser_trans *tt, *ttc;
770 char caller[MAXKTCNAMELEN];
772 /*not a super user */
773 if (!afsconf_SuperUser(tdir, acid, caller))
774 return VOLSERBAD_ACCESS;
776 Log("%s is executing Reclone Volume %u\n", caller, cloneId);
778 clonevp = originalvp = (Volume *) 0;
779 tt = (struct volser_trans *)0;
781 tt = FindTrans(atrans);
784 if (tt->vflags & VTDeleted) {
785 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
789 ttc = NewTrans(cloneId, tt->partition);
790 if (!ttc) { /* someone is messing with the clone already */
792 return VOLSERVOLBUSY;
794 strcpy(tt->lastProcName, "ReClone");
795 tt->rxCallPtr = acid;
797 originalvp = tt->volume;
798 if ((V_type(originalvp) == backupVolume)
799 || (V_type(originalvp) == readonlyVolume)) {
800 Log("1 Volser: Clone: The volume to be cloned must be a read/write; aborted\n");
804 if ((V_destroyMe(originalvp) == DESTROY_ME) || !V_inService(originalvp)) {
805 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
811 clonevp = VAttachVolume(&error, cloneId, V_VOLUPD);
813 Log("1 Volser: can't attach clone %d\n", cloneId);
817 newType = V_type(clonevp); /* type of the new volume */
819 if (originalvp->device != clonevp->device) {
820 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
825 if (V_type(clonevp) != readonlyVolume && V_type(clonevp) != backupVolume) {
826 Log("1 Volser: Clone: The \"recloned\" volume must be a read only volume; aborted\n");
830 if (V_type(originalvp) == readonlyVolume
831 && V_parentId(originalvp) != V_parentId(clonevp)) {
832 Log("1 Volser: Clone: Volume %u and volume %u were not cloned from the same parent volume; aborted\n", tt->volid, cloneId);
836 if (V_type(originalvp) == readwriteVolume
837 && tt->volid != V_parentId(clonevp)) {
838 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId, tt->volid);
844 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
846 CloneVolume(&error, originalvp, clonevp, clonevp);
848 Log("1 Volser: Clone: reclone operation failed with code %d\n",
854 /* fix up volume name and type, CloneVolume just propagated RW's */
855 if (newType == readonlyVolume) {
856 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".readonly");
857 V_type(clonevp) = readonlyVolume;
858 } else if (newType == backupVolume) {
859 AssignVolumeName(&V_disk(clonevp), V_name(originalvp), ".backup");
860 V_type(clonevp) = backupVolume;
861 V_backupId(originalvp) = cloneId;
863 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
865 /* pretend recloned volume is a totally new instance */
866 V_copyDate(clonevp) = time(0);
867 V_creationDate(clonevp) = V_copyDate(clonevp);
868 ClearVolumeStats(&V_disk(clonevp));
869 V_destroyMe(clonevp) = 0;
870 V_inService(clonevp) = 0;
871 if (newType == backupVolume) {
872 V_backupDate(originalvp) = V_copyDate(clonevp);
873 V_backupDate(clonevp) = V_copyDate(clonevp);
875 V_inUse(clonevp) = 0;
876 VUpdateVolume(&error, clonevp);
878 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
882 /* VUpdateVolume succeeded. Mark it in service so there's no window
883 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
884 * specialStatus; this is a reclone and this volume started online
886 V_inService(clonevp) = 1;
887 VDetachVolume(&error, clonevp); /* allow file server to get it's hands on it */
889 VUpdateVolume(&error, originalvp);
891 Log("1 Volser: Clone: original update %u\n", error);
895 tt->rxCallPtr = (struct rx_call *)0;
897 tt = (struct volser_trans *)0;
898 error = VOLSERTRELE_ERROR;
905 struct DiskPartition64 *tpartp = originalvp->partition;
906 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
912 VDetachVolume(&code, clonevp);
914 tt->rxCallPtr = (struct rx_call *)0;
922 /* create a new transaction, associated with volume and partition. Type of
923 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
924 * See volser.h for definition of iflags (the constants are named IT*).
927 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
928 afs_int32 iflags, afs_int32 *ttid)
932 code = VolTransCreate(acid, volume, partition, iflags, ttid);
933 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
939 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
940 afs_int32 iflags, afs_int32 *ttid)
942 register struct volser_trans *tt;
947 char caller[MAXKTCNAMELEN];
949 if (!afsconf_SuperUser(tdir, acid, caller))
950 return VOLSERBAD_ACCESS; /*not a super user */
951 if (iflags & ITCreate)
953 else if (iflags & ITBusy)
955 else if (iflags & ITReadOnly)
957 else if (iflags & ITOffline)
960 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
965 tt = NewTrans(volume, partition);
967 /* can't create a transaction? put the volume back */
968 Log("1 transcreate: can't create transaction\n");
969 return VOLSERVOLBUSY;
971 tv = XAttachVolume(&error, volume, partition, mode);
975 VDetachVolume(&code, tv);
983 strcpy(tt->lastProcName, "TransCreate");
985 return VOLSERTRELE_ERROR;
990 /* using aindex as a 0-based index, return the aindex'th volume on this server
991 * Both the volume number and partition number (one-based) are returned.
994 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
999 code = VolGetNthVolume(acid, aindex, avolume, apart);
1000 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1005 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1008 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1012 /* return the volume flags (VT* constants in volser.h) associated with this
1016 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1020 code = VolGetFlags(acid, atid, aflags);
1021 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1026 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1028 register struct volser_trans *tt;
1030 tt = FindTrans(atid);
1033 if (tt->vflags & VTDeleted) {
1034 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1039 strcpy(tt->lastProcName, "GetFlags");
1040 tt->rxCallPtr = acid;
1041 *aflags = tt->vflags;
1042 tt->rxCallPtr = (struct rx_call *)0;
1044 return VOLSERTRELE_ERROR;
1049 /* Change the volume flags (VT* constants in volser.h) associated with this
1050 * transaction. Effects take place immediately on volume, although volume
1051 * remains attached as usual by the transaction.
1054 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1058 code = VolSetFlags(acid, atid, aflags);
1059 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1065 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1067 register struct volser_trans *tt;
1068 register struct Volume *vp;
1070 char caller[MAXKTCNAMELEN];
1072 if (!afsconf_SuperUser(tdir, acid, caller))
1073 return VOLSERBAD_ACCESS; /*not a super user */
1074 /* find the trans */
1075 tt = FindTrans(atid);
1078 if (tt->vflags & VTDeleted) {
1079 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1084 strcpy(tt->lastProcName, "SetFlags");
1085 tt->rxCallPtr = acid;
1086 vp = tt->volume; /* pull volume out of transaction */
1088 /* check if we're allowed to make any updates */
1089 if (tt->iflags & ITReadOnly) {
1094 /* handle delete-on-salvage flag */
1095 if (aflags & VTDeleteOnSalvage) {
1096 V_destroyMe(tt->volume) = DESTROY_ME;
1098 V_destroyMe(tt->volume) = 0;
1101 if (aflags & VTOutOfService) {
1102 V_inService(vp) = 0;
1104 V_inService(vp) = 1;
1106 VUpdateVolume(&error, vp);
1107 tt->vflags = aflags;
1108 tt->rxCallPtr = (struct rx_call *)0;
1109 if (TRELE(tt) && !error)
1110 return VOLSERTRELE_ERROR;
1115 /* dumpS the volume associated with a particular transaction from a particular
1116 * date. Send the dump to a different transaction (destTrans) on the server
1117 * specified by the destServer structure.
1120 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1121 struct destServer *destination, afs_int32 destTrans,
1122 struct restoreCookie *cookie)
1127 VolForward(acid, fromTrans, fromDate, destination, destTrans, cookie);
1128 osi_auditU(acid, VS_ForwardEvent, code, AUD_LONG, fromTrans, AUD_HOST,
1129 destination->destHost, AUD_LONG, destTrans, AUD_END);
1134 VolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1135 struct destServer *destination, afs_int32 destTrans,
1136 struct restoreCookie *cookie)
1138 register struct volser_trans *tt;
1139 register afs_int32 code;
1140 register struct rx_connection *tcon;
1141 struct rx_call *tcall;
1142 register struct Volume *vp;
1143 struct rx_securityClass *securityObject;
1144 afs_int32 securityIndex;
1145 char caller[MAXKTCNAMELEN];
1147 if (!afsconf_SuperUser(tdir, acid, caller))
1148 return VOLSERBAD_ACCESS; /*not a super user */
1149 /* initialize things */
1150 tcon = (struct rx_connection *)0;
1151 tt = (struct volser_trans *)0;
1153 /* find the local transaction */
1154 tt = FindTrans(fromTrans);
1157 if (tt->vflags & VTDeleted) {
1158 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1163 strcpy(tt->lastProcName, "Forward");
1165 /* get auth info for the this connection (uses afs from ticket file) */
1166 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1172 /* make an rpc connection to the other server */
1174 rx_NewConnection(htonl(destination->destHost),
1175 htons(destination->destPort), VOLSERVICE_ID,
1176 securityObject, securityIndex);
1178 tt->rxCallPtr = (struct rx_call *)0;
1182 tcall = rx_NewCall(tcon);
1183 tt->rxCallPtr = tcall;
1184 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1185 code = StartAFSVolRestore(tcall, destTrans, (fromDate ? 1 : 0), cookie);
1190 /* these next calls implictly call rx_Write when writing out data */
1191 code = DumpVolume(tcall, vp, fromDate, 0); /* last field = don't dump all dirs */
1194 EndAFSVolRestore(tcall); /* probably doesn't do much */
1195 tt->rxCallPtr = (struct rx_call *)0;
1196 code = rx_EndCall(tcall, 0);
1197 rx_DestroyConnection(tcon); /* done with the connection */
1202 return VOLSERTRELE_ERROR;
1208 (void)rx_EndCall(tcall, 0);
1209 rx_DestroyConnection(tcon);
1212 tt->rxCallPtr = (struct rx_call *)0;
1218 /* Start a dump and send it to multiple places simultaneously.
1219 * If this returns an error (eg, return ENOENT), it means that
1220 * none of the releases worked. If this returns 0, that means
1221 * that one or more of the releases worked, and the caller has
1222 * to examine the results array to see which one(s).
1223 * This will only do EITHER incremental or full, not both, so it's
1224 * the caller's responsibility to be sure that all the destinations
1225 * need just an incremental (and from the same time), if that's
1229 SAFSVolForwardMultiple(struct rx_call *acid, afs_int32 fromTrans, afs_int32
1230 fromDate, manyDests *destinations, afs_int32 spare,
1231 struct restoreCookie *cookie, manyResults *results)
1233 afs_int32 securityIndex;
1234 struct rx_securityClass *securityObject;
1235 char caller[MAXKTCNAMELEN];
1236 struct volser_trans *tt;
1237 afs_int32 ec, code, *codes;
1238 struct rx_connection **tcons;
1239 struct rx_call **tcalls;
1241 int i, is_incremental;
1244 memset(results, 0, sizeof(manyResults));
1245 i = results->manyResults_len = destinations->manyDests_len;
1246 results->manyResults_val = codes =
1247 (afs_int32 *) malloc(i * sizeof(afs_int32));
1249 if (!results || !results->manyResults_val)
1252 if (!afsconf_SuperUser(tdir, acid, caller))
1253 return VOLSERBAD_ACCESS; /*not a super user */
1254 tt = FindTrans(fromTrans);
1257 if (tt->vflags & VTDeleted) {
1258 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1263 strcpy(tt->lastProcName, "ForwardMulti");
1265 /* (fromDate == 0) ==> full dump */
1266 is_incremental = (fromDate ? 1 : 0);
1269 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1273 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1279 /* get auth info for this connection (uses afs from ticket file) */
1280 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1282 goto fail; /* in order to audit each failure */
1285 /* make connections to all the other servers */
1286 for (i = 0; i < destinations->manyDests_len; i++) {
1287 struct replica *dest = &(destinations->manyDests_val[i]);
1289 rx_NewConnection(htonl(dest->server.destHost),
1290 htons(dest->server.destPort), VOLSERVICE_ID,
1291 securityObject, securityIndex);
1293 codes[i] = ENOTCONN;
1295 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1296 codes[i] = ENOTCONN;
1299 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1302 (void)rx_EndCall(tcalls[i], 0);
1304 rx_DestroyConnection(tcons[i]);
1311 /* these next calls implictly call rx_Write when writing out data */
1312 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1316 for (i--; i >= 0; i--) {
1317 struct replica *dest = &(destinations->manyDests_val[i]);
1319 if (!code && tcalls[i] && !codes[i]) {
1320 EndAFSVolRestore(tcalls[i]);
1323 ec = rx_EndCall(tcalls[i], 0);
1328 rx_DestroyConnection(tcons[i]); /* done with the connection */
1331 osi_auditU(acid, VS_ForwardEvent, (code ? code : codes[i]), AUD_LONG,
1332 fromTrans, AUD_HOST, dest->server.destHost, AUD_LONG,
1333 dest->trans, AUD_END);
1339 tt->rxCallPtr = (struct rx_call *)0;
1340 if (TRELE(tt) && !code) /* return the first code if it's set */
1341 return VOLSERTRELE_ERROR;
1348 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1352 code = VolDump(acid, fromTrans, fromDate, 0);
1353 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1358 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1363 code = VolDump(acid, fromTrans, fromDate, flags);
1364 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1369 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1373 register struct volser_trans *tt;
1374 char caller[MAXKTCNAMELEN];
1376 if (!afsconf_SuperUser(tdir, acid, caller))
1377 return VOLSERBAD_ACCESS; /*not a super user */
1378 tt = FindTrans(fromTrans);
1381 if (tt->vflags & VTDeleted) {
1382 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1386 strcpy(tt->lastProcName, "Dump");
1387 tt->rxCallPtr = acid;
1388 code = DumpVolume(acid, tt->volume, fromDate, (flags & VOLDUMPV2_OMITDIRS)
1389 ? 0 : 1); /* squirt out the volume's data, too */
1391 tt->rxCallPtr = (struct rx_call *)0;
1395 tt->rxCallPtr = (struct rx_call *)0;
1398 return VOLSERTRELE_ERROR;
1404 * Ha! No more helper process!
1407 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1408 struct restoreCookie *cookie)
1412 code = VolRestore(acid, atrans, aflags, cookie);
1413 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1418 VolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1419 struct restoreCookie *cookie)
1421 register struct volser_trans *tt;
1422 register afs_int32 code, tcode;
1423 char caller[MAXKTCNAMELEN];
1425 if (!afsconf_SuperUser(tdir, acid, caller))
1426 return VOLSERBAD_ACCESS; /*not a super user */
1427 tt = FindTrans(atrans);
1430 if (tt->vflags & VTDeleted) {
1431 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1435 strcpy(tt->lastProcName, "Restore");
1436 tt->rxCallPtr = acid;
1438 DFlushVolume(V_parentId(tt->volume)); /* Ensure dir buffers get dropped */
1440 code = RestoreVolume(acid, tt->volume, (aflags & 1), cookie); /* last is incrementalp */
1441 FSYNC_VolOp(tt->volid, NULL, FSYNC_VOL_BREAKCBKS, 0l, NULL);
1442 tt->rxCallPtr = (struct rx_call *)0;
1445 return (code ? code : tcode);
1448 /* end a transaction, returning the transaction's final error code in rcode */
1450 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1454 code = VolEndTrans(acid, destTrans, rcode);
1455 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1460 VolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1462 register struct volser_trans *tt;
1463 char caller[MAXKTCNAMELEN];
1465 if (!afsconf_SuperUser(tdir, acid, caller))
1466 return VOLSERBAD_ACCESS; /*not a super user */
1467 tt = FindTrans(destTrans);
1471 *rcode = tt->returnCode;
1472 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1478 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1482 code = VolSetForwarding(acid, atid, anewsite);
1483 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1489 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1491 register struct volser_trans *tt;
1492 char caller[MAXKTCNAMELEN];
1495 if (!afsconf_SuperUser(tdir, acid, caller))
1496 return VOLSERBAD_ACCESS; /*not a super user */
1497 tt = FindTrans(atid);
1500 if (tt->vflags & VTDeleted) {
1501 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1506 strcpy(tt->lastProcName, "SetForwarding");
1507 tt->rxCallPtr = acid;
1508 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1511 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1512 tt->rxCallPtr = (struct rx_call *)0;
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 strcpy(tt->lastProcName, "GetStatus");
1549 tt->rxCallPtr = acid;
1552 tt->rxCallPtr = (struct rx_call *)0;
1557 td = &tv->header->diskstuff;
1558 astatus->volID = td->id;
1559 astatus->nextUnique = td->uniquifier;
1560 astatus->type = td->type;
1561 astatus->parentID = td->parentId;
1562 astatus->cloneID = td->cloneId;
1563 astatus->backupID = td->backupId;
1564 astatus->restoredFromID = td->restoredFromId;
1565 astatus->maxQuota = td->maxquota;
1566 astatus->minQuota = td->minquota;
1567 astatus->owner = td->owner;
1568 astatus->creationDate = td->creationDate;
1569 astatus->accessDate = td->accessDate;
1570 astatus->updateDate = td->updateDate;
1571 astatus->expirationDate = td->expirationDate;
1572 astatus->backupDate = td->backupDate;
1573 astatus->copyDate = td->copyDate;
1574 tt->rxCallPtr = (struct rx_call *)0;
1576 return VOLSERTRELE_ERROR;
1582 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1583 register struct volintInfo *astatus)
1587 code = VolSetInfo(acid, atrans, astatus);
1588 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1593 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1594 register struct volintInfo *astatus)
1596 register struct Volume *tv;
1597 register struct VolumeDiskData *td;
1598 struct volser_trans *tt;
1599 char caller[MAXKTCNAMELEN];
1602 if (!afsconf_SuperUser(tdir, acid, caller))
1603 return VOLSERBAD_ACCESS; /*not a super user */
1604 tt = FindTrans(atrans);
1607 if (tt->vflags & VTDeleted) {
1608 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1612 strcpy(tt->lastProcName, "SetStatus");
1613 tt->rxCallPtr = acid;
1616 tt->rxCallPtr = (struct rx_call *)0;
1621 td = &tv->header->diskstuff;
1623 * Add more fields as necessary
1625 if (astatus->maxquota != -1)
1626 td->maxquota = astatus->maxquota;
1627 if (astatus->dayUse != -1)
1628 td->dayUse = astatus->dayUse;
1629 if (astatus->creationDate != -1)
1630 td->creationDate = astatus->creationDate;
1631 if (astatus->updateDate != -1)
1632 td->updateDate = astatus->updateDate;
1633 if (astatus->spare2 != -1)
1634 td->volUpdateCounter = (unsigned int)astatus->spare2;
1635 VUpdateVolume(&error, tv);
1636 tt->rxCallPtr = (struct rx_call *)0;
1638 return VOLSERTRELE_ERROR;
1644 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1648 code = VolGetName(acid, atrans, aname);
1649 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1654 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1656 register struct Volume *tv;
1657 register struct VolumeDiskData *td;
1658 struct volser_trans *tt;
1661 /* We need to at least fill it in */
1662 *aname = (char *)malloc(1);
1665 tt = FindTrans(atrans);
1668 if (tt->vflags & VTDeleted) {
1669 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1673 strcpy(tt->lastProcName, "GetName");
1674 tt->rxCallPtr = acid;
1677 tt->rxCallPtr = (struct rx_call *)0;
1682 td = &tv->header->diskstuff;
1683 len = strlen(td->name) + 1; /* don't forget the null */
1685 tt->rxCallPtr = (struct rx_call *)0;
1689 *aname = (char *)realloc(*aname, len);
1690 strcpy(*aname, td->name);
1691 tt->rxCallPtr = (struct rx_call *)0;
1693 return VOLSERTRELE_ERROR;
1698 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1701 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1702 afs_uint32 parentId, afs_uint32 cloneId)
1708 /*return a list of all partitions on the server. The non mounted
1709 *partitions are returned as -1 in the corresponding slot in partIds*/
1711 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1715 code = VolListPartitions(acid, partIds);
1716 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1721 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1726 strcpy(namehead, "/vicep"); /*7 including null terminator */
1728 /* Just return attached partitions. */
1730 for (i = 0; i < 26; i++) {
1731 namehead[6] = i + 'a';
1732 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1738 /*return a list of all partitions on the server. The non mounted
1739 *partitions are returned as -1 in the corresponding slot in partIds*/
1741 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1745 code = XVolListPartitions(acid, pEntries);
1746 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1751 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1754 struct partList partList;
1755 struct DiskPartition64 *dp;
1758 strcpy(namehead, "/vicep"); /*7 including null terminator */
1760 /* Only report attached partitions */
1761 for (i = 0; i < VOLMAXPARTS; i++) {
1762 #ifdef AFS_DEMAND_ATTACH_FS
1763 dp = VGetPartitionById(i, 0);
1766 namehead[6] = i + 'a';
1772 namehead[6] = 'a' + (k / 26);
1773 namehead[7] = 'a' + (k % 26);
1776 dp = VGetPartition(namehead, 0);
1779 partList.partId[j++] = i;
1781 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1782 if (!pEntries->partEntries_val)
1784 memcpy((char *)pEntries->partEntries_val, (char *)&partList,
1786 pEntries->partEntries_len = j;
1791 /*extract the volume id from string vname. Its of the form " V0*<id>.vol "*/
1793 ExtractVolId(char vname[])
1796 char name[VOLSER_MAXVOLNAME + 1];
1798 strcpy(name, vname);
1800 while (name[i] == 'V' || name[i] == '0')
1803 name[11] = '\0'; /* smash the "." */
1804 return (atol(&name[i]));
1807 /*return the name of the next volume header in the directory associated with dirp and dp.
1808 *the volume id is returned in volid, and volume header name is returned in volname*/
1810 GetNextVol(DIR * dirp, char *volname, afs_uint32 * volid)
1814 dp = readdir(dirp); /*read next entry in the directory */
1816 if ((dp->d_name[0] == 'V') && !strcmp(&(dp->d_name[11]), VHDREXT)) {
1817 *volid = ExtractVolId(dp->d_name);
1818 strcpy(volname, dp->d_name);
1819 return 0; /*return the name of the file representing a volume */
1821 strcpy(volname, "");
1822 return 0; /*volname doesnot represent a volume */
1825 strcpy(volname, "EOD");
1826 return 0; /*end of directory */
1832 * volint vol info structure type.
1835 VOLINT_INFO_TYPE_BASE, /**< volintInfo type */
1836 VOLINT_INFO_TYPE_EXT /**< volintXInfo type */
1837 } volint_info_type_t;
1840 * handle to various on-wire vol info types.
1843 volint_info_type_t volinfo_type;
1849 } volint_info_handle_t;
1852 * store value to a field at the appropriate location in on-wire structure.
1854 #define VOLINT_INFO_STORE(handle, name, val) \
1856 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1857 (handle)->volinfo_ptr.base->name = (val); \
1859 (handle)->volinfo_ptr.ext->name = (val); \
1864 * get pointer to appropriate offset of field in on-wire structure.
1866 #define VOLINT_INFO_PTR(handle, name) \
1867 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1868 &((handle)->volinfo_ptr.base->name) : \
1869 &((handle)->volinfo_ptr.ext->name))
1872 * fill in appropriate type of on-wire volume metadata structure.
1874 * @param vp pointer to volume object
1875 * @param handle pointer to wire format handle object
1877 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
1878 * @pre handle object must have a valid pointer and enumeration value
1880 * @note passing a NULL value for vp means that the fileserver doesn't
1881 * know about this particular volume, thus implying it is offline.
1883 * @return operation status
1888 FillVolInfo(Volume * vp, volint_info_handle_t * handle)
1890 unsigned int numStatBytes, now;
1891 register struct VolumeDiskData *hdr = &vp->header->diskstuff;
1893 /*read in the relevant info */
1894 strcpy((char *)VOLINT_INFO_PTR(handle, name), hdr->name);
1895 VOLINT_INFO_STORE(handle, status, VOK); /*its ok */
1896 VOLINT_INFO_STORE(handle, volid, hdr->id);
1897 VOLINT_INFO_STORE(handle, type, hdr->type); /*if ro volume */
1898 VOLINT_INFO_STORE(handle, cloneID, hdr->cloneId); /*if rw volume */
1899 VOLINT_INFO_STORE(handle, backupID, hdr->backupId);
1900 VOLINT_INFO_STORE(handle, parentID, hdr->parentId);
1901 VOLINT_INFO_STORE(handle, copyDate, hdr->copyDate);
1902 VOLINT_INFO_STORE(handle, size, hdr->diskused);
1903 VOLINT_INFO_STORE(handle, maxquota, hdr->maxquota);
1904 VOLINT_INFO_STORE(handle, filecount, hdr->filecount);
1905 now = FT_ApproxTime();
1906 if ((now - hdr->dayUseDate) > OneDay) {
1907 VOLINT_INFO_STORE(handle, dayUse, 0);
1909 VOLINT_INFO_STORE(handle, dayUse, hdr->dayUse);
1911 VOLINT_INFO_STORE(handle, creationDate, hdr->creationDate);
1912 VOLINT_INFO_STORE(handle, accessDate, hdr->accessDate);
1913 VOLINT_INFO_STORE(handle, updateDate, hdr->updateDate);
1914 VOLINT_INFO_STORE(handle, backupDate, hdr->backupDate);
1916 #ifdef AFS_DEMAND_ATTACH_FS
1918 * for DAFS, we "lie" about volume state --
1919 * instead of returning the raw state from the disk header,
1920 * we compute state based upon the fileserver's internal
1921 * in-core state enumeration value reported to us via fssync,
1922 * along with the blessed and inService flags from the header.
1923 * -- tkeiser 11/27/2007
1926 /* Conditions that offline status is based on:
1927 volume is unattached state
1928 volume state is in (one of several error states)
1929 volume not in service
1930 volume is not marked as blessed (not on hold)
1931 volume in salvage req. state
1932 volume needsSalvaged
1933 next op would set volume offline
1934 next op would not leave volume online (based on several conditions)
1937 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
1938 VIsErrorState(V_attachState(vp)) ||
1941 (V_attachState(vp) == VOL_STATE_SALVSYNC_REQ) ||
1942 hdr->needsSalvaged ||
1943 (vp->pending_vol_op &&
1944 (vp->pending_vol_op->com.command == FSYNC_VOL_OFF ||
1945 !VVolOpLeaveOnline_r(vp, vp->pending_vol_op) )
1948 VOLINT_INFO_STORE(handle, inUse, 0);
1950 VOLINT_INFO_STORE(handle, inUse, 1);
1953 /* offline status based on program type, where != fileServer enum (1) is offline */
1954 if (hdr->inUse == fileServer) {
1955 VOLINT_INFO_STORE(handle, inUse, 1);
1957 VOLINT_INFO_STORE(handle, inUse, 0);
1962 switch(handle->volinfo_type) {
1963 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
1964 case VOLINT_INFO_TYPE_BASE:
1966 #ifdef AFS_DEMAND_ATTACH_FS
1967 /* see comment above where we set inUse bit */
1968 if (hdr->needsSalvaged ||
1969 (vp && VIsErrorState(V_attachState(vp)))) {
1970 handle->volinfo_ptr.base->needsSalvaged = 1;
1972 handle->volinfo_ptr.base->needsSalvaged = 0;
1975 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
1977 handle->volinfo_ptr.base->destroyMe = hdr->destroyMe;
1978 handle->volinfo_ptr.base->spare0 = hdr->minquota;
1979 handle->volinfo_ptr.base->spare1 =
1980 (long)hdr->weekUse[0] +
1981 (long)hdr->weekUse[1] +
1982 (long)hdr->weekUse[2] +
1983 (long)hdr->weekUse[3] +
1984 (long)hdr->weekUse[4] +
1985 (long)hdr->weekUse[5] +
1986 (long)hdr->weekUse[6];
1987 handle->volinfo_ptr.base->flags = 0;
1988 handle->volinfo_ptr.base->spare2 = hdr->volUpdateCounter;
1989 handle->volinfo_ptr.base->spare3 = 0;
1993 case VOLINT_INFO_TYPE_EXT:
1995 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS) +
1996 (4 * VOLINT_STATS_NUM_TIME_FIELDS));
1999 * Copy out the stat fields in a single operation.
2001 if ((now - hdr->dayUseDate) > OneDay) {
2002 memset((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2005 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2006 (char *)&(hdr->stat_reads[0]),
2015 #ifdef AFS_DEMAND_ATTACH_FS
2018 * get struct Volume out of the fileserver.
2020 * @param[in] volumeId volumeId for which we want state information
2021 * @param[in] pname partition name string
2022 * @param[inout] vp pointer to pointer to Volume object which
2023 * will be populated (see note)
2025 * @return operation status
2027 * @retval non-zero failure
2029 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2034 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2039 res.hdr.response_len = sizeof(res.hdr);
2040 res.payload.buf = *vp;
2041 res.payload.len = sizeof(Volume);
2043 code = FSYNC_VolOp(volumeId,
2049 if (code != SYNC_OK) {
2050 switch (res.hdr.reason) {
2051 case FSYNC_WRONG_PART:
2052 case FSYNC_UNKNOWN_VOLID:
2065 * mode of volume list operation.
2068 VOL_INFO_LIST_SINGLE, /**< performing a single volume list op */
2069 VOL_INFO_LIST_MULTIPLE /**< performing a multi-volume list op */
2070 } vol_info_list_mode_t;
2073 * abstract interface to populate wire-format volume metadata structures.
2075 * @param[in] partId partition id
2076 * @param[in] volumeId volume id
2077 * @param[in] pname partition name
2078 * @param[in] volname volume file name
2079 * @param[in] handle handle to on-wire volume metadata object
2080 * @param[in] mode listing mode
2082 * @return operation status
2084 * @retval -2 DESTROY_ME flag is set
2085 * @retval -1 general failure; some data filled in
2086 * @retval -3 couldn't create vtrans; some data filled in
2089 GetVolInfo(afs_uint32 partId,
2090 afs_uint32 volumeId,
2093 volint_info_handle_t * handle,
2094 vol_info_list_mode_t mode)
2098 struct volser_trans *ttc = NULL;
2099 struct Volume *fill_tv, *tv = NULL;
2100 #ifdef AFS_DEMAND_ATTACH_FS
2101 struct Volume fs_tv_buf, *fs_tv = &fs_tv_buf; /* Create a structure, and a pointer to that structure */
2102 SYNC_PROTO_BUF_DECL(fs_res_buf); /* Buffer for the pending_vol_op */
2103 SYNC_response fs_res; /* Response handle for the pending_vol_op */
2104 FSSYNC_VolOp_info pending_vol_op_res; /* Pending vol ops to full in volume */
2106 /* Set up response handle for pending_vol_op */
2107 fs_res.hdr.response_len = sizeof(fs_res.hdr);
2108 fs_res.payload.buf = fs_res_buf;
2109 fs_res.payload.len = SYNC_PROTO_MAX_LEN;
2112 ttc = NewTrans(volumeId, partId);
2115 VOLINT_INFO_STORE(handle, status, VOLSERVOLBUSY);
2116 VOLINT_INFO_STORE(handle, volid, volumeId);
2120 /* Get volume from volserver */
2121 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2123 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2124 volumeId, pname, volname, error);
2129 * please note that destroyMe and needsSalvaged checks used to be ordered
2130 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2131 * more correct to check destroyMe before needsSalvaged.
2132 * -- tkeiser 11/28/2007
2135 if (tv->header->diskstuff.destroyMe == DESTROY_ME) {
2137 case VOL_INFO_LIST_MULTIPLE:
2141 case VOL_INFO_LIST_SINGLE:
2142 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2143 volumeId, pname, volname);
2150 if (tv->header->diskstuff.needsSalvaged) {
2151 /*this volume will be salvaged */
2152 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2153 volumeId, pname, volname);
2156 #ifdef AFS_DEMAND_ATTACH_FS
2157 /* If using DAFS, get volume from fsserver */
2158 if (GetVolObject(volumeId, pname, &fs_tv) != SYNC_OK) {
2162 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2163 if (FSYNC_VolOp(volumeId, pname, FSYNC_VOL_QUERY_VOP, 0, &fs_res) == SYNC_OK) {
2164 /* If we if the pending vol op */
2165 memcpy(&pending_vol_op_res, fs_res.payload.buf, sizeof(FSSYNC_VolOp_info));
2166 fs_tv->pending_vol_op=&pending_vol_op_res;
2168 fs_tv->pending_vol_op=NULL;
2171 /* populate the header from the volserver copy */
2172 fs_tv->header=tv->header;
2174 /* When using DAFS, use the fs volume info, populated with required structures */
2177 /* When not using DAFS, just use the local volume info */
2181 /* ok, we have all the data we need; fill in the on-wire struct */
2182 code = FillVolInfo(fill_tv, handle);
2186 VOLINT_INFO_STORE(handle, status, 0);
2187 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2188 VOLINT_INFO_STORE(handle, volid, volumeId);
2191 VDetachVolume(&error, tv);
2194 VOLINT_INFO_STORE(handle, status, 0);
2195 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2196 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2197 volumeId, pname, volname);
2201 DeleteTrans(ttc, 1);
2208 /*return the header information about the <volid> */
2210 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2211 afs_uint32 volumeId, volEntries *volumeInfo)
2215 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2216 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2221 VolListOneVolume(struct rx_call *acid, afs_int32 partid,
2222 afs_uint32 volumeId, volEntries *volumeInfo)
2225 struct DiskPartition64 *partP;
2226 char pname[9], volname[20];
2231 volint_info_handle_t handle;
2233 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2234 if (!volumeInfo->volEntries_val)
2236 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2238 pntr = volumeInfo->volEntries_val;
2239 volumeInfo->volEntries_len = 1;
2240 if (GetPartName(partid, pname))
2241 return VOLSERILLEGAL_PARTITION;
2242 if (!(partP = VGetPartition(pname, 0)))
2243 return VOLSERILLEGAL_PARTITION;
2244 dirp = opendir(VPartitionPath(partP));
2246 return VOLSERILLEGAL_PARTITION;
2248 strcpy(volname, "");
2250 while (strcmp(volname, "EOD") && !found) { /*while there are more volumes in the partition */
2252 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2253 GetNextVol(dirp, volname, &volid);
2254 continue; /*back to while loop */
2257 if (volid == volumeId) { /*copy other things too */
2262 GetNextVol(dirp, volname, &volid);
2266 #ifndef AFS_PTHREAD_ENV
2267 IOMGR_Poll(); /*make sure that the client does not time out */
2270 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2271 handle.volinfo_ptr.base = volumeInfo->volEntries_val;
2273 code = GetVolInfo(partid,
2278 VOL_INFO_LIST_SINGLE);
2282 return (found) ? 0 : ENODEV;
2285 /*------------------------------------------------------------------------
2286 * EXPORTED SAFSVolXListOneVolume
2289 * Returns extended info on volume a_volID on partition a_partID.
2292 * a_rxCidP : Pointer to the Rx call we're performing.
2293 * a_partID : Partition for which we want the extended list.
2294 * a_volID : Volume ID we wish to know about.
2295 * a_volumeXInfoP : Ptr to the extended info blob.
2298 * 0 Successful operation
2299 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2302 * Nothing interesting.
2306 *------------------------------------------------------------------------*/
2309 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2310 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2314 code = VolXListOneVolume(a_rxCidP, a_partID, a_volID, a_volumeXInfoP);
2315 osi_auditU(a_rxCidP, VS_XLst1VlEvent, code, AUD_LONG, a_volID, AUD_END);
2320 VolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2321 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2322 { /*SAFSVolXListOneVolume */
2324 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2325 struct DiskPartition64 *partP; /*Ptr to partition */
2326 char pname[9], volname[20]; /*Partition, volume names */
2327 DIR *dirp; /*Partition directory ptr */
2328 afs_uint32 currVolID; /*Current volume ID */
2329 int found = 0; /*Did we find the volume we need? */
2331 volint_info_handle_t handle;
2334 * Set up our pointers for action, marking our structure to hold exactly
2335 * one entry. Also, assume we'll fail in our quest.
2337 a_volumeXInfoP->volXEntries_val =
2338 (volintXInfo *) malloc(sizeof(volintXInfo));
2339 if (!a_volumeXInfoP->volXEntries_val)
2341 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2343 xInfoP = a_volumeXInfoP->volXEntries_val;
2344 a_volumeXInfoP->volXEntries_len = 1;
2348 * If the partition name we've been given is bad, bogue out.
2350 if (GetPartName(a_partID, pname))
2351 return (VOLSERILLEGAL_PARTITION);
2354 * Open the directory representing the given AFS parttion. If we can't
2357 if (!(partP = VGetPartition(pname, 0)))
2358 return VOLSERILLEGAL_PARTITION;
2359 dirp = opendir(VPartitionPath(partP));
2361 return (VOLSERILLEGAL_PARTITION);
2363 strcpy(volname, "");
2366 * Sweep through the partition directory, looking for the desired entry.
2367 * First, of course, figure out how many stat bytes to copy out of each
2370 while (strcmp(volname, "EOD") && !found) {
2372 * If this is not a volume, move on to the next entry in the
2373 * partition's directory.
2375 if (!strcmp(volname, "")) {
2376 GetNextVol(dirp, volname, &currVolID);
2380 if (currVolID == a_volID) {
2382 * We found the volume entry we're interested. Pull out the
2383 * extended information, remembering to poll (so that the client
2384 * doesn't time out) and to set up a transaction on the volume.
2388 } /*Found desired volume */
2390 GetNextVol(dirp, volname, &currVolID);
2394 #ifndef AFS_PTHREAD_ENV
2398 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2399 handle.volinfo_ptr.ext = a_volumeXInfoP->volXEntries_val;
2401 code = GetVolInfo(a_partID,
2406 VOL_INFO_LIST_SINGLE);
2411 * Clean up before going to dinner: close the partition directory,
2412 * return the proper value.
2415 return (found) ? 0 : ENODEV;
2416 } /*SAFSVolXListOneVolume */
2418 /*returns all the volumes on partition partid. If flags = 1 then all the
2419 * relevant info about the volumes is also returned */
2421 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2422 volEntries *volumeInfo)
2426 code = VolListVolumes(acid, partid, flags, volumeInfo);
2427 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2432 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2433 volEntries *volumeInfo)
2436 struct DiskPartition64 *partP;
2437 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2438 char pname[9], volname[20];
2442 volint_info_handle_t handle;
2444 volumeInfo->volEntries_val =
2445 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2446 if (!volumeInfo->volEntries_val)
2448 memset(volumeInfo->volEntries_val, 0, sizeof(volintInfo)); /* Clear structure */
2450 pntr = volumeInfo->volEntries_val;
2451 volumeInfo->volEntries_len = 0;
2452 if (GetPartName(partid, pname))
2453 return VOLSERILLEGAL_PARTITION;
2454 if (!(partP = VGetPartition(pname, 0)))
2455 return VOLSERILLEGAL_PARTITION;
2456 dirp = opendir(VPartitionPath(partP));
2458 return VOLSERILLEGAL_PARTITION;
2459 strcpy(volname, "");
2461 while (strcmp(volname, "EOD")) { /*while there are more partitions in the partition */
2463 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2464 GetNextVol(dirp, volname, &volid);
2465 continue; /*back to while loop */
2468 if (flags) { /*copy other things too */
2469 #ifndef AFS_PTHREAD_ENV
2470 IOMGR_Poll(); /*make sure that the client does not time out */
2473 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2474 handle.volinfo_ptr.base = pntr;
2477 code = GetVolInfo(partid,
2482 VOL_INFO_LIST_MULTIPLE);
2483 if (code == -2) { /* DESTROY_ME flag set */
2487 pntr->volid = volid;
2488 /*just volids are needed */
2492 volumeInfo->volEntries_len += 1;
2493 if ((allocSize - volumeInfo->volEntries_len) < 5) {
2494 /*running out of space, allocate more space */
2495 allocSize = (allocSize * 3) / 2;
2497 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2498 allocSize * sizeof(volintInfo));
2501 return VOLSERNO_MEMORY;
2503 volumeInfo->volEntries_val = pntr; /* point to new block */
2504 /* set pntr to the right position */
2505 pntr = volumeInfo->volEntries_val + volumeInfo->volEntries_len;
2510 GetNextVol(dirp, volname, &volid);
2518 /*------------------------------------------------------------------------
2519 * EXPORTED SAFSVolXListVolumes
2522 * Returns all the volumes on partition a_partID. If a_flags
2523 * is set to 1, then all the relevant extended volume information
2527 * a_rxCidP : Pointer to the Rx call we're performing.
2528 * a_partID : Partition for which we want the extended list.
2529 * a_flags : Various flags.
2530 * a_volumeXInfoP : Ptr to the extended info blob.
2533 * 0 Successful operation
2534 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2535 * VOLSERNO_MEMORY if we ran out of memory allocating
2539 * Nothing interesting.
2543 *------------------------------------------------------------------------*/
2546 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2547 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2551 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2552 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2557 VolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2558 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2559 { /*SAFSVolXListVolumes */
2561 volintXInfo *xInfoP; /*Ptr to the extended vol info */
2562 struct DiskPartition64 *partP; /*Ptr to partition */
2563 afs_int32 allocSize = 1000; /*To be changed to a larger figure */
2564 char pname[9], volname[20]; /*Partition, volume names */
2565 DIR *dirp; /*Partition directory ptr */
2566 afs_uint32 volid; /*Current volume ID */
2568 volint_info_handle_t handle;
2571 * Allocate a large array of extended volume info structures, then
2572 * set it up for action.
2574 a_volumeXInfoP->volXEntries_val =
2575 (volintXInfo *) malloc(allocSize * sizeof(volintXInfo));
2576 if (!a_volumeXInfoP->volXEntries_val)
2578 memset(a_volumeXInfoP->volXEntries_val, 0, sizeof(volintXInfo)); /* Clear structure */
2580 xInfoP = a_volumeXInfoP->volXEntries_val;
2581 a_volumeXInfoP->volXEntries_len = 0;
2584 * If the partition name we've been given is bad, bogue out.
2586 if (GetPartName(a_partID, pname))
2587 return (VOLSERILLEGAL_PARTITION);
2590 * Open the directory representing the given AFS parttion. If we can't
2593 if (!(partP = VGetPartition(pname, 0)))
2594 return VOLSERILLEGAL_PARTITION;
2595 dirp = opendir(VPartitionPath(partP));
2597 return (VOLSERILLEGAL_PARTITION);
2598 strcpy(volname, "");
2601 * Sweep through the partition directory, acting on each entry. First,
2602 * of course, figure out how many stat bytes to copy out of each volume.
2604 while (strcmp(volname, "EOD")) {
2607 * If this is not a volume, move on to the next entry in the
2608 * partition's directory.
2610 if (!strcmp(volname, "")) {
2611 GetNextVol(dirp, volname, &volid);
2617 * Full info about the volume desired. Poll to make sure the
2618 * client doesn't time out, then start up a new transaction.
2620 #ifndef AFS_PTHREAD_ENV
2624 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2625 handle.volinfo_ptr.ext = xInfoP;
2627 code = GetVolInfo(a_partID,
2632 VOL_INFO_LIST_MULTIPLE);
2633 if (code == -2) { /* DESTROY_ME flag set */
2638 * Just volume IDs are needed.
2640 xInfoP->volid = volid;
2644 * Bump the pointer in the data area we're building, along with
2645 * the count of the number of entries it contains.
2648 (a_volumeXInfoP->volXEntries_len)++;
2649 if ((allocSize - a_volumeXInfoP->volXEntries_len) < 5) {
2651 * We're running out of space in the area we've built. Grow it.
2653 allocSize = (allocSize * 3) / 2;
2654 xInfoP = (volintXInfo *)
2655 realloc((char *)a_volumeXInfoP->volXEntries_val,
2656 (allocSize * sizeof(volintXInfo)));
2657 if (xInfoP == NULL) {
2659 * Bummer, no memory. Bag it, tell our caller what went wrong.
2662 return (VOLSERNO_MEMORY);
2666 * Memory reallocation worked. Correct our pointers so they
2667 * now point to the new block and the current open position within
2670 a_volumeXInfoP->volXEntries_val = xInfoP;
2672 a_volumeXInfoP->volXEntries_val +
2673 a_volumeXInfoP->volXEntries_len;
2677 GetNextVol(dirp, volname, &volid);
2678 } /*Sweep through the partition directory */
2681 * We've examined all entries in the partition directory. Close it,
2682 * delete our transaction (if any), and go home happy.
2687 } /*SAFSVolXListVolumes */
2689 /*this call is used to monitor the status of volser for debugging purposes.
2690 *information about all the active transactions is returned in transInfo*/
2692 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2696 code = VolMonitor(acid, transInfo);
2697 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2702 VolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2704 transDebugInfo *pntr;
2705 afs_int32 allocSize = 50;
2706 struct volser_trans *tt, *allTrans;
2708 transInfo->transDebugEntries_val =
2709 (transDebugInfo *) malloc(allocSize * sizeof(transDebugInfo));
2710 if (!transInfo->transDebugEntries_val)
2712 pntr = transInfo->transDebugEntries_val;
2713 transInfo->transDebugEntries_len = 0;
2714 allTrans = TransList();
2715 if (allTrans == (struct volser_trans *)0)
2716 return 0; /*no active transactions */
2717 for (tt = allTrans; tt; tt = tt->next) { /*copy relevant info into pntr */
2718 pntr->tid = tt->tid;
2719 pntr->time = tt->time;
2720 pntr->creationTime = tt->creationTime;
2721 pntr->returnCode = tt->returnCode;
2722 pntr->volid = tt->volid;
2723 pntr->partition = tt->partition;
2724 pntr->iflags = tt->iflags;
2725 pntr->vflags = tt->vflags;
2726 pntr->tflags = tt->tflags;
2727 strcpy(pntr->lastProcName, tt->lastProcName);
2728 pntr->callValid = 0;
2729 if (tt->rxCallPtr) { /*record call related info */
2730 pntr->callValid = 1;
2731 pntr->readNext = tt->rxCallPtr->rnext;
2732 pntr->transmitNext = tt->rxCallPtr->tnext;
2733 pntr->lastSendTime = tt->rxCallPtr->lastSendTime;
2734 pntr->lastReceiveTime = tt->rxCallPtr->lastReceiveTime;
2737 transInfo->transDebugEntries_len += 1;
2738 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2739 allocSize = (allocSize * 3) / 2;
2741 (transDebugInfo *) realloc((char *)transInfo->
2742 transDebugEntries_val,
2744 sizeof(transDebugInfo));
2745 transInfo->transDebugEntries_val = pntr;
2747 transInfo->transDebugEntries_val +
2748 transInfo->transDebugEntries_len;
2749 /*set pntr to right position */
2758 SAFSVolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2759 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2760 afs_uint32 backupId)
2764 code = VolSetIdsTypes(acid, atid, name, type, pId, cloneId, backupId);
2765 osi_auditU(acid, VS_SetIdTyEvent, code, AUD_LONG, atid, AUD_STR, name,
2766 AUD_LONG, type, AUD_LONG, pId, AUD_LONG, cloneId, AUD_LONG,
2772 VolSetIdsTypes(struct rx_call *acid, afs_int32 atid, char name[],
2773 afs_int32 type, afs_uint32 pId, afs_uint32 cloneId,
2774 afs_uint32 backupId)
2778 register struct volser_trans *tt;
2779 char caller[MAXKTCNAMELEN];
2781 if (strlen(name) > 31)
2782 return VOLSERBADNAME;
2783 if (!afsconf_SuperUser(tdir, acid, caller))
2784 return VOLSERBAD_ACCESS; /*not a super user */
2785 /* find the trans */
2786 tt = FindTrans(atid);
2789 if (tt->vflags & VTDeleted) {
2790 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2794 strcpy(tt->lastProcName, "SetIdsTypes");
2795 tt->rxCallPtr = acid;
2799 V_backupId(tv) = backupId;
2800 V_cloneId(tv) = cloneId;
2801 V_parentId(tv) = pId;
2802 strcpy((&V_disk(tv))->name, name);
2803 VUpdateVolume(&error, tv);
2805 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2809 tt->rxCallPtr = (struct rx_call *)0;
2810 if (TRELE(tt) && !error)
2811 return VOLSERTRELE_ERROR;
2815 tt->rxCallPtr = (struct rx_call *)0;
2816 if (TRELE(tt) && !error)
2817 return VOLSERTRELE_ERROR;
2822 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2826 code = VolSetDate(acid, atid, cdate);
2827 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2833 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2837 register struct volser_trans *tt;
2838 char caller[MAXKTCNAMELEN];
2840 if (!afsconf_SuperUser(tdir, acid, caller))
2841 return VOLSERBAD_ACCESS; /*not a super user */
2842 /* find the trans */
2843 tt = FindTrans(atid);
2846 if (tt->vflags & VTDeleted) {
2847 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2851 strcpy(tt->lastProcName, "SetDate");
2852 tt->rxCallPtr = acid;
2855 V_creationDate(tv) = cdate;
2856 VUpdateVolume(&error, tv);
2858 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2862 tt->rxCallPtr = (struct rx_call *)0;
2863 if (TRELE(tt) && !error)
2864 return VOLSERTRELE_ERROR;
2868 tt->rxCallPtr = (struct rx_call *)0;
2869 if (TRELE(tt) && !error)
2870 return VOLSERTRELE_ERROR;
2875 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
2876 afs_uint32 volumeId)
2881 char caller[MAXKTCNAMELEN];
2883 register struct volser_trans *ttc;
2884 char pname[16], volname[20];
2885 struct DiskPartition64 *partP;
2886 afs_int32 ret = ENODEV;
2889 if (!afsconf_SuperUser(tdir, acid, caller))
2890 return VOLSERBAD_ACCESS; /*not a super user */
2891 if (GetPartName(partId, pname))
2892 return VOLSERILLEGAL_PARTITION;
2893 if (!(partP = VGetPartition(pname, 0)))
2894 return VOLSERILLEGAL_PARTITION;
2895 dirp = opendir(VPartitionPath(partP));
2897 return VOLSERILLEGAL_PARTITION;
2898 strcpy(volname, "");
2899 ttc = (struct volser_trans *)0;
2901 while (strcmp(volname, "EOD")) {
2902 if (!strcmp(volname, "")) { /* its not a volume, fetch next file */
2903 GetNextVol(dirp, volname, &volid);
2904 continue; /*back to while loop */
2907 if (volid == volumeId) { /*copy other things too */
2908 #ifndef AFS_PTHREAD_ENV
2909 IOMGR_Poll(); /*make sure that the client doesnot time out */
2911 ttc = NewTrans(volumeId, partId);
2913 return VOLSERVOLBUSY;
2915 #ifdef AFS_NAMEI_ENV
2916 ret = namei_ConvertROtoRWvolume(pname, volumeId);
2918 ret = inode_ConvertROtoRWvolume(pname, volumeId);
2922 GetNextVol(dirp, volname, &volid);
2926 DeleteTrans(ttc, 1);
2927 ttc = (struct volser_trans *)0;
2936 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
2937 register struct volintSize *size)
2940 register struct volser_trans *tt;
2941 char caller[MAXKTCNAMELEN];
2943 if (!afsconf_SuperUser(tdir, acid, caller))
2944 return VOLSERBAD_ACCESS; /*not a super user */
2945 tt = FindTrans(fromTrans);
2948 if (tt->vflags & VTDeleted) {
2952 strcpy(tt->lastProcName, "GetSize");
2953 tt->rxCallPtr = acid;
2954 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
2955 tt->rxCallPtr = (struct rx_call *)0;
2957 return VOLSERTRELE_ERROR;
2959 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
2964 SAFSVolSplitVolume(struct rx_call *acall, afs_uint32 vid, afs_uint32 new,
2965 afs_uint32 where, afs_int32 verbose)
2967 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
2969 Volume *vol=0, *newvol=0;
2970 struct volser_trans *tt = 0, *tt2 = 0;
2971 char caller[MAXKTCNAMELEN];
2974 if (!afsconf_SuperUser(tdir, acall, caller))
2977 vol = VAttachVolume(&code, vid, V_VOLUPD);
2983 newvol = VAttachVolume(&code, new, V_VOLUPD);
2985 VDetachVolume(&code2, vol);
2990 if (V_device(vol) != V_device(newvol)
2991 || V_uniquifier(newvol) != 2) {
2992 if (V_device(vol) != V_device(newvol)) {
2993 sprintf(line, "Volumes %u and %u are not in the same partition, aborted.\n",
2995 rx_Write(acall, line, strlen(line));
2997 if (V_uniquifier(newvol) != 2) {
2998 sprintf(line, "Volume %u is not freshly created, aborted.\n", new);
2999 rx_Write(acall, line, strlen(line));
3002 rx_Write(acall, line, 1);
3003 VDetachVolume(&code2, vol);
3004 VDetachVolume(&code2, newvol);
3007 tt = NewTrans(vid, V_device(vol));
3009 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3010 rx_Write(acall, line, strlen(line));
3012 rx_Write(acall, line, 1);
3013 VDetachVolume(&code2, vol);
3014 VDetachVolume(&code2, newvol);
3015 return VOLSERVOLBUSY;
3017 tt->iflags = ITBusy;
3019 strcpy(tt->lastProcName, "SplitVolume");
3021 tt2 = NewTrans(new, V_device(newvol));
3023 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3024 rx_Write(acall, line, strlen(line));
3026 rx_Write(acall, line, 1);
3028 VDetachVolume(&code2, vol);
3029 VDetachVolume(&code2, newvol);
3030 return VOLSERVOLBUSY;
3032 tt2->iflags = ITBusy;
3034 strcpy(tt2->lastProcName, "SplitVolume");
3036 code = split_volume(acall, vol, newvol, where, verbose);
3038 VDetachVolume(&code2, vol);
3040 VDetachVolume(&code2, newvol);
3041 DeleteTrans(tt2, 1);
3048 /* GetPartName - map partid (a decimal number) into pname (a string)
3049 * Since for NT we actually want to return the drive name, we map through the
3053 GetPartName(afs_int32 partid, char *pname)
3058 strcpy(pname, "/vicep");
3059 pname[6] = 'a' + partid;
3062 } else if (partid < VOLMAXPARTS) {
3063 strcpy(pname, "/vicep");
3065 pname[6] = 'a' + (partid / 26);
3066 pname[7] = 'a' + (partid % 26);