2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
14 Institution: The Information Technology Center, Carnegie-Mellon University
18 #define ITC /* Required by inode.h */
20 #include <afsconfig.h>
21 #include <afs/param.h>
28 #if defined(AFS_LINUX20_ENV)
33 * -1 - Unable to read the inodes.
34 * -2 - Unable to completely write temp file. Produces warning message in log.
37 ListViceInodes(char *devname, char *mountedOn, FD_t inodeFile,
38 afs_uint32 (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
39 char *wpath, void *rock)
41 Log("ListViceInodes not implemented for this platform!\n");
45 #if !defined(AFS_SGI_ENV)
48 #else /* AFS_OSF_ENV */
49 #ifdef AFS_VFSINCL_ENV
52 #include <sys/fs/ufs_fs.h>
54 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
55 #include <ufs/ufs/dinode.h>
56 #include <ufs/ffs/fs.h>
57 #define itod ino_to_fsba
62 #else /* AFS_VFSINCL_ENV */
64 #include <sys/filsys.h>
68 #endif /* AFS_VFSINCL_ENV */
69 #endif /* AFS_OSF_ENV */
70 #ifdef AFS_VFSINCL_ENV
71 #include <sys/vnode.h>
73 #include <sys/fs/ufs_inode.h>
75 #if !defined(AFS_DARWIN_ENV)
76 #include <ufs/inode.h>
79 #else /* AFS_VFSINCL_ENV */
81 #include <ufs/inode.h>
82 #else /* AFS_OSF_ENV */
83 #include <sys/inode.h>
85 #endif /* AFS_VFSINCL_ENV */
86 #endif /* AFS_SGI_ENV */
87 #include <afs/osi_inode.h>
90 #include <afs/afsint.h>
92 #include <afs/afssyscalls.h>
93 #include "viceinode.h"
94 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
102 #include "volinodes.h"
103 #include "partition.h"
105 #include "volume_inline.h"
107 /* Notice: parts of this module have been cribbed from vfsck.c */
110 static char *partition;
115 #include <jfs/filsys.h>
118 #define FSBSIZE (4096) /* filesystem block size */
119 #define FSBSHIFT (12) /* log2(FSBSIZE) */
120 #define FSBMASK (FSBSIZE - 1) /* FSBSIZE mask */
122 #define MIN_FSIZE DISKMAP_B /* minimum fs size (FSblocks) */
123 #define LAST_RSVD_I 15 /* last reserved inode */
128 * This will hopefully eventually make it into the system include files
130 #define INOPB (FSBSIZE / sizeof (struct dinode))
138 #endif /* AFS_AIX41_ENV */
141 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
142 XX This was lifted from some `com/cmd/fs/fshlpr_aix3/Fs.h', which indicated X
143 XX a longing to see it make it into a readily accessible include file. XXXXXX
144 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
146 * itoo - inode number to offset within disk block
149 #define itoo(x) (int) ((unsigned)(x) % INOPB)
151 int Bsize = FSBSIZE; /* block size for this system */
152 daddr_t fmax; /* total number of blocks n file system */
153 ino_t imax, inum; /* total number of I-nodes in file system */
155 static struct superblock fs;
156 struct dinode *ginode();
160 ListViceInodes(char *devname, char *mountedOn, FD_t inodeFile,
161 int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
162 char *wpath, void *rock)
164 char dev[50], rdev[51];
167 struct ViceInodeInfo info;
168 struct stat root_inode;
169 int ninodes = 0, err = 0;
171 pfd = INVALID_FD; /* initialize so we don't close on error output below. */
174 sleep(1); /* simulate operator */
180 partition = mountedOn;
181 sprintf(dev, "/dev/%s", devname);
182 sprintf(rdev, "/dev/r%s", devname);
184 if (stat(mountedOn, &root_inode) < 0) {
185 Log("cannot stat: %s\n", mountedOn);
189 if (root_inode.st_ino != ROOTDIR_I) {
190 Log("%s is not root of a filesystem\n", mountedOn);
196 * done with the superblock, now try to read the raw device.
198 if (ReadSuper(&fs, dev) < 0)
203 case FM_CLEAN: /* clean and unmounted */
204 Log("Most peculiar - Super blk in FM_CLEAN state!\n");
206 case FM_MOUNT: /* mounted cleanly */
209 case FM_MDIRTY: /* dirty when mounted or commit fail */
210 case FM_LOGREDO: /* log redo attempted but failed */
211 Log("File system %s is in a bad state.\n", rdev);
212 Log("Call your IBM representative.\n");
216 if (IsBigFilesFileSystem(&fs, (char *)0)) {
217 Log("%s is a big files filesystem, can't salvage.\n", mountedOn);
221 if (strncmp(fs.s_magic, fsv3magic, strlen(fsv3magic)) != 0) {
223 if ((strncmp(fs.s_magic, fsv3pmagic, strlen(fsv3pmagic)) != 0)
224 || (fs.s_version != fsv3pvers)) {
225 Log("Super block doesn't have the problem magic (%s vs v3magic %s v3pmagic %s)\n", fs.s_magic, fsv3magic, fsv3pmagic);
229 Log("Super block doesn't have the problem magic (%s vs v3magic %s)\n",
230 fs.s_magic, fsv3magic);
237 fragsize = (fs.s_fragsize) ? fs.s_fragsize : FSBSIZE;
238 iagsize = (fs.s_iagsize) ? fs.s_iagsize : fs.s_agsize;
239 ag512 = fragsize * fs.s_agsize / 512;
240 agblocks = fragsize * fs.s_agsize >> BSHIFT;
241 #endif /* AFS_AIX41_ENV */
243 fmax = fs.s_fsize / (FSBSIZE / 512); /* first invalid blk num */
245 pfd = OS_OPEN(rdev, O_RDONLY, 0666);
246 if (pfd == INVALID_FD) {
247 Log("Unable to open `%s' inode for reading\n", rdev);
252 * calculate the maximum number of inodes possible
255 imax = iagsize * (fs.s_fsize / ag512) - 1;
256 #else /* AFS_AIX41_ENV */
258 ((fmax / fs.s_agsize +
259 ((fmax % fs.s_agsize) >= fs.s_agsize / INOPB ? 1 : 0))
261 #endif /* AFS_AIX41_ENV */
264 * check for "FORCESALVAGE" equivalent:
265 * LAST_RSVD_I is a vice inode, with dead beef, and
266 * di_nlink == 2 to indicate the FORCE.
268 osi_Assert(p = ginode(LAST_RSVD_I));
270 if (p->di_vicemagic == VICEMAGIC && p->di_vicep1 == 0xdeadbeef
271 && p->di_nlink == 2) {
273 idec(root_inode.st_dev, LAST_RSVD_I, 0xdeadbeef);
276 for (inum = LAST_RSVD_I + 1; inum <= imax; ++inum) {
277 if ((p = ginode(inum)) == NULL || p->di_vicemagic != VICEMAGIC
278 || (p->di_mode & IFMT) != IFREG)
281 info.inodeNumber = inum;
282 info.byteCount = p->di_size;
283 info.linkCount = p->di_nlink;
284 info.u.param[0] = p->di_vicep1;
285 info.u.param[1] = p->di_vicep2;
286 info.u.param[2] = p->di_vicep3;
287 info.u.param[3] = p->di_vicep4;
289 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
292 if (inodeFile != INVALID_FD) {
293 if (OS_WRITE(inodeFile, &info, sizeof(info)) != sizeof(info)) {
294 Log("Error writing inode file for partition %s\n", partition);
301 if (inodeFile != INVALID_FD) {
302 if (OS_SYNC(inodeFile) == -1) {
303 Log("Unable to successfully fsync inode file for %s\n", partition);
309 * Paranoia: check that the file is really the right size
311 if (OS_SIZE(inodeFile) != ninodes * sizeof(struct ViceInodeInfo)) {
312 Log("Wrong size (%d instead of %d) in inode file for %s\n",
313 status.st_size, ninodes * sizeof(struct ViceInodeInfo),
325 if (pfd != INVALID_FD)
331 /* Read in the superblock for devName */
333 ReadSuper(struct superblock *fs, char *devName)
337 pfd = OS_OPEN(devName, O_RDONLY, 0666);
338 if (pfd == INVALID_FD) {
339 Log("Unable to open inode on %s for reading superblock.\n", devName);
343 if (bread(pfd, fs, SUPER_B, sizeof(struct superblock)) < 0) {
344 Log("Unable to read superblock on %s.\n", devName);
352 /* IsBigFilesFileSystem returns 1 if it's a big files filesystem, 0 otherwise. */
354 IsBigFilesFileSystem(struct superblock *sb)
356 if ((strncmp(sb->s_magic, fsv3pmagic, 4) == 0)
357 && (sb->s_version == fsbigfile)
371 static char buf[FSBSIZE];
372 static daddr_t last_blk = -1;
378 0) ? INODES_B + inum / INOPB : ag * agblocks + (inum -
381 #else /* AFS_AIX41_ENV */
382 ag = inum / fs.s_agsize;
385 0) ? INODES_B + inum / INOPB : ag * fs.s_agsize + (inum -
389 #endif /* AFS_AIX41_ENV */
391 if (last_blk != pblk) {
392 if (bread(pfd, buf, pblk, sizeof(buf)) < 0) {
399 dp = (struct dinode *)buf;
404 #else /* !AFS_AIX31_ENV */
406 #if defined(AFS_SGI_ENV)
408 /* libefs.h includes <assert.h>, which we don't want */
411 #ifdef AFS_SGI_XFS_IOPS_ENV
413 #include <afs/xfsattrs.h>
414 /* xfs_ListViceInodes
416 * xfs_ListViceInodes verifies and correct the XFS namespace as it collects
417 * the inode information. The name is required for the idec operation to work.
418 * Steps 2 and 3 below are for the AFS_XFS_NAME_VERS == 1. If the name space
419 * changes, the algorithm will need to change.
420 * 1) If the parent inode number does not match the directory's inod number,
421 * change it in the attribute.
422 * 2) If the unqifier in the attribute does not match the name, rename the
423 * file. This is done by doing an exclusive open, incrementing the tag
424 * number until a file can be created. If the tag changes, then the
425 * attribute will need updating.
426 * 3) If the tag in the attribute does not match the name, change the
428 * 4) Verify uid = RW volume id and gid = XFS_VICEMAGIC.
434 * Does the verifications listed above.
435 * We can't change the names until the readdir is complete, so we set the
436 * rename flag if the file needs renaming.
439 xfs_VerifyInode(char *dir, uint64_t pino, char *name, i_list_inode_t * info,
446 int update_chown = 0;
454 (void)sprintf(path, "%s/%s", dir, name);
455 /* Verify uid and gid fields */
456 if (info->ili_magic != XFS_VICEMAGIC) {
457 Log("%s magic for %s/%s (inode %s) from %d to %d\n",
458 Testing ? "Would have changed" : "Changing", dir, name,
459 PrintInode(stmp, info->ili_info.inodeNumber), info->ili_magic,
465 vno = info->ili_info.param[0];
466 if (info->ili_vno != AFS_XFS_VNO_CLIP(vno)) {
467 Log("%s volume id for %s/%s (inode %s) from %d to %d\n",
468 Testing ? "Would have changed" : "Changing", dir, name,
469 PrintInode(stmp, info->ili_info.inodeNumber), info->ili_vno,
470 AFS_XFS_VNO_CLIP(vno));
476 if (chown(path, AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC) < 0) {
477 Log("Can't chown %s to uid=%d, gid=0x%x\n", path,
478 AFS_XFS_VNO_CLIP(vno), XFS_VICEMAGIC);
483 /* Check Parent inode number. */
484 if (info->ili_pino != pino) {
485 afs_ino_str_t sino, sipino, spino;
486 (void)PrintInode(sino, info->ili_info.inodeNumber);
487 (void)PrintInode(sipino, info->ili_pino);
488 (void)PrintInode(spino, pino);
489 Log("%s parent ino for %s (inode %s) from %s to %s.\n",
490 Testing ? "Would have changed" : "Changing", path, sino, sipino,
496 /* Verify the file name. */
497 (void)strcpy(tmpName, ".");
498 (void)strcat(tmpName, int_to_base64(stmp, info->ili_info.param[2]));
499 if (strncmp(name, tmpName, strlen(tmpName))) {
500 Log("%s name %s (inode %s) in directory %s, unique=%d, tag=%d\n",
501 Testing ? "Would have returned bad" : "Bad", name,
502 PrintInode(stmp, info->ili_info.inodeNumber), dir,
503 info->ili_info.param[2], info->ili_tag);
509 /* update the tag? */
510 (void)strcat(tmpName, ".");
511 (void)strcat(tmpName, int_to_base64(stmp, info->ili_tag));
512 if (strcmp(name, tmpName)) {
514 (void)strcpy(tmpName, name);
515 p = strchr(tmpName + 1, '.');
517 Log("No tag found on name %s (inode %s)in directory, %s.\n",
518 name, PrintInode(stmp, info->ili_info.inodeNumber), dir,
519 Testing ? "would have renamed" : "will rename");
523 tag = base64_to_int(p + 1);
524 Log("%s the tag for %s (inode %s) from %d to %d.\n",
525 Testing ? "Would have changed" : "Will change", path,
526 PrintInode(stmp, info->ili_info.inodeNumber), dir, tag,
534 if (update_pino || update_tag) {
535 afs_xfs_attr_t attrs;
538 length = SIZEOF_XFS_ATTR_T;
539 if (attr_get(path, AFS_XFS_ATTR, (char *)&attrs, &length, ATTR_ROOT) <
541 Log("Can't get AFS attribute for %s\n", path);
545 attrs.at_pino = pino;
549 (path, AFS_XFS_ATTR, (char *)&attrs, length,
550 ATTR_ROOT | ATTR_REPLACE) < 0) {
551 Log("Can't set AFS attribute into %s\n", path);
565 xfs_RenameFiles(char *dir, xfs_Rename_t * renames, int n_renames)
568 char opath[128], nbase[128], npath[128];
569 afs_xfs_attr_t attrs;
570 int length = SIZEOF_XFS_ATTR_T;
575 for (i = 0; i < n_renames; i++) {
576 (void)sprintf(opath, "%s/%s", dir, renames[i].name);
577 (void)sprintf(nbase, "%s/.%s", dir,
578 int_to_base64(stmp, renames[i].uniq));
579 for (tag = 2, j = 0; j < 64; tag++, j++) {
580 (void)sprintf(npath, "%s.%s", nbase, int_to_base64(stmp, tag));
581 fd = afs_open(npath, O_CREAT | O_EXCL | O_RDWR, 0);
588 Log("Can't find a new name for %s\n", opath);
591 if (rename(opath, npath) < 0) {
592 Log("Can't rename %s to %s\n", opath, npath);
595 Log("Renamed %s to %s\n", opath, npath);
602 xfs_ListViceInodes(char *devname, char *mountedOn, FD_t inodeFile,
603 int (*judgeInode) (), afs_uint32 judgeParam, int *forcep,
604 int forceR, char *wpath, void *rock)
607 int info_size = sizeof(i_list_inode_t);
610 dirent64_t *top_direntp;
612 dirent64_t *vol_direntp;
613 struct stat64 sdirbuf;
614 struct stat64 sfilebuf;
615 afs_xfs_attr_t attrs;
616 afs_xfs_dattr_t dattrs;
618 char vol_dirname[1024];
621 xfs_Rename_t *renames = (xfs_Rename_t *) 0;
623 #define N_RENAME_STEP 64
631 if (stat64(mountedOn, &sdirbuf) < 0) {
632 perror("xfs_ListViceInodes: stat64");
636 if ((top_dirp = opendir(mountedOn)) == NULL) {
637 Log("Can't open directory %s to read inodes.\n", mountedOn);
641 while (top_direntp = readdir64(top_dirp)) {
642 /* Only descend directories with the AFSDIR attribute set.
643 * Could also verify the contents of the atribute, but currently
645 * Performance could be improved for single volume salvages by
646 * only going through the directory containing the volume's inodes.
647 * But I'm being complete as a first pass.
649 (void)sprintf(vol_dirname, "%s/%s", mountedOn, top_direntp->d_name);
650 length = SIZEOF_XFS_DATTR_T;
652 (vol_dirname, AFS_XFS_DATTR, (char *)&dattrs, &length, ATTR_ROOT))
655 if ((vol_dirp = opendir(vol_dirname)) == NULL) {
656 if (errno == ENOTDIR)
658 Log("Can't open directory %s to read inodes.\n", vol_dirname);
662 pino = top_direntp->d_ino;
664 while (vol_direntp = readdir64(vol_dirp)) {
665 if (vol_direntp->d_name[1] == '\0'
666 || vol_direntp->d_name[1] == '.')
669 info.ili_version = AFS_XFS_ILI_VERSION;
670 info_size = sizeof(i_list_inode_t);
672 ilistinode64(sdirbuf.st_dev, vol_direntp->d_ino, &info,
675 /* Where possible, give more explicit messages. */
679 Log("%s (device id %d) is not on an XFS filesystem.\n",
680 vol_dirname, sdirbuf.st_dev);
685 if (info_size != sizeof(i_list_inode_t)
686 || info.ili_version != AFS_XFS_ILI_VERSION) {
687 Log("Version skew between kernel and salvager.\n");
692 /* Continue, so we collect all the errors in the first pass. */
693 Log("Error listing inode named %s/%s: %s\n", vol_dirname,
694 vol_direntp->d_name, strerror(errno));
699 if (info.ili_attr_version != AFS_XFS_ATTR_VERS) {
700 Log("Unrecognized XFS attribute version %d in %s/%s. Upgrade salvager\n", info.ili_attr_version, vol_dirname, vol_direntp->d_name);
704 if (judgeInode && (*judgeInode) (&info.ili_info, judgeParam, rock) == 0)
709 (vol_dirname, pino, vol_direntp->d_name, &info,
715 /* Add this name to the list of items to rename. */
716 if (n_renames >= n_avail) {
717 n_avail += N_RENAME_STEP;
718 if (n_avail == N_RENAME_STEP)
719 renames = (xfs_Rename_t *)
720 malloc(n_avail * sizeof(xfs_Rename_t));
722 renames = (xfs_Rename_t *)
723 realloc((char *)renames,
724 n_avail * sizeof(xfs_Rename_t));
726 Log("Can't %salloc %lu bytes for rename list.\n",
727 (n_avail == N_RENAME_STEP) ? "m" : "re",
728 n_avail * sizeof(xfs_Rename_t));
732 (void)strcpy(renames[n_renames].name, vol_direntp->d_name);
733 renames[n_renames].uniq = info.ili_info.param[2];
737 if (inodeFile != INVALID_FD) {
739 (inodeFile, &info.ili_info, sizeof(vice_inode_info_t))
740 != sizeof(vice_inode_info_t)) {
741 Log("Error writing inode file for partition %s\n", mountedOn);
747 } /* end while vol_direntp */
750 vol_dirp = (DIR *) 0;
752 Log("Renaming files.\n");
753 if (xfs_RenameFiles(vol_dirname, renames, n_renames) < 0) {
761 free((char *)renames);
762 if (inodeFile != INVALID_FD) {
763 if (OS_SYNC(inodeFile) == -1) {
764 Log("Unable to successfully fsync inode file for %s\n", mountedOn);
765 return errors ? -1 : -2;
768 * Paranoia: check that the file is really the right size
770 if (OS_SIZE(inodeFile) != ninodes * sizeof(struct ViceInodeInfo)) {
771 Log("Wrong size (%d instead of %d) in inode file for %s\n",
772 OS_SIZE(inodeFile), ninodes * sizeof(struct ViceInodeInfo),
774 return errors ? -1 : -2;
779 Log("Errors encontered listing inodes, not salvaging partition.\n");
791 free((char *)renames);
798 ListViceInodes(char *devname, char *mountedOn, FD_t inodeFile,
799 int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
800 char *wpath, void *rock)
802 char dev[50], rdev[51];
804 struct efs_dinode *p;
805 struct ViceInodeInfo info;
806 struct stat root_inode;
807 int ninodes = 0, err = 0;
808 struct efs_dinode *dinodeBuf = NULL;
810 ino_t imax, inum; /* total number of I-nodes in file system */
814 sleep(1); /* simulate operator */
820 if (stat(mountedOn, &root_inode) < 0) {
821 Log("cannot stat: %s\n", mountedOn);
824 #ifdef AFS_SGI_XFS_IOPS_ENV
825 if (!strcmp("xfs", root_inode.st_fstype)) {
826 return xfs_ListViceInodes(devname, mountedOn, inodeFile, judgeInode,
827 judgeParam, forcep, forceR, wpath, rock);
831 Log("%s is not root of a filesystem\n", mountedOn);
836 #else /* AFS_SGI_ENV */
839 #define SPERB (MAXBSIZE / sizeof(short))
840 #define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
843 struct bufarea *b_next; /* must be first */
847 char b_buf[MAXBSIZE]; /* buffer space */
848 short b_lnks[SPERB]; /* link counts */
849 daddr_t b_indir[MAXNINDIR]; /* indirect block */
850 struct fs b_fs; /* super block */
851 struct cg b_cg; /* cylinder group */
855 typedef struct bufarea BUFAREA;
858 #define sblock sblk.b_un.b_fs
859 #endif /* AFS_HPUX_ENV */
861 extern char *afs_rawname();
863 ListViceInodes(char *devname, char *mountedOn, FD_t inodeFile,
864 int (*judgeInode) (), afs_uint32 judgeParam, int *forcep, int forceR,
865 char *wpath, void *rock)
871 #else /* !AFS_AIX_ENV */
876 int i, c, e, bufsize, code, err = 0;
877 char dev[50], rdev[100], err1[512], *ptr1;
878 struct dinode *inodes = NULL, *einodes, *dptr;
881 struct ViceInodeInfo info;
884 partition = mountedOn;
885 sprintf(rdev, "%s/%s", wpath, devname);
886 ptr1 = afs_rawname(rdev);
890 /* Bletch: this is terrible; is there a better way to do this? Does this work? vfsck doesn't even sleep!! */
892 sleep(5); /* Trying a smaller one for aix */
897 pfd = OS_OPEN(rdev, O_RDONLY, 0666);
898 if (pfd == INVALID_FD) {
899 sprintf(err1, "Could not open device %s to get inode list\n", rdev);
904 if (bread(pfd, (char *)&super.fs, SUPERB, sizeof super.fs) == -1) {
907 if (bread(pfd, (char *)&sblock, SBLOCK, SBSIZE) == -1) {
909 if (bread(pfd, super.block, SBLOCK, SBSIZE) == -1) {
910 #endif /* AFS_HPUX_ENV */
912 Log("Unable to read superblock, partition %s\n", partition);
918 * char *FSlabel(), *fslabel=0;
919 * fslabel = FSlabel(&super.fs);
921 if (super.fs.s_bsize == 0)
922 super.fs.s_bsize = 512;
923 if (super.fs.s_bsize != BSIZE) {
924 Log("SuperBlk: Cluster size not %d; run vfsck\n", BSIZE);
927 fmax = super.fs.s_fsize; /* first invalid blk num */
928 imax = ((ino_t) super.fs.s_isize - (SUPERB + 1)) * INOPB;
930 Log("Size check: imax==0!\n");
933 if (GetAuxInodeFile(partition, &status) == 0) {
934 Log("Can't access Aux inode file for partition %s, aborting\n",
938 for (inum = 1; inum <= imax; inum++) {
939 struct dauxinode *auxp;
940 if ((auxp = IsAfsInode(inum)) == NULL) {
941 /* Not an afs inode, keep going */
944 if ((p = ginode(inum)) == NULL)
946 /* deleted/non-existent inode when di_mode == 0 */
949 info.inodeNumber = (int)inum;
950 info.byteCount = p->di_size;
951 info.linkCount = p->di_nlink;
952 info.u.param[0] = auxp->aux_param1;
953 info.u.param[1] = auxp->aux_param2;
954 info.u.param[2] = auxp->aux_param3;
955 info.u.param[3] = auxp->aux_param4;
956 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
958 if (inodeFile != INVALID_FD) {
959 if (OS_WRITE(inodeFile, &info, sizeof(info)) != sizeof(info)) {
960 Log("Error writing inode file for partition %s\n", partition);
968 * run a few consistency checks of the superblock
969 * (Cribbed from vfsck)
972 #if defined(FD_FSMAGIC)
973 if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)
974 && (sblock.fs_magic != FD_FSMAGIC)
975 #if defined(AFS_HPUX101_ENV)
976 && (sblock.fs_magic != FD_FSMAGIC_2)
980 if ((sblock.fs_magic != FS_MAGIC) && (sblock.fs_magic != FS_MAGIC_LFN)) {
982 Log("There's something wrong with the superblock for partition %s; bad magic (%d) run vfsck\n", partition, sblock.fs_magic);
985 if (sblock.fs_ncg < 1) {
986 Log("There's something wrong with the superblock for partition %s; NCG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_ncg);
989 if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG) {
990 Log("There's something wrong with the superblock for partition %s; CPG OUT OF RANGE (%d) run vfsck\n", partition, sblock.fs_cpg);
993 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl
994 || (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl) {
995 Log("There's something wrong with the superblock for partition %s; NCYL LESS THAN NCG*CPG run vfsck\n", partition);
998 if (sblock.fs_sbsize > SBSIZE) {
999 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);
1003 if ((super.fs.fs_magic != FS_MAGIC)
1004 || (super.fs.fs_ncg < 1)
1005 #if defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1006 || (super.fs.fs_cpg < 1)
1008 || (super.fs.fs_cpg < 1 || super.fs.fs_cpg > MAXCPG)
1010 || (super.fs.fs_ncg * super.fs.fs_cpg < super.fs.fs_ncyl
1011 || (super.fs.fs_ncg - 1) * super.fs.fs_cpg >= super.fs.fs_ncyl)
1012 || (super.fs.fs_sbsize > SBSIZE)) {
1013 Log("There's something wrong with the superblock for partition %s; run vfsck\n", partition);
1016 #endif /* AFS_HPUX_ENV */
1019 bufsize = sblock.fs_ipg * sizeof(struct dinode);
1021 bufsize = super.fs.fs_ipg * sizeof(struct dinode);
1022 #endif /* AFS_HPUX_ENV */
1023 inodes = (struct dinode *)malloc(bufsize);
1024 einodes = (struct dinode *)(((char *)inodes) + bufsize);
1025 if (inodes == NULL) {
1026 Log("Unable to allocate enough memory to scan inodes; help!\n");
1029 Log("Scanning inodes on device %s...\n", rdev);
1031 for (c = 0; c < sblock.fs_ncg; c++) {
1032 i = c * sblock.fs_ipg;
1033 e = i + sblock.fs_ipg;
1034 #if defined(AFS_HPUX102_ENV)
1035 if (OS_SEEK(pfd, dbtoo(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1038 if (OS_SEEK(pfd, dbtob(fsbtodb(&sblock, itod(&sblock, i))), L_SET) ==
1042 for (c = 0; c < super.fs.fs_ncg; c++) {
1044 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1046 #if defined(AFS_DARWIN_ENV)
1047 #define offset_t off_t
1048 #define llseek lseek
1051 #endif /* AFS_SUN5_ENV */
1052 i = c * super.fs.fs_ipg;
1053 e = i + super.fs.fs_ipg;
1055 dblk1 = fsbtodb(&super.fs, itod(&super.fs, i));
1056 if (OS_SEEK(pfd, (off_t) ((off_t) dblk1 * DEV_BSIZE), L_SET) == -1) {
1058 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1059 f1 = fsbtodb(&super.fs, itod(&super.fs, i));
1060 off = (offset_t) f1 << DEV_BSHIFT;
1061 if (OS_SEEK(pfd, off, L_SET) == -1) {
1063 if (OS_SEEK(pfd, dbtob(fsbtodb(&super.fs, itod(&super.fs, i))), L_SET)
1065 #endif /* AFS_SUN5_ENV */
1066 #endif /* AFS_OSF_ENV */
1067 #endif /* AFS_HPUX_ENV */
1068 Log("Error reading inodes for partition %s; run vfsck\n",
1074 if (OS_READ(pfd, inodes, bufsize) != bufsize) {
1075 Log("Error reading inodes for partition %s; run vfsck\n",
1082 for (bj = bk = 0; bj < bufsize; bj = bj + 512, bk++) {
1083 if ((code = OS_READ(pfd, dptr, 512)) != 512) {
1084 Log("Error reading inode %d? for partition %s (errno = %d); run vfsck\n", bk + i, partition, errno);
1085 if (OS_SEEK(pfd, 512, L_SET) == -1) {
1086 Log("OS_SEEK failed\n");
1101 for (p = inodes; p < einodes && i < e; i++, p++) {
1103 Log("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1104 i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1105 p->di_size, p->di_nlink);
1107 ("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1108 i, p->di_vicep1, p->di_vicep2, p->di_vicep3, p->di_mode,
1109 p->di_size, p->di_nlink);
1112 #ifdef AFS_3DISPARES
1113 /* Check to see if this inode is a pre-"OSF1 4.0D" inode */
1114 if ((p->di_uid || p->di_gid)
1115 && !(p->di_flags & (IC_XUID | IC_XGID))) {
1116 Log("Found unconverted inode %d: Use 'fs_conv_dux40D convert' on partition %s\n", i, partition);
1120 osi_Panic("Tru64 needs AFS_3DISPARES\n");
1123 #if defined(AFS_SUN5_ENV)
1124 /* if this is a pre-sol2.6 unconverted inode, bail out */
1126 afs_uint32 p1, p2, p3, p4;
1130 q = (quad *) & (p->di_ic.ic_lsize);
1132 p2 = p->di_ic.ic_flags;
1134 p4 = p->di_ic.ic_uid;
1135 p5 = p->di_ic.ic_gid;
1137 if ((p2 || p3) && !p4 && (p5 == -2)) {
1138 Log("Found unconverted inode %d\n", i);
1139 Log("You should run the AFS file conversion utility\n");
1144 if (IS_DVICEMAGIC(p) && (p->di_mode & IFMT) == IFREG) {
1145 afs_uint32 p2 = p->di_vicep2, p3 = DI_VICEP3(p);
1147 info.u.param[0] = p->di_vicep1;
1148 #ifdef AFS_3DISPARES
1149 if (((p2 >> 3) == INODESPECIAL) && (p2 & 0x3)) {
1150 info.u.param[1] = INODESPECIAL;
1151 info.u.param[2] = p3;
1152 info.u.param[3] = p2 & 0x3;
1154 info.u.param[1] = ((p2 >> 27) << 16) + (p3 & 0xffff);
1155 info.u.param[2] = (p2 & 0x3fffff);
1157 (((p2 >> 22) & 0x1f) << 16) + (p3 >> 16);
1160 info.u.param[1] = p->di_vicep2;
1161 info.u.param[2] = DI_VICEP3(p);
1162 info.u.param[3] = p->di_vicep4;
1164 info.inodeNumber = i;
1165 info.byteCount = p->di_size;
1166 info.linkCount = p->di_nlink;
1167 if (judgeInode && (*judgeInode) (&info, judgeParam, rock) == 0)
1169 if (inodeFile != INVALID_FD) {
1170 if (OS_WRITE(inodeFile, &info, sizeof(info)) != sizeof(info)) {
1171 Log("Error writing inode file for partition %s\n",
1184 if (inodeFile != INVALID_FD) {
1185 if (OS_SYNC(inodeFile) == -1) {
1186 Log("Unable to successfully fsync inode file for %s\n", partition);
1192 * Paranoia: check that the file is really the right size
1194 if (OS_SIZE(inodeFile) != ninodes * sizeof(struct ViceInodeInfo)) {
1195 Log("Wrong size (%d instead of %d) in inode file for %s\n",
1196 OS_SIZE(inodeFile), ninodes * sizeof(struct ViceInodeInfo),
1213 #endif /* !AFS_SGI_ENV */
1214 #endif /* !AFS_AIX31_ENV */
1216 #ifdef AFS_DARWIN_ENV
1218 #define dbtob(db) ((unsigned)(db) << DEV_BSHIFT)
1222 bread(FD_t fd, char *buf, daddr_t blk, afs_int32 size)
1225 #ifdef AFS_AIX41_ENV
1226 offset_t off = (offset_t) blk << FSBSHIFT;
1227 if (OS_SEEK(fd, off, 0) < 0) {
1228 Log("Unable to seek to offset %llu for block %u\n", off, blk);
1231 #else /* AFS_AIX41_ENV */
1232 if (OS_SEEK(fd, blk * Bsize, 0) < 0) {
1233 Log("Unable to seek to offset %u for block %u\n", blk * Bsize, blk);
1235 #endif /* AFS_AIX41_ENV */
1237 if (OS_SEEK(fd, (off_t) dbtob(blk), L_SET) < 0) {
1238 Log("Unable to seek to offset %u for block %u\n", dbtob(blk), blk);
1241 if (OS_READ(fd, buf, size) != size) {
1242 Log("Unable to read block %d, partition %s\n", blk, partition);
1248 #endif /* AFS_LINUX20_ENV */
1250 convertVolumeInfo(FdHandle_t *fdhr, FdHandle_t *fdhw, afs_uint32 vid)
1252 struct VolumeDiskData vd;
1255 if (FDH_PREAD(fdhr, &vd, sizeof(struct VolumeDiskData), 0) !=
1256 sizeof(struct VolumeDiskData)) {
1257 Log("1 convertiVolumeInfo: read failed for %lu with code %d\n", vid,
1261 vd.restoredFromId = vd.id; /* remember the RO volume here */
1263 vd.id = vd.parentId;
1267 vd.uniquifier += 5000; /* just in case there are still file copies
1268 from the old RW volume around */
1270 /* For ROs, the copyDate contains the time that the RO volume was actually
1271 * created, and the creationDate just contains the last time the RO was
1272 * copied from the RW data. So, make the new RW creationDate more accurate
1273 * by setting it to copyDate, if copyDate is older. Since, we know the
1274 * volume is at least as old as copyDate. */
1275 if (vd.copyDate < vd.creationDate) {
1276 vd.creationDate = vd.copyDate;
1278 /* If copyDate is newer, just make copyDate and creationDate the same,
1279 * for consistency with other RWs */
1280 vd.copyDate = vd.creationDate;
1283 p = strrchr(vd.name, '.');
1284 if (p && !strcmp(p, ".readonly")) {
1288 if (FDH_PWRITE(fdhw, &vd, sizeof(struct VolumeDiskData), 0) !=
1289 sizeof(struct VolumeDiskData)) {
1290 Log("1 convertiVolumeInfo: write failed for %lu with code %d\n", vid,
1298 afs_int32 inodeType;
1305 UpdateThisVolume(struct ViceInodeInfo *inodeinfo, VolumeId singleVolumeNumber,
1306 struct specino *specinos)
1309 if ((inodeinfo->u.vnode.vnodeNumber == INODESPECIAL) &&
1310 (inodeinfo->u.vnode.volumeId == singleVolumeNumber)) {
1311 specinos[inodeinfo->u.special.type].inodeNumber =
1312 inodeinfo->inodeNumber;
1314 return 0; /* We aren't using a result file, we're caching */
1318 getDevName(char *pbuffer, char *wpath)
1320 char pbuf[128], *ptr;
1321 strcpy(pbuf, pbuffer);
1322 ptr = (char *)strrchr(pbuf, OS_DIRSEPC);
1325 strcpy(wpath, pbuf);
1328 ptr = (char *)strrchr(pbuffer, OS_DIRSEPC);
1330 strcpy(pbuffer, ptr + 1);
1336 #ifdef FSSYNC_BUILD_CLIENT
1338 inode_ConvertROtoRWvolume(char *pname, afs_uint32 volumeId)
1340 char dir_name[512], oldpath[512], newpath[512];
1342 char headername[16];
1344 int fd, err, forcep, j;
1345 ssize_t len, nBytes;
1347 struct DiskPartition64 *partP;
1348 struct ViceInodeInfo info;
1349 struct VolumeDiskHeader h;
1350 IHandle_t *ih, *ih2;
1351 FdHandle_t *fdP, *fdP2;
1354 char tmpDevName[100];
1356 struct specino specinos[VI_LINKTABLE+1];
1357 Inode nearInode = 0;
1358 # ifdef AFS_DEMAND_ATTACH_FS
1360 # endif /* AFS_DEMAND_ATTACH_FS */
1363 memset(&specinos, 0, sizeof(specinos));
1365 /* now do the work */
1367 for (partP = DiskPartitionList; partP && strcmp(partP->name, pname);
1368 partP = partP->next);
1370 Log("1 inode_ConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname);
1375 #ifdef AFS_DEMAND_ATTACH_FS
1376 locktype = VVolLockType(V_VOLUPD, 1);
1377 code = VLockVolumeByIdNB(volumeId, partP, locktype);
1385 if (VReadVolumeDiskHeader(volumeId, partP, &h)) {
1386 Log("1 inode_ConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n",
1387 afs_printable_uint32_lu(volumeId));
1391 FSYNC_VolOp(volumeId, pname, FSYNC_VOL_BREAKCBKS, 0, NULL);
1393 strcpy(tmpDevName, partP->devName);
1394 name = getDevName(tmpDevName, wpath);
1396 if ((err = ListViceInodes(name, VPartitionPath(partP),
1397 NULL, UpdateThisVolume, volumeId,
1398 &forcep, 0, wpath, &specinos)) < 0)
1400 Log("1 inode_ConvertROtoRWvolume: Couldn't get special inodes\n");
1405 #if defined(NEARINODE_HINT)
1406 nearInodeHash(volumeId, nearInode);
1407 nearInode %= partP->f_files;
1410 for (j = VI_VOLINFO; j < VI_LINKTABLE+1; j++) {
1411 if (specinos[j].inodeNumber > 0) {
1412 specinos[j].ninodeNumber =
1413 IH_CREATE(NULL, partP->device, VPartitionPath(partP),
1414 nearInode, h.parent, INODESPECIAL, j, h.parent);
1415 IH_INIT(ih, partP->device, volumeId,
1416 specinos[j].inodeNumber);
1419 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, volumeId);
1424 IH_INIT(ih2, partP->device, h.parent, specinos[j].ninodeNumber);
1425 fdP2 = IH_OPEN(ih2);
1427 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j, h.parent);
1432 if (j == VI_VOLINFO)
1433 convertVolumeInfo(fdP, fdP2, ih2->ih_vid);
1437 len = FDH_PREAD(fdP, buffer, sizeof(buffer), offset);
1442 nBytes = FDH_PWRITE(fdP2, buffer, len, offset);
1443 if (nBytes != len) {
1454 /* Unlink the old special inode; otherwise we will get duplicate
1455 * special inodes if we recreate the RO again */
1456 if (IH_DEC(ih, specinos[j].inodeNumber, volumeId) == -1) {
1458 Log("IH_DEC failed: %x, %s, %u errno %d\n", ih,
1459 PrintInode(stmp, specinos[j].inodeNumber), volumeId, errno);
1468 #ifdef AFS_64BIT_IOPS_ENV
1469 h.volumeInfo_lo = (afs_int32)specinos[VI_VOLINFO].ninodeNumber & 0xffffffff;
1470 h.volumeInfo_hi = (afs_int32)(specinos[VI_VOLINFO].ninodeNumber >> 32) && 0xffffffff;
1471 h.smallVnodeIndex_lo = (afs_int32)specinos[VI_SMALLINDEX].ninodeNumber & 0xffffffff;
1472 h.smallVnodeIndex_hi = (afs_int32)(specinos[VI_SMALLINDEX].ninodeNumber >> 32) & 0xffffffff;
1473 h.largeVnodeIndex_lo = (afs_int32)specinos[VI_LARGEINDEX].ninodeNumber & 0xffffffff;
1474 h.largeVnodeIndex_hi = (afs_int32)(specinos[VI_LARGEINDEX].ninodeNumber >> 32) & 0xffffffff;
1475 if (specinos[VI_LINKTABLE].ninodeNumber) {
1476 h.linkTable_lo = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1477 h.linkTable_hi = (afs_int32)specinos[VI_LINKTABLE].ninodeNumber & 0xffffffff;
1480 h.volumeInfo_lo = specinos[VI_VOLINFO].ninodeNumber;
1481 h.smallVnodeIndex_lo = specinos[VI_SMALLINDEX].ninodeNumber;
1482 h.largeVnodeIndex_lo = specinos[VI_LARGEINDEX].ninodeNumber;
1483 if (specinos[VI_LINKTABLE].ninodeNumber) {
1484 h.linkTable_lo = specinos[VI_LINKTABLE].ninodeNumber;
1488 if (VCreateVolumeDiskHeader(&h, partP)) {
1489 Log("1 inode_ConvertROtoRWvolume: Couldn't write header for RW-volume %lu\n",
1490 afs_printable_uint32_lu(h.id));
1495 if (VDestroyVolumeDiskHeader(partP, volumeId, h.parent)) {
1496 Log("1 inode_ConvertROtoRWvolume: Couldn't unlink header for RO-volume %lu\n",
1497 afs_printable_uint32_lu(volumeId));
1500 FSYNC_VolOp(volumeId, pname, FSYNC_VOL_DONE, 0, NULL);
1501 FSYNC_VolOp(h.id, pname, FSYNC_VOL_ON, 0, NULL);
1504 # ifdef AFS_DEMAND_ATTACH_FS
1506 VUnlockVolumeById(volumeId, partP);
1508 # endif /* AFS_DEMAND_ATTACH_FS */
1511 #endif /* FSSYNC_BUILD_CLIENT */
1512 #endif /* AFS_NAMEI_ENV */