2 * Copyright (c) 2007, Hartmut Reuter,
3 * RZG, Max-Planck-Institut f. Plasmaphysik.
13 #ifdef HAVE_SYS_FILE_H
17 #if defined(AFS_NAMEI_ENV) && !defined(AFS_NT40_ENV)
20 #include <rx/rx_queue.h>
21 #include <afs/afsint.h>
25 #include <afs/afssyscalls.h>
26 #include <afs/ihandle.h>
27 #include <afs/vnode.h>
28 #include <afs/volume.h>
29 #include <afs/partition.h>
30 #include <afs/viceinode.h>
36 #include "volser_internal.h"
37 #ifdef AFS_RXOSD_SUPPORT
40 #include "../vol/vol_osd_prototypes.h"
45 #define CHANGEPARENT 4
47 #define NAMEI_VNODEMASK 0x03ffffff
48 #define NAMEI_TAGMASK 0x7
49 #define NAMEI_TAGSHIFT 26
50 #define NAMEI_UNIQMASK 0xffffffff
51 #define NAMEI_UNIQSHIFT 32
60 struct rx_call
* call
;
66 ExtractVnodes(struct Msg
*m
, Volume
*vol
, afs_int32
class,
67 struct VnodeExtract
**list
,
68 afs_uint32
*length
, afs_uint32 where
,
69 struct VnodeDiskObject
*vd
,
70 afs_uint32
*parent
, struct VnodeDiskObject
*parentvd
)
73 char buf
[SIZEOF_LARGEDISKVNODE
];
74 struct VnodeDiskObject
*vnode
= (struct VnodeDiskObject
*)&buf
;
76 StreamHandle_t
*stream
= 0;
77 struct VnodeClassInfo
*vcp
= &VnodeClassInfo
[class];
78 struct VnodeExtract
*e
;
86 fdP
= IH_OPEN(vol
->vnodeIndex
[class].handle
);
88 sprintf(m
->line
, "Couldn't open %s Index of volume %" AFS_VOLID_FMT
"\n",
89 class ? "small":"large", afs_printable_VolumeId_lu(V_id(vol
)));
90 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
95 *list
= calloc(size
/ vcp
->diskSize
, sizeof(struct VnodeExtract
));
100 stream
= FDH_FDOPEN(fdP
, "r");
102 sprintf(m
->line
, "Couldn't stream open %s Index of volume %" AFS_VOLID_FMT
"\n",
103 class ? "small":"large", afs_printable_VolumeId_lu(V_id(vol
)));
104 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
108 code
= STREAM_ASEEK(stream
, vcp
->diskSize
);
112 offset
= vcp
->diskSize
;
114 while (!STREAM_EOF(stream
)) {
115 afs_int32 vN
= (offset
>> (vcp
->logSize
-1)) - 1 + class;
116 if (STREAM_READ(vnode
, vcp
->diskSize
, 1, stream
) == 1) {
117 if (vnode
->type
!= vNull
) {
119 e
->parent
= vnode
->parent
;
120 if (vN
== where
&& class == vLarge
) {
121 memcpy(vd
, vnode
, vcp
->diskSize
);
122 *parent
= vnode
->parent
;
126 offset
+= vcp
->diskSize
;
129 *length
= (e
- *list
);
130 if (class == vLarge
) {
132 offset
= (*parent
+ 1 - class) << (vcp
->logSize
-1);
133 code
= STREAM_ASEEK(stream
, offset
);
134 if (STREAM_READ(vnode
, vcp
->diskSize
, 1, stream
) == 1)
135 memcpy(parentvd
, vnode
, vcp
->diskSize
);
139 sprintf(m
->line
, "SplitVolume: extract didn't see directory %u\n", where
);
140 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
145 sprintf(m
->line
, "Volume %" AFS_VOLID_FMT
" has %u %s vnodes in volume %" AFS_VOLID_FMT
"\n",
146 afs_printable_VolumeId_lu(V_parentId(vol
)), *length
,
147 class? "small":"large", afs_printable_VolumeId_lu(V_id(vol
)));
148 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
153 STREAM_CLOSE(stream
);
164 FindVnodes(struct Msg
*m
, afs_uint32 where
,
165 struct VnodeExtract
*list
, afs_int32 length
,
166 struct VnodeExtract
*dlist
, afs_int32 dlength
,
167 afs_uint32
*needed
, afs_int32
class)
169 afs_int32 i
, j
, found
= 0;
170 afs_int32 parent
= 0;
173 for (i
=0; i
<length
; i
++) {
174 if (list
[i
].vN
== where
) { /* dir to be replaced by mount point */
175 list
[i
].flag
|= NEEDED
;
176 parent
= list
[i
].parent
;
180 if (list
[i
].parent
== where
) { /* all 1st generation children */
181 list
[i
].flag
|= (NEEDED
+ CHANGEPARENT
);
185 if (list
[0].vN
& 1) { /* only for directories */
188 "SplitVolume: directory %u where to start new volume not found\n",
190 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
194 for (i
=0; i
<length
; i
++) {
195 if (list
[i
].vN
== parent
) { /* dir where to create mount point */
196 list
[i
].flag
|= PARENT
;
202 sprintf(m
->line
, "SplitVolume: parent directory %u not found\n",
204 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
211 for (i
=0; i
<dlength
; i
++) {
212 if (!(dlist
[i
].flag
& NEEDED
)) /* dirs to remain in old volume */
214 for (j
=0; j
<length
; j
++) {
215 if (list
[j
].parent
== dlist
[i
].vN
&& !(list
[j
].flag
& NEEDED
)) {
216 list
[j
].flag
|= NEEDED
;
224 sprintf(m
->line
, "%u %s vnodes will go into the new volume\n",
225 *needed
, class ? "small" : "large");
226 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
232 copyDir(struct Msg
*m
, IHandle_t
*inh
, IHandle_t
*outh
)
234 FdHandle_t
*infdP
, *outfdP
;
239 infdP
= IH_OPEN(inh
);
241 sprintf(m
->line
, "Couldn't open input directory %" AFS_VOLID_FMT
".%u.%u\n",
242 afs_printable_VolumeId_lu(inh
->ih_vid
),
243 (afs_uint32
)(inh
->ih_ino
& NAMEI_VNODEMASK
),
244 (afs_uint32
)(inh
->ih_ino
>> NAMEI_UNIQSHIFT
));
245 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
248 outfdP
= IH_OPEN(outh
);
250 * In case that a file with the same (NAMEI) name existed before and is still
251 * open outfdP may point to the wrong (unlinked) file. To make sure we write
252 * into the correct file it's safer to 1st FDH_REALLYCLOSE it and then to
256 FDH_REALLYCLOSE(outfdP
);
257 outfdP
= IH_OPEN(outh
);
259 sprintf(m
->line
, "Couldn't open output directory %" AFS_VOLID_FMT
".%u.%u\n",
260 afs_printable_VolumeId_lu(outh
->ih_vid
),
261 (afs_uint32
)(outh
->ih_ino
& NAMEI_VNODEMASK
),
262 (afs_uint32
)(outh
->ih_ino
>> NAMEI_UNIQSHIFT
));
263 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
264 FDH_REALLYCLOSE(infdP
);
269 size
= FDH_SIZE(infdP
);
272 tlen
= size
> 2048 ? 2048 : size
;
273 if (FDH_PREAD(infdP
, tbuf
, tlen
, offset
) != tlen
) {
274 sprintf(m
->line
, "Couldn't read directory %" AFS_VOLID_FMT
".%u.%u\n",
275 afs_printable_VolumeId_lu(infdP
->fd_ih
->ih_vid
),
276 (afs_uint32
)(infdP
->fd_ih
->ih_ino
& NAMEI_VNODEMASK
),
277 (afs_uint32
)(infdP
->fd_ih
->ih_ino
>> NAMEI_UNIQSHIFT
));
278 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
279 FDH_REALLYCLOSE(infdP
);
280 FDH_REALLYCLOSE(outfdP
);
284 if (FDH_PWRITE(outfdP
, tbuf
, tlen
, offset
) != tlen
) {
285 sprintf(m
->line
, "Couldn't write directory %" AFS_VOLID_FMT
".%u.%u\n",
286 afs_printable_VolumeId_lu(outfdP
->fd_ih
->ih_vid
),
287 (afs_uint32
)(outfdP
->fd_ih
->ih_ino
& NAMEI_VNODEMASK
),
288 (afs_uint32
)(outfdP
->fd_ih
->ih_ino
>> NAMEI_UNIQSHIFT
));
289 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
290 FDH_REALLYCLOSE(infdP
);
291 FDH_REALLYCLOSE(outfdP
);
300 FDH_REALLYCLOSE(infdP
);
304 afs_int32
copyVnodes(struct Msg
*m
, Volume
*vol
, Volume
*newvol
,
306 struct VnodeExtract
*list
, afs_int32 length
,
307 afs_int32 where
, afs_uint64
*blocks
,
308 struct VnodeDiskObject
*parVnode
)
310 afs_int32 i
, code
= 0;
311 char buf
[SIZEOF_LARGEDISKVNODE
];
312 struct VnodeDiskObject
*vnode
= (struct VnodeDiskObject
*)&buf
;
314 FdHandle_t
*newfdP
= 0;
315 struct VnodeClassInfo
*vcp
= &VnodeClassInfo
[class];
316 struct VnodeExtract
*e
;
320 fdP
= IH_OPEN(vol
->vnodeIndex
[class].handle
);
322 Log("Couldn't open %s Index of volume %" AFS_VOLID_FMT
"\n",
323 class ? "small":"large", afs_printable_VolumeId_lu(V_id(vol
)));
327 newfdP
= IH_OPEN(newvol
->vnodeIndex
[class].handle
);
329 Log("Couldn't open %s Index of volume %" AFS_VOLID_FMT
"\n",
330 class ? "small":"large", afs_printable_VolumeId_lu(V_id(newvol
)));
335 for (i
=0; i
<length
; i
++) {
339 offset
= (e
->vN
+ 1 - class) << (vcp
->logSize
-1);
340 if (FDH_PREAD(fdP
, vnode
, vcp
->diskSize
, offset
) != vcp
->diskSize
) {
341 Log("Couldn't read in %s Index of volume %" AFS_VOLID_FMT
" at offset %llu\n",
342 class ? "small":"large",
343 afs_printable_VolumeId_lu(V_id(vol
)), offset
);
347 if (e
->flag
& PARENT
) {
349 * do a preventive copy on write for later update
353 #if defined(NEARINODE_HINT) && !defined(AFS_NAMEI_ENV)
355 V_pref(vol
,nearInode
)
358 newino
= IH_CREATE(V_linkHandle(vol
), V_device(vol
),
359 VPartitionPath(V_partition(vol
)),
360 nearInode
, V_parentId(vol
),
361 e
->vN
, vnode
->uniquifier
,
363 IH_INIT(newh
, V_device(vol
), V_parentId(vol
), newino
);
364 ino
= VNDISK_GET_INO(vnode
);
365 IH_INIT(h
, V_device(vol
), V_parentId(vol
), ino
);
366 code
= copyDir(m
, h
, newh
);
369 /* Now update the vnode and write it back to disk */
370 VNDISK_SET_INO(vnode
, newino
);
372 if (FDH_PWRITE(fdP
, vnode
, vcp
->diskSize
, offset
) != vcp
->diskSize
) {
373 Log("Couldn't write in %s Index of volume %" AFS_VOLID_FMT
" at offset %llu\n",
374 class ? "small":"large", afs_printable_VolumeId_lu(V_id(vol
)), offset
);
378 if (parVnode
!= NULL
)
379 memcpy(parVnode
, vnode
, sizeof(struct VnodeDiskObject
));
381 if (e
->flag
& NEEDED
&& e
->vN
!= where
) {
382 VNDISK_GET_LEN(size
, vnode
);
383 *blocks
+= (size
+ 0x3ff) >> 10;
384 ino
= VNDISK_GET_INO(vnode
);
387 Inode AFS_UNUSED nearInode
;
388 #if defined(NEARINODE_HINT) && !defined(AFS_NAMEI_ENV)
389 V_pref(vol
,nearInode
)
391 IH_INIT(h
, vol
->device
, V_parentId(vol
), ino
);
392 if (e
->parent
== where
)
394 newino
= IH_CREATE(V_linkHandle(newvol
), V_device(newvol
),
395 VPartitionPath(V_partition(newvol
)),
396 nearInode
, V_parentId(newvol
),
397 e
->vN
, vnode
->uniquifier
,
399 if (!VALID_INO(newino
)) {
400 Log("IH_CREATE failed for %" AFS_VOLID_FMT
".%u.%u\n",
401 afs_printable_VolumeId_lu(V_id(newvol
)), e
->vN
, vnode
->uniquifier
);
406 IH_INIT(newh
, newvol
->device
, V_parentId(newvol
), newino
);
407 code
= namei_replace_file_by_hardlink(newh
, h
);
408 VNDISK_SET_INO(vnode
, newino
);
409 #ifdef AFS_RXOSD_SUPPORT
411 code
= osd_split_objects(vol
, newvol
, vnode
, e
->vN
);
412 #endif /* AFS_RXOSD_SUPPORT */
416 if (e
->flag
& CHANGEPARENT
)
417 vnode
->parent
= 1; /* in new root-directory */
419 if (FDH_PWRITE(newfdP
, vnode
, vcp
->diskSize
, offset
) != vcp
->diskSize
) {
420 Log("Couldn't write in %s Index of volume %" AFS_VOLID_FMT
" to offset %llu\n",
421 class ? "small":"large", afs_printable_VolumeId_lu(V_id(newvol
)), offset
);
429 * Now copy the root directory from old to new volume
431 if (class == vLarge
) {
433 char buf2
[SIZEOF_LARGEDISKVNODE
];
434 struct VnodeDiskObject
*vnode2
= (struct VnodeDiskObject
*)&buf2
;
435 afs_uint64 newoffset
, size
;
437 newoffset
= vcp
->diskSize
;
438 if (FDH_PREAD(newfdP
, vnode2
, vcp
->diskSize
, newoffset
) != vcp
->diskSize
) {
439 Log("splitvolume: couldn't read in large Index of new volume %" AFS_VOLID_FMT
" at offset %u\n",
440 afs_printable_VolumeId_lu(V_id(newvol
)), vcp
->diskSize
);
444 offset
= (where
+ 1 - class) << (vcp
->logSize
-1);
445 if (FDH_PREAD(fdP
, vnode
, vcp
->diskSize
, offset
) != vcp
->diskSize
) {
446 Log("Couldn't read in large Index of old volume %" AFS_VOLID_FMT
" at offset %llu\n",
447 afs_printable_VolumeId_lu(V_id(vol
)), offset
);
451 VNDISK_GET_LEN(size
, vnode
);
452 *blocks
+= (size
+ 0x3ff) >> 10;
453 ino
= VNDISK_GET_INO(vnode
);
454 IH_INIT(h
, vol
->device
, V_parentId(vol
), ino
);
455 newino
= VNDISK_GET_INO(vnode2
);
456 IH_INIT(newh
, newvol
->device
, V_parentId(newvol
), newino
);
457 code
= copyDir(m
, h
, newh
);
459 Log("splitvolume: copyDir failed for new root from "
460 "%" AFS_VOLID_FMT
".%u.%u to %" AFS_VOLID_FMT
".1.1\n",
461 afs_printable_VolumeId_lu(V_id(vol
)), where
, vnode
->uniquifier
,
462 afs_printable_VolumeId_lu(V_id(newvol
)));
466 VNDISK_SET_INO(vnode
, newino
);
467 vnode
->uniquifier
= 1;
469 vnode
->parent
= vnode2
->parent
;
470 vnode
->serverModifyTime
= vnode2
->serverModifyTime
;
471 if (FDH_PWRITE(newfdP
, vnode
, vcp
->diskSize
, newoffset
) != vcp
->diskSize
) {
472 Log("splitvolume: couldn't write in large Index of %" AFS_VOLID_FMT
" at offset %u\n",
473 afs_printable_VolumeId_lu(V_id(newvol
)), vcp
->diskSize
);
486 findName(Volume
*vol
, struct VnodeDiskObject
*vd
, afs_uint32 vN
,
487 afs_uint32 un
, char *name
,afs_int32 length
)
493 ino
= VNDISK_GET_INO(vd
);
494 SetSalvageDirHandle(&dir
, V_id(vol
), V_device(vol
), ino
);
496 code
= afs_dir_InverseLookup(&dir
, vN
, un
, name
, length
);
502 createMountpoint(Volume
*vol
, Volume
*newvol
, struct VnodeDiskObject
*parent
,
503 afs_uint32 vN
, struct VnodeDiskObject
*vd
, char *name
)
509 struct VnodeDiskObject vnode
;
510 FdHandle_t
*fdP
, *fdP2
;
513 afs_int32
class = vSmall
;
514 struct VnodeClassInfo
*vcp
= &VnodeClassInfo
[class];
515 #if defined(NEARINODE_HINT) && !defined(AFS_NAMEI_ENV)
521 char symlink
[VNAMESIZE
+ 1];
524 FT_GetTimeOfDay(&now
, 0);
525 fdP
= IH_OPEN(vol
->vnodeIndex
[vSmall
].handle
);
527 Log("split volume: error opening small vnode index of %" AFS_VOLID_FMT
"\n", afs_printable_VolumeId_lu(V_id(vol
)));
530 offset
= vcp
->diskSize
;
532 rc
= FDH_PREAD(fdP
, &vnode
, vcp
->diskSize
, offset
);
533 if (rc
!= vcp
->diskSize
) {
535 Log("split volume: error reading small vnode index of %" AFS_VOLID_FMT
"\n", afs_printable_VolumeId_lu(V_id(vol
)));
540 if (rc
< vcp
->diskSize
)
543 if (vnode
.type
== vNull
)
545 offset
+= vcp
->diskSize
;
547 memset(&vnode
, 0, sizeof(vnode
));
548 vnode
.type
= vSymlink
;
549 V_nextVnodeUnique(vol
)++;
550 vnode
.uniquifier
= V_nextVnodeUnique(vol
);
551 vnode
.author
= vd
->author
;
552 vnode
.owner
= vd
->owner
;
553 vnode
.group
= vd
->group
;
554 vnode
.modeBits
= 0644;
555 vnode
.unixModifyTime
= now
.tv_sec
;
556 vnode
.serverModifyTime
= now
.tv_sec
;
557 vnode
.dataVersion
= 1;
561 newvN
= (offset
>> (VnodeClassInfo
[class].logSize
- 1)) - 1 + class;
562 #if defined(NEARINODE_HINT) && !defined(AFS_NAMEI_ENV)
563 V_pref(vol
,nearInode
)
565 newino
= IH_CREATE(V_linkHandle(vol
), V_device(vol
),
566 VPartitionPath(V_partition(vol
)), nearInode
,
567 V_parentId(vol
), newvN
, vnode
.uniquifier
, 1);
569 IH_INIT(h
, V_device(vol
), V_parentId(vol
), newino
);
572 Log("split volume: couldn't open inode for mountpoint %" AFS_VOLID_FMT
".%u.%u\n",
573 afs_printable_VolumeId_lu(V_id(vol
)), newvN
, vnode
.uniquifier
);
576 sprintf(symlink
, "#%s", V_name(newvol
));
577 size
= strlen(symlink
) + 1;
578 if (FDH_PWRITE(fdP2
, symlink
, size
, 0) != size
) {
579 Log("split volume: couldn't write mountpoint %" AFS_VOLID_FMT
".%u.%u\n",
580 afs_printable_VolumeId_lu(V_id(vol
)), newvN
, vnode
.uniquifier
);
583 FDH_REALLYCLOSE(fdP2
);
585 VNDISK_SET_INO(&vnode
, newino
);
586 VNDISK_SET_LEN(&vnode
, size
);
587 #ifndef AFS_RXOSD_SUPPORT
588 vnode
.vnodeMagic
= SMALLVNODEMAGIC
;
590 if (FDH_PWRITE(fdP
, &vnode
, vcp
->diskSize
, offset
) != vcp
->diskSize
) {
591 Log("split volume: couldn't write vnode for mountpoint %" AFS_VOLID_FMT
".%u.%u\n",
592 afs_printable_VolumeId_lu(V_id(vol
)), newvN
, vnode
.uniquifier
);
595 FDH_REALLYCLOSE(fdP
);
597 fid
.Volume
= V_id(vol
);
599 fid
.Unique
= vnode
.uniquifier
;
602 * Now update the parent directory.
605 ino
= VNDISK_GET_INO(parent
);
606 SetSalvageDirHandle(&dir
, V_id(vol
), V_device(vol
), ino
);
608 code
= afs_dir_Delete(&dir
, name
);
610 Log("splitvolume: couldn't delete directory entry for %s in %" AFS_VOLID_FMT
".%u.%u, code = %d\n",
611 name
, afs_printable_VolumeId_lu(V_id(vol
)), vN
, parent
->uniquifier
, code
);
614 code
= afs_dir_Create(&dir
, name
, &fid
);
617 /* Make sure the directory file doesn't remain open */
618 IH_INIT(hp
, V_device(vol
), V_parentId(vol
), ino
);
621 FDH_REALLYCLOSE(fdP
);
625 vcp
= &VnodeClassInfo
[class];
626 fdP
= IH_OPEN(vol
->vnodeIndex
[class].handle
);
627 offset
= (vN
+ 1 - class) << (vcp
->logSize
-1);
628 parent
->dataVersion
++;
629 if (FDH_PWRITE(fdP
, parent
, vcp
->diskSize
, offset
) != vcp
->diskSize
) {
630 Log("split volume: couldn't write vnode for parent directory %" AFS_VOLID_FMT
".%u.%u\n",
631 afs_printable_VolumeId_lu(V_id(vol
)), vN
, parent
->uniquifier
);
634 FDH_REALLYCLOSE(fdP
);
639 deleteVnodes(Volume
*vol
, afs_int32
class,
640 struct VnodeExtract
*list
, afs_int32 length
,
643 afs_int32 i
, code
= 0;
644 char buf
[SIZEOF_LARGEDISKVNODE
];
645 struct VnodeDiskObject
*vnode
= (struct VnodeDiskObject
*)&buf
;
647 struct VnodeClassInfo
*vcp
= &VnodeClassInfo
[class];
648 struct VnodeExtract
*e
;
653 fdP
= IH_OPEN(vol
->vnodeIndex
[class].handle
);
655 Log("Couldn't open %s Index of volume %" AFS_VOLID_FMT
"\n",
656 class ? "small":"large", afs_printable_VolumeId_lu(V_id(vol
)));
661 for (i
=0; i
<length
; i
++) {
663 if (e
->flag
& NEEDED
) {
664 offset
= (e
->vN
+ 1 - class) << (vcp
->logSize
-1);
665 if (FDH_PREAD(fdP
, vnode
, vcp
->diskSize
, offset
) != vcp
->diskSize
) {
666 Log("Couldn't read in %s Index of volume %" AFS_VOLID_FMT
" at offset %llu\n",
667 class ? "small":"large", afs_printable_VolumeId_lu(V_id(vol
)), offset
);
671 VNDISK_GET_LEN(size
, vnode
);
672 *blocks
+= (size
+ 0x3ff) >> 10;
673 ino
= VNDISK_GET_INO(vnode
);
676 IH_INIT(h
, vol
->device
, V_parentId(vol
), ino
);
677 IH_DEC(h
, ino
, V_parentId(vol
));
678 #ifdef AFS_RXOSD_SUPPORT
680 code
= osdRemove(vol
, vnode
, e
->vN
);
681 #endif /* AFS_RXOSD_SUPPORT */
683 memset(vnode
, 0, vcp
->diskSize
);
685 if (FDH_PWRITE(fdP
, vnode
, vcp
->diskSize
, offset
) != vcp
->diskSize
) {
686 Log("Couldn't write in %s Index of volume %" AFS_VOLID_FMT
" to offset %llu\n",
687 class ? "small":"large", afs_printable_VolumeId_lu(V_id(vol
)), offset
);
698 split_volume(struct rx_call
*call
, Volume
*vol
, Volume
*newvol
,
699 afs_uint32 where
, afs_int32 verbose
)
702 struct VnodeExtract
*dirList
= 0;
703 struct VnodeExtract
*fileList
= 0;
704 afs_uint64 blocks
= 0;
705 afs_uint32 filesNeeded
, dirsNeeded
;
707 char buf
[SIZEOF_LARGEDISKVNODE
];
708 char buf2
[SIZEOF_LARGEDISKVNODE
];
709 struct VnodeDiskObject
*rootVnode
= (struct VnodeDiskObject
*)&buf
;
710 struct VnodeDiskObject
*parVnode
= (struct VnodeDiskObject
*)&buf2
;
715 m
= calloc(1, sizeof(struct Msg
));
717 m
->verbose
= verbose
;
720 * First step: planning
722 * Find out which directories will belong to the new volume
727 "1st step: extract vnode essence from large vnode file\n");
728 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
731 code
= ExtractVnodes(m
, vol
, vLarge
, &dirList
, &dl
, where
, rootVnode
,
735 "ExtractVnodes failed for %" AFS_VOLID_FMT
" for directories with code %d\n",
736 afs_printable_VolumeId_lu(V_id(vol
)), code
);
737 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
742 sprintf(m
->line
, "2nd step: look for name of vnode %u in directory %" AFS_VOLID_FMT
".%u.%u\n",
743 where
, afs_printable_VolumeId_lu(V_id(vol
)), parent
, parVnode
->uniquifier
);
744 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
746 code
= findName(vol
, parVnode
, where
, rootVnode
->uniquifier
,
750 "splitvolume: could'nt find name of %u in directory %" AFS_VOLID_FMT
".%u.%u.\n",
751 where
, afs_printable_VolumeId_lu(V_id(vol
)), parent
, parVnode
->uniquifier
);
752 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
756 sprintf(m
->line
, "name of %u is %s\n", where
, name
);
757 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
761 sprintf(m
->line
, "3rd step: find all directory vnodes belonging to the subtree under %u \"%s\"\n",
763 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
765 code
= FindVnodes(m
, where
, dirList
, dl
, dirList
, dl
, &dirsNeeded
, 1);
768 "FindVnodes for directories failed with code %d\n", code
);
769 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
774 sprintf(m
->line
, "4th step extract vnode essence from small vnode file\n");
775 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
777 code
= ExtractVnodes(m
, vol
, vSmall
, &fileList
, &fl
, where
, 0, 0, 0);
780 "ExtractVnodes failed for %" AFS_VOLID_FMT
" for files with code %d\n",
781 afs_printable_VolumeId_lu(V_id(vol
)), code
);
782 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
786 sprintf(m
->line
, "5th step: find all small vnodes belonging to the subtree under %u \"%s\"\n",
788 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
790 FindVnodes(m
, where
, fileList
, fl
, dirList
, dl
, &filesNeeded
, 0);
793 * Third step: create hard links for all files needed
797 V_destroyMe(newvol
) = DESTROY_ME
;
798 V_inService(newvol
) = 0;
800 sprintf(m
->line
, "6th step: create hard links in the AFSIDat tree between files of the old and new volume\n");
801 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
803 code
= copyVnodes(m
, vol
, newvol
, 1, fileList
, fl
, where
, &blocks
, 0);
805 sprintf(m
->line
, "copyVnodes for files failed with code %d\n", code
);
806 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
811 * Forth step: create hard links for all directories and copy
812 * split directory to new root directory
816 sprintf(m
->line
, "7th step: create hard links in the AFSIDat tree between directories of the old and new volume and make dir %u to new volume's root directory.\n",
818 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
820 code
= copyVnodes(m
, vol
, newvol
, 0, dirList
, dl
, where
, &blocks
, parVnode
);
822 sprintf(m
->line
, "copyVnodes for directories failed with code %d\n", code
);
823 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
828 * Finalize new volume
832 sprintf(m
->line
, "8th step: write new volume's metadata to disk\n");
833 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
836 V_diskused(newvol
) = blocks
;
837 #ifdef AFS_RXOSD_SUPPORT
838 V_osdFlag(newvol
) = V_osdFlag(vol
);
840 V_filecount(newvol
) = filesNeeded
+ dirsNeeded
;
841 V_destroyMe(newvol
) = 0;
842 V_maxquota(newvol
) = V_maxquota(vol
);
843 V_uniquifier(newvol
) = V_uniquifier(vol
);
844 V_inService(newvol
) = 1;
845 VUpdateVolume(&code
, newvol
);
848 * Sixth step: change directory entry in old volume:
849 * rename old tree and create mount point for new volume.
852 sprintf(m
->line
, "9th step: create mountpoint \"%s\" for new volume in old volume's directory %u.\n", name
, parent
);
853 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
856 code
= createMountpoint(vol
, newvol
, parVnode
, parent
, rootVnode
, name
);
858 sprintf(m
->line
, "createMountpoint failed with code %d\n", code
);
859 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
863 * Now both volumes should be ready and consistent, but the old volume
864 * contains still the vnodes and data we transferred into the new one.
865 * Delete orphaned vnodes and data.
870 sprintf(m
->line
, "10th step: delete large vnodes belonging to subtree in the old volume.\n");
871 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
873 deleteVnodes(vol
, vLarge
, dirList
, dl
, &blocks
);
875 sprintf(m
->line
, "11th step: delete small vnodes belonging to subtree in the old volume.\n");
876 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
878 deleteVnodes(vol
, vSmall
, fileList
, fl
, &blocks
);
879 V_diskused(vol
) -= blocks
;
880 V_filecount(vol
) -= (filesNeeded
+ dirsNeeded
+ 1);
881 VUpdateVolume(&code
, vol
);
883 sprintf(m
->line
, "Finished!\n");
884 rx_Write(m
->call
, m
->line
, strlen(m
->line
));
889 rx_Write(m
->call
, m
->line
, 4);