Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / volser / volprocs.c
blobd6cd1047a67d344f9336855b30adb74f1a016f39
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
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>
15 #include <stdio.h>
16 #include <sys/types.h>
17 #include <string.h>
18 #include <errno.h>
19 #ifdef AFS_NT40_ENV
20 #include <stdlib.h>
21 #include <fcntl.h>
22 #include <winsock2.h>
23 #else
24 #include <sys/file.h>
25 #include <netinet/in.h>
26 #include <unistd.h>
27 #endif
29 #include <dirent.h>
30 #include <sys/stat.h>
32 #include <rx/xdr.h>
33 #include <rx/rx.h>
34 #include <rx/rxkad.h>
35 #include <afs/afsint.h>
36 #include <signal.h>
37 #include <afs/afs_assert.h>
38 #include <afs/prs_fs.h>
39 #include <afs/nfs.h>
40 #include <lwp.h>
41 #include <lock.h>
42 #include <afs/cellconfig.h>
43 #include <afs/keys.h>
44 #include <ubik.h>
45 #include <afs/ihandle.h>
46 #ifdef AFS_NT40_ENV
47 #include <afs/ntops.h>
48 #endif
49 #include <afs/vnode.h>
50 #include <afs/volume.h>
51 #include <afs/volume_inline.h>
52 #include <afs/partition.h>
53 #include "vol.h"
54 #include <afs/daemon_com.h>
55 #include <afs/fssync.h>
56 #include <afs/acl.h>
57 #include "afs/audit.h"
58 #include <afs/dir.h>
59 #include <afs/afsutil.h>
60 #include <afs/com_err.h>
61 #include <afs/vol_prototypes.h>
62 #include <afs/errors.h>
64 #include "volser.h"
65 #include "voltrans_inline.h"
66 #include "volint.h"
68 #include "volser_internal.h"
69 #include "physio.h"
70 #include "dumpstuff.h"
72 extern int DoLogging;
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)
83 #ifdef AFS_NT40_ENV
84 #define ENOTCONN 134
85 #endif
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 *,
94 afs_int32 *);
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 *,
102 afs_int32 *);
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,
120 volEntries *);
121 static afs_int32 VolXListOneVolume(struct rx_call *, afs_int32, afs_uint32,
122 volXEntries *);
123 static afs_int32 VolListVolumes(struct rx_call *, afs_int32, afs_int32,
124 volEntries *);
125 static afs_int32 VolXListVolumes(struct rx_call *, afs_int32, afs_int32,
126 volXEntries *);
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,
130 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
141 static_inline char *
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 */
150 VPFullUnlock_r(void)
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;
159 return 0;
163 VPFullUnlock(void)
165 int code;
166 VOL_LOCK;
167 code = VPFullUnlock_r();
168 VOL_UNLOCK;
169 return code;
172 /* get partition id from a name */
173 afs_int32
174 PartitionID(char *aname)
176 char tc;
177 int code = 0;
178 char ascii[3];
180 tc = *aname;
181 if (tc == 0)
182 return -1; /* unknown */
184 /* otherwise check for vicepa or /vicepa, or just plain "a" */
185 ascii[2] = 0;
186 if (!strncmp(aname, "/vicep", 6)) {
187 strncpy(ascii, aname + 6, 2);
188 } else
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 */
192 if (ascii[1] == 0) {
193 /* one char name, 0..25 */
194 if (ascii[0] < 'a' || ascii[0] > 'z')
195 return -1; /* wrongo */
196 return ascii[0] - 'a';
197 } else {
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)
205 return -1;
206 return code;
210 static int
211 ConvertVolume(afs_uint32 avol, char *aname, afs_int32 asize)
213 if (asize < 18)
214 return -1;
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);
217 return 0;
220 static int
221 ConvertPartition(int apartno, char *aname, int asize)
223 if (asize < 10)
224 return E2BIG;
225 if (apartno < 0)
226 return EINVAL;
227 strcpy(aname, "/vicep");
228 if (apartno < 26) {
229 aname[6] = 'a' + apartno;
230 aname[7] = 0;
231 } else {
232 apartno -= 26;
233 aname[6] = 'a' + (apartno / 26);
234 aname[7] = 'a' + (apartno % 26);
235 aname[8] = 0;
237 return 0;
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 */
244 static void
245 SalvageUnknownVolume(VolumeId volid, char *part)
247 afs_int32 code;
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);
254 if (code) {
255 Log("SalvageUnknownVolume: error %ld trying to salvage vol %lu part %s\n",
256 afs_printable_int32_ld(code), afs_printable_uint32_lu(volid),
257 part);
260 #endif /* AFS_DEMAND_ATTACH_FS */
262 static struct Volume *
263 VAttachVolumeByName_retry(Error *ec, char *partition, char *name, int mode)
265 struct Volume *vp;
267 *ec = 0;
268 vp = VAttachVolumeByName(ec, partition, name, mode);
270 #ifdef AFS_DEMAND_ATTACH_FS
272 int i;
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) {
287 *ec = VSALVAGE;
290 #endif /* AFS_DEMAND_ATTACH_FS */
292 return vp;
295 static struct Volume *
296 VAttachVolume_retry(Error *ec, afs_uint32 avolid, int amode)
298 struct Volume *vp;
300 *ec = 0;
301 vp = VAttachVolume(ec, avolid, amode);
303 #ifdef AFS_DEMAND_ATTACH_FS
305 int i;
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) {
313 *ec = VSALVAGE;
316 #endif /* AFS_DEMAND_ATTACH_FS */
318 return vp;
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))) {
328 *error = EINVAL;
329 return NULL;
331 if (ConvertVolume(avolid, vbuf, sizeof(vbuf))) {
332 *error = EINVAL;
333 return NULL;
336 return VAttachVolumeByName_retry((Error *)error, pbuf, vbuf, amode);
339 /* Adapted from the file server; create a root directory for this volume */
340 static Error
341 ViceCreateRoot(Volume *vp)
343 DirHandle dir;
344 struct acl_accessList *ACL;
345 AFSFid did;
346 Inode inodeNumber, nearInode AFS_UNUSED;
347 struct VnodeDiskObject *vnode;
348 struct VnodeClassInfo *vcp = &VnodeClassInfo[vLarge];
349 IHandle_t *h;
350 FdHandle_t *fdP;
351 afs_fsize_t length;
352 ssize_t nBytes;
354 vnode = (struct VnodeDiskObject *)malloc(SIZEOF_LARGEDISKVNODE);
355 if (!vnode)
356 return ENOMEM;
357 memset(vnode, 0, SIZEOF_LARGEDISKVNODE);
359 V_pref(vp, nearInode);
360 inodeNumber =
361 IH_CREATE(V_linkHandle(vp), V_device(vp),
362 VPartitionPath(V_partition(vp)), nearInode, V_parentId(vp),
363 1, 1, 0);
364 if (!VALID_INO(inodeNumber)) {
365 Log("ViceCreateRoot: IH_CREATE: %s\n", afs_error_message(errno));
366 free(vnode);
367 return EIO;
370 SetSalvageDirHandle(&dir, V_parentId(vp), vp->device, inodeNumber);
371 did.Volume = V_id(vp);
372 did.Vnode = (VnodeId) 1;
373 did.Unique = 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
384 * change
386 ACL = VVnodeDiskACL(vnode);
387 ACL->size = sizeof(struct acl_accessList);
388 ACL->version = ACL_ACLVERSION;
389 ACL->total = 1;
390 ACL->positive = 1;
391 ACL->negative = 0;
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;
398 vnode->cloned = 0;
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);
407 vnode->author = 0;
408 vnode->owner = 0;
409 vnode->parent = 0;
410 vnode->vnodeMagic = vcp->magic;
412 IH_INIT(h, vp->device, V_parentId(vp),
413 vp->vnodeIndex[vLarge].handle->ih_ino);
414 fdP = IH_OPEN(h);
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);
419 IH_RELEASE(h);
420 VNDISK_GET_LEN(length, vnode);
421 V_diskused(vp) = nBlocks(length);
423 free(vnode);
424 return 0;
427 afs_int32
428 SAFSVolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition
429 *partition)
431 afs_int32 code;
432 struct diskPartition64 *dp = (struct diskPartition64 *)
433 malloc(sizeof(struct diskPartition64));
435 code = VolPartitionInfo(acid, pname, dp);
436 if (!code) {
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);
443 free(dp);
444 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
445 return code;
448 afs_int32
449 SAFSVolPartitionInfo64(struct rx_call *acid, char *pname, struct diskPartition64
450 *partition)
452 afs_int32 code;
454 code = VolPartitionInfo(acid, pname, partition);
455 osi_auditU(acid, VS_ParInfEvent, code, AUD_STR, pname, AUD_END);
456 return code;
459 afs_int32
460 VolPartitionInfo(struct rx_call *acid, char *pname, struct diskPartition64
461 *partition)
463 struct DiskPartition64 *dp;
465 VResetDiskUsage();
466 dp = VGetPartition(pname, 0);
467 if (dp) {
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;
473 return 0;
474 } else
475 return VOLSERILLEGAL_PARTITION;
478 /* obliterate a volume completely, and slowly. */
479 afs_int32
480 SAFSVolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
482 afs_int32 code;
484 code = VolNukeVolume(acid, apartID, avolID);
485 osi_auditU(acid, VS_NukVolEvent, code, AUD_LONG, avolID, AUD_END);
486 return code;
489 static afs_int32
490 VolNukeVolume(struct rx_call *acid, afs_int32 apartID, afs_uint32 avolID)
492 char partName[50];
493 afs_int32 error;
494 Error verror;
495 afs_int32 code;
496 struct Volume *tvp;
497 char caller[MAXKTCNAMELEN];
499 /* check for access */
500 if (!afsconf_SuperUser(tdir, acid, caller))
501 return VOLSERBAD_ACCESS;
502 if (DoLogging) {
503 char buffer[16];
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)
509 return VOLSERNOVOL;
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);
516 if (tvp)
517 VDetachVolume(&verror, tvp);
518 return code;
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.
527 afs_int32
528 SAFSVolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
529 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
530 afs_int32 *atrans)
532 afs_int32 code;
534 code =
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,
538 AUD_END);
539 return code;
542 static afs_int32
543 VolCreateVolume(struct rx_call *acid, afs_int32 apart, char *aname,
544 afs_int32 atype, afs_uint32 aparent, afs_uint32 *avolid,
545 afs_int32 *atrans)
547 Error error;
548 Volume *vp;
549 Error junk; /* discardable error code */
550 afs_uint32 volumeID;
551 afs_int32 doCreateRoot = 1;
552 struct volser_trans *tt;
553 char ppath[30];
554 char caller[MAXKTCNAMELEN];
556 if (strlen(aname) > 31)
557 return VOLSERBADNAME;
558 if (!afsconf_SuperUser(tdir, acid, caller))
559 return VOLSERBAD_ACCESS;
560 if (DoLogging) {
561 char buffer[16];
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)
569 return EINVAL;
570 if ((volumeID = *avolid) == 0) {
572 Log("1 Volser: CreateVolume: missing volume number; %s volume not created\n", aname);
573 return E2BIG;
576 if ((aparent == volumeID) && (atype == readwriteVolume)) {
577 doCreateRoot = 0;
579 if (aparent == 0)
580 aparent = volumeID;
581 tt = NewTrans(volumeID, apart);
582 if (!tt) {
583 Log("1 createvolume: failed to create trans\n");
584 return VOLSERVOLBUSY; /* volume already busy! */
586 vp = VCreateVolume(&error, ppath, volumeID, aparent);
587 if (error) {
588 #ifdef AFS_DEMAND_ATTACH_FS
589 if (error != VVOLEXISTS && error != EXDEV) {
590 SalvageUnknownVolume(volumeID, ppath);
592 #endif
593 Log("1 Volser: CreateVolume: Unable to create the volume; aborted, error code %u\n", error);
594 LogError(error);
595 DeleteTrans(tt, 1);
596 return EIO;
598 V_uniquifier(vp) = 1;
599 V_updateDate(vp) = V_creationDate(vp) = V_copyDate(vp);
600 V_inService(vp) = V_blessed(vp) = 1;
601 V_type(vp) = atype;
602 AssignVolumeName(&V_disk(vp), aname, 0);
603 if (doCreateRoot) {
604 error = ViceCreateRoot(vp);
605 if (error) {
606 Log("1 Volser: CreateVolume: Unable to create volume root dir; "
607 "error code %u\n", (unsigned)error);
608 DeleteTrans(tt, 1);
609 V_needsSalvaged(vp) = 1;
610 VDetachVolume(&junk, vp);
611 return EIO;
614 V_destroyMe(vp) = DESTROY_ME;
615 V_inService(vp) = 0;
616 V_maxquota(vp) = 5000; /* set a quota of 5000 at init time */
617 VUpdateVolume(&error, vp);
618 if (error) {
619 Log("1 Volser: create UpdateVolume failed, code %d\n", error);
620 LogError(error);
621 DeleteTrans(tt, 1);
622 VDetachVolume(&junk, vp); /* rather return the real error code */
623 return error;
625 VTRANS_OBJ_LOCK(tt);
626 tt->volume = vp;
627 *atrans = tt->tid;
628 TSetRxCall_r(tt, acid, "CreateVolume");
629 VTRANS_OBJ_UNLOCK(tt);
630 Log("1 Volser: CreateVolume: volume %u (%s) created\n", volumeID, aname);
631 TClearRxCall(tt);
632 if (TRELE(tt))
633 return VOLSERTRELE_ERROR;
634 return 0;
637 /* delete the volume associated with this transaction */
638 afs_int32
639 SAFSVolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
641 afs_int32 code;
643 code = VolDeleteVolume(acid, atrans);
644 osi_auditU(acid, VS_DelVolEvent, code, AUD_LONG, atrans, AUD_END);
645 return code;
648 static afs_int32
649 VolDeleteVolume(struct rx_call *acid, afs_int32 atrans)
651 struct volser_trans *tt;
652 Error error;
653 char caller[MAXKTCNAMELEN];
655 if (!afsconf_SuperUser(tdir, acid, caller))
656 return VOLSERBAD_ACCESS;
657 tt = FindTrans(atrans);
658 if (!tt)
659 return ENOENT;
660 if (tt->vflags & VTDeleted) {
661 Log("1 Volser: Delete: volume %u already deleted \n", tt->volid);
662 TRELE(tt);
663 return ENOENT;
665 if (DoLogging) {
666 char buffer[16];
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 */
676 VTRANS_OBJ_LOCK(tt);
677 tt->vflags |= VTDeleted; /* so we know not to do anything else to it */
678 TClearRxCall_r(tt);
679 VTRANS_OBJ_UNLOCK(tt);
680 if (TRELE(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 */
698 afs_int32
699 SAFSVolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
700 afs_int32 newType, char *newName, afs_uint32 *newNumber)
702 afs_int32 code;
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,
707 AUD_END);
708 return code;
711 static afs_int32
712 VolClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 purgeId,
713 afs_int32 newType, char *newName, afs_uint32 *newNumber)
715 afs_uint32 newId;
716 struct Volume *originalvp, *purgevp, *newvp;
717 Error error, code;
718 struct volser_trans *tt, *ttc;
719 char caller[MAXKTCNAMELEN];
720 #ifdef AFS_DEMAND_ATTACH_FS
721 struct Volume *salv_vp = NULL;
722 #endif
724 if (strlen(newName) > 31)
725 return VOLSERBADNAME;
726 if (!afsconf_SuperUser(tdir, acid, caller))
727 return VOLSERBAD_ACCESS; /*not a super user */
728 if (DoLogging) {
729 char buffer[16];
730 Log("%s on %s is executing Clone Volume new name=%s\n", caller,
731 callerAddress(acid, buffer), newName);
733 error = 0;
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");
741 goto fail;
743 newId = *newNumber;
745 tt = FindTrans(atrans);
746 if (!tt)
747 return ENOENT;
748 if (tt->vflags & VTDeleted) {
749 Log("1 Volser: Clone: volume %u has been deleted \n", tt->volid);
750 TRELE(tt);
751 return ENOENT;
753 ttc = NewTrans(newId, tt->partition);
754 if (!ttc) { /* someone is messing with the clone already */
755 TRELE(tt);
756 return VOLSERVOLBUSY;
758 TSetRxCall(tt, acid, "Clone");
761 if (purgeId) {
762 purgevp = VAttachVolume_retry(&error, purgeId, V_VOLUPD);
763 if (error) {
764 Log("1 Volser: Clone: Could not attach 'purge' volume %u; clone aborted\n", purgeId);
765 goto fail;
767 } else {
768 purgevp = NULL;
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",
773 V_id(originalvp));
774 error = VOFFLINE;
775 goto fail;
777 if (purgevp) {
778 if (originalvp->device != purgevp->device) {
779 Log("1 Volser: Clone: Volumes %u and %u are on different devices\n", tt->volid, purgeId);
780 error = EXDEV;
781 goto fail;
783 if (V_type(purgevp) != readonlyVolume) {
784 Log("1 Volser: Clone: The \"purge\" volume must be a read only volume; aborted\n");
785 error = EINVAL;
786 goto fail;
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);
790 error = EXDEV;
791 goto fail;
795 error = 0;
796 #ifdef AFS_DEMAND_ATTACH_FS
797 salv_vp = originalvp;
798 #endif
800 if (purgeId == newId) {
801 newvp = purgevp;
802 } else {
803 newvp =
804 VCreateVolume(&error, originalvp->partition->name, newId,
805 V_parentId(originalvp));
806 if (error) {
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;
810 goto fail;
813 if (newType == readonlyVolume)
814 V_cloneId(originalvp) = newId;
815 Log("1 Volser: Clone: Cloning volume %u to new volume %u\n", tt->volid,
816 newId);
817 if (purgevp)
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 */
821 if (error) {
822 Log("1 Volser: Clone: clone operation failed with code %u\n", error);
823 LogError(error);
824 goto fail;
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);
843 V_inUse(newvp) = 0;
844 VUpdateVolume(&error, newvp);
845 if (error) {
846 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
847 LogError(error);
848 goto fail;
850 VDetachVolume(&error, newvp); /* allow file server to get it's hands on it */
851 newvp = NULL;
852 VUpdateVolume(&error, originalvp);
853 if (error) {
854 Log("1 Volser: Clone: original update %u\n", error);
855 LogError(error);
856 goto fail;
858 TClearRxCall(tt);
859 #ifdef AFS_DEMAND_ATTACH_FS
860 salv_vp = NULL;
861 #endif
862 if (TRELE(tt)) {
863 tt = (struct volser_trans *)0;
864 error = VOLSERTRELE_ERROR;
865 goto fail;
867 DeleteTrans(ttc, 1);
868 return 0;
870 fail:
871 if (purgevp)
872 VDetachVolume(&code, purgevp);
873 if (newvp)
874 VDetachVolume(&code, newvp);
875 if (tt) {
876 TClearRxCall(tt);
877 TRELE(tt);
879 if (ttc)
880 DeleteTrans(ttc, 1);
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 */
886 return error;
889 /* reclone this volume into the specified id */
890 afs_int32
891 SAFSVolReClone(struct rx_call *acid, afs_int32 atrans, afs_uint32 cloneId)
893 afs_int32 code;
895 code = VolReClone(acid, atrans, cloneId);
896 osi_auditU(acid, VS_ReCloneEvent, code, AUD_LONG, atrans, AUD_LONG,
897 cloneId, AUD_END);
898 return code;
901 static afs_int32
902 VolReClone(struct rx_call *acid, afs_int32 atrans, afs_int32 cloneId)
904 struct Volume *originalvp, *clonevp;
905 Error error, code;
906 afs_int32 newType;
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;
914 if (DoLogging) {
915 char buffer[16];
916 Log("%s on %s is executing Reclone Volume %u\n", caller,
917 callerAddress(acid, buffer), cloneId);
919 error = 0;
920 clonevp = originalvp = (Volume *) 0;
921 tt = (struct volser_trans *)0;
923 tt = FindTrans(atrans);
924 if (!tt)
925 return ENOENT;
926 if (tt->vflags & VTDeleted) {
927 Log("1 Volser: VolReClone: volume %u has been deleted \n", tt->volid);
928 TRELE(tt);
929 return ENOENT;
931 ttc = NewTrans(cloneId, tt->partition);
932 if (!ttc) { /* someone is messing with the clone already */
933 TRELE(tt);
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",
941 V_id(originalvp));
942 error = VOFFLINE;
943 goto fail;
946 clonevp = VAttachVolume_retry(&error, cloneId, V_VOLUPD);
947 if (error) {
948 Log("1 Volser: can't attach clone %d\n", cloneId);
949 goto fail;
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",
956 tt->volid, cloneId);
957 error = EXDEV;
958 goto fail;
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);
962 error = EXDEV;
963 goto fail;
966 if (DoPreserveVolumeStats) {
967 CopyVolumeStats(&V_disk(clonevp), &saved_header);
970 error = 0;
971 Log("1 Volser: Clone: Recloning volume %u to volume %u\n", tt->volid,
972 cloneId);
973 CloneVolume(&error, originalvp, clonevp, clonevp);
974 if (error) {
975 Log("1 Volser: Clone: reclone operation failed with code %d\n",
976 error);
977 LogError(error);
978 goto fail;
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));
998 } else {
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);
1009 if (error) {
1010 Log("1 Volser: Clone: VUpdate failed code %u\n", error);
1011 LogError(error);
1012 goto fail;
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 */
1020 clonevp = NULL;
1021 VUpdateVolume(&error, originalvp);
1022 if (error) {
1023 Log("1 Volser: Clone: original update %u\n", error);
1024 LogError(error);
1025 goto fail;
1027 TClearRxCall(tt);
1028 if (TRELE(tt)) {
1029 tt = (struct volser_trans *)0;
1030 error = VOLSERTRELE_ERROR;
1031 goto fail;
1034 DeleteTrans(ttc, 1);
1037 struct DiskPartition64 *tpartp = originalvp->partition;
1038 FSYNC_VolOp(cloneId, tpartp->name, FSYNC_VOL_BREAKCBKS, 0, NULL);
1040 return 0;
1042 fail:
1043 if (clonevp)
1044 VDetachVolume(&code, clonevp);
1045 if (tt) {
1046 TClearRxCall(tt);
1047 TRELE(tt);
1049 if (ttc)
1050 DeleteTrans(ttc, 1);
1051 return error;
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*).
1058 afs_int32
1059 SAFSVolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1060 afs_int32 iflags, afs_int32 *ttid)
1062 afs_int32 code;
1064 code = VolTransCreate(acid, volume, partition, iflags, ttid);
1065 osi_auditU(acid, VS_TransCrEvent, code, AUD_LONG, *ttid, AUD_LONG, volume,
1066 AUD_END);
1067 return code;
1070 static afs_int32
1071 VolTransCreate(struct rx_call *acid, afs_uint32 volume, afs_int32 partition,
1072 afs_int32 iflags, afs_int32 *ttid)
1074 struct volser_trans *tt;
1075 Volume *tv;
1076 afs_int32 error;
1077 Error code;
1078 afs_int32 mode;
1079 char caller[MAXKTCNAMELEN];
1081 if (!afsconf_SuperUser(tdir, acid, caller))
1082 return VOLSERBAD_ACCESS; /*not a super user */
1083 if (iflags & ITCreate)
1084 mode = V_SECRETLY;
1085 else if (iflags & ITBusy)
1086 mode = V_CLONE;
1087 else if (iflags & ITReadOnly)
1088 mode = V_READONLY;
1089 else if (iflags & ITOffline)
1090 mode = V_VOLUPD;
1091 else {
1092 Log("1 Volser: TransCreate: Could not create trans, error %u\n",
1093 EINVAL);
1094 LogError(EINVAL);
1095 return EINVAL;
1097 tt = NewTrans(volume, partition);
1098 if (!tt) {
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);
1104 if (error) {
1105 /* give up */
1106 if (tv)
1107 VDetachVolume(&code, tv);
1108 DeleteTrans(tt, 1);
1109 return error;
1111 VTRANS_OBJ_LOCK(tt);
1112 tt->volume = tv;
1113 *ttid = tt->tid;
1114 tt->iflags = iflags;
1115 tt->vflags = 0;
1116 TSetRxCall_r(tt, NULL, "TransCreate");
1117 VTRANS_OBJ_UNLOCK(tt);
1118 if (TRELE(tt))
1119 return VOLSERTRELE_ERROR;
1121 return 0;
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.
1127 afs_int32
1128 SAFSVolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1129 afs_int32 *apart)
1131 afs_int32 code;
1133 code = VolGetNthVolume(acid, aindex, avolume, apart);
1134 osi_auditU(acid, VS_GetNVolEvent, code, AUD_LONG, *avolume, AUD_END);
1135 return code;
1138 static afs_int32
1139 VolGetNthVolume(struct rx_call *acid, afs_int32 aindex, afs_uint32 *avolume,
1140 afs_int32 *apart)
1142 Log("1 Volser: GetNthVolume: Not yet implemented\n");
1143 return VOLSERNO_OP;
1146 /* return the volume flags (VT* constants in volser.h) associated with this
1147 * transaction.
1149 afs_int32
1150 SAFSVolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1152 afs_int32 code;
1154 code = VolGetFlags(acid, atid, aflags);
1155 osi_auditU(acid, VS_GetFlgsEvent, code, AUD_LONG, atid, AUD_END);
1156 return code;
1159 static afs_int32
1160 VolGetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 *aflags)
1162 struct volser_trans *tt;
1164 tt = FindTrans(atid);
1165 if (!tt)
1166 return ENOENT;
1167 if (tt->vflags & VTDeleted) {
1168 Log("1 Volser: VolGetFlags: volume %u has been deleted \n",
1169 tt->volid);
1170 TRELE(tt);
1171 return ENOENT;
1173 TSetRxCall(tt, acid, "GetFlags");
1174 *aflags = tt->vflags;
1175 TClearRxCall(tt);
1176 if (TRELE(tt))
1177 return VOLSERTRELE_ERROR;
1179 return 0;
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.
1186 afs_int32
1187 SAFSVolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1189 afs_int32 code;
1191 code = VolSetFlags(acid, atid, aflags);
1192 osi_auditU(acid, VS_SetFlgsEvent, code, AUD_LONG, atid, AUD_LONG, aflags,
1193 AUD_END);
1194 return code;
1197 static afs_int32
1198 VolSetFlags(struct rx_call *acid, afs_int32 atid, afs_int32 aflags)
1200 struct volser_trans *tt;
1201 struct Volume *vp;
1202 Error error;
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);
1209 if (!tt)
1210 return ENOENT;
1211 if (tt->vflags & VTDeleted) {
1212 Log("1 Volser: VolSetFlags: volume %u has been deleted \n",
1213 tt->volid);
1214 TRELE(tt);
1215 return ENOENT;
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) {
1222 TRELE(tt);
1223 return EROFS;
1226 /* handle delete-on-salvage flag */
1227 if (aflags & VTDeleteOnSalvage) {
1228 V_destroyMe(tt->volume) = DESTROY_ME;
1229 } else {
1230 V_destroyMe(tt->volume) = 0;
1233 if (aflags & VTOutOfService) {
1234 V_inService(vp) = 0;
1235 } else {
1236 V_inService(vp) = 1;
1238 VUpdateVolume(&error, vp);
1239 VTRANS_OBJ_LOCK(tt);
1240 tt->vflags = aflags;
1241 TClearRxCall_r(tt);
1242 VTRANS_OBJ_UNLOCK(tt);
1243 if (TRELE(tt) && !error)
1244 return VOLSERTRELE_ERROR;
1246 return 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.
1253 afs_int32
1254 SAFSVolForward(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1255 struct destServer *destination, afs_int32 destTrans,
1256 struct restoreCookie *cookie)
1258 afs_int32 code;
1260 code =
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);
1264 return code;
1267 static afs_int32
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;
1273 afs_int32 code;
1274 struct rx_connection *tcon;
1275 struct rx_call *tcall;
1276 struct Volume *vp;
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);
1289 if (!tt)
1290 return ENOENT;
1291 if (tt->vflags & VTDeleted) {
1292 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1293 TRELE(tt);
1294 return ENOENT;
1296 vp = tt->volume;
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);
1301 if (code) {
1302 TRELE(tt);
1303 return code;
1306 /* make an rpc connection to the other server */
1307 tcon =
1308 rx_NewConnection(htonl(destination->destHost),
1309 htons(destination->destPort), VOLSERVICE_ID,
1310 securityObject, securityIndex);
1311 if (!tcon) {
1312 TClearRxCall(tt);
1313 TRELE(tt);
1314 return ENOTCONN;
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);
1320 if (code) {
1321 goto fail;
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 */
1326 if (code)
1327 goto fail;
1328 EndAFSVolRestore(tcall); /* probably doesn't do much */
1329 TClearRxCall(tt);
1330 code = rx_EndCall(tcall, 0);
1331 rx_DestroyConnection(tcon); /* done with the connection */
1332 tcon = NULL;
1333 if (code)
1334 goto fail;
1335 if (TRELE(tt))
1336 return VOLSERTRELE_ERROR;
1338 return 0;
1340 fail:
1341 if (tcon) {
1342 (void)rx_EndCall(tcall, 0);
1343 rx_DestroyConnection(tcon);
1345 if (tt) {
1346 TClearRxCall(tt);
1347 TRELE(tt);
1349 return code;
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
1360 * what we're doing.
1362 afs_int32
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;
1374 struct Volume *vp;
1375 int i, is_incremental;
1377 if (results) {
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)
1384 return ENOMEM;
1386 if (!afsconf_SuperUser(tdir, acid, caller))
1387 return VOLSERBAD_ACCESS; /*not a super user */
1388 tt = FindTrans(fromTrans);
1389 if (!tt)
1390 return ENOENT;
1391 if (tt->vflags & VTDeleted) {
1392 Log("1 Volser: VolForward: volume %u has been deleted \n", tt->volid);
1393 TRELE(tt);
1394 return ENOENT;
1396 vp = tt->volume;
1397 TSetRxCall(tt, NULL, "ForwardMulti");
1399 /* (fromDate == 0) ==> full dump */
1400 is_incremental = (fromDate ? 1 : 0);
1402 tcons =
1403 (struct rx_connection **)malloc(i * sizeof(struct rx_connection *));
1404 if (!tcons) {
1405 return ENOMEM;
1407 tcalls = (struct rx_call **)malloc(i * sizeof(struct rx_call *));
1408 if (!tcalls) {
1409 free(tcons);
1410 return ENOMEM;
1413 /* get auth info for this connection (uses afs from ticket file) */
1414 code = afsconf_ClientAuth(tdir, &securityObject, &securityIndex);
1415 if (code) {
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]);
1422 tcons[i] =
1423 rx_NewConnection(htonl(dest->server.destHost),
1424 htons(dest->server.destPort), VOLSERVICE_ID,
1425 securityObject, securityIndex);
1426 if (!tcons[i]) {
1427 codes[i] = ENOTCONN;
1428 } else {
1429 if (!(tcalls[i] = rx_NewCall(tcons[i])))
1430 codes[i] = ENOTCONN;
1431 else {
1432 codes[i] =
1433 StartAFSVolRestore(tcalls[i], dest->trans, is_incremental,
1434 cookie);
1435 if (codes[i]) {
1436 (void)rx_EndCall(tcalls[i], 0);
1437 tcalls[i] = 0;
1438 rx_DestroyConnection(tcons[i]);
1439 tcons[i] = 0;
1445 /* these next calls implictly call rx_Write when writing out data */
1446 code = DumpVolMulti(tcalls, i, vp, fromDate, 0, codes);
1449 fail:
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]);
1456 if (tcalls[i]) {
1457 ec = rx_EndCall(tcalls[i], 0);
1458 if (!codes[i])
1459 codes[i] = ec;
1461 if (tcons[i]) {
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);
1469 free(tcons);
1470 free(tcalls);
1472 if (tt) {
1473 TClearRxCall(tt);
1474 if (TRELE(tt) && !code) /* return the first code if it's set */
1475 return VOLSERTRELE_ERROR;
1478 return code;
1481 afs_int32
1482 SAFSVolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate)
1484 afs_int32 code;
1486 code = VolDump(acid, fromTrans, fromDate, 0);
1487 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1488 return code;
1491 afs_int32
1492 SAFSVolDumpV2(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1493 afs_int32 flags)
1495 afs_int32 code;
1497 code = VolDump(acid, fromTrans, fromDate, flags);
1498 osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END);
1499 return code;
1502 static afs_int32
1503 VolDump(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
1504 afs_int32 flags)
1506 int code = 0;
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);
1513 if (!tt)
1514 return ENOENT;
1515 if (tt->vflags & VTDeleted) {
1516 Log("1 Volser: VolDump: volume %u has been deleted \n", tt->volid);
1517 TRELE(tt);
1518 return ENOENT;
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 */
1523 if (code) {
1524 TClearRxCall(tt);
1525 TRELE(tt);
1526 return code;
1528 TClearRxCall(tt);
1530 if (TRELE(tt))
1531 return VOLSERTRELE_ERROR;
1533 return 0;
1537 * Ha! No more helper process!
1539 afs_int32
1540 SAFSVolRestore(struct rx_call *acid, afs_int32 atrans, afs_int32 aflags,
1541 struct restoreCookie *cookie)
1543 afs_int32 code;
1545 code = VolRestore(acid, atrans, aflags, cookie);
1546 osi_auditU(acid, VS_RestoreEvent, code, AUD_LONG, atrans, AUD_END);
1547 return code;
1550 static afs_int32
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);
1561 if (!tt)
1562 return ENOENT;
1563 if (tt->vflags & VTDeleted) {
1564 Log("1 Volser: VolRestore: volume %u has been deleted \n", tt->volid);
1565 TRELE(tt);
1566 return ENOENT;
1568 if (DoLogging) {
1569 char buffer[16];
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);
1579 TClearRxCall(tt);
1580 tcode = TRELE(tt);
1582 return (code ? code : tcode);
1585 /* end a transaction, returning the transaction's final error code in rcode */
1586 afs_int32
1587 SAFSVolEndTrans(struct rx_call *acid, afs_int32 destTrans, afs_int32 *rcode)
1589 afs_int32 code;
1591 code = VolEndTrans(acid, destTrans, rcode);
1592 osi_auditU(acid, VS_EndTrnEvent, code, AUD_LONG, destTrans, AUD_END);
1593 return code;
1596 static afs_int32
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);
1605 if (!tt) {
1606 return ENOENT;
1608 *rcode = tt->returnCode;
1609 DeleteTrans(tt, 1); /* this does an implicit TRELE */
1611 return 0;
1614 afs_int32
1615 SAFSVolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1617 afs_int32 code;
1619 code = VolSetForwarding(acid, atid, anewsite);
1620 osi_auditU(acid, VS_SetForwEvent, code, AUD_LONG, atid, AUD_HOST,
1621 htonl(anewsite), AUD_END);
1622 return code;
1625 static afs_int32
1626 VolSetForwarding(struct rx_call *acid, afs_int32 atid, afs_int32 anewsite)
1628 struct volser_trans *tt;
1629 char caller[MAXKTCNAMELEN];
1630 char partName[16];
1632 if (!afsconf_SuperUser(tdir, acid, caller))
1633 return VOLSERBAD_ACCESS; /*not a super user */
1634 tt = FindTrans(atid);
1635 if (!tt)
1636 return ENOENT;
1637 if (tt->vflags & VTDeleted) {
1638 Log("1 Volser: VolSetForwarding: volume %u has been deleted \n",
1639 tt->volid);
1640 TRELE(tt);
1641 return ENOENT;
1643 TSetRxCall(tt, acid, "SetForwarding");
1644 if (volutil_PartitionName2_r(tt->partition, partName, sizeof(partName)) != 0) {
1645 partName[0] = '\0';
1647 FSYNC_VolOp(tt->volid, partName, FSYNC_VOL_MOVE, anewsite, NULL);
1648 TClearRxCall(tt);
1649 if (TRELE(tt))
1650 return VOLSERTRELE_ERROR;
1652 return 0;
1655 afs_int32
1656 SAFSVolGetStatus(struct rx_call *acid, afs_int32 atrans,
1657 struct volser_status *astatus)
1659 afs_int32 code;
1661 code = VolGetStatus(acid, atrans, astatus);
1662 osi_auditU(acid, VS_GetStatEvent, code, AUD_LONG, atrans, AUD_END);
1663 return code;
1666 static afs_int32
1667 VolGetStatus(struct rx_call *acid, afs_int32 atrans,
1668 struct volser_status *astatus)
1670 struct Volume *tv;
1671 struct VolumeDiskData *td;
1672 struct volser_trans *tt;
1675 tt = FindTrans(atrans);
1676 if (!tt)
1677 return ENOENT;
1678 if (tt->vflags & VTDeleted) {
1679 Log("1 Volser: VolGetStatus: volume %u has been deleted \n",
1680 tt->volid);
1681 TRELE(tt);
1682 return ENOENT;
1684 TSetRxCall(tt, acid, "GetStatus");
1685 tv = tt->volume;
1686 if (!tv) {
1687 TClearRxCall(tt);
1688 TRELE(tt);
1689 return ENOENT;
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;
1709 TClearRxCall(tt);
1710 if (TRELE(tt))
1711 return VOLSERTRELE_ERROR;
1713 return 0;
1716 afs_int32
1717 SAFSVolSetInfo(struct rx_call *acid, afs_int32 atrans,
1718 struct volintInfo *astatus)
1720 afs_int32 code;
1722 code = VolSetInfo(acid, atrans, astatus);
1723 osi_auditU(acid, VS_SetInfoEvent, code, AUD_LONG, atrans, AUD_END);
1724 return code;
1727 static afs_int32
1728 VolSetInfo(struct rx_call *acid, afs_int32 atrans,
1729 struct volintInfo *astatus)
1731 struct Volume *tv;
1732 struct VolumeDiskData *td;
1733 struct volser_trans *tt;
1734 char caller[MAXKTCNAMELEN];
1735 Error error;
1737 if (!afsconf_SuperUser(tdir, acid, caller))
1738 return VOLSERBAD_ACCESS; /*not a super user */
1739 tt = FindTrans(atrans);
1740 if (!tt)
1741 return ENOENT;
1742 if (tt->vflags & VTDeleted) {
1743 Log("1 Volser: VolSetInfo: volume %u has been deleted \n", tt->volid);
1744 TRELE(tt);
1745 return ENOENT;
1747 TSetRxCall(tt, acid, "SetStatus");
1748 tv = tt->volume;
1749 if (!tv) {
1750 TClearRxCall(tt);
1751 TRELE(tt);
1752 return ENOENT;
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);
1770 TClearRxCall(tt);
1771 if (TRELE(tt))
1772 return VOLSERTRELE_ERROR;
1773 return 0;
1777 afs_int32
1778 SAFSVolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1780 afs_int32 code;
1782 code = VolGetName(acid, atrans, aname);
1783 osi_auditU(acid, VS_GetNameEvent, code, AUD_LONG, atrans, AUD_END);
1784 return code;
1787 static afs_int32
1788 VolGetName(struct rx_call *acid, afs_int32 atrans, char **aname)
1790 struct Volume *tv;
1791 struct VolumeDiskData *td;
1792 struct volser_trans *tt;
1793 int len;
1795 /* We need to at least fill it in */
1796 *aname = (char *)malloc(1);
1797 if (!*aname)
1798 return ENOMEM;
1799 tt = FindTrans(atrans);
1800 if (!tt)
1801 return ENOENT;
1802 if (tt->vflags & VTDeleted) {
1803 Log("1 Volser: VolGetName: volume %u has been deleted \n", tt->volid);
1804 TRELE(tt);
1805 return ENOENT;
1807 TSetRxCall(tt, acid, "GetName");
1808 tv = tt->volume;
1809 if (!tv) {
1810 TClearRxCall(tt);
1811 TRELE(tt);
1812 return ENOENT;
1815 td = &tv->header->diskstuff;
1816 len = strlen(td->name) + 1; /* don't forget the null */
1817 if (len >= SIZE) {
1818 TClearRxCall(tt);
1819 TRELE(tt);
1820 return E2BIG;
1822 *aname = (char *)realloc(*aname, len);
1823 strcpy(*aname, td->name);
1824 TClearRxCall(tt);
1825 if (TRELE(tt))
1826 return VOLSERTRELE_ERROR;
1828 return 0;
1831 /*this is a handshake to indicate that the next call will be SAFSVolRestore
1832 * - a noop now !*/
1833 afs_int32
1834 SAFSVolSignalRestore(struct rx_call *acid, char volname[], int volType,
1835 afs_uint32 parentId, afs_uint32 cloneId)
1837 return 0;
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*/
1843 afs_int32
1844 SAFSVolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1846 afs_int32 code;
1848 code = VolListPartitions(acid, partIds);
1849 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1850 return code;
1853 static afs_int32
1854 VolListPartitions(struct rx_call *acid, struct pIDs *partIds)
1856 char namehead[9];
1857 int i;
1859 strcpy(namehead, "/vicep"); /*7 including null terminator */
1861 /* Just return attached partitions. */
1862 namehead[7] = '\0';
1863 for (i = 0; i < 26; i++) {
1864 namehead[6] = i + 'a';
1865 partIds->partIds[i] = VGetPartition(namehead, 0) ? i : -1;
1868 return 0;
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*/
1873 afs_int32
1874 SAFSVolXListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1876 afs_int32 code;
1878 code = XVolListPartitions(acid, pEntries);
1879 osi_auditU(acid, VS_ListParEvent, code, AUD_END);
1880 return code;
1883 static afs_int32
1884 XVolListPartitions(struct rx_call *acid, struct partEntries *pEntries)
1886 char namehead[9];
1887 struct partList partList;
1888 struct DiskPartition64 *dp;
1889 int i, j = 0;
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);
1897 #else
1898 if (i < 26) {
1899 namehead[6] = i + 'a';
1900 namehead[7] = '\0';
1901 } else {
1902 int k;
1904 k = i - 26;
1905 namehead[6] = 'a' + (k / 26);
1906 namehead[7] = 'a' + (k % 26);
1907 namehead[8] = '\0';
1909 dp = VGetPartition(namehead, 0);
1910 #endif
1911 if (dp)
1912 partList.partId[j++] = i;
1914 if (j > 0) {
1915 pEntries->partEntries_val = (afs_int32 *) malloc(j * sizeof(int));
1916 if (!pEntries->partEntries_val)
1917 return ENOMEM;
1918 memcpy(pEntries->partEntries_val, partList.partId,
1919 j * sizeof(int));
1920 pEntries->partEntries_len = j;
1921 } else {
1922 pEntries->partEntries_val = NULL;
1923 pEntries->partEntries_len = 0;
1925 return 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)
1934 struct dirent *dp;
1936 dp = readdir(dirp); /*read next entry in the directory */
1937 if (dp) {
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 */
1942 } else {
1943 strcpy(volname, "");
1944 return 0; /*volname doesnot represent a volume */
1946 } else {
1947 strcpy(volname, "EOD");
1948 return 0; /*end of directory */
1954 * volint vol info structure type.
1956 typedef enum {
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.
1964 typedef struct {
1965 volint_info_type_t volinfo_type;
1966 union {
1967 void * opaque;
1968 volintInfo * base;
1969 volintXInfo * ext;
1970 } volinfo_ptr;
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) \
1977 do { \
1978 if ((handle)->volinfo_type == VOLINT_INFO_TYPE_BASE) { \
1979 (handle)->volinfo_ptr.base->name = (val); \
1980 } else { \
1981 (handle)->volinfo_ptr.ext->name = (val); \
1983 } while(0)
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
2006 * @retval 0 success
2007 * @retval 1 failure
2009 static int
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);
2030 } else {
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)
2058 if (!vp ||
2059 (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2060 VIsErrorState(V_attachState(vp)) ||
2061 !hdr->inService ||
2062 !hdr->blessed ||
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);
2071 } else {
2072 VOLINT_INFO_STORE(handle, inUse, 1);
2074 #else
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);
2078 } else {
2079 VOLINT_INFO_STORE(handle, inUse, 0);
2081 #endif
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;
2093 } else {
2094 handle->volinfo_ptr.base->needsSalvaged = 0;
2096 #else
2097 handle->volinfo_ptr.base->needsSalvaged = hdr->needsSalvaged;
2098 #endif
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;
2112 break;
2115 case VOLINT_INFO_TYPE_EXT:
2116 numStatBytes =
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]),
2125 0, numStatBytes);
2126 } else {
2127 memcpy((char *)&(handle->volinfo_ptr.ext->stat_reads[0]),
2128 (char *)&(hdr->stat_reads[0]),
2129 numStatBytes);
2131 break;
2134 return 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
2148 * @retval 0 success
2149 * @retval non-zero failure
2151 * @note if FSYNC_VolOp fails in certain ways, *vp will be set to NULL
2153 * @internal
2155 static int
2156 GetVolObject(afs_uint32 volumeId, char * pname, Volume ** vp)
2158 int code;
2159 SYNC_response res;
2161 res.hdr.response_len = sizeof(res.hdr);
2162 res.payload.buf = *vp;
2163 res.payload.len = sizeof(Volume);
2165 code = FSYNC_VolOp(volumeId,
2166 pname,
2167 FSYNC_VOL_QUERY,
2169 &res);
2171 if (code != SYNC_OK) {
2172 switch (res.hdr.reason) {
2173 case FSYNC_WRONG_PART:
2174 case FSYNC_UNKNOWN_VOLID:
2175 *vp = NULL;
2176 code = SYNC_OK;
2177 break;
2181 return code;
2184 #endif
2187 * mode of volume list operation.
2189 typedef enum {
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
2205 * @retval 0 success
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
2210 static int
2211 GetVolInfo(afs_uint32 partId,
2212 afs_uint32 volumeId,
2213 char * pname,
2214 char * volname,
2215 volint_info_handle_t * handle,
2216 vol_info_list_mode_t mode)
2218 int code = -1;
2219 Error error;
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;
2232 #endif
2234 ttc = NewTrans(volumeId, partId);
2235 if (!ttc) {
2236 code = -3;
2237 VOLINT_INFO_STORE(handle, status, VBUSY);
2238 VOLINT_INFO_STORE(handle, volid, volumeId);
2239 goto drop;
2242 /* Get volume from volserver */
2243 if (mode == VOL_INFO_LIST_MULTIPLE)
2244 tv = VAttachVolumeByName(&error, pname, volname, V_PEEK);
2245 else {
2246 #ifdef AFS_DEMAND_ATTACH_FS
2247 int mode = V_PEEK;
2248 #else
2249 int mode = V_READONLY; /* informs the fileserver to update the volume headers. */
2250 #endif
2251 tv = VAttachVolumeByName_retry(&error, pname, volname, mode);
2254 if (error) {
2255 Log("1 Volser: GetVolInfo: Could not attach volume %u (%s:%s) error=%d\n",
2256 volumeId, pname, volname, error);
2257 goto drop;
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) {
2268 switch (mode) {
2269 case VOL_INFO_LIST_MULTIPLE:
2270 code = -2;
2271 goto drop;
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);
2277 default:
2278 goto drop;
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) {
2292 goto drop;
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;
2300 } else {
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 */
2308 fill_tv = fs_tv;
2309 #else
2310 /* When not using DAFS, just use the local volume info */
2311 fill_tv = tv;
2312 #endif
2314 /* ok, we have all the data we need; fill in the on-wire struct */
2315 code = FillVolInfo(fill_tv, handle);
2317 drop:
2318 if (code == -1) {
2319 VOLINT_INFO_STORE(handle, status, 0);
2320 strcpy((char *)VOLINT_INFO_PTR(handle, name), volname);
2321 VOLINT_INFO_STORE(handle, volid, volumeId);
2323 if (tv) {
2324 VDetachVolume(&error, tv);
2325 tv = NULL;
2326 if (error) {
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);
2333 if (ttc) {
2334 DeleteTrans(ttc, 1);
2335 ttc = NULL;
2337 return code;
2341 /*return the header information about the <volid> */
2342 afs_int32
2343 SAFSVolListOneVolume(struct rx_call *acid, afs_int32 partid,
2344 afs_uint32 volumeId, volEntries *volumeInfo)
2346 afs_int32 code;
2348 code = VolListOneVolume(acid, partid, volumeId, volumeInfo);
2349 osi_auditU(acid, VS_Lst1VolEvent, code, AUD_LONG, volumeId, AUD_END);
2350 return code;
2353 static afs_int32
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];
2359 DIR *dirp;
2360 afs_uint32 volid;
2361 int found = 0;
2362 volint_info_handle_t handle;
2364 volumeInfo->volEntries_val = (volintInfo *) malloc(sizeof(volintInfo));
2365 if (!volumeInfo->volEntries_val)
2366 return ENOMEM;
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));
2375 if (dirp == NULL)
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 */
2388 found = 1;
2389 break;
2392 GetNextVol(dirp, volname, &volid);
2395 if (found) {
2396 #ifndef AFS_PTHREAD_ENV
2397 IOMGR_Poll(); /*make sure that the client does not time out */
2398 #endif
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. */
2407 GetVolInfo(partid,
2408 volid,
2409 pname,
2410 volname,
2411 &handle,
2412 VOL_INFO_LIST_SINGLE);
2415 closedir(dirp);
2416 return (found) ? 0 : ENODEV;
2419 /*------------------------------------------------------------------------
2420 * EXPORTED SAFSVolXListOneVolume
2422 * Description:
2423 * Returns extended info on volume a_volID on partition a_partID.
2425 * Arguments:
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.
2431 * Returns:
2432 * 0 Successful operation
2433 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2435 * Environment:
2436 * Nothing interesting.
2438 * Side Effects:
2439 * As advertised.
2440 *------------------------------------------------------------------------*/
2442 afs_int32
2443 SAFSVolXListOneVolume(struct rx_call *a_rxCidP, afs_int32 a_partID,
2444 afs_uint32 a_volID, volXEntries *a_volumeXInfoP)
2446 afs_int32 code;
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);
2450 return code;
2453 static afs_int32
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)
2472 return ENOMEM;
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
2485 * do that, we lose.
2487 if (!(partP = VGetPartition(pname, 0)))
2488 return VOLSERILLEGAL_PARTITION;
2489 dirp = opendir(VPartitionPath(partP));
2490 if (dirp == NULL)
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
2498 * volume.
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);
2507 continue;
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.
2516 found = 1;
2517 break;
2518 } /*Found desired volume */
2520 GetNextVol(dirp, volname, &currVolID);
2523 if (found) {
2524 #ifndef AFS_PTHREAD_ENV
2525 IOMGR_Poll();
2526 #endif
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,
2536 a_volID,
2537 pname,
2538 volname,
2539 &handle,
2540 VOL_INFO_LIST_SINGLE);
2544 * Clean up before going to dinner: close the partition directory,
2545 * return the proper value.
2547 closedir(dirp);
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 */
2553 afs_int32
2554 SAFSVolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2555 volEntries *volumeInfo)
2557 afs_int32 code;
2559 code = VolListVolumes(acid, partid, flags, volumeInfo);
2560 osi_auditU(acid, VS_ListVolEvent, code, AUD_END);
2561 return code;
2564 static afs_int32
2565 VolListVolumes(struct rx_call *acid, afs_int32 partid, afs_int32 flags,
2566 volEntries *volumeInfo)
2568 volintInfo *pntr;
2569 struct DiskPartition64 *partP;
2570 afs_int32 allocSize = 1000; /*to be changed to a larger figure */
2571 char pname[9], volname[20];
2572 DIR *dirp;
2573 afs_uint32 volid;
2574 int code;
2575 volint_info_handle_t handle;
2577 volumeInfo->volEntries_val =
2578 (volintInfo *) malloc(allocSize * sizeof(volintInfo));
2579 if (!volumeInfo->volEntries_val)
2580 return ENOMEM;
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));
2590 if (dirp == NULL)
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 */
2604 #endif
2606 handle.volinfo_type = VOLINT_INFO_TYPE_BASE;
2607 handle.volinfo_ptr.base = pntr;
2610 code = GetVolInfo(partid,
2611 volid,
2612 pname,
2613 volname,
2614 &handle,
2615 VOL_INFO_LIST_MULTIPLE);
2616 if (code == -2) { /* DESTROY_ME flag set */
2617 goto drop2;
2619 } else {
2620 pntr->volid = volid;
2621 /*just volids are needed */
2624 pntr++;
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;
2629 pntr =
2630 (volintInfo *) realloc((char *)volumeInfo->volEntries_val,
2631 allocSize * sizeof(volintInfo));
2632 if (pntr == NULL) {
2633 closedir(dirp);
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;
2642 drop2:
2643 GetNextVol(dirp, volname, &volid);
2647 closedir(dirp);
2648 return 0;
2651 /*------------------------------------------------------------------------
2652 * EXPORTED SAFSVolXListVolumes
2654 * Description:
2655 * Returns all the volumes on partition a_partID. If a_flags
2656 * is set to 1, then all the relevant extended volume information
2657 * is also returned.
2659 * Arguments:
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.
2665 * Returns:
2666 * 0 Successful operation
2667 * VOLSERILLEGAL_PARTITION if we got a bogus partition ID
2668 * VOLSERNO_MEMORY if we ran out of memory allocating
2669 * our return blob
2671 * Environment:
2672 * Nothing interesting.
2674 * Side Effects:
2675 * As advertised.
2676 *------------------------------------------------------------------------*/
2678 afs_int32
2679 SAFSVolXListVolumes(struct rx_call *a_rxCidP, afs_int32 a_partID,
2680 afs_int32 a_flags, volXEntries *a_volumeXInfoP)
2682 afs_int32 code;
2684 code = VolXListVolumes(a_rxCidP, a_partID, a_flags, a_volumeXInfoP);
2685 osi_auditU(a_rxCidP, VS_XLstVolEvent, code, AUD_END);
2686 return code;
2689 static afs_int32
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 */
2700 int code;
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)
2710 return ENOMEM;
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
2724 * do that, we lose.
2726 if (!(partP = VGetPartition(pname, 0)))
2727 return VOLSERILLEGAL_PARTITION;
2728 dirp = opendir(VPartitionPath(partP));
2729 if (dirp == NULL)
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);
2745 continue;
2748 if (a_flags) {
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
2754 IOMGR_Poll();
2755 #endif
2757 handle.volinfo_type = VOLINT_INFO_TYPE_EXT;
2758 handle.volinfo_ptr.ext = xInfoP;
2760 code = GetVolInfo(a_partID,
2761 volid,
2762 pname,
2763 volname,
2764 &handle,
2765 VOL_INFO_LIST_MULTIPLE);
2766 if (code == -2) { /* DESTROY_ME flag set */
2767 goto drop2;
2769 } else {
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.
2780 xInfoP++;
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.
2794 closedir(dirp);
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
2801 * the new block.
2803 a_volumeXInfoP->volXEntries_val = xInfoP;
2804 xInfoP =
2805 a_volumeXInfoP->volXEntries_val +
2806 a_volumeXInfoP->volXEntries_len;
2809 drop2:
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.
2817 closedir(dirp);
2818 return (0);
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*/
2824 afs_int32
2825 SAFSVolMonitor(struct rx_call *acid, transDebugEntries *transInfo)
2827 afs_int32 code;
2829 code = VolMonitor(acid, transInfo);
2830 osi_auditU(acid, VS_MonitorEvent, code, AUD_END);
2831 return code;
2834 static afs_int32
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)
2844 return ENOMEM;
2845 pntr = transInfo->transDebugEntries_val;
2846 transInfo->transDebugEntries_len = 0;
2848 VTRANS_LOCK;
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 */
2853 nt = tt->next;
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);
2874 pntr++;
2875 transInfo->transDebugEntries_len += 1;
2876 if ((allocSize - transInfo->transDebugEntries_len) < 5) { /*alloc some more space */
2877 allocSize = (allocSize * 3) / 2;
2878 pntr =
2879 (transDebugInfo *) realloc((char *)transInfo->
2880 transDebugEntries_val,
2881 allocSize *
2882 sizeof(transDebugInfo));
2883 transInfo->transDebugEntries_val = pntr;
2884 pntr =
2885 transInfo->transDebugEntries_val +
2886 transInfo->transDebugEntries_len;
2887 /*set pntr to right position */
2891 done:
2892 VTRANS_UNLOCK;
2894 return 0;
2897 afs_int32
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)
2902 afs_int32 code;
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,
2907 backupId, AUD_END);
2908 return code;
2911 static afs_int32
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)
2916 struct Volume *tv;
2917 Error error = 0;
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);
2927 if (!tt)
2928 return ENOENT;
2929 if (tt->vflags & VTDeleted) {
2930 Log("1 Volser: VolSetIds: volume %u has been deleted \n", tt->volid);
2931 TRELE(tt);
2932 return ENOENT;
2934 TSetRxCall(tt, acid, "SetIdsTypes");
2935 tv = tt->volume;
2937 V_type(tv) = type;
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);
2943 if (error) {
2944 Log("1 Volser: SetIdsTypes: VUpdate failed code %d\n", error);
2945 LogError(error);
2946 goto fail;
2948 TClearRxCall(tt);
2949 if (TRELE(tt) && !error)
2950 return VOLSERTRELE_ERROR;
2952 return error;
2953 fail:
2954 TClearRxCall(tt);
2955 if (TRELE(tt) && !error)
2956 return VOLSERTRELE_ERROR;
2957 return error;
2960 afs_int32
2961 SAFSVolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2963 afs_int32 code;
2965 code = VolSetDate(acid, atid, cdate);
2966 osi_auditU(acid, VS_SetDateEvent, code, AUD_LONG, atid, AUD_LONG, cdate,
2967 AUD_END);
2968 return code;
2971 static afs_int32
2972 VolSetDate(struct rx_call *acid, afs_int32 atid, afs_int32 cdate)
2974 struct Volume *tv;
2975 Error error = 0;
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);
2983 if (!tt)
2984 return ENOENT;
2985 if (tt->vflags & VTDeleted) {
2986 Log("1 Volser: VolSetDate: volume %u has been deleted \n", tt->volid);
2987 TRELE(tt);
2988 return ENOENT;
2990 TSetRxCall(tt, acid, "SetDate");
2991 tv = tt->volume;
2993 V_creationDate(tv) = cdate;
2994 VUpdateVolume(&error, tv);
2995 if (error) {
2996 Log("1 Volser: SetDate: VUpdate failed code %d\n", error);
2997 LogError(error);
2998 goto fail;
3000 TClearRxCall(tt);
3001 if (TRELE(tt) && !error)
3002 return VOLSERTRELE_ERROR;
3004 return error;
3005 fail:
3006 TClearRxCall(tt);
3007 if (TRELE(tt) && !error)
3008 return VOLSERTRELE_ERROR;
3009 return error;
3012 afs_int32
3013 SAFSVolConvertROtoRWvolume(struct rx_call *acid, afs_int32 partId,
3014 afs_uint32 volumeId)
3016 #ifdef AFS_NT40_ENV
3017 return EXDEV;
3018 #else
3019 char caller[MAXKTCNAMELEN];
3020 DIR *dirp;
3021 struct volser_trans *ttc;
3022 char pname[16], volname[20];
3023 struct DiskPartition64 *partP;
3024 afs_int32 ret = ENODEV;
3025 afs_uint32 volid;
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));
3034 if (dirp == NULL)
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 */
3048 #endif
3049 ttc = NewTrans(volumeId, partId);
3050 if (!ttc) {
3051 return VOLSERVOLBUSY;
3053 #ifdef AFS_NAMEI_ENV
3054 ret = namei_ConvertROtoRWvolume(pname, volumeId);
3055 #else
3056 ret = inode_ConvertROtoRWvolume(pname, volumeId);
3057 #endif
3058 break;
3060 GetNextVol(dirp, volname, &volid);
3063 if (ttc) {
3064 DeleteTrans(ttc, 1);
3065 ttc = (struct volser_trans *)0;
3068 closedir(dirp);
3069 return ret;
3070 #endif
3073 afs_int32
3074 SAFSVolGetSize(struct rx_call *acid, afs_int32 fromTrans, afs_int32 fromDate,
3075 struct volintSize *size)
3077 int code = 0;
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);
3084 if (!tt)
3085 return ENOENT;
3086 if (tt->vflags & VTDeleted) {
3087 TRELE(tt);
3088 return ENOENT;
3090 TSetRxCall(tt, acid, "GetSize");
3091 code = SizeDumpVolume(acid, tt->volume, fromDate, 1, size); /* measure volume's data */
3092 TClearRxCall(tt);
3093 if (TRELE(tt))
3094 return VOLSERTRELE_ERROR;
3096 /* osi_auditU(acid, VS_DumpEvent, code, AUD_LONG, fromTrans, AUD_END); */
3097 return code;
3100 afs_int32
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)
3105 Error code, code2;
3106 Volume *vol=0, *newvol=0;
3107 struct volser_trans *tt = 0, *tt2 = 0;
3108 char caller[MAXKTCNAMELEN];
3109 char line[128];
3111 if (!afsconf_SuperUser(tdir, acall, caller))
3112 return EPERM;
3114 vol = VAttachVolume(&code, vid, V_VOLUPD);
3115 if (!vol) {
3116 if (!code)
3117 code = ENOENT;
3118 return code;
3120 newvol = VAttachVolume(&code, new, V_VOLUPD);
3121 if (!newvol) {
3122 VDetachVolume(&code2, vol);
3123 if (!code)
3124 code = ENOENT;
3125 return code;
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",
3131 vid, new);
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));
3138 line[0] = 0;
3139 rx_Write(acall, line, 1);
3140 VDetachVolume(&code2, vol);
3141 VDetachVolume(&code2, newvol);
3142 return EINVAL;
3144 tt = NewTrans(vid, V_device(vol));
3145 if (!tt) {
3146 sprintf(line, "Couldn't create transaction for %u, aborted.\n", vid);
3147 rx_Write(acall, line, strlen(line));
3148 line[0] = 0;
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;
3156 tt->vflags = 0;
3157 TSetRxCall_r(tt, NULL, "SplitVolume");
3158 VTRANS_OBJ_UNLOCK(tt);
3160 tt2 = NewTrans(new, V_device(newvol));
3161 if (!tt2) {
3162 sprintf(line, "Couldn't create transaction for %u, aborted.\n", new);
3163 rx_Write(acall, line, strlen(line));
3164 line[0] = 0;
3165 rx_Write(acall, line, 1);
3166 DeleteTrans(tt, 1);
3167 VDetachVolume(&code2, vol);
3168 VDetachVolume(&code2, newvol);
3169 return VOLSERVOLBUSY;
3171 VTRANS_OBJ_LOCK(tt2);
3172 tt2->iflags = ITBusy;
3173 tt2->vflags = 0;
3174 TSetRxCall_r(tt2, NULL, "SplitVolume");
3175 VTRANS_OBJ_UNLOCK(tt2);
3177 code = split_volume(acall, vol, newvol, where, verbose);
3179 VDetachVolume(&code2, vol);
3180 DeleteTrans(tt, 1);
3181 VDetachVolume(&code2, newvol);
3182 DeleteTrans(tt2, 1);
3183 return code;
3184 #else
3185 return VOLSERBADOP;
3186 #endif
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
3191 * partition struct.
3193 static int
3194 GetPartName(afs_int32 partid, char *pname)
3196 if (partid < 0)
3197 return -1;
3198 if (partid < 26) {
3199 strcpy(pname, "/vicep");
3200 pname[6] = 'a' + partid;
3201 pname[7] = '\0';
3202 return 0;
3203 } else if (partid < VOLMAXPARTS) {
3204 strcpy(pname, "/vicep");
3205 partid -= 26;
3206 pname[6] = 'a' + (partid / 26);
3207 pname[7] = 'a' + (partid % 26);
3208 pname[8] = '\0';
3209 return 0;
3210 } else
3211 return -1;