Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / vol / listinodes.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
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
8 */
9
10 /*
11
12 System: VICE-TWO
13 Module: listinodes.c
14 Institution: The Information Technology Center, Carnegie-Mellon University
15
16 */
17
18 #define ITC /* Required by inode.h */
19
20 #include <afsconfig.h>
21 #include <afs/param.h>
22
23 #include <roken.h>
24 #include <afs/opr.h>
25
26 #include <ctype.h>
27
28 #ifndef AFS_NAMEI_ENV
29 #if defined(AFS_LINUX20_ENV)
30 /* ListViceInodes
31 *
32 * Return codes:
33 * 0 - success
34 * -1 - Unable to read the inodes.
35 * -2 - Unable to completely write temp file. Produces warning message in log.
36 */
37 int
38 ListViceInodes(char *devname, char *mountedOn, FD_t inodeFile,
39 afs_uint32 (*judgeInode) (), VolumeId judgeParam, int *forcep, int forceR,
40 char *wpath, void *rock)
41 {
42 Log("ListViceInodes not implemented for this platform!\n");
43 return -1;
44 }
45 #else
46 #if !defined(AFS_SGI_ENV)
47 #ifdef AFS_OSF_ENV
48 #include <ufs/fs.h>
49 #else /* AFS_OSF_ENV */
50 #ifdef AFS_VFSINCL_ENV
51 #define VFS
52 #ifdef AFS_SUN5_ENV
53 #include <sys/fs/ufs_fs.h>
54 #else
55 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
56 #include <ufs/ufs/dinode.h>
57 #include <ufs/ffs/fs.h>
58 #define itod ino_to_fsba
59 #else
60 #include <ufs/fs.h>
61 #endif
62 #endif
63 #else /* AFS_VFSINCL_ENV */
64 #ifdef AFS_AIX_ENV
65 #include <sys/filsys.h>
66 #else
67 #include <sys/fs.h>
68 #endif
69 #endif /* AFS_VFSINCL_ENV */
70 #endif /* AFS_OSF_ENV */
71 #ifdef AFS_VFSINCL_ENV
72 #include <sys/vnode.h>
73 #ifdef AFS_SUN5_ENV
74 #include <sys/fs/ufs_inode.h>
75 #else
76 #if !defined(AFS_DARWIN_ENV)
77 #include <ufs/inode.h>
78 #endif
79 #endif
80 #else /* AFS_VFSINCL_ENV */
81 #ifdef AFS_OSF_ENV
82 #include <ufs/inode.h>
83 #else /* AFS_OSF_ENV */
84 #include <sys/inode.h>
85 #endif
86 #endif /* AFS_VFSINCL_ENV */
87 #endif /* AFS_SGI_ENV */
88 #include <afs/osi_inode.h>
89 #include <sys/file.h>
90 #include <rx/xdr.h>
91 #include <afs/afsint.h>
92 #include "nfs.h"
93 #include <afs/afssyscalls.h>
94 #include "viceinode.h"
95 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
96 #include <sys/ino.h>
97 #endif
98
99 #include <rx/rx_queue.h>
100
101 #include "lock.h"
102 #include "ihandle.h"
103 #include "vnode.h"
104 #include "volume.h"
105 #include "volinodes.h"
106 #include "partition.h"
107 #include "fssync.h"
108 #include "volume_inline.h"
109
110 /* Notice: parts of this module have been cribbed from vfsck.c */
111
112 #define ROOTINODE 2
113 static char *partition;
114 int Testing=0;
115 FD_t pfd;
116
117 #ifdef AFS_AIX32_ENV
118 #include <jfs/filsys.h>
119
120 #ifndef FSBSIZE
121 #define FSBSIZE (4096) /* filesystem block size */
122 #define FSBSHIFT (12) /* log2(FSBSIZE) */
123 #define FSBMASK (FSBSIZE - 1) /* FSBSIZE mask */
124
125 #define MIN_FSIZE DISKMAP_B /* minimum fs size (FSblocks) */
126 #define LAST_RSVD_I 15 /* last reserved inode */
127 #endif
128
129 #ifndef INOPB
130 /*
131 * This will hopefully eventually make it into the system include files
132 */
133 #define INOPB (FSBSIZE / sizeof (struct dinode))
134 #endif
135
136 #ifdef AFS_AIX41_ENV
137 int fragsize;
138 int iagsize;
139 int ag512;
140 int agblocks;
141 #endif /* AFS_AIX41_ENV */
142
143 /*
144 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
145 XX This was lifted from some `com/cmd/fs/fshlpr_aix3/Fs.h', which indicated X
146 XX a longing to see it make it into a readily accessible include file. XXXXXX
147 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
148 *
149 * itoo - inode number to offset within disk block
150 */
151 #undef itoo
152 #define itoo(x) (int) ((unsigned)(x) % INOPB)
153
154 int Bsize = FSBSIZE; /* block size for this system */
155 daddr_t fmax; /* total number of blocks n file system */
156 ino_t imax, inum; /* total number of I-nodes in file system */
157
158 static struct superblock fs;
159 struct dinode *ginode();
160
161
162 int
163 ListViceInodes(char *devname, char *mountedOn, FD_t inodeFile,
164 int (*judgeInode) (), VolumeId judgeParam, int *forcep, int forceR,
165 char *wpath, void *rock)
166 {
167 char dev[50], rdev[51];
168 struct stat status;
169 struct dinode *p;
170 struct ViceInodeInfo info;
171 struct stat root_inode;
172 int ninodes = 0, err = 0;
173
174 pfd = INVALID_FD; /* initialize so we don't close on error output below. */
175 *forcep = 0;
176 sync();
177 sleep(1); /* simulate operator */
178 sync();
179 sleep(1);
180 sync();
181 sleep(1);
182
183 partition = mountedOn;
184 sprintf(dev, "/dev/%s", devname);
185 sprintf(rdev, "/dev/r%s", devname);
186
187 if (stat(mountedOn, &root_inode) < 0) {
188 Log("cannot stat: %s\n", mountedOn);
189 return -1;
190 }
191
192 if (root_inode.st_ino != ROOTDIR_I) {
193 Log("%s is not root of a filesystem\n", mountedOn);
194 return -1;
195 }
196
197
198 /*
199 * done with the superblock, now try to read the raw device.
200 */
201 if (ReadSuper(&fs, dev) < 0)
202 return -1;
203
204 switch (fs.s_fmod) {
205 default:
206 case FM_CLEAN: /* clean and unmounted */
207 Log("Most peculiar - Super blk in FM_CLEAN state!\n");
208 goto out;
209 case FM_MOUNT: /* mounted cleanly */
210 break;
211
212 case FM_MDIRTY: /* dirty when mounted or commit fail */
213 case FM_LOGREDO: /* log redo attempted but failed */
214 Log("File system %s is in a bad state.\n", rdev);
215 Log("Call your IBM representative.\n");
216 return -1;
217 }
218 #ifdef AFS_AIX42_ENV
219 if (IsBigFilesFileSystem(&fs, (char *)0)) {
220 Log("%s is a big files filesystem, can't salvage.\n", mountedOn);
221 return -1;
222 }
223 #else
224 if (strncmp(fs.s_magic, fsv3magic, strlen(fsv3magic)) != 0) {
225 #ifdef AFS_AIX41_ENV
226 if ((strncmp(fs.s_magic, fsv3pmagic, strlen(fsv3pmagic)) != 0)
227 || (fs.s_version != fsv3pvers)) {
228 Log("Super block doesn't have the problem magic (%s vs v3magic %s v3pmagic %s)\n", fs.s_magic, fsv3magic, fsv3pmagic);
229 return -1;
230 }
231 #else
232 Log("Super block doesn't have the problem magic (%s vs v3magic %s)\n",
233 fs.s_magic, fsv3magic);
234 return -1;
235 #endif
236 }
237 #endif
238
239 #ifdef AFS_AIX41_ENV
240 fragsize = (fs.s_fragsize) ? fs.s_fragsize : FSBSIZE;
241 iagsize = (fs.s_iagsize) ? fs.s_iagsize : fs.s_agsize;
242 ag512 = fragsize * fs.s_agsize / 512;
243 agblocks = fragsize * fs.s_agsize >> BSHIFT;
244 #endif /* AFS_AIX41_ENV */
245
246 fmax = fs.s_fsize / (FSBSIZE / 512); /* first invalid blk num */
247
248 pfd = OS_OPEN(rdev, O_RDONLY, 0666);
249 if (pfd == INVALID_FD) {
250 Log("Unable to open `%s' inode for reading\n", rdev);
251 return -1;
252 }
253
254 /*
255 * calculate the maximum number of inodes possible
256 */
257 #ifdef AFS_AIX41_ENV
258 imax = iagsize * (fs.s_fsize / ag512) - 1;
259 #else /* AFS_AIX41_ENV */
260 imax =
261 ((fmax / fs.s_agsize +
262 ((fmax % fs.s_agsize) >= fs.s_agsize / INOPB ? 1 : 0))
263 * fs.s_agsize) - 1;
264 #endif /* AFS_AIX41_ENV */
265
266 /*
267 * check for "FORCESALVAGE" equivalent:
268 * LAST_RSVD_I is a vice inode, with dead beef, and
269 * di_nlink == 2 to indicate the FORCE.
270 */
271 opr_Verify(p = ginode(LAST_RSVD_I));
272
273 if (p->di_vicemagic == VICEMAGIC && p->di_vicep1 == 0xdeadbeef
274 && p->di_nlink == 2) {
275 *forcep = 1;
276 idec(root_inode.st_dev, LAST_RSVD_I, 0xdeadbeef);
277 }
278
279 for (inum = LAST_RSVD_I + 1; inum <= imax; ++inum) {
280 if ((p = ginode(inum)) == NULL || p->di_vicemagic != VICEMAGIC
281 || (p->di_mode & IFMT) != IFREG)
282 continue;
283
284 info.inodeNumber = inum;
285 info.byteCount = p->di_size;
286 info.linkCount = p->di_nlink;
287 info.u.param[0] = p->di_vicep1;
288 info.u.param[1] = p->di_vicep2;
289 info.u.param[2] = p->di_vicep3;
290 info.u.param[3] = p->di_vicep4;
291
292 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
293 continue;
294
295 if (inodeFile != INVALID_FD) {
296 if (OS_WRITE(inodeFile, &info, sizeof(info)) != sizeof(info)) {
297 Log("Error writing inode file for partition %s\n", partition);
298 goto out;
299 }
300 }
301 ++ninodes;
302 }
303
304 if (inodeFile != INVALID_FD) {
305 if (OS_SYNC(inodeFile) == -1) {
306 Log("Unable to successfully fsync inode file for %s\n", partition);
307 err = -2;
308 goto out1;
309 }
310
311 /*
312 * Paranoia: check that the file is really the right size
313 */
314 if (OS_SIZE(inodeFile) != ninodes * sizeof(struct ViceInodeInfo)) {
315 Log("Wrong size (%d instead of %d) in inode file for %s\n",
316 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
317 partition);
318 err = -2;
319 goto out1;
320 }
321 }
322 OS_CLOSE(pfd);
323 return 0;
324
325 out:
326 err = -1;
327 out1:
328 if (pfd != INVALID_FD)
329 OS_CLOSE(pfd);
330
331 return err;
332 }
333
334 /* Read in the superblock for devName */
335 int
336 ReadSuper(struct superblock *fs, char *devName)
337 {
338 FD_t pfd;
339
340 pfd = OS_OPEN(devName, O_RDONLY, 0666);
341 if (pfd == INVALID_FD) {
342 Log("Unable to open inode on %s for reading superblock.\n", devName);
343 return -1;
344 }
345
346 if (bread(pfd, fs, SUPER_B, sizeof(struct superblock)) < 0) {
347 Log("Unable to read superblock on %s.\n", devName);
348 return -1;
349 }
350 OS_CLOSE(pfd);
351 return (0);
352 }
353
354 #ifdef AFS_AIX42_ENV
355 /* IsBigFilesFileSystem returns 1 if it's a big files filesystem, 0 otherwise. */
356 int
357 IsBigFilesFileSystem(struct superblock *sb)
358 {
359 if ((strncmp(sb->s_magic, fsv3pmagic, 4) == 0)
360 && (sb->s_version == fsbigfile)
361 && (sb->s_bigexp))
362 return 1;
363 else
364 return 0;
365 }
366 #endif
367
368 struct dinode *
369 ginode(inum)
370 {
371 int ag;
372 daddr_t pblk;
373 struct dinode *dp;
374 static char buf[FSBSIZE];
375 static daddr_t last_blk = -1;
376
377 #ifdef AFS_AIX41_ENV
378 ag = inum / iagsize;
379 pblk =
380 (ag ==
381 0) ? INODES_B + inum / INOPB : ag * agblocks + (inum -
382 ag * iagsize) /
383 INOPB;
384 #else /* AFS_AIX41_ENV */
385 ag = inum / fs.s_agsize;
386 pblk =
387 (ag ==
388 0) ? INODES_B + inum / INOPB : ag * fs.s_agsize + (inum -
389 ag *
390 fs.s_agsize) /
391 INOPB;
392 #endif /* AFS_AIX41_ENV */
393
394 if (last_blk != pblk) {
395 if (bread(pfd, buf, pblk, sizeof(buf)) < 0) {
396 last_blk = -1;
397 return 0;
398 }
399 last_blk = pblk;
400 }
401
402 dp = (struct dinode *)buf;
403 dp += itoo(inum);
404 return (dp);
405 }
406
407 #else /* !AFS_AIX31_ENV */
408
409 #if defined(AFS_SGI_ENV)
410
411 /* libefs.h includes <assert.h>, which we don't want */
412 #define __ASSERT_H__
413
414 #ifdef AFS_SGI_XFS_IOPS_ENV
415 #include <afs/xfsattrs.h>
416 /* xfs_ListViceInodes
417 *
418 * xfs_ListViceInodes verifies and correct the XFS namespace as it collects
419 * the inode information. The name is required for the idec operation to work.
420 * Steps 2 and 3 below are for the AFS_XFS_NAME_VERS == 1. If the name space
421 * changes, the algorithm will need to change.
422 * 1) If the parent inode number does not match the directory's inod number,
423 * change it in the attribute.
424 * 2) If the unqifier in the attribute does not match the name, rename the
425 * file. This is done by doing an exclusive open, incrementing the tag
426 * number until a file can be created. If the tag changes, then the
427 * attribute will need updating.
428 * 3) If the tag in the attribute does not match the name, change the
429 * attribute.
430 * 4) Verify uid = RW volume id and gid = XFS_VICEMAGIC.
431 *
432 */
433
434 /* xfs_VerifyInode
435 *
436 * Does the verifications listed above.
437 * We can't change the names until the readdir is complete, so we set the
438 * rename flag if the file needs renaming.
439 */
440 int
441 xfs_VerifyInode(char *dir, uint64_t pino, char *name, i_list_inode_t * info,
442 int *rename)
443 {
444 char path[1024];
445 int vno;
446 int update_pino = 0;
447 int update_tag = 0;
448 int update_chown = 0;
449 int retCode = 0;
450 char tmpName[32];
451 int tag;
452 afs_ino_str_t stmp;
453
454 *rename = 0;
455 (void)sprintf(path, "%s/%s", dir, name);
456 /* Verify uid and gid fields */
457 if (info->ili_magic != XFS_VICEMAGIC) {
458 Log("%s magic for %s/%s (inode %s) from %d to %d\n",
459 Testing ? "Would have changed" : "Changing", dir, name,
460 PrintInode(stmp, info->ili_info.inodeNumber), info->ili_magic,
461 XFS_VICEMAGIC);
462 if (!Testing)
463 update_chown = 1;
464 }
465
466 vno = info->ili_info.param[0];
467 if (info->ili_vno != AFS_XFS_VNO_CLIP(vno)) {
468 Log("%s volume id for %s/%s (inode %s) from %d to %d\n",
469 Testing ? "Would have changed" : "Changing", dir, name,
470 PrintInode(stmp, info->ili_info.inodeNumber), info->ili_vno,
471 AFS_XFS_VNO_CLIP(vno));
472 if (!Testing)
473 update_chown = 1;
474 }
475
476 if (update_chown) {
477 if (chown(path, AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC) < 0) {
478 Log("Can't chown %s to uid=%d, gid=0x%x\n", path,
479 AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC);
480 retCode = -1;
481 }
482 }
483
484 /* Check Parent inode number. */
485 if (info->ili_pino != pino) {
486 afs_ino_str_t sino, sipino, spino;
487 (void)PrintInode(sino, info->ili_info.inodeNumber);
488 (void)PrintInode(sipino, info->ili_pino);
489 (void)PrintInode(spino, pino);
490 Log("%s parent ino for %s (inode %s) from %s to %s.\n",
491 Testing ? "Would have changed" : "Changing", path, sino, sipino,
492 spino);
493 if (!Testing)
494 update_pino = 1;
495 }
496
497 /* Verify the file name. */
498 (void)strcpy(tmpName, ".");
499 (void)strcat(tmpName, int_to_base64(stmp, info->ili_info.param[2]));
500 if (strncmp(name, tmpName, strlen(tmpName))) {
501 Log("%s name %s (inode %s) in directory %s, unique=%d, tag=%d\n",
502 Testing ? "Would have returned bad" : "Bad", name,
503 PrintInode(stmp, info->ili_info.inodeNumber), dir,
504 info->ili_info.param[2], info->ili_tag);
505 if (!Testing)
506 *rename = 1;
507 }
508
509 if (!*rename) {
510 /* update the tag? */
511 (void)strcat(tmpName, ".");
512 (void)strcat(tmpName, int_to_base64(stmp, info->ili_tag));
513 if (strcmp(name, tmpName)) {
514 char *p;
515 (void)strcpy(tmpName, name);
516 p = strchr(tmpName + 1, '.');
517 if (!p) {
518 Log("No tag found on name %s (inode %s)in directory, %s.\n",
519 name, PrintInode(stmp, info->ili_info.inodeNumber), dir,
520 Testing ? "would have renamed" : "will rename");
521 if (!Testing)
522 *rename = 1;
523 } else {
524 tag = base64_to_int(p + 1);
525 Log("%s the tag for %s (inode %s) from %d to %d.\n",
526 Testing ? "Would have changed" : "Will change", path,
527 PrintInode(stmp, info->ili_info.inodeNumber), dir, tag,
528 info->ili_tag);
529 if (!Testing)
530 update_tag = 1;
531 }
532 }
533 }
534
535 if (update_pino || update_tag) {
536 afs_xfs_attr_t attrs;
537 int length;
538
539 length = SIZEOF_XFS_ATTR_T;
540 if (attr_get(path, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT) <
541 0) {
542 Log("Can't get AFS attribute for %s\n", path);
543 return -1;
544 }
545 if (update_pino)
546 attrs.at_pino = pino;
547 if (update_tag)
548 attrs.at_tag = tag;
549 if (attr_set
550 (path, AFS_XFS_ATTR, (char *)&attrs, length,
551 ATTR_ROOT | ATTR_REPLACE) < 0) {
552 Log("Can't set AFS attribute into %s\n", path);
553 retCode = -1;
554 }
555 }
556
557 return retCode;
558 }
559
560 typedef struct {
561 int uniq;
562 char name[28];
563 } xfs_Rename_t;
564
565 int
566 xfs_RenameFiles(char *dir, xfs_Rename_t * renames, int n_renames)
567 {
568 int i, j;
569 char opath[128], nbase[128], npath[128];
570 afs_xfs_attr_t attrs;
571 int length = SIZEOF_XFS_ATTR_T;
572 b64_string_t stmp;
573 int tag;
574 int fd;
575
576 for (i = 0; i < n_renames; i++) {
577 (void)sprintf(opath, "%s/%s", dir, renames[i].name);
578 (void)sprintf(nbase, "%s/.%s", dir,
579 int_to_base64(stmp, renames[i].uniq));
580 for (tag = 2, j = 0; j < 64; tag++, j++) {
581 (void)sprintf(npath, "%s.%s", nbase, int_to_base64(stmp, tag));
582 fd = afs_open(npath, O_CREAT | O_EXCL | O_RDWR, 0);
583 if (fd > 0) {
584 close(fd);
585 break;
586 }
587 }
588 if (j != 64) {
589 Log("Can't find a new name for %s\n", opath);
590 return -1;
591 }
592 if (rename(opath, npath) < 0) {
593 Log("Can't rename %s to %s\n", opath, npath);
594 return -1;
595 }
596 Log("Renamed %s to %s\n", opath, npath);
597 return 0;
598 }
599 }
600
601
602 int
603 xfs_ListViceInodes(char *devname, char *mountedOn, FD_t inodeFile,
604 int (*judgeInode) (), VolumeId judgeParam, int *forcep,
605 int forceR, char *wpath, void *rock)
606 {
607 i_list_inode_t info;
608 int info_size = sizeof(i_list_inode_t);
609 int fd;
610 DIR *top_dirp;
611 dirent64_t *top_direntp;
612 DIR *vol_dirp;
613 dirent64_t *vol_direntp;
614 struct stat64 sdirbuf;
615 struct stat64 sfilebuf;
616 afs_xfs_attr_t attrs;
617 afs_xfs_dattr_t dattrs;
618 int length;
619 char vol_dirname[1024];
620 int ninodes = 0;
621 int code = 0;
622 xfs_Rename_t *renames = (xfs_Rename_t *) 0;
623 int rename;
624 #define N_RENAME_STEP 64
625 int n_renames = 0;
626 int n_avail = 0;
627 uint64_t pino;
628 int errors = 0;
629
630 *forcep = 0;
631
632 if (stat64(mountedOn, &sdirbuf) < 0) {
633 perror("xfs_ListViceInodes: stat64");
634 return -1;
635 }
636
637 if ((top_dirp = opendir(mountedOn)) == NULL) {
638 Log("Can't open directory %s to read inodes.\n", mountedOn);
639 return -1;
640 }
641
642 while (top_direntp = readdir64(top_dirp)) {
643 /* Only descend directories with the AFSDIR attribute set.
644 * Could also verify the contents of the atribute, but currently
645 * they are not used.
646 * Performance could be improved for single volume salvages by
647 * only going through the directory containing the volume's inodes.
648 * But I'm being complete as a first pass.
649 */
650 (void)sprintf(vol_dirname, "%s/%s", mountedOn, top_direntp->d_name);
651 length = SIZEOF_XFS_DATTR_T;
652 if (attr_get
653 (vol_dirname, AFS_XFS_DATTR, (char *)&dattrs, &length, ATTR_ROOT))
654 continue;
655
656 if ((vol_dirp = opendir(vol_dirname)) == NULL) {
657 if (errno == ENOTDIR)
658 continue;
659 Log("Can't open directory %s to read inodes.\n", vol_dirname);
660 goto err1_exit;
661 }
662
663 pino = top_direntp->d_ino;
664 n_renames = 0;
665 while (vol_direntp = readdir64(vol_dirp)) {
666 if (vol_direntp->d_name[1] == '\0'
667 || vol_direntp->d_name[1] == '.')
668 continue;
669
670 info.ili_version = AFS_XFS_ILI_VERSION;
671 info_size = sizeof(i_list_inode_t);
672 code =
673 ilistinode64(sdirbuf.st_dev, vol_direntp->d_ino, &info,
674 &info_size);
675 if (code) {
676 /* Where possible, give more explicit messages. */
677 switch (errno) {
678 case ENXIO:
679 case ENOSYS:
680 Log("%s (device id %d) is not on an XFS filesystem.\n",
681 vol_dirname, sdirbuf.st_dev);
682 goto err1_exit;
683 break;
684 case EINVAL:
685 case E2BIG:
686 if (info_size != sizeof(i_list_inode_t)
687 || info.ili_version != AFS_XFS_ILI_VERSION) {
688 Log("Version skew between kernel and salvager.\n");
689 goto err1_exit;
690 }
691 break;
692 }
693 /* Continue, so we collect all the errors in the first pass. */
694 Log("Error listing inode named %s/%s: %s\n", vol_dirname,
695 vol_direntp->d_name, strerror(errno));
696 errors++;
697 continue;
698 }
699
700 if (info.ili_attr_version != AFS_XFS_ATTR_VERS) {
701 Log("Unrecognized XFS attribute version %d in %s/%s. Upgrade salvager\n", info.ili_attr_version, vol_dirname, vol_direntp->d_name);
702 goto err1_exit;
703 }
704
705 if (judgeInode && (*judgeInode) (&info.ili_info, judgeParam, rock) == 0)
706 continue;
707
708 rename = 0;
709 if (xfs_VerifyInode
710 (vol_dirname, pino, vol_direntp->d_name, &info,
711 &rename) < 0) {
712 errors++;
713 }
714
715 if (rename) {
716 /* Add this name to the list of items to rename. */
717 if (n_renames >= n_avail) {
718 n_avail += N_RENAME_STEP;
719 if (n_avail == N_RENAME_STEP)
720 renames = malloc(n_avail * sizeof(xfs_Rename_t));
721 else
722 renames = realloc(renames,
723 n_avail * sizeof(xfs_Rename_t));
724 if (!renames) {
725 Log("Can't %salloc %lu bytes for rename list.\n",
726 (n_avail == N_RENAME_STEP) ? "m" : "re",
727 n_avail * sizeof(xfs_Rename_t));
728 goto err1_exit;
729 }
730 }
731 (void)strcpy(renames[n_renames].name, vol_direntp->d_name);
732 renames[n_renames].uniq = info.ili_info.param[2];
733 n_renames++;
734 }
735
736 if (inodeFile != INVALID_FD) {
737 if (OS_WRITE
738 (inodeFile, &info.ili_info, sizeof(vice_inode_info_t))
739 != sizeof(vice_inode_info_t)) {
740 Log("Error writing inode file for partition %s\n", mountedOn);
741 goto err1_exit;
742 }
743 }
744 ninodes++;
745
746 } /* end while vol_direntp */
747
748 closedir(vol_dirp);
749 vol_dirp = (DIR *) 0;
750 if (n_renames) {
751 Log("Renaming files.\n");
752 if (xfs_RenameFiles(vol_dirname, renames, n_renames) < 0) {
753 goto err1_exit;
754 }
755 }
756 }
757
758 closedir(top_dirp);
759 if (renames)
760 free(renames);
761 if (inodeFile != INVALID_FD) {
762 if (OS_SYNC(inodeFile) == -1) {
763 Log("Unable to successfully fsync inode file for %s\n", mountedOn);
764 return errors ? -1 : -2;
765 }
766 /*
767 * Paranoia: check that the file is really the right size
768 */
769 if (OS_SIZE(inodeFile) != ninodes * sizeof(struct ViceInodeInfo)) {
770 Log("Wrong size (%d instead of %d) in inode file for %s\n",
771 OS_SIZE(inodeFile), ninodes * sizeof(struct ViceInodeInfo),
772 partition);
773 return errors ? -1 : -2;
774 }
775 }
776
777 if (errors) {
778 Log("Errors encontered listing inodes, not salvaging partition.\n");
779 return -1;
780 }
781
782 return 0;
783
784 err1_exit:
785 if (vol_dirp)
786 closedir(vol_dirp);
787 if (top_dirp)
788 closedir(top_dirp);
789 if (renames)
790 free(renames);
791 return -1;
792 }
793
794 #endif
795
796 int
797 ListViceInodes(char *devname, char *mountedOn, FD_t inodeFile,
798 int (*judgeInode) (), VolumeId judgeParam, int *forcep, int forceR,
799 char *wpath, void *rock)
800 {
801 char dev[50], rdev[51];
802 struct stat status;
803 struct efs_dinode *p;
804 struct ViceInodeInfo info;
805 struct stat root_inode;
806 int ninodes = 0, err = 0;
807 struct efs_dinode *dinodeBuf = NULL;
808 int last_cgno;
809 ino_t imax, inum; /* total number of I-nodes in file system */
810
811 *forcep = 0;
812 sync();
813 sleep(1); /* simulate operator */
814 sync();
815 sleep(1);
816 sync();
817 sleep(1);
818
819 if (stat(mountedOn, &root_inode) < 0) {
820 Log("cannot stat: %s\n", mountedOn);
821 return -1;
822 }
823 #ifdef AFS_SGI_XFS_IOPS_ENV
824 if (!strcmp("xfs", root_inode.st_fstype)) {
825 return xfs_ListViceInodes(devname, mountedOn, inodeFile, judgeInode,
826 judgeParam, forcep, forceR, wpath, rock);
827 } else
828 #endif
829 {
830 Log("%s is not root of a filesystem\n", mountedOn);
831 return -1;
832 }
833 }
834
835 #else /* AFS_SGI_ENV */
836
837 #ifdef AFS_HPUX_ENV
838 #define SPERB (MAXBSIZE / sizeof(short))
839 #define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
840
841 struct bufarea {
842 struct bufarea *b_next; /* must be first */
843 daddr_t b_bno;
844 int b_size;
845 union {
846 char b_buf[MAXBSIZE]; /* buffer space */
847 short b_lnks[SPERB]; /* link counts */
848 daddr_t b_indir[MAXNINDIR]; /* indirect block */
849 struct fs b_fs; /* super block */
850 struct cg b_cg; /* cylinder group */
851 } b_un;
852 char b_dirty;
853 };
854 typedef struct bufarea BUFAREA;
855
856 BUFAREA sblk;
857 #define sblock sblk.b_un.b_fs
858 #endif /* AFS_HPUX_ENV */
859
860 extern char *afs_rawname();
861 int
862 ListViceInodes(char *devname, char *mountedOn, FD_t inodeFile,
863 int (*judgeInode) (), VolumeId judgeParam, int *forcep, int forceR,
864 char *wpath, void *rock)
865 {
866 union {
867 #ifdef AFS_AIX_ENV
868 struct filsys fs;
869 char block[BSIZE];
870 #else /* !AFS_AIX_ENV */
871 struct fs fs;
872 char block[SBSIZE];
873 #endif
874 } super;
875 int i, c, e, bufsize, code, err = 0;
876 char dev[50], rdev[100], err1[512], *ptr1;
877 struct dinode *inodes = NULL, *einodes, *dptr;
878 int ninodes = 0;
879 struct dinode *p;
880 struct ViceInodeInfo info;
881
882 *forcep = 0;
883 partition = mountedOn;
884 sprintf(rdev, "%s/%s", wpath, devname);
885 ptr1 = afs_rawname(rdev);
886 strcpy(rdev, ptr1);
887
888 sync();
889 /* Bletch: this is terrible; is there a better way to do this? Does this work? vfsck doesn't even sleep!! */
890 #ifdef AFS_AIX_ENV
891 sleep(5); /* Trying a smaller one for aix */
892 #else
893 sleep(10);
894 #endif
895
896 pfd = OS_OPEN(rdev, O_RDONLY, 0666);
897 if (pfd == INVALID_FD) {
898 sprintf(err1, "Could not open device %s to get inode list\n", rdev);
899 perror(err1);
900 return -1;
901 }
902 #ifdef AFS_AIX_ENV
903 if (bread(pfd, (char *)&super.fs, SUPERB, sizeof super.fs) == -1) {
904 #else
905 #ifdef AFS_HPUX_ENV
906 if (bread(pfd, (char *)&sblock, SBLOCK, SBSIZE) == -1) {
907 #else
908 if (bread(pfd, super.block, SBLOCK, SBSIZE) == -1) {
909 #endif /* AFS_HPUX_ENV */
910 #endif
911 Log("Unable to read superblock, partition %s\n", partition);
912 goto out;
913 }
914
915 #ifdef AFS_AIX_ENV
916 /*
917 * char *FSlabel(), *fslabel=0;
918 * fslabel = FSlabel(&super.fs);
919 */
920 if (super.fs.s_bsize == 0)
921 super.fs.s_bsize = 512;
922 if (super.fs.s_bsize != BSIZE) {
923 Log("SuperBlk: Cluster size not %d; run vfsck\n", BSIZE);
924 goto out;
925 }
926 fmax = super.fs.s_fsize; /* first invalid blk num */
927 imax = ((ino_t) super.fs.s_isize - (SUPERB + 1)) * INOPB;
928 if (imax == 0) {
929 Log("Size check: imax==0!\n");
930 goto out;
931 }
932 if (GetAuxInodeFile(partition, &status) == 0) {
933 Log("Can't access Aux inode file for partition %s, aborting\n",
934 partition);
935 goto out;
936 }
937 for (inum = 1; inum <= imax; inum++) {
938 struct dauxinode *auxp;
939 if ((auxp = IsAfsInode(inum)) == NULL) {
940 /* Not an afs inode, keep going */
941 continue;
942 }
943 if ((p = ginode(inum)) == NULL)
944 continue;
945 /* deleted/non-existent inode when di_mode == 0 */
946 if (!p->di_mode)
947 continue;
948 info.inodeNumber = (int)inum;
949 info.byteCount = p->di_size;
950 info.linkCount = p->di_nlink;
951 info.u.param[0] = auxp->aux_param1;
952 info.u.param[1] = auxp->aux_param2;
953 info.u.param[2] = auxp->aux_param3;
954 info.u.param[3] = auxp->aux_param4;
955 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
956 continue;
957 if (inodeFile != INVALID_FD) {
958 if (OS_WRITE(inodeFile, &info, sizeof(info)) != sizeof(info)) {
959 Log("Error writing inode file for partition %s\n", partition);
960 goto out;
961 }
962 }
963 ninodes++;
964 }
965 #else
966 /*
967 * run a few consistency checks of the superblock
968 * (Cribbed from vfsck)
969 */
970 #ifdef AFS_HPUX_ENV
971 #if defined(FD_FSMAGIC)
972 if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)
973 && (sblock.fs_magic != FD_FSMAGIC)
974 #if defined(AFS_HPUX101_ENV)
975 && (sblock.fs_magic != FD_FSMAGIC_2)
976 #endif
977 ) {
978 #else
979 if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)) {
980 #endif
981 Log("There's something wrong with the superblock for partition %s; bad magic (%d) run vfsck\n", partition, sblock.fs_magic);
982 goto out;
983 }
984 if (sblock.fs_ncg < 1) {
985 Log("There's something wrong with the superblock for partition %s; NCG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_ncg);
986 goto out;
987 }
988 if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) {
989 Log("There's something wrong with the superblock for partition %s; CPG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_cpg);
990 goto out;
991 }
992 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl
993 || (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
994 Log("There's something wrong with the superblock for partition %s; NCYL LESS THAN NCG*CPG run vfsck\n", partition);
995 goto out;
996 }
997 if (sblock.fs_sbsize > SBSIZE) {
998 Log("There's something wrong with the superblock for partition %s; bsize too large (%d vs. %d) run vfsck\n", partition, sblock.fs_sbsize, sblock.fs_bsize);
999 goto out;
1000 }
1001 #else
1002 if ((super.fs.fs_magic != FS_MAGIC)
1003 || (super.fs.fs_ncg < 1)
1004 #if defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1005 || (super.fs.fs_cpg < 1)
1006 #else
1007 || (super.fs.fs_cpg < 1 || super.fs.fs_cpg > MAXCPG)
1008 #endif
1009 || (super.fs.fs_ncg * super.fs.fs_cpg < super.fs.fs_ncyl
1010 || (super.fs.fs_ncg - 1) * super.fs.fs_cpg >= super.fs.fs_ncyl)
1011 || (super.fs.fs_sbsize > SBSIZE)) {
1012 Log("There's something wrong with the superblock for partition %s; run vfsck\n", partition);
1013 goto out;
1014 }
1015 #endif /* AFS_HPUX_ENV */
1016
1017 #ifdef AFS_HPUX_ENV
1018 bufsize = sblock.fs_ipg * sizeof(struct dinode);
1019 #else
1020 bufsize = super.fs.fs_ipg * sizeof(struct dinode);
1021 #endif /* AFS_HPUX_ENV */
1022 inodes = malloc(bufsize);
1023 einodes = (struct dinode *)(((char *)inodes) + bufsize);
1024 if (inodes == NULL) {
1025 Log("Unable to allocate enough memory to scan inodes; help!\n");
1026 goto out;
1027 }
1028 Log("Scanning inodes on device %s...\n", rdev);
1029 #ifdef AFS_HPUX_ENV
1030 for (c = 0; c < sblock.fs_ncg; c++) {
1031 i = c * sblock.fs_ipg;
1032 e = i + sblock.fs_ipg;
1033 #if defined(AFS_HPUX102_ENV)
1034 if (OS_SEEK(pfd, dbtoo(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1035 -1) {
1036 #else
1037 if (OS_SEEK(pfd, dbtob(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1038 -1) {
1039 #endif
1040 #else
1041 for (c = 0; c < super.fs.fs_ncg; c++) {
1042 daddr_t dblk1;
1043 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1044 daddr_t f1;
1045 #if defined(AFS_DARWIN_ENV)
1046 #define offset_t off_t
1047 #define llseek lseek
1048 #endif
1049 offset_t off;
1050 #endif /* AFS_SUN5_ENV */
1051 i = c * super.fs.fs_ipg;
1052 e = i + super.fs.fs_ipg;
1053 #ifdef AFS_OSF_ENV
1054 dblk1 = fsbtodb(&super.fs, itod(&super.fs, i));
1055 if (OS_SEEK(pfd, (off_t) ((off_t) dblk1 * DEV_BSIZE), L_SET) == -1) {
1056 #else
1057 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1058 f1 = fsbtodb(&super.fs, itod(&super.fs, i));
1059 off = (offset_t) f1 << DEV_BSHIFT;
1060 if (OS_SEEK(pfd, off, L_SET) == -1) {
1061 #else
1062 if (OS_SEEK(pfd, dbtob(fsbtodb(&super.fs, itod(&super.fs, i))), L_SET)
1063 == -1) {
1064 #endif /* AFS_SUN5_ENV */
1065 #endif /* AFS_OSF_ENV */
1066 #endif /* AFS_HPUX_ENV */
1067 Log("Error reading inodes for partition %s; run vfsck\n",
1068 partition);
1069 goto out;
1070 }
1071 while (i < e) {
1072 if (!forceR) {
1073 if (OS_READ(pfd, inodes, bufsize) != bufsize) {
1074 Log("Error reading inodes for partition %s; run vfsck\n",
1075 partition);
1076 goto out;
1077 }
1078 } else {
1079 int bj, bk;
1080 dptr = inodes;
1081 for (bj = bk = 0; bj < bufsize; bj = bj + 512, bk++) {
1082 if ((code = OS_READ(pfd, dptr, 512)) != 512) {
1083 Log("Error reading inode %d? for partition %s (errno = %d); run vfsck\n", bk + i, partition, errno);
1084 if (OS_SEEK(pfd, 512, L_SET) == -1) {
1085 Log("OS_SEEK failed\n");
1086 goto out;
1087 }
1088 dptr->di_mode = 0;
1089 dptr++;
1090 dptr->di_mode = 0;
1091 dptr++;
1092 dptr->di_mode = 0;
1093 dptr++;
1094 dptr->di_mode = 0;
1095 dptr++;
1096 } else
1097 dptr += 4;
1098 }
1099 }
1100 for (p = inodes; p < einodes && i < e; i++, p++) {
1101 #ifdef notdef
1102 Log("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1103 i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1104 p->di_size, p->di_nlink);
1105 printf
1106 ("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1107 i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1108 p->di_size, p->di_nlink);
1109 #endif
1110 #ifdef AFS_OSF_ENV
1111 #ifdef AFS_3DISPARES
1112 /* Check to see if this inode is a pre-"OSF1 4.0D" inode */
1113 if ((p->di_uid || p->di_gid)
1114 && !(p->di_flags & (IC_XUID | IC_XGID))) {
1115 Log("Found unconverted inode %d: Use 'fs_conv_dux40D convert' on partition %s\n", i, partition);
1116 goto out;
1117 }
1118 #else
1119 osi_Panic("Tru64 needs AFS_3DISPARES\n");
1120 #endif
1121 #endif
1122 #if defined(AFS_SUN5_ENV)
1123 /* if this is a pre-sol2.6 unconverted inode, bail out */
1124 {
1125 afs_uint32 p1, p2, p3, p4;
1126 int p5;
1127 quad *q;
1128
1129 q = (quad *) & (p->di_ic.ic_lsize);
1130 p1 = p->di_gen;
1131 p2 = p->di_ic.ic_flags;
1132 p3 = q->val[0];
1133 p4 = p->di_ic.ic_uid;
1134 p5 = p->di_ic.ic_gid;
1135
1136 if ((p2 || p3) && !p4 && (p5 == -2)) {
1137 Log("Found unconverted inode %d\n", i);
1138 Log("You should run the AFS file conversion utility\n");
1139 goto out;
1140 }
1141 }
1142 #endif
1143 if (IS_DVICEMAGIC(p) && (p->di_mode & IFMT) == IFREG) {
1144 afs_uint32 p2 = p->di_vicep2, p3 = DI_VICEP3(p);
1145
1146 info.u.param[0] = p->di_vicep1;
1147 #ifdef AFS_3DISPARES
1148 if (((p2 >> 3) == INODESPECIAL) && (p2 & 0x3)) {
1149 info.u.param[1] = INODESPECIAL;
1150 info.u.param[2] = p3;
1151 info.u.param[3] = p2 & 0x3;
1152 } else {
1153 info.u.param[1] = ((p2 >> 27) << 16) + (p3 & 0xffff);
1154 info.u.param[2] = (p2 & 0x3fffff);
1155 info.u.param[3] =
1156 (((p2 >> 22) & 0x1f) << 16) + (p3 >> 16);
1157 }
1158 #else
1159 info.u.param[1] = p->di_vicep2;
1160 info.u.param[2] = DI_VICEP3(p);
1161 info.u.param[3] = p->di_vicep4;
1162 #endif
1163 info.inodeNumber = i;
1164 info.byteCount = p->di_size;
1165 info.linkCount = p->di_nlink;
1166 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1167 continue;
1168 if (inodeFile != INVALID_FD) {
1169 if (OS_WRITE(inodeFile, &info, sizeof(info)) != sizeof(info)) {
1170 Log("Error writing inode file for partition %s\n",
1171 partition);
1172 goto out;
1173 }
1174 }
1175 ninodes++;
1176 }
1177 }
1178 }
1179 }
1180 if (inodes)
1181 free(inodes);
1182 #endif
1183 if (inodeFile != INVALID_FD) {
1184 if (OS_SYNC(inodeFile) == -1) {
1185 Log("Unable to successfully fsync inode file for %s\n", partition);
1186 err = -2;
1187 goto out1;
1188 }
1189
1190 /*
1191 * Paranoia: check that the file is really the right size
1192 */
1193 if (OS_SIZE(inodeFile) != ninodes * sizeof(struct ViceInodeInfo)) {
1194 Log("Wrong size (%d instead of %d) in inode file for %s\n",
1195 OS_SIZE(inodeFile), ninodes * sizeof(struct ViceInodeInfo),
1196 partition);
1197 err = -2;
1198 goto out1;
1199 }
1200 }
1201 OS_CLOSE(pfd);
1202 return 0;
1203
1204 out:
1205 err = -1;
1206 out1:
1207 OS_CLOSE(pfd);
1208 if (inodes)
1209 free(inodes);
1210 return err;
1211 }
1212 #endif /* !AFS_SGI_ENV */
1213 #endif /* !AFS_AIX31_ENV */
1214
1215 #ifdef AFS_DARWIN_ENV
1216 #undef dbtob
1217 #define dbtob(db) ((unsigned)(db) << DEV_BSHIFT)
1218 #endif
1219
1220 int
1221 bread(FD_t fd, char *buf, daddr_t blk, afs_int32 size)
1222 {
1223 #ifdef AFS_AIX_ENV
1224 #ifdef AFS_AIX41_ENV
1225 offset_t off = (offset_t) blk << FSBSHIFT;
1226 if (OS_SEEK(fd, off, 0) < 0) {
1227 Log("Unable to seek to offset %llu for block %u\n", off, blk);
1228 return -1;
1229 }
1230 #else /* AFS_AIX41_ENV */
1231 if (OS_SEEK(fd, blk * Bsize, 0) < 0) {
1232 Log("Unable to seek to offset %u for block %u\n", blk * Bsize, blk);
1233 }
1234 #endif /* AFS_AIX41_ENV */
1235 #else
1236 if (OS_SEEK(fd, (off_t) dbtob(blk), L_SET) < 0) {
1237 Log("Unable to seek to offset %u for block %u\n", dbtob(blk), blk);
1238 }
1239 #endif
1240 if (OS_READ(fd, buf, size) != size) {
1241 Log("Unable to read block %d, partition %s\n", blk, partition);
1242 return -1;
1243 }
1244 return 0;
1245 }
1246
1247 #endif /* AFS_LINUX20_ENV */
1248 static afs_int32
1249 convertVolumeInfo(FdHandle_t *fdhr, FdHandle_t *fdhw, VolumeId vid)
1250 {
1251 struct VolumeDiskData vd;
1252 char *p;
1253
1254 if (FDH_PREAD(fdhr, &vd, sizeof(struct VolumeDiskData), 0) !=
1255 sizeof(struct VolumeDiskData)) {
1256 Log("1 convertiVolumeInfo: read failed for %lu with code %d\n", vid,
1257 errno);
1258 return -1;
1259 }
1260 vd.restoredFromId = vd.id; /* remember the RO volume here */
1261 vd.cloneId = vd.id;
1262 vd.id = vd.parentId;
1263 vd.type = RWVOL;
1264 vd.dontSalvage = 0;
1265 vd.inUse = 0;
1266 vd.uniquifier += 5000; /* just in case there are still file copies
1267 from the old RW volume around */
1268
1269 /* For ROs, the copyDate contains the time that the RO volume was actually
1270 * created, and the creationDate just contains the last time the RO was
1271 * copied from the RW data. So, make the new RW creationDate more accurate
1272 * by setting it to copyDate, if copyDate is older. Since, we know the
1273 * volume is at least as old as copyDate. */
1274 if (vd.copyDate < vd.creationDate) {
1275 vd.creationDate = vd.copyDate;
1276 } else {
1277 /* If copyDate is newer, just make copyDate and creationDate the same,
1278 * for consistency with other RWs */
1279 vd.copyDate = vd.creationDate;
1280 }
1281
1282 p = strrchr(vd.name, '.');
1283 if (p && !strcmp(p, ".readonly")) {
1284 memset(p, 0, 9);
1285 }
1286
1287 if (FDH_PWRITE(fdhw, &vd, sizeof(struct VolumeDiskData), 0) !=
1288 sizeof(struct VolumeDiskData)) {
1289 Log("1 convertiVolumeInfo: write failed for %lu with code %d\n", vid,
1290 errno);
1291 return -1;
1292 }
1293 return 0;
1294 }
1295
1296 struct specino {
1297 afs_int32 inodeType;
1298 Inode inodeNumber;
1299 Inode ninodeNumber;
1300 };
1301
1302
1303 int
1304 UpdateThisVolume(struct ViceInodeInfo *inodeinfo, VolumeId singleVolumeNumber,
1305 struct specino *specinos)
1306 {
1307 struct dinode *p;
1308 if ((inodeinfo->u.vnode.vnodeNumber == INODESPECIAL) &&
1309 (inodeinfo->u.vnode.volumeId == singleVolumeNumber)) {
1310 specinos[inodeinfo->u.special.type].inodeNumber =
1311 inodeinfo->inodeNumber;
1312 }
1313 return 0; /* We aren't using a result file, we're caching */
1314 }
1315
1316 static char *
1317 getDevName(char *pbuffer, char *wpath)
1318 {
1319 char pbuf[128], *ptr;
1320 strcpy(pbuf, pbuffer);
1321 ptr = (char *)strrchr(pbuf, OS_DIRSEPC);
1322 if (ptr) {
1323 *ptr = '\0';
1324 strcpy(wpath, pbuf);
1325 } else
1326 return NULL;
1327 ptr = (char *)strrchr(pbuffer, OS_DIRSEPC);
1328 if (ptr) {
1329 strcpy(pbuffer, ptr + 1);
1330 return pbuffer;
1331 } else
1332 return NULL;
1333 }
1334
1335 #ifdef FSSYNC_BUILD_CLIENT
1336 int
1337 inode_ConvertROtoRWvolume(char *pname, VolumeId volumeId)
1338 {
1339 char dir_name[512], oldpath[512], newpath[512];
1340 char volname[20];
1341 char headername[16];
1342 char *name;
1343 int fd, err, forcep, j;
1344 ssize_t len, nBytes;
1345 struct dirent *dp;
1346 struct DiskPartition64 *partP;
1347 struct ViceInodeInfo info;
1348 struct VolumeDiskHeader h;
1349 IHandle_t *ih, *ih2;
1350 FdHandle_t *fdP, *fdP2;
1351 afs_foff_t offset;
1352 char wpath[100];
1353 char tmpDevName[100];
1354 char buffer[128];
1355 struct specino specinos[VI_LINKTABLE+1];
1356 Inode nearInode = 0;
1357 # ifdef AFS_DEMAND_ATTACH_FS
1358 int locktype = 0;
1359 # endif /* AFS_DEMAND_ATTACH_FS */
1360 int code = 0;
1361
1362 memset(&specinos, 0, sizeof(specinos));
1363
1364 /* now do the work */
1365
1366 for (partP = DiskPartitionList; partP && strcmp(partP->name, pname);
1367 partP = partP->next);
1368 if (!partP) {
1369 Log("1 inode_ConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname);
1370 code = EIO;
1371 goto done;
1372 }
1373
1374 #ifdef AFS_DEMAND_ATTACH_FS
1375 locktype = VVolLockType(V_VOLUPD, 1);
1376 code = VLockVolumeByIdNB(volumeId, partP, locktype);
1377 if (code) {
1378 locktype = 0;
1379 code = EIO;
1380 goto done;
1381 }
1382 #endif
1383
1384 if (VReadVolumeDiskHeader(volumeId, partP, &h)) {
1385 Log("1 inode_ConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n",
1386 afs_printable_uint32_lu(volumeId));
1387 return EIO;
1388 }
1389
1390 FSYNC_VolOp(volumeId, pname, FSYNC_VOL_BREAKCBKS, 0, NULL);
1391
1392 strcpy(tmpDevName, partP->devName);
1393 name = getDevName(tmpDevName, wpath);
1394
1395 if ((err = ListViceInodes(name, VPartitionPath(partP),
1396 NULL, UpdateThisVolume, volumeId,
1397 &forcep, 0, wpath, &specinos)) < 0)
1398 {
1399 Log("1 inode_ConvertROtoRWvolume: Couldn't get special inodes\n");
1400 code = EIO;
1401 goto done;
1402 }
1403
1404 #if defined(NEARINODE_HINT)
1405 nearInodeHash(volumeId, nearInode);
1406 nearInode %= partP->f_files;
1407 #endif
1408
1409 for (j = VI_VOLINFO; j < VI_LINKTABLE+1; j++) {
1410 if (specinos[j].inodeNumber > 0) {
1411 specinos[j].ninodeNumber =
1412 IH_CREATE(NULL, partP->device, VPartitionPath(partP),
1413 nearInode, h.parent, INODESPECIAL, j, h.parent);
1414 IH_INIT(ih, partP->device, volumeId,
1415 specinos[j].inodeNumber);
1416 fdP = IH_OPEN(ih);
1417 if (!fdP) {
1418 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, volumeId);
1419 code = -1;
1420 goto done;
1421 }
1422
1423 IH_INIT(ih2, partP->device, h.parent, specinos[j].ninodeNumber);
1424 fdP2 = IH_OPEN(ih2);
1425 if (!fdP2) {
1426 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, h.parent);
1427 code = -1;
1428 goto done;
1429 }
1430
1431 if (j == VI_VOLINFO)
1432 convertVolumeInfo(fdP, fdP2, ih2->ih_vid);
1433 else {
1434 offset = 0;
1435 while (1) {
1436 len = FDH_PREAD(fdP, buffer, sizeof(buffer), offset);
1437 if (len < 0)
1438 return errno;
1439 if (len == 0)
1440 break;
1441 nBytes = FDH_PWRITE(fdP2, buffer, len, offset);
1442 if (nBytes != len) {
1443 code = -1;
1444 goto done;
1445 }
1446 offset += len;
1447 }
1448 }
1449
1450 FDH_CLOSE(fdP);
1451 FDH_CLOSE(fdP2);
1452
1453 /* Unlink the old special inode; otherwise we will get duplicate
1454 * special inodes if we recreate the RO again */
1455 if (IH_DEC(ih, specinos[j].inodeNumber, volumeId) == -1) {
1456 afs_ino_str_t stmp;
1457 Log("IH_DEC failed: %x, %s, %u errno %d\n", ih,
1458 PrintInode(stmp, specinos[j].inodeNumber), volumeId, errno);
1459 }
1460
1461 IH_RELEASE(ih);
1462 IH_RELEASE(ih2);
1463 }
1464 }
1465
1466 h.id = h.parent;
1467 #ifdef AFS_64BIT_IOPS_ENV
1468 h.volumeInfo_lo = (afs_int32)specinos[VI_VOLINFO].ninodeNumber & 0xffffffff;
1469 h.volumeInfo_hi = (afs_int32)(specinos[VI_VOLINFO].ninodeNumber >> 32) && 0xffffffff;
1470 h.smallVnodeIndex_lo = (afs_int32)specinos[VI_SMALLINDEX].ninodeNumber & 0xffffffff;
1471 h.smallVnodeIndex_hi = (afs_int32)(specinos[VI_SMALLINDEX].ninodeNumber >> 32) & 0xffffffff;
1472 h.largeVnodeIndex_lo = (afs_int32)specinos[VI_LARGEINDEX].ninodeNumber & 0xffffffff;
1473 h.largeVnodeIndex_hi = (afs_int32)(specinos[VI_LARGEINDEX].ninodeNumber >> 32) & 0xffffffff;
1474 if (specinos[VI_LINKTABLE].ninodeNumber) {
1475 h.linkTable_lo = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1476 h.linkTable_hi = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1477 }
1478 #else
1479 h.volumeInfo_lo = specinos[VI_VOLINFO].ninodeNumber;
1480 h.smallVnodeIndex_lo = specinos[VI_SMALLINDEX].ninodeNumber;
1481 h.largeVnodeIndex_lo = specinos[VI_LARGEINDEX].ninodeNumber;
1482 if (specinos[VI_LINKTABLE].ninodeNumber) {
1483 h.linkTable_lo = specinos[VI_LINKTABLE].ninodeNumber;
1484 }
1485 #endif
1486
1487 if (VCreateVolumeDiskHeader(&h, partP)) {
1488 Log("1 inode_ConvertROtoRWvolume: Couldn't write header for RW-volume %lu\n",
1489 afs_printable_uint32_lu(h.id));
1490 code = EIO;
1491 goto done;
1492 }
1493
1494 if (VDestroyVolumeDiskHeader(partP, volumeId, h.parent)) {
1495 Log("1 inode_ConvertROtoRWvolume: Couldn't unlink header for RO-volume %lu\n",
1496 afs_printable_uint32_lu(volumeId));
1497 }
1498
1499 FSYNC_VolOp(volumeId, pname, FSYNC_VOL_DONE, 0, NULL);
1500 FSYNC_VolOp(h.id, pname, FSYNC_VOL_ON, 0, NULL);
1501
1502 done:
1503 # ifdef AFS_DEMAND_ATTACH_FS
1504 if (locktype) {
1505 VUnlockVolumeById(volumeId, partP);
1506 }
1507 # endif /* AFS_DEMAND_ATTACH_FS */
1508 return code;
1509 }
1510 #endif /* FSSYNC_BUILD_CLIENT */
1511 #endif /* AFS_NAMEI_ENV */