Bug Summary

File:volser/vol_split.c
Location:line 253, column 7
Description:Access to field 'fd_ih' results in a dereference of a null pointer (loaded from variable 'outfdP')

Annotated Source Code

1/*
2 * Copyright (c) 2007, Hartmut Reuter,
3 * RZG, Max-Planck-Institut f. Plasmaphysik.
4 * All Rights Reserved.
5 *
6 */
7
8#include <afsconfig.h>
9#include <afs/param.h>
10
11#include <roken.h>
12
13#ifdef HAVE_SYS_FILE_H1
14#include <sys/file.h>
15#endif
16
17#if defined(AFS_NAMEI_ENV1) && !defined(AFS_NT40_ENV)
18#include <afs/afs_assert.h>
19#include <afs/dir.h>
20#include <rx/xdr.h>
21#include <afs/afsint.h>
22#include <afs/nfs.h>
23#include <lwp.h>
24#include <lock.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>
31
32#include "vol.h"
33#include "volint.h"
34#include "volser.h"
35#include "physio.h"
36#include "volser_internal.h"
37#ifdef AFS_RXOSD_SUPPORT
38#include "rxosd.h"
39#include "vol_osd.h"
40#include "../vol/vol_osd_prototypes.h"
41#endif
42
43#define NEEDED1 1
44#define PARENT2 2
45#define CHANGEPARENT4 4
46
47#define NAMEI_VNODEMASK0x03ffffff 0x03ffffff
48#define NAMEI_TAGMASK0x7 0x7
49#define NAMEI_TAGSHIFT26 26
50#define NAMEI_UNIQMASK0xffffffff 0xffffffff
51#define NAMEI_UNIQSHIFT32 32
52
53struct VnodeExtract {
54 afs_uint32 vN;
55 afs_uint32 parent;
56 afs_uint32 flag;
57};
58
59struct Msg {
60 struct rx_call * call;
61 int verbose;
62 char line[1024];
63};
64
65static afs_int32
66ExtractVnodes(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)
71{
72 afs_int32 code = 0;
73 char buf[SIZEOF_LARGEDISKVNODE256];
74 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)&buf;
75 FdHandle_t *fdP = 0;
76 StreamHandle_t *stream = 0;
77 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
78 struct VnodeExtract *e;
79 afs_sfsize_t size;
80 afs_foff_t offset;
81
82 *length = 0;
83 if (parent)
84 *parent = 0;
85
86 fdP = IH_OPEN(vol->vnodeIndex[class].handle)ih_open(vol->vnodeIndex[class].handle);
87 if (!fdP) {
88 sprintf(m->line, "Couldn't open %s Index of volume %u\n",
89 class ? "small":"large", V_id(vol)((vol)->header->diskstuff.id));
90 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
91 code = EIO5;
92 goto Bad_Extract;
93 }
94 size = FDH_SIZE(fdP)ih_size((fdP)->fd_fd);
95 *list = (struct VnodeExtract *) malloc(size / vcp->diskSize
96 * sizeof(struct VnodeExtract));
97 if (!(*list)) {
98 code = ENOMEM12;
99 goto Bad_Extract;
100 }
101 memset(*list, 0, size / vcp->diskSize * sizeof(struct VnodeExtract));
102 stream = FDH_FDOPEN(fdP, "r")stream_fdopen((fdP)->fd_fd);
103 if (!stream) {
104 sprintf(m->line, "Couldn't stream open %s Index of volume %u\n",
105 class ? "small":"large", V_id(vol)((vol)->header->diskstuff.id));
106 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
107 code = EIO5;
108 goto Bad_Extract;
109 }
110 code = STREAM_ASEEK(stream, vcp->diskSize)stream_aseek(stream, vcp->diskSize);
111 if (code)
112 goto Bad_Extract;
113
114 offset = vcp->diskSize;
115 e = *list;
116 while (!STREAM_EOF(stream)((stream)->str_eof)) {
117 afs_int32 vN = (offset >> (vcp->logSize -1)) - 1 + class;
118 if (STREAM_READ(vnode, vcp->diskSize, 1, stream)stream_read(vnode, vcp->diskSize, 1, stream) == 1) {
119 if (vnode->type != vNull0) {
120 e->vN = vN;
121 e->parent = vnode->parent;
122 if (vN == where && class == vLarge0) {
123 memcpy(vd, vnode, vcp->diskSize);
124 *parent = vnode->parent;
125 }
126 e++;
127 }
128 offset += vcp->diskSize;
129 }
130 }
131 *length = (e - *list);
132 if (class == vLarge0) {
133 if (*parent) {
134 offset = (*parent + 1 - class) << (vcp->logSize -1);
135 code = STREAM_ASEEK(stream, offset)stream_aseek(stream, offset);
136 if (STREAM_READ(vnode, vcp->diskSize, 1, stream)stream_read(vnode, vcp->diskSize, 1, stream) == 1)
137 memcpy(parentvd, vnode, vcp->diskSize);
138 else
139 code = EIO5;
140 } else {
141 sprintf(m->line, "SplitVolume: extract didn't see directory %u\n", where);
142 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
143 code = ENOENT2;
144 }
145 }
146 if (m->verbose) {
147 sprintf(m->line, "Volume %u has %u %s vnodes in volume %u\n",
148 V_parentId(vol)((vol)->header->diskstuff.parentId), *length, class? "small":"large",
149 V_id(vol)((vol)->header->diskstuff.id));
150 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
151 }
152
153Bad_Extract:
154 if (stream)
155 STREAM_CLOSE(stream)stream_close(stream, 0);
156 if (fdP)
157 FDH_CLOSE(fdP)(fd_close(fdP), (fdP)=((void *)0), 0);
158 if (code) {
159 free(*list);
160 *list = 0;
161 }
162 return code;
163}
164
165static afs_int32
166FindVnodes(struct Msg *m, afs_uint32 where,
167 struct VnodeExtract *list, afs_int32 length,
168 struct VnodeExtract *dlist, afs_int32 dlength,
169 afs_uint32 *needed, afs_int32 class)
170{
171 afs_int32 i, j, found = 0;
172 afs_int32 parent = 0;
173
174 *needed = 0;
175 for (i=0; i<length; i++) {
176 if (list[i].vN == where) { /* dir to be replaced by mount point */
177 list[i].flag |= NEEDED1;
178 parent = list[i].parent;
179 found = 1;
180 (*needed)++;
181 }
182 if (list[i].parent == where) { /* all 1st generation children */
183 list[i].flag |= (NEEDED1 + CHANGEPARENT4);
184 (*needed)++;
185 }
186 }
187 if (list[0].vN & 1) { /* only for directories */
188 if (!found) {
189 sprintf(m->line,
190 "SplitVolume: directory %u where to start new volume not found\n",
191 where);
192 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
193 return ENOENT2;
194 }
195 found = 0;
196 for (i=0; i<length; i++) {
197 if (list[i].vN == parent) { /* dir where to create mount point */
198 list[i].flag |= PARENT2;
199 found = 1;
200 break;
201 }
202 }
203 if (!found) {
204 sprintf(m->line, "SplitVolume: parent directory %u not found\n",
205 parent);
206 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
207 return ENOENT2;
208 }
209 }
210 found = 1;
211 while (found) {
212 found = 0;
213 for (i=0; i<dlength; i++) {
214 if (!(dlist[i].flag & NEEDED1)) /* dirs to remain in old volume */
215 continue;
216 for (j=0; j<length; j++) {
217 if (list[j].parent == dlist[i].vN && !(list[j].flag & NEEDED1)) {
218 list[j].flag |= NEEDED1;
219 (*needed)++;
220 found = 1;
221 }
222 }
223 }
224 }
225 if (m->verbose) {
226 sprintf(m->line, "%u %s vnodes will go into the new volume\n",
227 *needed, class ? "small" : "large");
228 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
229 }
230 return 0;
231}
232
233static afs_int32
234copyDir(struct Msg *m, IHandle_t *inh, IHandle_t *outh)
235{
236 FdHandle_t *infdP, *outfdP;
237 char *tbuf;
238 afs_sfsize_t size;
239 afs_foff_t offset;
240
241 infdP = IH_OPEN(inh)ih_open(inh);
242 if (!infdP) {
1
Taking false branch
243 sprintf(m->line, "Couldn't open input directory %u.%u.%u\n",
244 infdP->fd_ih->ih_vid,
245 (afs_uint32)(infdP->fd_ih->ih_ino & NAMEI_VNODEMASK0x03ffffff),
246 (afs_uint32)(infdP->fd_ih->ih_ino >> NAMEI_UNIQSHIFT32));
247 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
248 return EIO5;
249 }
250 outfdP = IH_OPEN(outh)ih_open(outh);
251 if (!outfdP) {
2
Taking true branch
252 sprintf(m->line, "Couldn't open output directory %u.%u.%u\n",
253 outfdP->fd_ih->ih_vid,
3
Access to field 'fd_ih' results in a dereference of a null pointer (loaded from variable 'outfdP')
254 (afs_uint32)(outfdP->fd_ih->ih_ino & NAMEI_VNODEMASK0x03ffffff),
255 (afs_uint32)(outfdP->fd_ih->ih_ino >> NAMEI_UNIQSHIFT32));
256 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
257 FDH_REALLYCLOSE(infdP)(fd_reallyclose(infdP), (infdP)=((void *)0), 0);
258 return EIO5;
259 }
260 tbuf = malloc(2048);
261 offset = 0;
262 size = FDH_SIZE(infdP)ih_size((infdP)->fd_fd);
263 while (size) {
264 size_t tlen;
265 tlen = size > 2048 ? 2048 : size;
266 if (FDH_PREAD(infdP, tbuf, tlen, offset)pread((infdP)->fd_fd, tbuf, tlen, offset) != tlen) {
267 sprintf(m->line, "Couldn't read directory %u.%u.%u\n",
268 infdP->fd_ih->ih_vid,
269 (afs_uint32)(infdP->fd_ih->ih_ino & NAMEI_VNODEMASK0x03ffffff),
270 (afs_uint32)(infdP->fd_ih->ih_ino >> NAMEI_UNIQSHIFT32));
271 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
272 FDH_REALLYCLOSE(infdP)(fd_reallyclose(infdP), (infdP)=((void *)0), 0);
273 FDH_REALLYCLOSE(outfdP)(fd_reallyclose(outfdP), (outfdP)=((void *)0), 0);
274 free(tbuf);
275 return EIO5;
276 }
277 if (FDH_PWRITE(outfdP, tbuf, tlen, offset)pwrite((outfdP)->fd_fd, tbuf, tlen, offset) != tlen) {
278 sprintf(m->line, "Couldn't write directory %u.%u.%u\n",
279 outfdP->fd_ih->ih_vid,
280 (afs_uint32)(outfdP->fd_ih->ih_ino & NAMEI_VNODEMASK0x03ffffff),
281 (afs_uint32)(outfdP->fd_ih->ih_ino >> NAMEI_UNIQSHIFT32));
282 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
283 FDH_REALLYCLOSE(infdP)(fd_reallyclose(infdP), (infdP)=((void *)0), 0);
284 FDH_REALLYCLOSE(outfdP)(fd_reallyclose(outfdP), (outfdP)=((void *)0), 0);
285 free(tbuf);
286 return EIO5;
287 }
288 size -= tlen;
289 offset += tlen;
290 }
291 free(tbuf);
292 FDH_CLOSE(outfdP)(fd_close(outfdP), (outfdP)=((void *)0), 0);
293 FDH_REALLYCLOSE(infdP)(fd_reallyclose(infdP), (infdP)=((void *)0), 0);
294 return 0;
295}
296
297afs_int32 copyVnodes(struct Msg *m, Volume *vol, Volume *newvol,
298 afs_int32 class,
299 struct VnodeExtract *list, afs_int32 length,
300 afs_int32 where, afs_uint64 *blocks,
301 struct VnodeDiskObject *parVnode)
302{
303 afs_int32 i, code = 0;
304 char buf[SIZEOF_LARGEDISKVNODE256];
305 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)&buf;
306 FdHandle_t *fdP = 0;
307 FdHandle_t *newfdP = 0;
308 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
309 struct VnodeExtract *e;
310 afs_sfsize_t size;
311 afs_uint64 offset;
312 Inode ino, newino;
313
314 fdP = IH_OPEN(vol->vnodeIndex[class].handle)ih_open(vol->vnodeIndex[class].handle);
315 if (!fdP) {
316 Log("Couldn't open %s Index of volume %u\n",
317 class ? "small":"large", V_id(vol)((vol)->header->diskstuff.id));
318 code = EIO5;
319 goto Bad_Copy;
320 }
321 newfdP = IH_OPEN(newvol->vnodeIndex[class].handle)ih_open(newvol->vnodeIndex[class].handle);
322 if (!newfdP) {
323 Log("Couldn't open %s Index of volume %u\n",
324 class ? "small":"large", V_id(newvol)((newvol)->header->diskstuff.id));
325 code = EIO5;
326 goto Bad_Copy;
327 }
328 size = FDH_SIZE(fdP)ih_size((fdP)->fd_fd);
329
330 for (i=0; i<length; i++) {
331 e = &list[i];
332 if (e->flag) {
333 afs_uint64 size;
334 offset = (e->vN + 1 - class) << (vcp->logSize -1);
335 if (FDH_PREAD(fdP, vnode, vcp->diskSize, offset)pread((fdP)->fd_fd, vnode, vcp->diskSize, offset) != vcp->diskSize) {
336 Log("Couldn't read in %s Index of volume %u at offset %llu\n",
337 class ? "small":"large", V_id(vol)((vol)->header->diskstuff.id), offset);
338 code = EIO5;
339 goto Bad_Copy;
340 }
341 if (e->flag & PARENT2) {
342 /*
343 * do a preventive copy on write for later update
344 */
345 IHandle_t *newh = 0;
346 IHandle_t *h = 0;
347#if defined(NEARINODE_HINT) && !defined(AFS_NAMEI_ENV1)
348 Inode nearInode;
349 V_pref(vol,nearInode)nearInode = 0
350#endif
351
352 newino = IH_CREATE(V_linkHandle(vol), V_device(vol),namei_icreate(((vol)->linkHandle), VPartitionPath(((vol)->
partition)), ((vol)->header->diskstuff.parentId), e->
vN, vnode->uniquifier, vnode->dataVersion)
353 VPartitionPath(V_partition(vol)),namei_icreate(((vol)->linkHandle), VPartitionPath(((vol)->
partition)), ((vol)->header->diskstuff.parentId), e->
vN, vnode->uniquifier, vnode->dataVersion)
354 nearInode, V_parentId(vol),namei_icreate(((vol)->linkHandle), VPartitionPath(((vol)->
partition)), ((vol)->header->diskstuff.parentId), e->
vN, vnode->uniquifier, vnode->dataVersion)
355 e->vN, vnode->uniquifier,namei_icreate(((vol)->linkHandle), VPartitionPath(((vol)->
partition)), ((vol)->header->diskstuff.parentId), e->
vN, vnode->uniquifier, vnode->dataVersion)
356 vnode->dataVersion)namei_icreate(((vol)->linkHandle), VPartitionPath(((vol)->
partition)), ((vol)->header->diskstuff.parentId), e->
vN, vnode->uniquifier, vnode->dataVersion)
;
357 IH_INIT(newh, V_device(vol), V_parentId(vol), newino)((newh) = ih_init((((vol)->device)), (((vol)->header->
diskstuff.parentId)), (newino)))
;
358 ino = VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
;
359 IH_INIT(h, V_device(vol), V_parentId(vol), ino)((h) = ih_init((((vol)->device)), (((vol)->header->diskstuff
.parentId)), (ino)))
;
360 code = copyDir(m, h, newh);
361 if (code)
362 goto Bad_Copy;
363 /* Now update the vnode and write it back to disk */
364 VNDISK_SET_INO(vnode, newino)((vnode)->vn_ino_lo = (int)(newino&0xffffffff), ((vnode
)->vn_ino_hi = (newino) ? (int)(((newino)>>32)&0xffffffff
) : 0))
;
365 vnode->cloned = 0;
366 if (FDH_PWRITE(fdP, vnode, vcp->diskSize, offset)pwrite((fdP)->fd_fd, vnode, vcp->diskSize, offset) != vcp->diskSize) {
367 Log("Couldn't write in %s Index of volume %u at offset %llu\n",
368 class ? "small":"large", V_id(vol)((vol)->header->diskstuff.id), offset);
369 code = EIO5;
370 goto Bad_Copy;
371 }
372 memcpy(parVnode, vnode, sizeof(struct VnodeDiskObject));
373 }
374 if (e->flag & NEEDED1 && e->vN != where) {
375 VNDISK_GET_LEN(size, vnode)(size) = ((afs_int64)((vnode)->vn_length_hi) << 32) |
((vnode)->length);
;
376 *blocks += (size + 0x3ff) >> 10;
377 ino = VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
;
378 if (ino) {
379 IHandle_t *h, *newh;
380 Inode AFS_UNUSED__attribute__((unused)) nearInode;
381#if defined(NEARINODE_HINT) && !defined(AFS_NAMEI_ENV1)
382 V_pref(vol,nearInode)nearInode = 0
383#endif
384 IH_INIT(h, vol->device, V_parentId(vol), ino)((h) = ih_init((vol->device), (((vol)->header->diskstuff
.parentId)), (ino)))
;
385 if (e->parent == where)
386 vnode->parent = 1;
387 newino = IH_CREATE(V_linkHandle(newvol), V_device(newvol),namei_icreate(((newvol)->linkHandle), VPartitionPath(((newvol
)->partition)), ((newvol)->header->diskstuff.parentId
), e->vN, vnode->uniquifier, vnode->dataVersion)
388 VPartitionPath(V_partition(newvol)),namei_icreate(((newvol)->linkHandle), VPartitionPath(((newvol
)->partition)), ((newvol)->header->diskstuff.parentId
), e->vN, vnode->uniquifier, vnode->dataVersion)
389 nearInode, V_parentId(newvol),namei_icreate(((newvol)->linkHandle), VPartitionPath(((newvol
)->partition)), ((newvol)->header->diskstuff.parentId
), e->vN, vnode->uniquifier, vnode->dataVersion)
390 e->vN, vnode->uniquifier,namei_icreate(((newvol)->linkHandle), VPartitionPath(((newvol
)->partition)), ((newvol)->header->diskstuff.parentId
), e->vN, vnode->uniquifier, vnode->dataVersion)
391 vnode->dataVersion)namei_icreate(((newvol)->linkHandle), VPartitionPath(((newvol
)->partition)), ((newvol)->header->diskstuff.parentId
), e->vN, vnode->uniquifier, vnode->dataVersion)
;
392 if (!VALID_INO(newino)((newino) != (Inode)-1 && (newino) != (Inode)0)) {
393 Log("IH_CREATE failed for %u.%u.%u\n",
394 V_id(newvol)((newvol)->header->diskstuff.id), e->vN, vnode->uniquifier);
395 code = EIO5;
396 goto Bad_Copy;
397 }
398 nearInode = newino;
399 IH_INIT(newh, newvol->device, V_parentId(newvol), newino)((newh) = ih_init((newvol->device), (((newvol)->header->
diskstuff.parentId)), (newino)))
;
400 code = namei_replace_file_by_hardlink(newh, h);
401 VNDISK_SET_INO(vnode, newino)((vnode)->vn_ino_lo = (int)(newino&0xffffffff), ((vnode
)->vn_ino_hi = (newino) ? (int)(((newino)>>32)&0xffffffff
) : 0))
;
402#ifdef AFS_RXOSD_SUPPORT
403 } else {
404 code = osd_split_objects(vol, newvol, vnode, e->vN);
405#endif /* AFS_RXOSD_SUPPORT */
406 }
407 if (code)
408 goto Bad_Copy;
409 if (e->flag & CHANGEPARENT4)
410 vnode->parent = 1; /* in new root-directory */
411 vnode->cloned = 0;
412 if (FDH_PWRITE(newfdP, vnode, vcp->diskSize, offset)pwrite((newfdP)->fd_fd, vnode, vcp->diskSize, offset) != vcp->diskSize) {
413 Log("Couldn't write in %s Index of volume %u to offset %llu\n",
414 class ? "small":"large", V_id(newvol)((newvol)->header->diskstuff.id), offset);
415 code = EIO5;
416 goto Bad_Copy;
417 }
418 }
419 }
420 }
421 /*
422 * Now copy the root directory from old to new volume
423 */
424 if (class == vLarge0) {
425 IHandle_t *h, *newh;
426 char buf2[SIZEOF_LARGEDISKVNODE256];
427 struct VnodeDiskObject *vnode2 = (struct VnodeDiskObject *)&buf2;
428 afs_uint64 newoffset;
429
430 newoffset = vcp->diskSize;
431 if (FDH_PREAD(newfdP, vnode2, vcp->diskSize, newoffset)pread((newfdP)->fd_fd, vnode2, vcp->diskSize, newoffset
)
!= vcp->diskSize) {
432 Log("splitvolume: couldn't read in large Index of new volume %u at offset %u\n",
433 V_id(newvol)((newvol)->header->diskstuff.id), vcp->diskSize);
434 code = EIO5;
435 goto Bad_Copy;
436 }
437 offset = (where + 1 - class) << (vcp->logSize -1);
438 if (FDH_PREAD(fdP, vnode, vcp->diskSize, offset)pread((fdP)->fd_fd, vnode, vcp->diskSize, offset) != vcp->diskSize) {
439 Log("Couldn't read in large Index of old volume %u at offset %llu\n",
440 V_id(vol)((vol)->header->diskstuff.id), offset);
441 code = EIO5;
442 goto Bad_Copy;
443 }
444 VNDISK_GET_LEN(size, vnode)(size) = ((afs_int64)((vnode)->vn_length_hi) << 32) |
((vnode)->length);
;
445 *blocks += (size + 0x3ff) >> 10;
446 ino = VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
;
447 IH_INIT(h, vol->device, V_parentId(vol), ino)((h) = ih_init((vol->device), (((vol)->header->diskstuff
.parentId)), (ino)))
;
448 newino = VNDISK_GET_INO(vnode2)((Inode)((vnode2)->vn_ino_lo | ((vnode2)->vn_ino_hi ? (
((Inode)(vnode2)->vn_ino_hi)<<32) : 0)))
;
449 IH_INIT(newh, newvol->device, V_parentId(newvol), newino)((newh) = ih_init((newvol->device), (((newvol)->header->
diskstuff.parentId)), (newino)))
;
450 code = copyDir(m, h, newh);
451 if (code) {
452 Log("splitvolume: copyDir failed for new root from "
453 "%u.%u.%u to %u.1.1\n",
454 V_id(vol)((vol)->header->diskstuff.id), where, vnode->uniquifier, V_id(newvol)((newvol)->header->diskstuff.id));
455 code = EIO5;
456 goto Bad_Copy;
457 }
458 VNDISK_SET_INO(vnode, newino)((vnode)->vn_ino_lo = (int)(newino&0xffffffff), ((vnode
)->vn_ino_hi = (newino) ? (int)(((newino)>>32)&0xffffffff
) : 0))
;
459 vnode->uniquifier = 1;
460 vnode->cloned = 0;
461 vnode->parent = vnode2->parent;
462 vnode->serverModifyTime = vnode2->serverModifyTime;
463 if (FDH_PWRITE(newfdP, vnode, vcp->diskSize, newoffset)pwrite((newfdP)->fd_fd, vnode, vcp->diskSize, newoffset
)
!= vcp->diskSize) {
464 Log("splitvolume: couldn't write in large Index of %u at offset %u\n",
465 V_id(newvol)((newvol)->header->diskstuff.id), vcp->diskSize);
466 code = EIO5;
467 }
468 }
469Bad_Copy:
470 if (fdP)
471 FDH_CLOSE(fdP)(fd_close(fdP), (fdP)=((void *)0), 0);
472 if (newfdP)
473 FDH_CLOSE(newfdP)(fd_close(newfdP), (newfdP)=((void *)0), 0);
474 return code;
475}
476
477static afs_int32
478findName(Volume *vol, struct VnodeDiskObject *vd, afs_uint32 vN,
479 afs_uint32 un, char *name,afs_int32 length)
480{
481 afs_int32 code;
482 Inode ino;
483 DirHandle dir;
484
485 ino = VNDISK_GET_INO(vd)((Inode)((vd)->vn_ino_lo | ((vd)->vn_ino_hi ? (((Inode)
(vd)->vn_ino_hi)<<32) : 0)))
;
486 SetSalvageDirHandle(&dir, V_id(vol)((vol)->header->diskstuff.id), V_device(vol)((vol)->device), ino);
487
488 code = afs_dir_InverseLookup(&dir, vN, un, name, length);
489 FidZap(&dir);
490 return code;
491}
492
493static afs_int32
494createMountpoint(Volume *vol, Volume *newvol, struct VnodeDiskObject *parent,
495 afs_uint32 vN, struct VnodeDiskObject *vd, char *name)
496{
497 afs_int32 code;
498 Inode ino, newino;
499 DirHandle dir;
500 IHandle_t *h;
501 struct VnodeDiskObject vnode;
502 FdHandle_t *fdP, *fdP2;
503 afs_uint64 size;
504 afs_foff_t offset;
505 afs_int32 class = vSmall1;
506 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
507#if defined(NEARINODE_HINT) && !defined(AFS_NAMEI_ENV1)
508 Inode nearInode = 0;
509#endif
510 AFSFid fid;
511 struct timeval now;
512 afs_uint32 newvN;
513 char symlink[32];
514 ssize_t rc;
515
516 FT_GetTimeOfDay(&now, 0);
517 fdP = IH_OPEN(vol->vnodeIndex[vSmall].handle)ih_open(vol->vnodeIndex[1].handle);
518 if (!fdP) {
519 Log("split volume: error opening small vnode index of %u\n", V_id(vol)((vol)->header->diskstuff.id));
520 return EIO5;
521 }
522 offset = vcp->diskSize;
523 while (1) {
524 rc = FDH_PREAD(fdP, &vnode, vcp->diskSize, offset)pread((fdP)->fd_fd, &vnode, vcp->diskSize, offset);
525 if (rc != vcp->diskSize) {
526 if (rc < 0) {
527 Log("split volume: error reading small vnode index of %u\n", V_id(vol)((vol)->header->diskstuff.id));
528 return EIO5;
529 }
530 if (rc == 0)
531 break;
532 if (rc < vcp->diskSize)
533 break;
534 }
535 if (vnode.type == vNull0)
536 break;
537 offset += vcp->diskSize;
538 }
539 memset(&vnode, 0, sizeof(vnode));
540 vnode.type = vSymlink3;
541 V_nextVnodeUnique(vol)((vol)->nextVnodeUnique)++;
542 vnode.uniquifier = V_nextVnodeUnique(vol)((vol)->nextVnodeUnique);
543 vnode.author = vd->author;
544 vnode.owner = vd->owner;
545 vnode.group = vd->group;
546 vnode.modeBits = 0644;
547 vnode.unixModifyTime = now.tv_sec;
548 vnode.serverModifyTime = now.tv_sec;
549 vnode.dataVersion = 1;
550 vnode.linkCount = 1;
551 vnode.parent = vN;
552
553 newvN = (offset >> (VnodeClassInfo[class].logSize - 1)) - 1 + class;
554#if defined(NEARINODE_HINT) && !defined(AFS_NAMEI_ENV1)
555 V_pref(vol,nearInode)nearInode = 0
556#endif
557 newino = IH_CREATE(V_linkHandle(vol), V_device(vol),namei_icreate(((vol)->linkHandle), VPartitionPath(((vol)->
partition)), ((vol)->header->diskstuff.parentId), newvN
, vnode.uniquifier, 1)
558 VPartitionPath(V_partition(vol)), nearInode,namei_icreate(((vol)->linkHandle), VPartitionPath(((vol)->
partition)), ((vol)->header->diskstuff.parentId), newvN
, vnode.uniquifier, 1)
559 V_parentId(vol), newvN, vnode.uniquifier, 1)namei_icreate(((vol)->linkHandle), VPartitionPath(((vol)->
partition)), ((vol)->header->diskstuff.parentId), newvN
, vnode.uniquifier, 1)
;
560
561 IH_INIT(h, V_device(vol), V_parentId(vol), newino)((h) = ih_init((((vol)->device)), (((vol)->header->diskstuff
.parentId)), (newino)))
;
562 fdP2 = IH_OPEN(h)ih_open(h);
563 if (!fdP2) {
564 Log("split volume: couldn't open inode for mountpoint %u.%u.%u\n",
565 V_id(vol)((vol)->header->diskstuff.id), newvN, vnode.uniquifier);
566 return EIO5;
567 }
568 sprintf(symlink, "#%s", V_name(newvol)((newvol)->header->diskstuff.name));
569 size = strlen(symlink) + 1;
570 if (FDH_PWRITE(fdP2, symlink, size, 0)pwrite((fdP2)->fd_fd, symlink, size, 0) != size) {
571 Log("split volume: couldn't write mountpoint %u.%u.%u\n",
572 V_id(vol)((vol)->header->diskstuff.id), newvN, vnode.uniquifier);
573 return EIO5;
574 }
575 FDH_REALLYCLOSE(fdP2)(fd_reallyclose(fdP2), (fdP2)=((void *)0), 0);
576 IH_RELEASE(h)(ih_release(h), (h)=((void *)0), 0);
577 VNDISK_SET_INO(&vnode, newino)((&vnode)->vn_ino_lo = (int)(newino&0xffffffff), (
(&vnode)->vn_ino_hi = (newino) ? (int)(((newino)>>
32)&0xffffffff) : 0))
;
578 VNDISK_SET_LEN(&vnode, size)((&vnode)->vn_length_hi) = ((afs_int64)size) >> 32
; ((&vnode)->length) = (size) & 0xFFFFFFFF;
;
579#ifndef AFS_RXOSD_SUPPORT
580 vnode.vnodeMagic = SMALLVNODEMAGIC0xda8c041F;
581#endif
582 if (FDH_PWRITE(fdP, &vnode, vcp->diskSize, offset)pwrite((fdP)->fd_fd, &vnode, vcp->diskSize, offset) != vcp->diskSize) {
583 Log("split volume: couldn't write vnode for mountpoint %u.%u.%u\n",
584 V_id(vol)((vol)->header->diskstuff.id), newvN, vnode.uniquifier);
585 return EIO5;
586 }
587 FDH_REALLYCLOSE(fdP)(fd_reallyclose(fdP), (fdP)=((void *)0), 0);
588
589 fid.Volume = V_id(vol)((vol)->header->diskstuff.id);
590 fid.Vnode = newvN;
591 fid.Unique = vnode.uniquifier;
592
593 /*
594 * Now update the parent directory.
595 */
596
597 ino = VNDISK_GET_INO(parent)((Inode)((parent)->vn_ino_lo | ((parent)->vn_ino_hi ? (
((Inode)(parent)->vn_ino_hi)<<32) : 0)))
;
598 SetSalvageDirHandle(&dir, V_id(vol)((vol)->header->diskstuff.id), V_device(vol)((vol)->device), ino);
599
600 code = afs_dir_Delete(&dir, name);
601 if (code) {
602 Log("splitvolume: couldn't delete directory entry for %s in %u.%u.%u, code = %d\n",
603 name, V_id(vol)((vol)->header->diskstuff.id), vN, parent->uniquifier, code);
604 return code;
605 }
606 code = afs_dir_Create(&dir, name, &fid);
607 FidZap(&dir);
608
609 class = vLarge0;
610 vcp = &VnodeClassInfo[class];
611 fdP = IH_OPEN(vol->vnodeIndex[class].handle)ih_open(vol->vnodeIndex[class].handle);
612 offset = (vN + 1 - class) << (vcp->logSize -1);
613 parent->dataVersion++;
614 if (FDH_PWRITE(fdP, parent, vcp->diskSize, offset)pwrite((fdP)->fd_fd, parent, vcp->diskSize, offset) != vcp->diskSize) {
615 Log("split volume: couldn't write vnode for parent directory %u.%u.%u\n",
616 V_id(vol)((vol)->header->diskstuff.id), vN, parent->uniquifier);
617 return EIO5;
618 }
619 FDH_REALLYCLOSE(fdP)(fd_reallyclose(fdP), (fdP)=((void *)0), 0);
620 return code;
621}
622
623static afs_int32
624deleteVnodes(Volume *vol, afs_int32 class,
625 struct VnodeExtract *list, afs_int32 length,
626 afs_uint64 *blocks)
627{
628 afs_int32 i, code = 0;
629 char buf[SIZEOF_LARGEDISKVNODE256];
630 struct VnodeDiskObject *vnode = (struct VnodeDiskObject *)&buf;
631 FdHandle_t *fdP = 0;
632 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
633 struct VnodeExtract *e;
634 afs_sfsize_t size;
635 afs_uint64 offset;
636 Inode ino;
637
638 fdP = IH_OPEN(vol->vnodeIndex[class].handle)ih_open(vol->vnodeIndex[class].handle);
639 if (!fdP) {
640 Log("Couldn't open %s Index of volume %u\n",
641 class ? "small":"large", V_id(vol)((vol)->header->diskstuff.id));
642 code = EIO5;
643 goto Bad_Delete;
644 }
645
646 for (i=0; i<length; i++) {
647 e = &list[i];
648 if (e->flag & NEEDED1) {
649 offset = (e->vN + 1 - class) << (vcp->logSize -1);
650 if (FDH_PREAD(fdP, vnode, vcp->diskSize, offset)pread((fdP)->fd_fd, vnode, vcp->diskSize, offset) != vcp->diskSize) {
651 Log("Couldn't read in %s Index of volume %u at offset %llu\n",
652 class ? "small":"large", V_id(vol)((vol)->header->diskstuff.id), offset);
653 code = EIO5;
654 goto Bad_Delete;
655 }
656 VNDISK_GET_LEN(size, vnode)(size) = ((afs_int64)((vnode)->vn_length_hi) << 32) |
((vnode)->length);
;
657 *blocks += (size + 0x3ff) >> 10;
658 ino = VNDISK_GET_INO(vnode)((Inode)((vnode)->vn_ino_lo | ((vnode)->vn_ino_hi ? (((
Inode)(vnode)->vn_ino_hi)<<32) : 0)))
;
659 if (ino) {
660 IHandle_t *h;
661 IH_INIT(h, vol->device, V_parentId(vol), ino)((h) = ih_init((vol->device), (((vol)->header->diskstuff
.parentId)), (ino)))
;
662 IH_DEC(h, ino, V_parentId(vol))namei_dec(h, ino, ((vol)->header->diskstuff.parentId));
663#ifdef AFS_RXOSD_SUPPORT
664 } else {
665 code = osdRemove(vol, vnode, e->vN);
666#endif /* AFS_RXOSD_SUPPORT */
667 }
668 memset(vnode, 0, vcp->diskSize);
669 vnode->type = vNull0;
670 if (FDH_PWRITE(fdP, vnode, vcp->diskSize, offset)pwrite((fdP)->fd_fd, vnode, vcp->diskSize, offset) != vcp->diskSize) {
671 Log("Couldn't write in %s Index of volume %u to offset %llu\n",
672 class ? "small":"large", V_id(vol)((vol)->header->diskstuff.id), offset);
673 }
674 }
675 }
676Bad_Delete:
677 if (fdP)
678 FDH_CLOSE(fdP)(fd_close(fdP), (fdP)=((void *)0), 0);
679 return code;
680}
681
682afs_int32
683split_volume(struct rx_call *call, Volume *vol, Volume *newvol,
684 afs_uint32 where, afs_int32 verbose)
685{
686 Errorbit32 code = 0;
687 struct VnodeExtract *dirList = 0;
688 struct VnodeExtract *fileList = 0;
689 afs_uint64 blocks = 0;
690 afs_uint32 filesNeeded, dirsNeeded;
691 afs_uint32 dl, fl;
692 char buf[SIZEOF_LARGEDISKVNODE256];
693 char buf2[SIZEOF_LARGEDISKVNODE256];
694 struct VnodeDiskObject *rootVnode = (struct VnodeDiskObject *)&buf;
695 struct VnodeDiskObject *parVnode = (struct VnodeDiskObject *)&buf2;
696 char name[256];
697 afs_uint32 parent;
698 struct Msg *m;
699
700 m = (struct Msg *) malloc(sizeof(struct Msg));
701 memset(m, 0, sizeof(struct Msg));
702 m->call = call;
703 m->verbose = verbose;
704
705 /*
706 * First step: planning
707 *
708 * Find out which directories will belong to the new volume
709 *
710 */
711 if (verbose) {
712 sprintf(m->line,
713 "1st step: extract vnode essence from large vnode file\n");
714 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
715 }
716
717 code = ExtractVnodes(m, vol, vLarge0, &dirList, &dl, where, rootVnode,
718 &parent, parVnode);
719 if (code) {
720 sprintf(m->line,
721 "ExtractVnodes failed for %u for directories with code %d\n",
722 V_id(vol)((vol)->header->diskstuff.id), code);
723 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
724 return code;
725 }
726
727 if (verbose) {
728 sprintf(m->line, "2nd step: look for name of vnode %u in directory %u.%u.%u\n",
729 where, V_id(vol)((vol)->header->diskstuff.id), parent, parVnode->uniquifier);
730 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
731 }
732 code = findName(vol, parVnode, where, rootVnode->uniquifier,
733 name, sizeof(name));
734 if (code) {
735 sprintf(m->line,
736 "splitvolume: could'nt find name of %u in directory %u.%u.%u.\n",
737 where, V_id(vol)((vol)->header->diskstuff.id), parent, parVnode->uniquifier);
738 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
739 return code;
740 }
741 if (verbose) {
742 sprintf(m->line, "name of %u is %s\n", where, name);
743 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
744 }
745
746 if (verbose) {
747 sprintf(m->line, "3rd step: find all directory vnodes belonging to the subtree under %u \"%s\"\n",
748 where, name);
749 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
750 }
751 code = FindVnodes(m, where, dirList, dl, dirList, dl, &dirsNeeded, 1);
752 if (code) {
753 sprintf(m->line,
754 "FindVnodes for directories failed with code %d\n", code);
755 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
756 return code;
757 }
758
759 if (verbose) {
760 sprintf(m->line, "4th step extract vnode essence from small vnode file\n");
761 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
762 }
763 code = ExtractVnodes(m, vol, vSmall1, &fileList, &fl, where, 0, 0, 0);
764 if (code) {
765 sprintf(m->line,
766 "ExtractVnodes failed for %u for files with code %d\n",
767 V_id(vol)((vol)->header->diskstuff.id), code);
768 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
769 return code;
770 }
771 if (verbose) {
772 sprintf(m->line, "5th step: find all small vnodes belonging to the subtree under %u \"%s\"\n",
773 where, name);
774 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
775 }
776 FindVnodes(m, where, fileList, fl, dirList, dl, &filesNeeded, 0);
777
778 /*
779 * Third step: create hard links for all files needed
780 *
781 */
782
783 V_destroyMe(newvol)((newvol)->header->diskstuff.destroyMe) = DESTROY_ME0xD3;
784 V_inService(newvol)((newvol)->header->diskstuff.inService) = 0;
785 if (verbose) {
786 sprintf(m->line, "6th step: create hard links in the AFSIDat tree between files of the old and new volume\n");
787 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
788 }
789 code = copyVnodes(m, vol, newvol, 1, fileList, fl, where, &blocks, 0);
790 if (code) {
791 sprintf(m->line, "copyVnodes for files failed with code %d\n", code);
792 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
793 return code;
794 }
795
796 /*
797 * Forth step: create hard links for all directories and copy
798 * split directory to new root directory
799 */
800
801 if (verbose) {
802 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",
803 where);
804 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
805 }
806 code = copyVnodes(m, vol, newvol, 0, dirList, dl, where, &blocks, parVnode);
807 if (code) {
808 sprintf(m->line, "copyVnodes for directories failed with code %d\n", code);
809 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
810 return code;
811 }
812
813 /*
814 * Finalize new volume
815 *
816 */
817 if (verbose) {
818 sprintf(m->line, "8th step: write new volume's metadata to disk\n");
819 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
820 }
821
822 V_diskused(newvol)((newvol)->header->diskstuff.diskused) = blocks;
823#ifdef AFS_RXOSD_SUPPORT
824 V_osdFlag(newvol) = V_osdFlag(vol);
825#endif
826 V_filecount(newvol)((newvol)->header->diskstuff.filecount) = filesNeeded + dirsNeeded;
827 V_destroyMe(newvol)((newvol)->header->diskstuff.destroyMe) = 0;
828 V_maxquota(newvol)((newvol)->header->diskstuff.maxquota) = V_maxquota(vol)((vol)->header->diskstuff.maxquota);
829 V_uniquifier(newvol)((newvol)->header->diskstuff.uniquifier) = V_uniquifier(vol)((vol)->header->diskstuff.uniquifier);
830 V_inService(newvol)((newvol)->header->diskstuff.inService) = 1;
831 VUpdateVolume(&code, newvol);
832
833 /*
834 * Sixth step: change directory entry in old volume:
835 * rename old tree and create mount point for new volume.
836 */
837 if (verbose) {
838 sprintf(m->line, "9th step: create mountpoint \"%s\" for new volume in old volume's directory %u.\n", name, parent);
839 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
840 }
841
842 code = createMountpoint(vol, newvol, parVnode, parent, rootVnode, name);
843 if (code) {
844 sprintf(m->line, "createMountpoint failed with code %d\n", code);
845 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
846 return code;
847 }
848 /*
849 * Now both volumes should be ready and consistent, but the old volume
850 * contains still the vnodes and data we transferred into the new one.
851 * Delete orphaned vnodes and data.
852 */
853
854 blocks = 0;
855 if (verbose) {
856 sprintf(m->line, "10th step: delete large vnodes belonging to subtree in the old volume.\n");
857 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
858 }
859 deleteVnodes(vol, vLarge0, dirList, dl, &blocks);
860 if (verbose) {
861 sprintf(m->line, "11th step: delete small vnodes belonging to subtree in the old volume.\n");
862 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
863 }
864 deleteVnodes(vol, vSmall1, fileList, fl, &blocks);
865 V_diskused(vol)((vol)->header->diskstuff.diskused) -= blocks;
866 V_filecount(vol)((vol)->header->diskstuff.filecount) -= (filesNeeded + dirsNeeded + 1);
867 VUpdateVolume(&code, vol);
868
869 sprintf(m->line, "Finished!\n");
870 rx_Write(m->call, m->line, strlen(m->line))rx_WriteProc(m->call, m->line, strlen(m->line));
871 m->line[0] = 0;
872 m->line[1] = 0;
873 m->line[2] = 0;
874 m->line[3] = 0;
875 rx_Write(m->call, m->line, 4)rx_WriteProc(m->call, m->line, 4);
876 free(m);
877 return code;
878}
879#endif