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>
16 #include <sys/types.h>
25 #include <netinet/in.h>
35 #include <afs/afsint.h>
37 #include <afs/afs_assert.h>
38 #include <afs/prs_fs.h>
42 #include <afs/cellconfig.h>
45 #include <afs/ihandle.h>
47 #include <afs/ntops.h>
49 #include <afs/vnode.h>
50 #include <afs/volume.h>
51 #include <afs/volume_inline.h>
52 #include <afs/partition.h>
54 #include <afs/daemon_com.h>
55 #include <afs/fssync.h>
57 #include "afs/audit.h"
59 #include <afs/afsutil.h>
60 #include <afs/com_err.h>
61 #include <afs/vol_prototypes.h>
62 #include <afs/errors.h>
65 #include "voltrans_inline.h"
68 #include "volser_internal.h"
70 #include "dumpstuff.h"
73 extern struct afsconf_dir
*tdir
;
74 extern int DoPreserveVolumeStats
;
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
);
134 * Return the host address of the caller as a string.
136 * @param[in] acid incoming rx call
137 * @param[out] buffer buffer to be filled with the addess string
139 * @return address as formatted by inet_ntoa
142 callerAddress(struct rx_call
*acid
, char *buffer
)
144 afs_uint32 ip
= rx_HostOf(rx_PeerOf(rx_ConnectionOf(acid
)));
145 return afs_inet_ntoa_r(ip
, buffer
);
148 /* this call unlocks all of the partition locks we've set */
152 struct DiskPartition64
*tp
;
153 for (tp
= DiskPartitionList
; tp
; tp
= tp
->next
) {
154 if (tp
->lock_fd
!= INVALID_FD
) {
155 OS_CLOSE(tp
->lock_fd
);
156 tp
->lock_fd
= INVALID_FD
;
167 code
= VPFullUnlock_r();
172 /* get partition id from a name */
174 PartitionID(char *aname
)
182 return -1; /* unknown */
184 /* otherwise check for vicepa or /vicepa, or just plain "a" */
186 if (!strncmp(aname
, "/vicep", 6)) {
187 strncpy(ascii
, aname
+ 6, 2);
189 return -1; /* bad partition name */
190 /* now partitions are named /vicepa ... /vicepz, /vicepaa, /vicepab, .../vicepzz, and are numbered
191 * from 0. Do the appropriate conversion */
193 /* one char name, 0..25 */
194 if (ascii
[0] < 'a' || ascii
[0] > 'z')
195 return -1; /* wrongo */
196 return ascii
[0] - 'a';
198 /* two char name, 26 .. <whatever> */
199 if (ascii
[0] < 'a' || ascii
[0] > 'z')
200 return -1; /* wrongo */
201 if (ascii
[1] < 'a' || ascii
[1] > 'z')
202 return -1; /* just as bad */
203 code
= (ascii
[0] - 'a') * 26 + (ascii
[1] - 'a') + 26;
204 if (code
> VOLMAXPARTS
)
211 ConvertVolume(afs_uint32 avol
, char *aname
, afs_int32 asize
)
215 /* 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 */
216 (void)afs_snprintf(aname
, asize
, VFORMAT
, (unsigned long)avol
);
221 ConvertPartition(int apartno
, char *aname
, int asize
)
227 strcpy(aname
, "/vicep");
229 aname
[6] = 'a' + apartno
;
233 aname
[6] = 'a' + (apartno
/ 26);
234 aname
[7] = 'a' + (apartno
% 26);
240 #ifdef AFS_DEMAND_ATTACH_FS
241 /* normally we should use the regular salvaging functions from the volume
242 * package, but this is a special case where we have a volume ID, but no
243 * volume structure to give the volume package */
245 SalvageUnknownVolume(VolumeId volid
, char *part
)
249 Log("Scheduling salvage for allegedly nonexistent volume %lu part %s\n",
250 afs_printable_uint32_lu(volid
), part
);
252 code
= FSYNC_VolOp(volid
, part
, FSYNC_VOL_FORCE_ERROR
,
253 FSYNC_SALVAGE
, NULL
);
255 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
256 afs_printable_int32_ld(code
), afs_printable_uint32_lu(volid
),
260 #endif /* AFS_DEMAND_ATTACH_FS */
262 static struct Volume
*
263 VAttachVolumeByName_retry(Error
*ec
, char *partition
, char *name
, int mode
)
268 vp
= VAttachVolumeByName(ec
, partition
, name
, mode
);
270 #ifdef AFS_DEMAND_ATTACH_FS
274 * The fileserver will take care of keeping track of how many
275 * demand-salvages have been performed, and will force the volume to
276 * ERROR if we've done too many. The limit on This loop is just a
277 * failsafe to prevent trying to salvage forever. We want to attempt
278 * attachment at least SALVAGE_COUNT_MAX times, since we want to
279 * avoid prematurely exiting this loop, if we can.
281 for (i
= 0; i
< SALVAGE_COUNT_MAX
*2 && *ec
== VSALVAGING
; i
++) {
282 sleep(SALVAGE_PRIO_UPDATE_INTERVAL
);
283 vp
= VAttachVolumeByName(ec
, partition
, name
, mode
);
286 if (*ec
== VSALVAGING
) {
290 #endif /* AFS_DEMAND_ATTACH_FS */
295 static struct Volume
*
296 VAttachVolume_retry(Error
*ec
, afs_uint32 avolid
, int amode
)
301 vp
= VAttachVolume(ec
, avolid
, amode
);
303 #ifdef AFS_DEMAND_ATTACH_FS
306 /* see comment above in VAttachVolumeByName_retry */
307 for (i
= 0; i
< SALVAGE_COUNT_MAX
*2 && *ec
== VSALVAGING
; i
++) {
308 sleep(SALVAGE_PRIO_UPDATE_INTERVAL
);
309 vp
= VAttachVolume(ec
, avolid
, amode
);
312 if (*ec
== VSALVAGING
) {
316 #endif /* AFS_DEMAND_ATTACH_FS */
321 /* the only attach function that takes a partition is "...ByName", so we use it */
322 static struct Volume
*
323 XAttachVolume(afs_int32
*error
, afs_uint32 avolid
, afs_int32 apartid
, int amode
)
325 char pbuf
[30], vbuf
[20];
327 if (ConvertPartition(apartid
, pbuf
, sizeof(pbuf
))) {
331 if (ConvertVolume(avolid
, vbuf
, sizeof(vbuf
))) {
336 return VAttachVolumeByName_retry((Error
*)error
, pbuf
, vbuf
, amode
);
339 /* Adapted from the file server; create a root directory for this volume */
341 ViceCreateRoot(Volume
*vp
)
344 struct acl_accessList
*ACL
;
346 Inode inodeNumber
, nearInode AFS_UNUSED
;
347 struct VnodeDiskObject
*vnode
;
348 struct VnodeClassInfo
*vcp
= &VnodeClassInfo
[vLarge
];
354 vnode
= (struct VnodeDiskObject
*)malloc(SIZEOF_LARGEDISKVNODE
);
357 memset(vnode
, 0, SIZEOF_LARGEDISKVNODE
);
359 V_pref(vp
, nearInode
);
361 IH_CREATE(V_linkHandle(vp
), V_device(vp
),
362 VPartitionPath(V_partition(vp
)), nearInode
, V_parentId(vp
),
364 if (!VALID_INO(inodeNumber
)) {
365 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno
));
370 SetSalvageDirHandle(&dir
, V_parentId(vp
), vp
->device
, inodeNumber
);
371 did
.Volume
= V_id(vp
);
372 did
.Vnode
= (VnodeId
) 1;
375 osi_Assert(!(MakeDir(&dir
, (afs_int32
*)&did
, (afs_int32
*)&did
)));
376 DFlush(); /* flush all modified dir buffers out */
377 DZap((afs_int32
*)&dir
); /* Remove all buffers for this dir */
378 length
= Length(&dir
); /* Remember size of this directory */
380 FidZap(&dir
); /* Done with the dir handle obtained via SetSalvageDirHandle() */
382 /* build a single entry ACL that gives all rights to system:administrators */
383 /* this section of code assumes that access list format is not going to
386 ACL
= VVnodeDiskACL(vnode
);
387 ACL
->size
= sizeof(struct acl_accessList
);
388 ACL
->version
= ACL_ACLVERSION
;
392 ACL
->entries
[0].id
= -204; /* this assumes System:administrators is group -204 */
393 ACL
->entries
[0].rights
=
394 PRSFS_READ
| PRSFS_WRITE
| PRSFS_INSERT
| PRSFS_LOOKUP
| PRSFS_DELETE
395 | PRSFS_LOCK
| PRSFS_ADMINISTER
;
397 vnode
->type
= vDirectory
;
399 vnode
->modeBits
= 0777;
400 vnode
->linkCount
= 2;
401 VNDISK_SET_LEN(vnode
, length
);
402 vnode
->uniquifier
= 1;
403 V_uniquifier(vp
) = vnode
->uniquifier
+ 1;
404 vnode
->dataVersion
= 1;
405 VNDISK_SET_INO(vnode
, inodeNumber
);
406 vnode
->unixModifyTime
= vnode
->serverModifyTime
= V_creationDate(vp
);
410 vnode
->vnodeMagic
= vcp
->magic
;
412 IH_INIT(h
, vp
->device
, V_parentId(vp
),
413 vp
->vnodeIndex
[vLarge
].handle
->ih_ino
);
415 osi_Assert(fdP
!= NULL
);
416 nBytes
= FDH_PWRITE(fdP
, vnode
, SIZEOF_LARGEDISKVNODE
, vnodeIndexOffset(vcp
, 1));
417 osi_Assert(nBytes
== SIZEOF_LARGEDISKVNODE
);
418 FDH_REALLYCLOSE(fdP
);
420 VNDISK_GET_LEN(length
, vnode
);
421 V_diskused(vp
) = nBlocks(length
);
428 SAFSVolPartitionInfo(struct rx_call
*acid
, char *pname
, struct diskPartition
432 struct diskPartition64
*dp
= (struct diskPartition64
*)
433 malloc(sizeof(struct diskPartition64
));
435 code
= VolPartitionInfo(acid
, pname
, dp
);
437 strncpy(partition
->name
, dp
->name
, 32);
438 strncpy(partition
->devName
, dp
->devName
, 32);
439 partition
->lock_fd
= dp
->lock_fd
;
440 partition
->free
=RoundInt64ToInt32(dp
->free
);
441 partition
->minFree
=RoundInt64ToInt32(dp
->minFree
);
444 osi_auditU(acid
, VS_ParInfEvent
, code
, AUD_STR
, pname
, AUD_END
);
449 SAFSVolPartitionInfo64(struct rx_call
*acid
, char *pname
, struct diskPartition64
454 code
= VolPartitionInfo(acid
, pname
, partition
);
455 osi_auditU(acid
, VS_ParInfEvent
, code
, AUD_STR
, pname
, AUD_END
);
460 VolPartitionInfo(struct rx_call
*acid
, char *pname
, struct diskPartition64
463 struct DiskPartition64
*dp
;
466 dp
= VGetPartition(pname
, 0);
468 strncpy(partition
->name
, dp
->name
, 32);
469 strncpy(partition
->devName
, dp
->devName
, 32);
470 partition
->lock_fd
= (int)dp
->lock_fd
;
471 partition
->free
= dp
->free
;
472 partition
->minFree
= dp
->totalUsable
;
475 return VOLSERILLEGAL_PARTITION
;
478 /* obliterate a volume completely, and slowly. */
480 SAFSVolNukeVolume(struct rx_call
*acid
, afs_int32 apartID
, afs_uint32 avolID
)
484 code
= VolNukeVolume(acid
, apartID
, avolID
);
485 osi_auditU(acid
, VS_NukVolEvent
, code
, AUD_LONG
, avolID
, AUD_END
);
490 VolNukeVolume(struct rx_call
*acid
, afs_int32 apartID
, afs_uint32 avolID
)
497 char caller
[MAXKTCNAMELEN
];
499 /* check for access */
500 if (!afsconf_SuperUser(tdir
, acid
, caller
))
501 return VOLSERBAD_ACCESS
;
504 Log("%s on %s is executing VolNukeVolume %u\n", caller
,
505 callerAddress(acid
, buffer
), avolID
);
508 if (volutil_PartitionName2_r(apartID
, partName
, sizeof(partName
)) != 0)
510 /* we first try to attach the volume in update mode, so that the file
511 * server doesn't try to use it (and abort) while (or after) we delete it.
512 * If we don't get the volume, that's fine, too. We just won't put it back.
514 tvp
= XAttachVolume(&error
, avolID
, apartID
, V_VOLUPD
);
515 code
= nuke(partName
, avolID
);
517 VDetachVolume(&verror
, tvp
);
521 /* create a new volume, with name aname, on the specified partition (1..n)
522 * and of type atype (readwriteVolume, readonlyVolume, backupVolume).
523 * As input, if *avolid is 0, we allocate a new volume id, otherwise we use *avolid
524 * for the volume id (useful for things like volume restore).
525 * Return the new volume id in *avolid.
528 SAFSVolCreateVolume(struct rx_call
*acid
, afs_int32 apart
, char *aname
,
529 afs_int32 atype
, afs_uint32 aparent
, afs_uint32
*avolid
,
535 VolCreateVolume(acid
, apart
, aname
, atype
, aparent
, avolid
, atrans
);
536 osi_auditU(acid
, VS_CrVolEvent
, code
, AUD_LONG
, *atrans
, AUD_LONG
,
537 *avolid
, AUD_STR
, aname
, AUD_LONG
, atype
, AUD_LONG
, aparent
,
543 VolCreateVolume(struct rx_call
*acid
, afs_int32 apart
, char *aname
,
544 afs_int32 atype
, afs_uint32 aparent
, afs_uint32
*avolid
,
549 Error junk
; /* discardable error code */
551 afs_int32 doCreateRoot
= 1;
552 struct volser_trans
*tt
;
554 char caller
[MAXKTCNAMELEN
];
556 if (strlen(aname
) > 31)
557 return VOLSERBADNAME
;
558 if (!afsconf_SuperUser(tdir
, acid
, caller
))
559 return VOLSERBAD_ACCESS
;
562 Log("%s on %s is executing CreateVolume '%s'\n", caller
,
563 callerAddress(acid
, buffer
), aname
);
565 if ((error
= ConvertPartition(apart
, ppath
, sizeof(ppath
))))
566 return error
; /*a standard unix error */
567 if (atype
!= readwriteVolume
&& atype
!= readonlyVolume
568 && atype
!= backupVolume
)
570 if ((volumeID
= *avolid
) == 0) {
572 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname
);
576 if ((aparent
== volumeID
) && (atype
== readwriteVolume
)) {
581 tt
= NewTrans(volumeID
, apart
);
583 Log("1 createvolume: failed to create trans\n");
584 return VOLSERVOLBUSY
; /* volume already busy! */
586 vp
= VCreateVolume(&error
, ppath
, volumeID
, aparent
);
588 #ifdef AFS_DEMAND_ATTACH_FS
589 if (error
!= VVOLEXISTS
&& error
!= EXDEV
) {
590 SalvageUnknownVolume(volumeID
, ppath
);
593 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error
);
598 V_uniquifier(vp
) = 1;
599 V_updateDate(vp
) = V_creationDate(vp
) = V_copyDate(vp
);
600 V_inService(vp
) = V_blessed(vp
) = 1;
602 AssignVolumeName(&V_disk(vp
), aname
, 0);
604 error
= ViceCreateRoot(vp
);
606 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
607 "error code %u\n", (unsigned)error
);
609 V_needsSalvaged(vp
) = 1;
610 VDetachVolume(&junk
, vp
);
614 V_destroyMe(vp
) = DESTROY_ME
;
616 V_maxquota(vp
) = 5000; /* set a quota of 5000 at init time */
617 VUpdateVolume(&error
, vp
);
619 Log("1 Volser: create UpdateVolume failed, code %d\n", error
);
622 VDetachVolume(&junk
, vp
); /* rather return the real error code */
628 TSetRxCall_r(tt
, acid
, "CreateVolume");
629 VTRANS_OBJ_UNLOCK(tt
);
630 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID
, aname
);
633 return VOLSERTRELE_ERROR
;
637 /* delete the volume associated with this transaction */
639 SAFSVolDeleteVolume(struct rx_call
*acid
, afs_int32 atrans
)
643 code
= VolDeleteVolume(acid
, atrans
);
644 osi_auditU(acid
, VS_DelVolEvent
, code
, AUD_LONG
, atrans
, AUD_END
);
649 VolDeleteVolume(struct rx_call
*acid
, afs_int32 atrans
)
651 struct volser_trans
*tt
;
653 char caller
[MAXKTCNAMELEN
];
655 if (!afsconf_SuperUser(tdir
, acid
, caller
))
656 return VOLSERBAD_ACCESS
;
657 tt
= FindTrans(atrans
);
660 if (tt
->vflags
& VTDeleted
) {
661 Log("1 Volser: Delete: volume %u already deleted \n", tt
->volid
);
667 Log("%s on %s is executing Delete Volume %u\n", caller
,
668 callerAddress(acid
, buffer
), tt
->volid
);
670 TSetRxCall(tt
, acid
, "DeleteVolume");
671 VPurgeVolume(&error
, tt
->volume
); /* don't check error code, it is not set! */
672 V_destroyMe(tt
->volume
) = DESTROY_ME
;
673 if (tt
->volume
->needsPutBack
) {
674 tt
->volume
->needsPutBack
= VOL_PUTBACK_DELETE
; /* so endtrans does the right fssync opcode */
677 tt
->vflags
|= VTDeleted
; /* so we know not to do anything else to it */
679 VTRANS_OBJ_UNLOCK(tt
);
681 return VOLSERTRELE_ERROR
;
683 Log("1 Volser: Delete: volume %u deleted \n", tt
->volid
);
684 return 0; /* vpurgevolume doesn't set an error code */
687 /* make a clone of the volume associated with atrans, possibly giving it a new
688 * number (allocate a new number if *newNumber==0, otherwise use *newNumber
689 * for the clone's id). The new clone is given the name newName. Finally,
690 * due to efficiency considerations, if purgeId is non-zero, we purge that
691 * volume when doing the clone operation. This may be useful when making
692 * new backup volumes, for instance since the net result of a clone and a
693 * purge generally leaves many inode ref counts the same, while doing them
694 * separately would result in far more iincs and idecs being peformed
695 * (and they are slow operations).
697 /* for efficiency reasons, sometimes faster to piggyback a purge here */
699 SAFSVolClone(struct rx_call
*acid
, afs_int32 atrans
, afs_uint32 purgeId
,
700 afs_int32 newType
, char *newName
, afs_uint32
*newNumber
)
704 code
= VolClone(acid
, atrans
, purgeId
, newType
, newName
, newNumber
);
705 osi_auditU(acid
, VS_CloneEvent
, code
, AUD_LONG
, atrans
, AUD_LONG
, purgeId
,
706 AUD_STR
, newName
, AUD_LONG
, newType
, AUD_LONG
, *newNumber
,
712 VolClone(struct rx_call
*acid
, afs_int32 atrans
, afs_uint32 purgeId
,
713 afs_int32 newType
, char *newName
, afs_uint32
*newNumber
)
716 struct Volume
*originalvp
, *purgevp
, *newvp
;
718 struct volser_trans
*tt
, *ttc
;
719 char caller
[MAXKTCNAMELEN
];
720 #ifdef AFS_DEMAND_ATTACH_FS
721 struct Volume
*salv_vp
= NULL
;
724 if (strlen(newName
) > 31)
725 return VOLSERBADNAME
;
726 if (!afsconf_SuperUser(tdir
, acid
, caller
))
727 return VOLSERBAD_ACCESS
; /*not a super user */
730 Log("%s on %s is executing Clone Volume new name=%s\n", caller
,
731 callerAddress(acid
, buffer
), newName
);
734 originalvp
= (Volume
*) 0;
735 purgevp
= (Volume
*) 0;
736 newvp
= (Volume
*) 0;
737 tt
= ttc
= (struct volser_trans
*)0;
739 if (!newNumber
|| !*newNumber
) {
740 Log("1 Volser: Clone: missing volume number for the clone; aborted\n");
745 tt
= FindTrans(atrans
);
748 if (tt
->vflags
& VTDeleted
) {
749 Log("1 Volser: Clone: volume %u has been deleted \n", tt
->volid
);
753 ttc
= NewTrans(newId
, tt
->partition
);
754 if (!ttc
) { /* someone is messing with the clone already */
756 return VOLSERVOLBUSY
;
758 TSetRxCall(tt
, acid
, "Clone");
762 purgevp
= VAttachVolume_retry(&error
, purgeId
, V_VOLUPD
);
764 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId
);
770 originalvp
= tt
->volume
;
771 if ((V_destroyMe(originalvp
) == DESTROY_ME
) || !V_inService(originalvp
)) {
772 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
778 if (originalvp
->device
!= purgevp
->device
) {
779 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt
->volid
, purgeId
);
783 if (V_type(purgevp
) != readonlyVolume
) {
784 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
788 if (V_parentId(originalvp
) != V_parentId(purgevp
)) {
789 Log("1 Volser: Clone: Volume %u and volume %u were not originally cloned from the same parent; aborted\n", purgeId
, tt
->volid
);
796 #ifdef AFS_DEMAND_ATTACH_FS
797 salv_vp
= originalvp
;
800 if (purgeId
== newId
) {
804 VCreateVolume(&error
, originalvp
->partition
->name
, newId
,
805 V_parentId(originalvp
));
807 Log("1 Volser: Clone: Couldn't create new volume %lu for parent %lu; clone aborted\n",
808 afs_printable_uint32_lu(newId
), afs_printable_uint32_lu(V_parentId(originalvp
)));
809 newvp
= (Volume
*) 0;
813 if (newType
== readonlyVolume
)
814 V_cloneId(originalvp
) = newId
;
815 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt
->volid
,
818 Log("1 Volser: Clone: Purging old read only volume %u\n", purgeId
);
819 CloneVolume(&error
, originalvp
, newvp
, purgevp
);
820 purgevp
= NULL
; /* clone releases it, maybe even if error */
822 Log("1 Volser: Clone: clone operation failed with code %u\n", error
);
826 if (newType
== readonlyVolume
) {
827 AssignVolumeName(&V_disk(newvp
), V_name(originalvp
), ".readonly");
828 V_type(newvp
) = readonlyVolume
;
829 } else if (newType
== backupVolume
) {
830 AssignVolumeName(&V_disk(newvp
), V_name(originalvp
), ".backup");
831 V_type(newvp
) = backupVolume
;
832 V_backupId(originalvp
) = newId
;
834 strcpy(newvp
->header
->diskstuff
.name
, newName
);
835 V_creationDate(newvp
) = V_copyDate(newvp
);
836 ClearVolumeStats(&V_disk(newvp
));
837 V_destroyMe(newvp
) = DESTROY_ME
;
838 V_inService(newvp
) = 0;
839 if (newType
== backupVolume
) {
840 V_backupDate(originalvp
) = V_copyDate(newvp
);
841 V_backupDate(newvp
) = V_copyDate(newvp
);
844 VUpdateVolume(&error
, newvp
);
846 Log("1 Volser: Clone: VUpdate failed code %u\n", error
);
850 VDetachVolume(&error
, newvp
); /* allow file server to get it's hands on it */
852 VUpdateVolume(&error
, originalvp
);
854 Log("1 Volser: Clone: original update %u\n", error
);
859 #ifdef AFS_DEMAND_ATTACH_FS
863 tt
= (struct volser_trans
*)0;
864 error
= VOLSERTRELE_ERROR
;
872 VDetachVolume(&code
, purgevp
);
874 VDetachVolume(&code
, newvp
);
881 #ifdef AFS_DEMAND_ATTACH_FS
882 if (salv_vp
&& error
!= VVOLEXISTS
&& error
!= EXDEV
) {
883 V_needsSalvaged(salv_vp
) = 1;
885 #endif /* AFS_DEMAND_ATTACH_FS */
889 /* reclone this volume into the specified id */
891 SAFSVolReClone(struct rx_call
*acid
, afs_int32 atrans
, afs_uint32 cloneId
)
895 code
= VolReClone(acid
, atrans
, cloneId
);
896 osi_auditU(acid
, VS_ReCloneEvent
, code
, AUD_LONG
, atrans
, AUD_LONG
,
902 VolReClone(struct rx_call
*acid
, afs_int32 atrans
, afs_int32 cloneId
)
904 struct Volume
*originalvp
, *clonevp
;
907 struct volser_trans
*tt
, *ttc
;
908 char caller
[MAXKTCNAMELEN
];
909 VolumeDiskData saved_header
;
911 /*not a super user */
912 if (!afsconf_SuperUser(tdir
, acid
, caller
))
913 return VOLSERBAD_ACCESS
;
916 Log("%s on %s is executing Reclone Volume %u\n", caller
,
917 callerAddress(acid
, buffer
), cloneId
);
920 clonevp
= originalvp
= (Volume
*) 0;
921 tt
= (struct volser_trans
*)0;
923 tt
= FindTrans(atrans
);
926 if (tt
->vflags
& VTDeleted
) {
927 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt
->volid
);
931 ttc
= NewTrans(cloneId
, tt
->partition
);
932 if (!ttc
) { /* someone is messing with the clone already */
934 return VOLSERVOLBUSY
;
936 TSetRxCall(tt
, acid
, "ReClone");
938 originalvp
= tt
->volume
;
939 if ((V_destroyMe(originalvp
) == DESTROY_ME
) || !V_inService(originalvp
)) {
940 Log("1 Volser: Clone: Volume %d is offline and cannot be cloned\n",
946 clonevp
= VAttachVolume_retry(&error
, cloneId
, V_VOLUPD
);
948 Log("1 Volser: can't attach clone %d\n", cloneId
);
952 newType
= V_type(clonevp
); /* type of the new volume */
954 if (originalvp
->device
!= clonevp
->device
) {
955 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n",
960 if (V_parentId(originalvp
) != V_parentId(clonevp
)) {
961 Log("1 Volser: Clone: Volume %u was not originally cloned from volume %u; aborted\n", cloneId
, tt
->volid
);
966 if (DoPreserveVolumeStats
) {
967 CopyVolumeStats(&V_disk(clonevp
), &saved_header
);
971 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt
->volid
,
973 CloneVolume(&error
, originalvp
, clonevp
, clonevp
);
975 Log("1 Volser: Clone: reclone operation failed with code %d\n",
981 /* fix up volume name and type, CloneVolume just propagated RW's */
982 if (newType
== readonlyVolume
) {
983 AssignVolumeName(&V_disk(clonevp
), V_name(originalvp
), ".readonly");
984 V_type(clonevp
) = readonlyVolume
;
985 } else if (newType
== backupVolume
) {
986 AssignVolumeName(&V_disk(clonevp
), V_name(originalvp
), ".backup");
987 V_type(clonevp
) = backupVolume
;
988 V_backupId(originalvp
) = cloneId
;
990 /* don't do strcpy onto diskstuff.name, it's still OK from 1st clone */
992 /* update the creationDate, since this represents the last cloning date
993 * for ROs. But do not update copyDate; let it stay so we can identify
994 * when the clone was first created. */
995 V_creationDate(clonevp
) = time(0);
996 if (DoPreserveVolumeStats
) {
997 CopyVolumeStats(&saved_header
, &V_disk(clonevp
));
999 ClearVolumeStats(&V_disk(clonevp
));
1001 V_destroyMe(clonevp
) = 0;
1002 V_inService(clonevp
) = 0;
1003 if (newType
== backupVolume
) {
1004 V_backupDate(originalvp
) = V_creationDate(clonevp
);
1005 V_backupDate(clonevp
) = V_creationDate(clonevp
);
1007 V_inUse(clonevp
) = 0;
1008 VUpdateVolume(&error
, clonevp
);
1010 Log("1 Volser: Clone: VUpdate failed code %u\n", error
);
1014 /* VUpdateVolume succeeded. Mark it in service so there's no window
1015 * between FSYNC_VOL_ON and VolSetFlags where it's offline with no
1016 * specialStatus; this is a reclone and this volume started online
1018 V_inService(clonevp
) = 1;
1019 VDetachVolume(&error
, clonevp
); /* allow file server to get it's hands on it */
1021 VUpdateVolume(&error
, originalvp
);
1023 Log("1 Volser: Clone: original update %u\n", error
);
1029 tt
= (struct volser_trans
*)0;
1030 error
= VOLSERTRELE_ERROR
;
1034 DeleteTrans(ttc
, 1);
1037 struct DiskPartition64
*tpartp
= originalvp
->partition
;
1038 FSYNC_VolOp(cloneId
, tpartp
->name
, FSYNC_VOL_BREAKCBKS
, 0, NULL
);
1044 VDetachVolume(&code
, clonevp
);
1050 DeleteTrans(ttc
, 1);
1054 /* create a new transaction, associated with volume and partition. Type of
1055 * volume transaction is spec'd by iflags. New trans id is returned in ttid.
1056 * See volser.h for definition of iflags (the constants are named IT*).
1059 SAFSVolTransCreate(struct rx_call
*acid
, afs_uint32 volume
, afs_int32 partition
,
1060 afs_int32 iflags
, afs_int32
*ttid
)
1064 code
= VolTransCreate(acid
, volume
, partition
, iflags
, ttid
);
1065 osi_auditU(acid
, VS_TransCrEvent
, code
, AUD_LONG
, *ttid
, AUD_LONG
, volume
,
1071 VolTransCreate(struct rx_call
*acid
, afs_uint32 volume
, afs_int32 partition
,
1072 afs_int32 iflags
, afs_int32
*ttid
)
1074 struct volser_trans
*tt
;
1079 char caller
[MAXKTCNAMELEN
];
1081 if (!afsconf_SuperUser(tdir
, acid
, caller
))
1082 return VOLSERBAD_ACCESS
; /*not a super user */
1083 if (iflags
& ITCreate
)
1085 else if (iflags
& ITBusy
)
1087 else if (iflags
& ITReadOnly
)
1089 else if (iflags
& ITOffline
)
1092 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1097 tt
= NewTrans(volume
, partition
);
1099 /* can't create a transaction? put the volume back */
1100 Log("1 transcreate: can't create transaction\n");
1101 return VOLSERVOLBUSY
;
1103 tv
= XAttachVolume(&error
, volume
, partition
, mode
);
1107 VDetachVolume(&code
, tv
);
1111 VTRANS_OBJ_LOCK(tt
);
1114 tt
->iflags
= iflags
;
1116 TSetRxCall_r(tt
, NULL
, "TransCreate");
1117 VTRANS_OBJ_UNLOCK(tt
);
1119 return VOLSERTRELE_ERROR
;
1124 /* using aindex as a 0-based index, return the aindex'th volume on this server
1125 * Both the volume number and partition number (one-based) are returned.
1128 SAFSVolGetNthVolume(struct rx_call
*acid
, afs_int32 aindex
, afs_uint32
*avolume
,
1133 code
= VolGetNthVolume(acid
, aindex
, avolume
, apart
);
1134 osi_auditU(acid
, VS_GetNVolEvent
, code
, AUD_LONG
, *avolume
, AUD_END
);
1139 VolGetNthVolume(struct rx_call
*acid
, afs_int32 aindex
, afs_uint32
*avolume
,
1142 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1146 /* return the volume flags (VT* constants in volser.h) associated with this
1150 SAFSVolGetFlags(struct rx_call
*acid
, afs_int32 atid
, afs_int32
*aflags
)
1154 code
= VolGetFlags(acid
, atid
, aflags
);
1155 osi_auditU(acid
, VS_GetFlgsEvent
, code
, AUD_LONG
, atid
, AUD_END
);
1160 VolGetFlags(struct rx_call
*acid
, afs_int32 atid
, afs_int32
*aflags
)
1162 struct volser_trans
*tt
;
1164 tt
= FindTrans(atid
);
1167 if (tt
->vflags
& VTDeleted
) {
1168 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1173 TSetRxCall(tt
, acid
, "GetFlags");
1174 *aflags
= tt
->vflags
;
1177 return VOLSERTRELE_ERROR
;
1182 /* Change the volume flags (VT* constants in volser.h) associated with this
1183 * transaction. Effects take place immediately on volume, although volume
1184 * remains attached as usual by the transaction.
1187 SAFSVolSetFlags(struct rx_call
*acid
, afs_int32 atid
, afs_int32 aflags
)
1191 code
= VolSetFlags(acid
, atid
, aflags
);
1192 osi_auditU(acid
, VS_SetFlgsEvent
, code
, AUD_LONG
, atid
, AUD_LONG
, aflags
,
1198 VolSetFlags(struct rx_call
*acid
, afs_int32 atid
, afs_int32 aflags
)
1200 struct volser_trans
*tt
;
1203 char caller
[MAXKTCNAMELEN
];
1205 if (!afsconf_SuperUser(tdir
, acid
, caller
))
1206 return VOLSERBAD_ACCESS
; /*not a super user */
1207 /* find the trans */
1208 tt
= FindTrans(atid
);
1211 if (tt
->vflags
& VTDeleted
) {
1212 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1217 TSetRxCall(tt
, acid
, "SetFlags");
1218 vp
= tt
->volume
; /* pull volume out of transaction */
1220 /* check if we're allowed to make any updates */
1221 if (tt
->iflags
& ITReadOnly
) {
1226 /* handle delete-on-salvage flag */
1227 if (aflags
& VTDeleteOnSalvage
) {
1228 V_destroyMe(tt
->volume
) = DESTROY_ME
;
1230 V_destroyMe(tt
->volume
) = 0;
1233 if (aflags
& VTOutOfService
) {
1234 V_inService(vp
) = 0;
1236 V_inService(vp
) = 1;
1238 VUpdateVolume(&error
, vp
);
1239 VTRANS_OBJ_LOCK(tt
);
1240 tt
->vflags
= aflags
;
1242 VTRANS_OBJ_UNLOCK(tt
);
1243 if (TRELE(tt
) && !error
)
1244 return VOLSERTRELE_ERROR
;
1249 /* dumpS the volume associated with a particular transaction from a particular
1250 * date. Send the dump to a different transaction (destTrans) on the server
1251 * specified by the destServer structure.
1254 SAFSVolForward(struct rx_call
*acid
, afs_int32 fromTrans
, afs_int32 fromDate
,
1255 struct destServer
*destination
, afs_int32 destTrans
,
1256 struct restoreCookie
*cookie
)
1261 VolForward(acid
, fromTrans
, fromDate
, destination
, destTrans
, cookie
);
1262 osi_auditU(acid
, VS_ForwardEvent
, code
, AUD_LONG
, fromTrans
, AUD_HOST
,
1263 htonl(destination
->destHost
), AUD_LONG
, destTrans
, AUD_END
);
1268 VolForward(struct rx_call
*acid
, afs_int32 fromTrans
, afs_int32 fromDate
,
1269 struct destServer
*destination
, afs_int32 destTrans
,
1270 struct restoreCookie
*cookie
)
1272 struct volser_trans
*tt
;
1274 struct rx_connection
*tcon
;
1275 struct rx_call
*tcall
;
1277 struct rx_securityClass
*securityObject
;
1278 afs_int32 securityIndex
;
1279 char caller
[MAXKTCNAMELEN
];
1281 if (!afsconf_SuperUser(tdir
, acid
, caller
))
1282 return VOLSERBAD_ACCESS
; /*not a super user */
1283 /* initialize things */
1284 tcon
= (struct rx_connection
*)0;
1285 tt
= (struct volser_trans
*)0;
1287 /* find the local transaction */
1288 tt
= FindTrans(fromTrans
);
1291 if (tt
->vflags
& VTDeleted
) {
1292 Log("1 Volser: VolForward: volume %u has been deleted \n", tt
->volid
);
1297 TSetRxCall(tt
, NULL
, "Forward");
1299 /* get auth info for the this connection (uses afs from ticket file) */
1300 code
= afsconf_ClientAuth(tdir
, &securityObject
, &securityIndex
);
1306 /* make an rpc connection to the other server */
1308 rx_NewConnection(htonl(destination
->destHost
),
1309 htons(destination
->destPort
), VOLSERVICE_ID
,
1310 securityObject
, securityIndex
);
1316 tcall
= rx_NewCall(tcon
);
1317 TSetRxCall(tt
, tcall
, "Forward");
1318 /* start restore going. fromdate == 0 --> doing an incremental dump/restore */
1319 code
= StartAFSVolRestore(tcall
, destTrans
, (fromDate
? 1 : 0), cookie
);
1324 /* these next calls implictly call rx_Write when writing out data */
1325 code
= DumpVolume(tcall
, vp
, fromDate
, 0); /* last field = don't dump all dirs */
1328 EndAFSVolRestore(tcall
); /* probably doesn't do much */
1330 code
= rx_EndCall(tcall
, 0);
1331 rx_DestroyConnection(tcon
); /* done with the connection */
1336 return VOLSERTRELE_ERROR
;
1342 (void)rx_EndCall(tcall
, 0);
1343 rx_DestroyConnection(tcon
);
1352 /* Start a dump and send it to multiple places simultaneously.
1353 * If this returns an error (eg, return ENOENT), it means that
1354 * none of the releases worked. If this returns 0, that means
1355 * that one or more of the releases worked, and the caller has
1356 * to examine the results array to see which one(s).
1357 * This will only do EITHER incremental or full, not both, so it's
1358 * the caller's responsibility to be sure that all the destinations
1359 * need just an incremental (and from the same time), if that's
1363 SAFSVolForwardMultiple(struct rx_call
*acid
, afs_int32 fromTrans
, afs_int32
1364 fromDate
, manyDests
*destinations
, afs_int32 spare
,
1365 struct restoreCookie
*cookie
, manyResults
*results
)
1367 afs_int32 securityIndex
;
1368 struct rx_securityClass
*securityObject
;
1369 char caller
[MAXKTCNAMELEN
];
1370 struct volser_trans
*tt
;
1371 afs_int32 ec
, code
, *codes
;
1372 struct rx_connection
**tcons
;
1373 struct rx_call
**tcalls
;
1375 int i
, is_incremental
;
1378 memset(results
, 0, sizeof(manyResults
));
1379 i
= results
->manyResults_len
= destinations
->manyDests_len
;
1380 results
->manyResults_val
= codes
=
1381 (afs_int32
*) malloc(i
* sizeof(afs_int32
));
1383 if (!results
|| !results
->manyResults_val
)
1386 if (!afsconf_SuperUser(tdir
, acid
, caller
))
1387 return VOLSERBAD_ACCESS
; /*not a super user */
1388 tt
= FindTrans(fromTrans
);
1391 if (tt
->vflags
& VTDeleted
) {
1392 Log("1 Volser: VolForward: volume %u has been deleted \n", tt
->volid
);
1397 TSetRxCall(tt
, NULL
, "ForwardMulti");
1399 /* (fromDate == 0) ==> full dump */
1400 is_incremental
= (fromDate
? 1 : 0);
1403 (struct rx_connection
**)malloc(i
* sizeof(struct rx_connection
*));
1407 tcalls
= (struct rx_call
**)malloc(i
* sizeof(struct rx_call
*));
1413 /* get auth info for this connection (uses afs from ticket file) */
1414 code
= afsconf_ClientAuth(tdir
, &securityObject
, &securityIndex
);
1416 goto fail
; /* in order to audit each failure */
1419 /* make connections to all the other servers */
1420 for (i
= 0; i
< destinations
->manyDests_len
; i
++) {
1421 struct replica
*dest
= &(destinations
->manyDests_val
[i
]);
1423 rx_NewConnection(htonl(dest
->server
.destHost
),
1424 htons(dest
->server
.destPort
), VOLSERVICE_ID
,
1425 securityObject
, securityIndex
);
1427 codes
[i
] = ENOTCONN
;
1429 if (!(tcalls
[i
] = rx_NewCall(tcons
[i
])))
1430 codes
[i
] = ENOTCONN
;
1433 StartAFSVolRestore(tcalls
[i
], dest
->trans
, is_incremental
,
1436 (void)rx_EndCall(tcalls
[i
], 0);
1438 rx_DestroyConnection(tcons
[i
]);
1445 /* these next calls implictly call rx_Write when writing out data */
1446 code
= DumpVolMulti(tcalls
, i
, vp
, fromDate
, 0, codes
);
1450 for (i
--; i
>= 0; i
--) {
1451 struct replica
*dest
= &(destinations
->manyDests_val
[i
]);
1453 if (!code
&& tcalls
[i
] && !codes
[i
]) {
1454 EndAFSVolRestore(tcalls
[i
]);
1457 ec
= rx_EndCall(tcalls
[i
], 0);
1462 rx_DestroyConnection(tcons
[i
]); /* done with the connection */
1465 osi_auditU(acid
, VS_ForwardEvent
, (code
? code
: codes
[i
]), AUD_LONG
,
1466 fromTrans
, AUD_HOST
, htonl(dest
->server
.destHost
), AUD_LONG
,
1467 dest
->trans
, AUD_END
);
1474 if (TRELE(tt
) && !code
) /* return the first code if it's set */
1475 return VOLSERTRELE_ERROR
;
1482 SAFSVolDump(struct rx_call
*acid
, afs_int32 fromTrans
, afs_int32 fromDate
)
1486 code
= VolDump(acid
, fromTrans
, fromDate
, 0);
1487 osi_auditU(acid
, VS_DumpEvent
, code
, AUD_LONG
, fromTrans
, AUD_END
);
1492 SAFSVolDumpV2(struct rx_call
*acid
, afs_int32 fromTrans
, afs_int32 fromDate
,
1497 code
= VolDump(acid
, fromTrans
, fromDate
, flags
);
1498 osi_auditU(acid
, VS_DumpEvent
, code
, AUD_LONG
, fromTrans
, AUD_END
);
1503 VolDump(struct rx_call
*acid
, afs_int32 fromTrans
, afs_int32 fromDate
,
1507 struct volser_trans
*tt
;
1508 char caller
[MAXKTCNAMELEN
];
1510 if (!afsconf_SuperUser(tdir
, acid
, caller
))
1511 return VOLSERBAD_ACCESS
; /*not a super user */
1512 tt
= FindTrans(fromTrans
);
1515 if (tt
->vflags
& VTDeleted
) {
1516 Log("1 Volser: VolDump: volume %u has been deleted \n", tt
->volid
);
1520 TSetRxCall(tt
, acid
, "Dump");
1521 code
= DumpVolume(acid
, tt
->volume
, fromDate
, (flags
& VOLDUMPV2_OMITDIRS
)
1522 ? 0 : 1); /* squirt out the volume's data, too */
1531 return VOLSERTRELE_ERROR
;
1537 * Ha! No more helper process!
1540 SAFSVolRestore(struct rx_call
*acid
, afs_int32 atrans
, afs_int32 aflags
,
1541 struct restoreCookie
*cookie
)
1545 code
= VolRestore(acid
, atrans
, aflags
, cookie
);
1546 osi_auditU(acid
, VS_RestoreEvent
, code
, AUD_LONG
, atrans
, AUD_END
);
1551 VolRestore(struct rx_call
*acid
, afs_int32 atrans
, afs_int32 aflags
,
1552 struct restoreCookie
*cookie
)
1554 struct volser_trans
*tt
;
1555 afs_int32 code
, tcode
;
1556 char caller
[MAXKTCNAMELEN
];
1558 if (!afsconf_SuperUser(tdir
, acid
, caller
))
1559 return VOLSERBAD_ACCESS
; /*not a super user */
1560 tt
= FindTrans(atrans
);
1563 if (tt
->vflags
& VTDeleted
) {
1564 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt
->volid
);
1570 Log("%s on %s is executing Restore %u\n", caller
,
1571 callerAddress(acid
, buffer
), tt
->volid
);
1573 TSetRxCall(tt
, acid
, "Restore");
1575 DFlushVolume(V_parentId(tt
->volume
)); /* Ensure dir buffers get dropped */
1577 code
= RestoreVolume(acid
, tt
->volume
, (aflags
& 1), cookie
); /* last is incrementalp */
1578 FSYNC_VolOp(tt
->volid
, NULL
, FSYNC_VOL_BREAKCBKS
, 0l, NULL
);
1582 return (code
? code
: tcode
);
1585 /* end a transaction, returning the transaction's final error code in rcode */
1587 SAFSVolEndTrans(struct rx_call
*acid
, afs_int32 destTrans
, afs_int32
*rcode
)
1591 code
= VolEndTrans(acid
, destTrans
, rcode
);
1592 osi_auditU(acid
, VS_EndTrnEvent
, code
, AUD_LONG
, destTrans
, AUD_END
);
1597 VolEndTrans(struct rx_call
*acid
, afs_int32 destTrans
, afs_int32
*rcode
)
1599 struct volser_trans
*tt
;
1600 char caller
[MAXKTCNAMELEN
];
1602 if (!afsconf_SuperUser(tdir
, acid
, caller
))
1603 return VOLSERBAD_ACCESS
; /*not a super user */
1604 tt
= FindTrans(destTrans
);
1608 *rcode
= tt
->returnCode
;
1609 DeleteTrans(tt
, 1); /* this does an implicit TRELE */
1615 SAFSVolSetForwarding(struct rx_call
*acid
, afs_int32 atid
, afs_int32 anewsite
)
1619 code
= VolSetForwarding(acid
, atid
, anewsite
);
1620 osi_auditU(acid
, VS_SetForwEvent
, code
, AUD_LONG
, atid
, AUD_HOST
,
1621 htonl(anewsite
), AUD_END
);
1626 VolSetForwarding(struct rx_call
*acid
, afs_int32 atid
, afs_int32 anewsite
)
1628 struct volser_trans
*tt
;
1629 char caller
[MAXKTCNAMELEN
];
1632 if (!afsconf_SuperUser(tdir
, acid
, caller
))
1633 return VOLSERBAD_ACCESS
; /*not a super user */
1634 tt
= FindTrans(atid
);
1637 if (tt
->vflags
& VTDeleted
) {
1638 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1643 TSetRxCall(tt
, acid
, "SetForwarding");
1644 if (volutil_PartitionName2_r(tt
->partition
, partName
, sizeof(partName
)) != 0) {
1647 FSYNC_VolOp(tt
->volid
, partName
, FSYNC_VOL_MOVE
, anewsite
, NULL
);
1650 return VOLSERTRELE_ERROR
;
1656 SAFSVolGetStatus(struct rx_call
*acid
, afs_int32 atrans
,
1657 struct volser_status
*astatus
)
1661 code
= VolGetStatus(acid
, atrans
, astatus
);
1662 osi_auditU(acid
, VS_GetStatEvent
, code
, AUD_LONG
, atrans
, AUD_END
);
1667 VolGetStatus(struct rx_call
*acid
, afs_int32 atrans
,
1668 struct volser_status
*astatus
)
1671 struct VolumeDiskData
*td
;
1672 struct volser_trans
*tt
;
1675 tt
= FindTrans(atrans
);
1678 if (tt
->vflags
& VTDeleted
) {
1679 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1684 TSetRxCall(tt
, acid
, "GetStatus");
1692 td
= &tv
->header
->diskstuff
;
1693 astatus
->volID
= td
->id
;
1694 astatus
->nextUnique
= td
->uniquifier
;
1695 astatus
->type
= td
->type
;
1696 astatus
->parentID
= td
->parentId
;
1697 astatus
->cloneID
= td
->cloneId
;
1698 astatus
->backupID
= td
->backupId
;
1699 astatus
->restoredFromID
= td
->restoredFromId
;
1700 astatus
->maxQuota
= td
->maxquota
;
1701 astatus
->minQuota
= td
->minquota
;
1702 astatus
->owner
= td
->owner
;
1703 astatus
->creationDate
= td
->creationDate
;
1704 astatus
->accessDate
= td
->accessDate
;
1705 astatus
->updateDate
= td
->updateDate
;
1706 astatus
->expirationDate
= td
->expirationDate
;
1707 astatus
->backupDate
= td
->backupDate
;
1708 astatus
->copyDate
= td
->copyDate
;
1711 return VOLSERTRELE_ERROR
;
1717 SAFSVolSetInfo(struct rx_call
*acid
, afs_int32 atrans
,
1718 struct volintInfo
*astatus
)
1722 code
= VolSetInfo(acid
, atrans
, astatus
);
1723 osi_auditU(acid
, VS_SetInfoEvent
, code
, AUD_LONG
, atrans
, AUD_END
);
1728 VolSetInfo(struct rx_call
*acid
, afs_int32 atrans
,
1729 struct volintInfo
*astatus
)
1732 struct VolumeDiskData
*td
;
1733 struct volser_trans
*tt
;
1734 char caller
[MAXKTCNAMELEN
];
1737 if (!afsconf_SuperUser(tdir
, acid
, caller
))
1738 return VOLSERBAD_ACCESS
; /*not a super user */
1739 tt
= FindTrans(atrans
);
1742 if (tt
->vflags
& VTDeleted
) {
1743 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt
->volid
);
1747 TSetRxCall(tt
, acid
, "SetStatus");
1755 td
= &tv
->header
->diskstuff
;
1757 * Add more fields as necessary
1759 if (astatus
->maxquota
!= -1)
1760 td
->maxquota
= astatus
->maxquota
;
1761 if (astatus
->dayUse
!= -1)
1762 td
->dayUse
= astatus
->dayUse
;
1763 if (astatus
->creationDate
!= -1)
1764 td
->creationDate
= astatus
->creationDate
;
1765 if (astatus
->updateDate
!= -1)
1766 td
->updateDate
= astatus
->updateDate
;
1767 if (astatus
->spare2
!= -1)
1768 td
->volUpdateCounter
= (unsigned int)astatus
->spare2
;
1769 VUpdateVolume(&error
, tv
);
1772 return VOLSERTRELE_ERROR
;
1778 SAFSVolGetName(struct rx_call
*acid
, afs_int32 atrans
, char **aname
)
1782 code
= VolGetName(acid
, atrans
, aname
);
1783 osi_auditU(acid
, VS_GetNameEvent
, code
, AUD_LONG
, atrans
, AUD_END
);
1788 VolGetName(struct rx_call
*acid
, afs_int32 atrans
, char **aname
)
1791 struct VolumeDiskData
*td
;
1792 struct volser_trans
*tt
;
1795 /* We need to at least fill it in */
1796 *aname
= (char *)malloc(1);
1799 tt
= FindTrans(atrans
);
1802 if (tt
->vflags
& VTDeleted
) {
1803 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt
->volid
);
1807 TSetRxCall(tt
, acid
, "GetName");
1815 td
= &tv
->header
->diskstuff
;
1816 len
= strlen(td
->name
) + 1; /* don't forget the null */
1822 *aname
= (char *)realloc(*aname
, len
);
1823 strcpy(*aname
, td
->name
);
1826 return VOLSERTRELE_ERROR
;
1831 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1834 SAFSVolSignalRestore(struct rx_call
*acid
, char volname
[], int volType
,
1835 afs_uint32 parentId
, afs_uint32 cloneId
)
1841 /*return a list of all partitions on the server. The non mounted
1842 *partitions are returned as -1 in the corresponding slot in partIds*/
1844 SAFSVolListPartitions(struct rx_call
*acid
, struct pIDs
*partIds
)
1848 code
= VolListPartitions(acid
, partIds
);
1849 osi_auditU(acid
, VS_ListParEvent
, code
, AUD_END
);
1854 VolListPartitions(struct rx_call
*acid
, struct pIDs
*partIds
)
1859 strcpy(namehead
, "/vicep"); /*7 including null terminator */
1861 /* Just return attached partitions. */
1863 for (i
= 0; i
< 26; i
++) {
1864 namehead
[6] = i
+ 'a';
1865 partIds
->partIds
[i
] = VGetPartition(namehead
, 0) ? i
: -1;
1871 /*return a list of all partitions on the server. The non mounted
1872 *partitions are returned as -1 in the corresponding slot in partIds*/
1874 SAFSVolXListPartitions(struct rx_call
*acid
, struct partEntries
*pEntries
)
1878 code
= XVolListPartitions(acid
, pEntries
);
1879 osi_auditU(acid
, VS_ListParEvent
, code
, AUD_END
);
1884 XVolListPartitions(struct rx_call
*acid
, struct partEntries
*pEntries
)
1887 struct partList partList
;
1888 struct DiskPartition64
*dp
;
1891 strcpy(namehead
, "/vicep"); /*7 including null terminator */
1893 /* Only report attached partitions */
1894 for (i
= 0; i
< VOLMAXPARTS
; i
++) {
1895 #ifdef AFS_DEMAND_ATTACH_FS
1896 dp
= VGetPartitionById(i
, 0);
1899 namehead
[6] = i
+ 'a';
1905 namehead
[6] = 'a' + (k
/ 26);
1906 namehead
[7] = 'a' + (k
% 26);
1909 dp
= VGetPartition(namehead
, 0);
1912 partList
.partId
[j
++] = i
;
1915 pEntries
->partEntries_val
= (afs_int32
*) malloc(j
* sizeof(int));
1916 if (!pEntries
->partEntries_val
)
1918 memcpy(pEntries
->partEntries_val
, partList
.partId
,
1920 pEntries
->partEntries_len
= j
;
1922 pEntries
->partEntries_val
= NULL
;
1923 pEntries
->partEntries_len
= 0;
1929 /*return the name of the next volume header in the directory associated with dirp and dp.
1930 *the volume id is returned in volid, and volume header name is returned in volname*/
1932 GetNextVol(DIR * dirp
, char *volname
, afs_uint32
* volid
)
1936 dp
= readdir(dirp
); /*read next entry in the directory */
1938 if ((dp
->d_name
[0] == 'V') && !strcmp(&(dp
->d_name
[11]), VHDREXT
)) {
1939 *volid
= VolumeNumber(dp
->d_name
);
1940 strcpy(volname
, dp
->d_name
);
1941 return 0; /*return the name of the file representing a volume */
1943 strcpy(volname
, "");
1944 return 0; /*volname doesnot represent a volume */
1947 strcpy(volname
, "EOD");
1948 return 0; /*end of directory */
1954 * volint vol info structure type.
1957 VOLINT_INFO_TYPE_BASE
, /**< volintInfo type */
1958 VOLINT_INFO_TYPE_EXT
/**< volintXInfo type */
1959 } volint_info_type_t
;
1962 * handle to various on-wire vol info types.
1965 volint_info_type_t volinfo_type
;
1971 } volint_info_handle_t
;
1974 * store value to a field at the appropriate location in on-wire structure.
1976 #define VOLINT_INFO_STORE(handle, name, val) \
1978 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1979 (handle)->volinfo_ptr.base->name = (val); \
1981 (handle)->volinfo_ptr.ext->name = (val); \
1986 * get pointer to appropriate offset of field in on-wire structure.
1988 #define VOLINT_INFO_PTR(handle, name) \
1989 (((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) ? \
1990 &((handle)->volinfo_ptr.base->name) : \
1991 &((handle)->volinfo_ptr.ext->name))
1994 * fill in appropriate type of on-wire volume metadata structure.
1996 * @param vp pointer to volume object
1997 * @param handle pointer to wire format handle object
1999 * @pre vp object must contain header & pending_vol_op structurs (populate if from RPC)
2000 * @pre handle object must have a valid pointer and enumeration value
2002 * @note passing a NULL value for vp means that the fileserver doesn't
2003 * know about this particular volume, thus implying it is offline.
2005 * @return operation status
2010 FillVolInfo(Volume
* vp
, volint_info_handle_t
* handle
)
2012 unsigned int numStatBytes
, now
;
2013 struct VolumeDiskData
*hdr
= &vp
->header
->diskstuff
;
2015 /*read in the relevant info */
2016 strcpy((char *)VOLINT_INFO_PTR(handle
, name
), hdr
->name
);
2017 VOLINT_INFO_STORE(handle
, status
, VOK
); /*its ok */
2018 VOLINT_INFO_STORE(handle
, volid
, hdr
->id
);
2019 VOLINT_INFO_STORE(handle
, type
, hdr
->type
); /*if ro volume */
2020 VOLINT_INFO_STORE(handle
, cloneID
, hdr
->cloneId
); /*if rw volume */
2021 VOLINT_INFO_STORE(handle
, backupID
, hdr
->backupId
);
2022 VOLINT_INFO_STORE(handle
, parentID
, hdr
->parentId
);
2023 VOLINT_INFO_STORE(handle
, copyDate
, hdr
->copyDate
);
2024 VOLINT_INFO_STORE(handle
, size
, hdr
->diskused
);
2025 VOLINT_INFO_STORE(handle
, maxquota
, hdr
->maxquota
);
2026 VOLINT_INFO_STORE(handle
, filecount
, hdr
->filecount
);
2027 now
= FT_ApproxTime();
2028 if ((now
- hdr
->dayUseDate
) > OneDay
) {
2029 VOLINT_INFO_STORE(handle
, dayUse
, 0);
2031 VOLINT_INFO_STORE(handle
, dayUse
, hdr
->dayUse
);
2033 VOLINT_INFO_STORE(handle
, creationDate
, hdr
->creationDate
);
2034 VOLINT_INFO_STORE(handle
, accessDate
, hdr
->accessDate
);
2035 VOLINT_INFO_STORE(handle
, updateDate
, hdr
->updateDate
);
2036 VOLINT_INFO_STORE(handle
, backupDate
, hdr
->backupDate
);
2038 #ifdef AFS_DEMAND_ATTACH_FS
2040 * for DAFS, we "lie" about volume state --
2041 * instead of returning the raw state from the disk header,
2042 * we compute state based upon the fileserver's internal
2043 * in-core state enumeration value reported to us via fssync,
2044 * along with the blessed and inService flags from the header.
2045 * -- tkeiser 11/27/2007
2048 /* Conditions that offline status is based on:
2049 volume is unattached state
2050 volume state is in (one of several error states)
2051 volume not in service
2052 volume is not marked as blessed (not on hold)
2053 volume in salvage req. state
2054 volume needsSalvaged
2055 next op would set volume offline
2056 next op would not leave volume online (based on several conditions)
2059 (V_attachState(vp
) == VOL_STATE_UNATTACHED
) ||
2060 VIsErrorState(V_attachState(vp
)) ||
2063 (V_attachState(vp
) == VOL_STATE_SALVSYNC_REQ
) ||
2064 hdr
->needsSalvaged
||
2065 (vp
->pending_vol_op
&&
2066 (vp
->pending_vol_op
->com
.command
== FSYNC_VOL_OFF
||
2067 !VVolOpLeaveOnline_r(vp
, vp
->pending_vol_op
) )
2070 VOLINT_INFO_STORE(handle
, inUse
, 0);
2072 VOLINT_INFO_STORE(handle
, inUse
, 1);
2075 /* offline status based on program type, where != fileServer enum (1) is offline */
2076 if (hdr
->inUse
== fileServer
) {
2077 VOLINT_INFO_STORE(handle
, inUse
, 1);
2079 VOLINT_INFO_STORE(handle
, inUse
, 0);
2084 switch(handle
->volinfo_type
) {
2085 /* NOTE: VOLINT_INFO_STORE not used in this section because values are specific to one volinfo_type */
2086 case VOLINT_INFO_TYPE_BASE
:
2088 #ifdef AFS_DEMAND_ATTACH_FS
2089 /* see comment above where we set inUse bit */
2090 if (hdr
->needsSalvaged
||
2091 (vp
&& VIsErrorState(V_attachState(vp
)))) {
2092 handle
->volinfo_ptr
.base
->needsSalvaged
= 1;
2094 handle
->volinfo_ptr
.base
->needsSalvaged
= 0;
2097 handle
->volinfo_ptr
.base
->needsSalvaged
= hdr
->needsSalvaged
;
2099 handle
->volinfo_ptr
.base
->destroyMe
= hdr
->destroyMe
;
2100 handle
->volinfo_ptr
.base
->spare0
= hdr
->minquota
;
2101 handle
->volinfo_ptr
.base
->spare1
=
2102 (long)hdr
->weekUse
[0] +
2103 (long)hdr
->weekUse
[1] +
2104 (long)hdr
->weekUse
[2] +
2105 (long)hdr
->weekUse
[3] +
2106 (long)hdr
->weekUse
[4] +
2107 (long)hdr
->weekUse
[5] +
2108 (long)hdr
->weekUse
[6];
2109 handle
->volinfo_ptr
.base
->flags
= 0;
2110 handle
->volinfo_ptr
.base
->spare2
= hdr
->volUpdateCounter
;
2111 handle
->volinfo_ptr
.base
->spare3
= 0;
2115 case VOLINT_INFO_TYPE_EXT
:
2117 4 * ((2 * VOLINT_STATS_NUM_RWINFO_FIELDS
) +
2118 (4 * VOLINT_STATS_NUM_TIME_FIELDS
));
2121 * Copy out the stat fields in a single operation.
2123 if ((now
- hdr
->dayUseDate
) > OneDay
) {
2124 memset(&(handle
->volinfo_ptr
.ext
->stat_reads
[0]),
2127 memcpy((char *)&(handle
->volinfo_ptr
.ext
->stat_reads
[0]),
2128 (char *)&(hdr
->stat_reads
[0]),
2137 #ifdef AFS_DEMAND_ATTACH_FS
2140 * get struct Volume out of the fileserver.
2142 * @param[in] volumeId volumeId for which we want state information
2143 * @param[in] pname partition name string
2144 * @param[inout] vp pointer to pointer to Volume object which
2145 * will be populated (see note)
2147 * @return operation status
2149 * @retval non-zero failure
2151 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2156 GetVolObject(afs_uint32 volumeId
, char * pname
, Volume
** vp
)
2161 res
.hdr
.response_len
= sizeof(res
.hdr
);
2162 res
.payload
.buf
= *vp
;
2163 res
.payload
.len
= sizeof(Volume
);
2165 code
= FSYNC_VolOp(volumeId
,
2171 if (code
!= SYNC_OK
) {
2172 switch (res
.hdr
.reason
) {
2173 case FSYNC_WRONG_PART
:
2174 case FSYNC_UNKNOWN_VOLID
:
2187 * mode of volume list operation.
2190 VOL_INFO_LIST_SINGLE
, /**< performing a single volume list op */
2191 VOL_INFO_LIST_MULTIPLE
/**< performing a multi-volume list op */
2192 } vol_info_list_mode_t
;
2195 * abstract interface to populate wire-format volume metadata structures.
2197 * @param[in] partId partition id
2198 * @param[in] volumeId volume id
2199 * @param[in] pname partition name
2200 * @param[in] volname volume file name
2201 * @param[in] handle handle to on-wire volume metadata object
2202 * @param[in] mode listing mode
2204 * @return operation status
2206 * @retval -2 DESTROY_ME flag is set
2207 * @retval -1 general failure; some data filled in
2208 * @retval -3 couldn't create vtrans; some data filled in
2211 GetVolInfo(afs_uint32 partId
,
2212 afs_uint32 volumeId
,
2215 volint_info_handle_t
* handle
,
2216 vol_info_list_mode_t mode
)
2220 struct volser_trans
*ttc
= NULL
;
2221 struct Volume
*fill_tv
, *tv
= NULL
;
2222 #ifdef AFS_DEMAND_ATTACH_FS
2223 struct Volume fs_tv_buf
, *fs_tv
= &fs_tv_buf
; /* Create a structure, and a pointer to that structure */
2224 SYNC_PROTO_BUF_DECL(fs_res_buf
); /* Buffer for the pending_vol_op */
2225 SYNC_response fs_res
; /* Response handle for the pending_vol_op */
2226 FSSYNC_VolOp_info pending_vol_op_res
; /* Pending vol ops to full in volume */
2228 /* Set up response handle for pending_vol_op */
2229 fs_res
.hdr
.response_len
= sizeof(fs_res
.hdr
);
2230 fs_res
.payload
.buf
= fs_res_buf
;
2231 fs_res
.payload
.len
= SYNC_PROTO_MAX_LEN
;
2234 ttc
= NewTrans(volumeId
, partId
);
2237 VOLINT_INFO_STORE(handle
, status
, VBUSY
);
2238 VOLINT_INFO_STORE(handle
, volid
, volumeId
);
2242 /* Get volume from volserver */
2243 if (mode
== VOL_INFO_LIST_MULTIPLE
)
2244 tv
= VAttachVolumeByName(&error
, pname
, volname
, V_PEEK
);
2246 #ifdef AFS_DEMAND_ATTACH_FS
2249 int mode
= V_READONLY
; /* informs the fileserver to update the volume headers. */
2251 tv
= VAttachVolumeByName_retry(&error
, pname
, volname
, mode
);
2255 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2256 volumeId
, pname
, volname
, error
);
2261 * please note that destroyMe and needsSalvaged checks used to be ordered
2262 * in the opposite manner for ListVolumes and XListVolumes. I think it's
2263 * more correct to check destroyMe before needsSalvaged.
2264 * -- tkeiser 11/28/2007
2267 if (tv
->header
->diskstuff
.destroyMe
== DESTROY_ME
) {
2269 case VOL_INFO_LIST_MULTIPLE
:
2273 case VOL_INFO_LIST_SINGLE
:
2274 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) will be destroyed on next salvage\n",
2275 volumeId
, pname
, volname
);
2282 if (tv
->header
->diskstuff
.needsSalvaged
) {
2283 /*this volume will be salvaged */
2284 Log("1 Volser: GetVolInfo: Volume %u (%s:%s) needs to be salvaged\n",
2285 volumeId
, pname
, volname
);
2288 #ifdef AFS_DEMAND_ATTACH_FS
2289 /* If using DAFS, get volume from fsserver */
2290 if (GetVolObject(volumeId
, pname
, &fs_tv
) != SYNC_OK
|| fs_tv
== NULL
) {
2295 /* fs_tv is a shallow copy, must populate certain structures before passing along */
2296 if (FSYNC_VolOp(volumeId
, pname
, FSYNC_VOL_QUERY_VOP
, 0, &fs_res
) == SYNC_OK
) {
2297 /* If we if the pending vol op */
2298 memcpy(&pending_vol_op_res
, fs_res
.payload
.buf
, sizeof(FSSYNC_VolOp_info
));
2299 fs_tv
->pending_vol_op
=&pending_vol_op_res
;
2301 fs_tv
->pending_vol_op
=NULL
;
2304 /* populate the header from the volserver copy */
2305 fs_tv
->header
=tv
->header
;
2307 /* When using DAFS, use the fs volume info, populated with required structures */
2310 /* When not using DAFS, just use the local volume info */
2314 /* ok, we have all the data we need; fill in the on-wire struct */
2315 code
= FillVolInfo(fill_tv
, handle
);
2319 VOLINT_INFO_STORE(handle
, status
, 0);
2320 strcpy((char *)VOLINT_INFO_PTR(handle
, name
), volname
);
2321 VOLINT_INFO_STORE(handle
, volid
, volumeId
);
2324 VDetachVolume(&error
, tv
);
2327 VOLINT_INFO_STORE(handle
, status
, 0);
2328 strcpy((char *)VOLINT_INFO_PTR(handle
, name
), volname
);
2329 Log("1 Volser: GetVolInfo: Could not detach volume %u (%s:%s)\n",
2330 volumeId
, pname
, volname
);
2334 DeleteTrans(ttc
, 1);
2341 /*return the header information about the <volid> */
2343 SAFSVolListOneVolume(struct rx_call
*acid
, afs_int32 partid
,
2344 afs_uint32 volumeId
, volEntries
*volumeInfo
)
2348 code
= VolListOneVolume(acid
, partid
, volumeId
, volumeInfo
);
2349 osi_auditU(acid
, VS_Lst1VolEvent
, code
, AUD_LONG
, volumeId
, AUD_END
);
2354 VolListOneVolume(struct rx_call
*acid
, afs_int32 partid
,
2355 afs_uint32 volumeId
, volEntries
*volumeInfo
)
2357 struct DiskPartition64
*partP
;
2358 char pname
[9], volname
[20];
2362 volint_info_handle_t handle
;
2364 volumeInfo
->volEntries_val
= (volintInfo
*) malloc(sizeof(volintInfo
));
2365 if (!volumeInfo
->volEntries_val
)
2367 memset(volumeInfo
->volEntries_val
, 0, sizeof(volintInfo
)); /* Clear structure */
2369 volumeInfo
->volEntries_len
= 1;
2370 if (GetPartName(partid
, pname
))
2371 return VOLSERILLEGAL_PARTITION
;
2372 if (!(partP
= VGetPartition(pname
, 0)))
2373 return VOLSERILLEGAL_PARTITION
;
2374 dirp
= opendir(VPartitionPath(partP
));
2376 return VOLSERILLEGAL_PARTITION
;
2378 strcpy(volname
, "");
2380 while (strcmp(volname
, "EOD") && !found
) { /*while there are more volumes in the partition */
2382 if (!strcmp(volname
, "")) { /* its not a volume, fetch next file */
2383 GetNextVol(dirp
, volname
, &volid
);
2384 continue; /*back to while loop */
2387 if (volid
== volumeId
) { /*copy other things too */
2392 GetNextVol(dirp
, volname
, &volid
);
2396 #ifndef AFS_PTHREAD_ENV
2397 IOMGR_Poll(); /*make sure that the client does not time out */
2400 handle
.volinfo_type
= VOLINT_INFO_TYPE_BASE
;
2401 handle
.volinfo_ptr
.base
= volumeInfo
->volEntries_val
;
2403 /* The return code from GetVolInfo is ignored; there is no error from
2404 * it that results in the whole call being aborted. Any volume
2405 * attachment failures are reported in 'status' field in the
2406 * volumeInfo payload. */
2412 VOL_INFO_LIST_SINGLE
);
2416 return (found
) ? 0 : ENODEV
;
2419 /*------------------------------------------------------------------------
2420 * EXPORTED SAFSVolXListOneVolume
2423 * Returns extended info on volume a_volID on partition a_partID.
2426 * a_rxCidP : Pointer to the Rx call we're performing.
2427 * a_partID : Partition for which we want the extended list.
2428 * a_volID : Volume ID we wish to know about.
2429 * a_volumeXInfoP : Ptr to the extended info blob.
2432 * 0 Successful operation
2433 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2436 * Nothing interesting.
2440 *------------------------------------------------------------------------*/
2443 SAFSVolXListOneVolume(struct rx_call
*a_rxCidP
, afs_int32 a_partID
,
2444 afs_uint32 a_volID
, volXEntries
*a_volumeXInfoP
)
2448 code
= VolXListOneVolume(a_rxCidP
, a_partID
, a_volID
, a_volumeXInfoP
);
2449 osi_auditU(a_rxCidP
, VS_XLst1VlEvent
, code
, AUD_LONG
, a_volID
, AUD_END
);
2454 VolXListOneVolume(struct rx_call
*a_rxCidP
, afs_int32 a_partID
,
2455 afs_uint32 a_volID
, volXEntries
*a_volumeXInfoP
)
2456 { /*SAFSVolXListOneVolume */
2458 struct DiskPartition64
*partP
; /*Ptr to partition */
2459 char pname
[9], volname
[20]; /*Partition, volume names */
2460 DIR *dirp
; /*Partition directory ptr */
2461 afs_uint32 currVolID
; /*Current volume ID */
2462 int found
= 0; /*Did we find the volume we need? */
2463 volint_info_handle_t handle
;
2466 * Set up our pointers for action, marking our structure to hold exactly
2467 * one entry. Also, assume we'll fail in our quest.
2469 a_volumeXInfoP
->volXEntries_val
=
2470 (volintXInfo
*) malloc(sizeof(volintXInfo
));
2471 if (!a_volumeXInfoP
->volXEntries_val
)
2473 memset(a_volumeXInfoP
->volXEntries_val
, 0, sizeof(volintXInfo
)); /* Clear structure */
2475 a_volumeXInfoP
->volXEntries_len
= 1;
2478 * If the partition name we've been given is bad, bogue out.
2480 if (GetPartName(a_partID
, pname
))
2481 return (VOLSERILLEGAL_PARTITION
);
2484 * Open the directory representing the given AFS parttion. If we can't
2487 if (!(partP
= VGetPartition(pname
, 0)))
2488 return VOLSERILLEGAL_PARTITION
;
2489 dirp
= opendir(VPartitionPath(partP
));
2491 return (VOLSERILLEGAL_PARTITION
);
2493 strcpy(volname
, "");
2496 * Sweep through the partition directory, looking for the desired entry.
2497 * First, of course, figure out how many stat bytes to copy out of each
2500 while (strcmp(volname
, "EOD") && !found
) {
2502 * If this is not a volume, move on to the next entry in the
2503 * partition's directory.
2505 if (!strcmp(volname
, "")) {
2506 GetNextVol(dirp
, volname
, &currVolID
);
2510 if (currVolID
== a_volID
) {
2512 * We found the volume entry we're interested. Pull out the
2513 * extended information, remembering to poll (so that the client
2514 * doesn't time out) and to set up a transaction on the volume.
2518 } /*Found desired volume */
2520 GetNextVol(dirp
, volname
, &currVolID
);
2524 #ifndef AFS_PTHREAD_ENV
2528 handle
.volinfo_type
= VOLINT_INFO_TYPE_EXT
;
2529 handle
.volinfo_ptr
.ext
= a_volumeXInfoP
->volXEntries_val
;
2531 /* The return code from GetVolInfo is ignored; there is no error from
2532 * it that results in the whole call being aborted. Any volume
2533 * attachment failures are reported in 'status' field in the
2534 * volumeInfo payload. */
2535 GetVolInfo(a_partID
,
2540 VOL_INFO_LIST_SINGLE
);
2544 * Clean up before going to dinner: close the partition directory,
2545 * return the proper value.
2548 return (found
) ? 0 : ENODEV
;
2549 } /*SAFSVolXListOneVolume */
2551 /*returns all the volumes on partition partid. If flags = 1 then all the
2552 * relevant info about the volumes is also returned */
2554 SAFSVolListVolumes(struct rx_call
*acid
, afs_int32 partid
, afs_int32 flags
,
2555 volEntries
*volumeInfo
)
2559 code
= VolListVolumes(acid
, partid
, flags
, volumeInfo
);
2560 osi_auditU(acid
, VS_ListVolEvent
, code
, AUD_END
);
2565 VolListVolumes(struct rx_call
*acid
, afs_int32 partid
, afs_int32 flags
,
2566 volEntries
*volumeInfo
)
2569 struct DiskPartition64
*partP
;
2570 afs_int32 allocSize
= 1000; /*to be changed to a larger figure */
2571 char pname
[9], volname
[20];
2575 volint_info_handle_t handle
;
2577 volumeInfo
->volEntries_val
=
2578 (volintInfo
*) malloc(allocSize
* sizeof(volintInfo
));
2579 if (!volumeInfo
->volEntries_val
)
2581 memset(volumeInfo
->volEntries_val
, 0, sizeof(volintInfo
)); /* Clear structure */
2583 pntr
= volumeInfo
->volEntries_val
;
2584 volumeInfo
->volEntries_len
= 0;
2585 if (GetPartName(partid
, pname
))
2586 return VOLSERILLEGAL_PARTITION
;
2587 if (!(partP
= VGetPartition(pname
, 0)))
2588 return VOLSERILLEGAL_PARTITION
;
2589 dirp
= opendir(VPartitionPath(partP
));
2591 return VOLSERILLEGAL_PARTITION
;
2592 strcpy(volname
, "");
2594 while (strcmp(volname
, "EOD")) { /*while there are more partitions in the partition */
2596 if (!strcmp(volname
, "")) { /* its not a volume, fetch next file */
2597 GetNextVol(dirp
, volname
, &volid
);
2598 continue; /*back to while loop */
2601 if (flags
) { /*copy other things too */
2602 #ifndef AFS_PTHREAD_ENV
2603 IOMGR_Poll(); /*make sure that the client does not time out */
2606 handle
.volinfo_type
= VOLINT_INFO_TYPE_BASE
;
2607 handle
.volinfo_ptr
.base
= pntr
;
2610 code
= GetVolInfo(partid
,
2615 VOL_INFO_LIST_MULTIPLE
);
2616 if (code
== -2) { /* DESTROY_ME flag set */
2620 pntr
->volid
= volid
;
2621 /*just volids are needed */
2625 volumeInfo
->volEntries_len
+= 1;
2626 if ((allocSize
- volumeInfo
->volEntries_len
) < 5) {
2627 /*running out of space, allocate more space */
2628 allocSize
= (allocSize
* 3) / 2;
2630 (volintInfo
*) realloc((char *)volumeInfo
->volEntries_val
,
2631 allocSize
* sizeof(volintInfo
));
2634 return VOLSERNO_MEMORY
;
2636 volumeInfo
->volEntries_val
= pntr
; /* point to new block */
2637 /* set pntr to the right position */
2638 pntr
= volumeInfo
->volEntries_val
+ volumeInfo
->volEntries_len
;
2643 GetNextVol(dirp
, volname
, &volid
);
2651 /*------------------------------------------------------------------------
2652 * EXPORTED SAFSVolXListVolumes
2655 * Returns all the volumes on partition a_partID. If a_flags
2656 * is set to 1, then all the relevant extended volume information
2660 * a_rxCidP : Pointer to the Rx call we're performing.
2661 * a_partID : Partition for which we want the extended list.
2662 * a_flags : Various flags.
2663 * a_volumeXInfoP : Ptr to the extended info blob.
2666 * 0 Successful operation
2667 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2668 * VOLSERNO_MEMORY if we ran out of memory allocating
2672 * Nothing interesting.
2676 *------------------------------------------------------------------------*/
2679 SAFSVolXListVolumes(struct rx_call
*a_rxCidP
, afs_int32 a_partID
,
2680 afs_int32 a_flags
, volXEntries
*a_volumeXInfoP
)
2684 code
= VolXListVolumes(a_rxCidP
, a_partID
, a_flags
, a_volumeXInfoP
);
2685 osi_auditU(a_rxCidP
, VS_XLstVolEvent
, code
, AUD_END
);
2690 VolXListVolumes(struct rx_call
*a_rxCidP
, afs_int32 a_partID
,
2691 afs_int32 a_flags
, volXEntries
*a_volumeXInfoP
)
2692 { /*SAFSVolXListVolumes */
2694 volintXInfo
*xInfoP
; /*Ptr to the extended vol info */
2695 struct DiskPartition64
*partP
; /*Ptr to partition */
2696 afs_int32 allocSize
= 1000; /*To be changed to a larger figure */
2697 char pname
[9], volname
[20]; /*Partition, volume names */
2698 DIR *dirp
; /*Partition directory ptr */
2699 afs_uint32 volid
; /*Current volume ID */
2701 volint_info_handle_t handle
;
2704 * Allocate a large array of extended volume info structures, then
2705 * set it up for action.
2707 a_volumeXInfoP
->volXEntries_val
=
2708 (volintXInfo
*) malloc(allocSize
* sizeof(volintXInfo
));
2709 if (!a_volumeXInfoP
->volXEntries_val
)
2711 memset(a_volumeXInfoP
->volXEntries_val
, 0, sizeof(volintXInfo
)); /* Clear structure */
2713 xInfoP
= a_volumeXInfoP
->volXEntries_val
;
2714 a_volumeXInfoP
->volXEntries_len
= 0;
2717 * If the partition name we've been given is bad, bogue out.
2719 if (GetPartName(a_partID
, pname
))
2720 return (VOLSERILLEGAL_PARTITION
);
2723 * Open the directory representing the given AFS parttion. If we can't
2726 if (!(partP
= VGetPartition(pname
, 0)))
2727 return VOLSERILLEGAL_PARTITION
;
2728 dirp
= opendir(VPartitionPath(partP
));
2730 return (VOLSERILLEGAL_PARTITION
);
2731 strcpy(volname
, "");
2734 * Sweep through the partition directory, acting on each entry. First,
2735 * of course, figure out how many stat bytes to copy out of each volume.
2737 while (strcmp(volname
, "EOD")) {
2740 * If this is not a volume, move on to the next entry in the
2741 * partition's directory.
2743 if (!strcmp(volname
, "")) {
2744 GetNextVol(dirp
, volname
, &volid
);
2750 * Full info about the volume desired. Poll to make sure the
2751 * client doesn't time out, then start up a new transaction.
2753 #ifndef AFS_PTHREAD_ENV
2757 handle
.volinfo_type
= VOLINT_INFO_TYPE_EXT
;
2758 handle
.volinfo_ptr
.ext
= xInfoP
;
2760 code
= GetVolInfo(a_partID
,
2765 VOL_INFO_LIST_MULTIPLE
);
2766 if (code
== -2) { /* DESTROY_ME flag set */
2771 * Just volume IDs are needed.
2773 xInfoP
->volid
= volid
;
2777 * Bump the pointer in the data area we're building, along with
2778 * the count of the number of entries it contains.
2781 (a_volumeXInfoP
->volXEntries_len
)++;
2782 if ((allocSize
- a_volumeXInfoP
->volXEntries_len
) < 5) {
2784 * We're running out of space in the area we've built. Grow it.
2786 allocSize
= (allocSize
* 3) / 2;
2787 xInfoP
= (volintXInfo
*)
2788 realloc((char *)a_volumeXInfoP
->volXEntries_val
,
2789 (allocSize
* sizeof(volintXInfo
)));
2790 if (xInfoP
== NULL
) {
2792 * Bummer, no memory. Bag it, tell our caller what went wrong.
2795 return (VOLSERNO_MEMORY
);
2799 * Memory reallocation worked. Correct our pointers so they
2800 * now point to the new block and the current open position within
2803 a_volumeXInfoP
->volXEntries_val
= xInfoP
;
2805 a_volumeXInfoP
->volXEntries_val
+
2806 a_volumeXInfoP
->volXEntries_len
;
2810 GetNextVol(dirp
, volname
, &volid
);
2811 } /*Sweep through the partition directory */
2814 * We've examined all entries in the partition directory. Close it,
2815 * delete our transaction (if any), and go home happy.
2820 } /*SAFSVolXListVolumes */
2822 /*this call is used to monitor the status of volser for debugging purposes.
2823 *information about all the active transactions is returned in transInfo*/
2825 SAFSVolMonitor(struct rx_call
*acid
, transDebugEntries
*transInfo
)
2829 code
= VolMonitor(acid
, transInfo
);
2830 osi_auditU(acid
, VS_MonitorEvent
, code
, AUD_END
);
2835 VolMonitor(struct rx_call
*acid
, transDebugEntries
*transInfo
)
2837 transDebugInfo
*pntr
;
2838 afs_int32 allocSize
= 50;
2839 struct volser_trans
*tt
, *nt
, *allTrans
;
2841 transInfo
->transDebugEntries_val
=
2842 (transDebugInfo
*) malloc(allocSize
* sizeof(transDebugInfo
));
2843 if (!transInfo
->transDebugEntries_val
)
2845 pntr
= transInfo
->transDebugEntries_val
;
2846 transInfo
->transDebugEntries_len
= 0;
2849 allTrans
= TransList();
2850 if (allTrans
== (struct volser_trans
*)0)
2851 goto done
; /*no active transactions */
2852 for (tt
= allTrans
; tt
; tt
= nt
) { /*copy relevant info into pntr */
2854 VTRANS_OBJ_LOCK(tt
);
2855 pntr
->tid
= tt
->tid
;
2856 pntr
->time
= tt
->time
;
2857 pntr
->creationTime
= tt
->creationTime
;
2858 pntr
->returnCode
= tt
->returnCode
;
2859 pntr
->volid
= tt
->volid
;
2860 pntr
->partition
= tt
->partition
;
2861 pntr
->iflags
= tt
->iflags
;
2862 pntr
->vflags
= tt
->vflags
;
2863 pntr
->tflags
= tt
->tflags
;
2864 strcpy(pntr
->lastProcName
, tt
->lastProcName
);
2865 pntr
->callValid
= 0;
2866 if (tt
->rxCallPtr
) { /*record call related info */
2867 pntr
->callValid
= 1;
2868 pntr
->readNext
= tt
->rxCallPtr
->rnext
;
2869 pntr
->transmitNext
= tt
->rxCallPtr
->tnext
;
2870 pntr
->lastSendTime
= tt
->rxCallPtr
->lastSendTime
;
2871 pntr
->lastReceiveTime
= tt
->rxCallPtr
->lastReceiveTime
;
2873 VTRANS_OBJ_UNLOCK(tt
);
2875 transInfo
->transDebugEntries_len
+= 1;
2876 if ((allocSize
- transInfo
->transDebugEntries_len
) < 5) { /*alloc some more space */
2877 allocSize
= (allocSize
* 3) / 2;
2879 (transDebugInfo
*) realloc((char *)transInfo
->
2880 transDebugEntries_val
,
2882 sizeof(transDebugInfo
));
2883 transInfo
->transDebugEntries_val
= pntr
;
2885 transInfo
->transDebugEntries_val
+
2886 transInfo
->transDebugEntries_len
;
2887 /*set pntr to right position */
2898 SAFSVolSetIdsTypes(struct rx_call
*acid
, afs_int32 atid
, char name
[],
2899 afs_int32 type
, afs_uint32 pId
, afs_uint32 cloneId
,
2900 afs_uint32 backupId
)
2904 code
= VolSetIdsTypes(acid
, atid
, name
, type
, pId
, cloneId
, backupId
);
2905 osi_auditU(acid
, VS_SetIdTyEvent
, code
, AUD_LONG
, atid
, AUD_STR
, name
,
2906 AUD_LONG
, type
, AUD_LONG
, pId
, AUD_LONG
, cloneId
, AUD_LONG
,
2912 VolSetIdsTypes(struct rx_call
*acid
, afs_int32 atid
, char name
[],
2913 afs_int32 type
, afs_uint32 pId
, afs_uint32 cloneId
,
2914 afs_uint32 backupId
)
2918 struct volser_trans
*tt
;
2919 char caller
[MAXKTCNAMELEN
];
2921 if (strlen(name
) > 31)
2922 return VOLSERBADNAME
;
2923 if (!afsconf_SuperUser(tdir
, acid
, caller
))
2924 return VOLSERBAD_ACCESS
; /*not a super user */
2925 /* find the trans */
2926 tt
= FindTrans(atid
);
2929 if (tt
->vflags
& VTDeleted
) {
2930 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt
->volid
);
2934 TSetRxCall(tt
, acid
, "SetIdsTypes");
2938 V_backupId(tv
) = backupId
;
2939 V_cloneId(tv
) = cloneId
;
2940 V_parentId(tv
) = pId
;
2941 strcpy((&V_disk(tv
))->name
, name
);
2942 VUpdateVolume(&error
, tv
);
2944 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error
);
2949 if (TRELE(tt
) && !error
)
2950 return VOLSERTRELE_ERROR
;
2955 if (TRELE(tt
) && !error
)
2956 return VOLSERTRELE_ERROR
;
2961 SAFSVolSetDate(struct rx_call
*acid
, afs_int32 atid
, afs_int32 cdate
)
2965 code
= VolSetDate(acid
, atid
, cdate
);
2966 osi_auditU(acid
, VS_SetDateEvent
, code
, AUD_LONG
, atid
, AUD_LONG
, cdate
,
2972 VolSetDate(struct rx_call
*acid
, afs_int32 atid
, afs_int32 cdate
)
2976 struct volser_trans
*tt
;
2977 char caller
[MAXKTCNAMELEN
];
2979 if (!afsconf_SuperUser(tdir
, acid
, caller
))
2980 return VOLSERBAD_ACCESS
; /*not a super user */
2981 /* find the trans */
2982 tt
= FindTrans(atid
);
2985 if (tt
->vflags
& VTDeleted
) {
2986 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt
->volid
);
2990 TSetRxCall(tt
, acid
, "SetDate");
2993 V_creationDate(tv
) = cdate
;
2994 VUpdateVolume(&error
, tv
);
2996 Log("1 Volser: SetDate: VUpdate failed code %d\n", error
);
3001 if (TRELE(tt
) && !error
)
3002 return VOLSERTRELE_ERROR
;
3007 if (TRELE(tt
) && !error
)
3008 return VOLSERTRELE_ERROR
;
3013 SAFSVolConvertROtoRWvolume(struct rx_call
*acid
, afs_int32 partId
,
3014 afs_uint32 volumeId
)
3019 char caller
[MAXKTCNAMELEN
];
3021 struct volser_trans
*ttc
;
3022 char pname
[16], volname
[20];
3023 struct DiskPartition64
*partP
;
3024 afs_int32 ret
= ENODEV
;
3027 if (!afsconf_SuperUser(tdir
, acid
, caller
))
3028 return VOLSERBAD_ACCESS
; /*not a super user */
3029 if (GetPartName(partId
, pname
))
3030 return VOLSERILLEGAL_PARTITION
;
3031 if (!(partP
= VGetPartition(pname
, 0)))
3032 return VOLSERILLEGAL_PARTITION
;
3033 dirp
= opendir(VPartitionPath(partP
));
3035 return VOLSERILLEGAL_PARTITION
;
3036 strcpy(volname
, "");
3037 ttc
= (struct volser_trans
*)0;
3039 while (strcmp(volname
, "EOD")) {
3040 if (!strcmp(volname
, "")) { /* its not a volume, fetch next file */
3041 GetNextVol(dirp
, volname
, &volid
);
3042 continue; /*back to while loop */
3045 if (volid
== volumeId
) { /*copy other things too */
3046 #ifndef AFS_PTHREAD_ENV
3047 IOMGR_Poll(); /*make sure that the client doesnot time out */
3049 ttc
= NewTrans(volumeId
, partId
);
3051 return VOLSERVOLBUSY
;
3053 #ifdef AFS_NAMEI_ENV
3054 ret
= namei_ConvertROtoRWvolume(pname
, volumeId
);
3056 ret
= inode_ConvertROtoRWvolume(pname
, volumeId
);
3060 GetNextVol(dirp
, volname
, &volid
);
3064 DeleteTrans(ttc
, 1);
3065 ttc
= (struct volser_trans
*)0;
3074 SAFSVolGetSize(struct rx_call
*acid
, afs_int32 fromTrans
, afs_int32 fromDate
,
3075 struct volintSize
*size
)
3078 struct volser_trans
*tt
;
3079 char caller
[MAXKTCNAMELEN
];
3081 if (!afsconf_SuperUser(tdir
, acid
, caller
))
3082 return VOLSERBAD_ACCESS
; /*not a super user */
3083 tt
= FindTrans(fromTrans
);
3086 if (tt
->vflags
& VTDeleted
) {
3090 TSetRxCall(tt
, acid
, "GetSize");
3091 code
= SizeDumpVolume(acid
, tt
->volume
, fromDate
, 1, size
); /* measure volume's data */
3094 return VOLSERTRELE_ERROR
;
3096 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3101 SAFSVolSplitVolume(struct rx_call
*acall
, afs_uint32 vid
, afs_uint32
new,
3102 afs_uint32 where
, afs_int32 verbose
)
3104 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
3106 Volume
*vol
=0, *newvol
=0;
3107 struct volser_trans
*tt
= 0, *tt2
= 0;
3108 char caller
[MAXKTCNAMELEN
];
3111 if (!afsconf_SuperUser(tdir
, acall
, caller
))
3114 vol
= VAttachVolume(&code
, vid
, V_VOLUPD
);
3120 newvol
= VAttachVolume(&code
, new, V_VOLUPD
);
3122 VDetachVolume(&code2
, vol
);
3127 if (V_device(vol
) != V_device(newvol
)
3128 || V_uniquifier(newvol
) != 2) {
3129 if (V_device(vol
) != V_device(newvol
)) {
3130 sprintf(line
, "Volumes %u and %u are not in the same partition, aborted.\n",
3132 rx_Write(acall
, line
, strlen(line
));
3134 if (V_uniquifier(newvol
) != 2) {
3135 sprintf(line
, "Volume %u is not freshly created, aborted.\n", new);
3136 rx_Write(acall
, line
, strlen(line
));
3139 rx_Write(acall
, line
, 1);
3140 VDetachVolume(&code2
, vol
);
3141 VDetachVolume(&code2
, newvol
);
3144 tt
= NewTrans(vid
, V_device(vol
));
3146 sprintf(line
, "Couldn't create transaction for %u, aborted.\n", vid
);
3147 rx_Write(acall
, line
, strlen(line
));
3149 rx_Write(acall
, line
, 1);
3150 VDetachVolume(&code2
, vol
);
3151 VDetachVolume(&code2
, newvol
);
3152 return VOLSERVOLBUSY
;
3154 VTRANS_OBJ_LOCK(tt
);
3155 tt
->iflags
= ITBusy
;
3157 TSetRxCall_r(tt
, NULL
, "SplitVolume");
3158 VTRANS_OBJ_UNLOCK(tt
);
3160 tt2
= NewTrans(new, V_device(newvol
));
3162 sprintf(line
, "Couldn't create transaction for %u, aborted.\n", new);
3163 rx_Write(acall
, line
, strlen(line
));
3165 rx_Write(acall
, line
, 1);
3167 VDetachVolume(&code2
, vol
);
3168 VDetachVolume(&code2
, newvol
);
3169 return VOLSERVOLBUSY
;
3171 VTRANS_OBJ_LOCK(tt2
);
3172 tt2
->iflags
= ITBusy
;
3174 TSetRxCall_r(tt2
, NULL
, "SplitVolume");
3175 VTRANS_OBJ_UNLOCK(tt2
);
3177 code
= split_volume(acall
, vol
, newvol
, where
, verbose
);
3179 VDetachVolume(&code2
, vol
);
3181 VDetachVolume(&code2
, newvol
);
3182 DeleteTrans(tt2
, 1);
3189 /* GetPartName - map partid (a decimal number) into pname (a string)
3190 * Since for NT we actually want to return the drive name, we map through the
3194 GetPartName(afs_int32 partid
, char *pname
)
3199 strcpy(pname
, "/vicep");
3200 pname
[6] = 'a' + partid
;
3203 } else if (partid
< VOLMAXPARTS
) {
3204 strcpy(pname
, "/vicep");
3206 pname
[6] = 'a' + (partid
/ 26);
3207 pname
[7] = 'a' + (partid
% 26);