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>
29 #if defined(AFS_LINUX20_ENV)
34 * -1 - Unable to read the inodes.
35 * -2 - Unable to completely write temp file. Produces warning message in log.
38 ListViceInodes(char *devname
, char *mountedOn
, FD_t inodeFile
,
39 afs_uint32 (*judgeInode
) (), VolumeId judgeParam
, int *forcep
, int forceR
,
40 char *wpath
, void *rock
)
42 Log("ListViceInodes not implemented for this platform!\n");
46 #if !defined(AFS_SGI_ENV)
49 #else /* AFS_OSF_ENV */
50 #ifdef AFS_VFSINCL_ENV
53 #include <sys/fs/ufs_fs.h>
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
63 #else /* AFS_VFSINCL_ENV */
65 #include <sys/filsys.h>
69 #endif /* AFS_VFSINCL_ENV */
70 #endif /* AFS_OSF_ENV */
71 #ifdef AFS_VFSINCL_ENV
72 #include <sys/vnode.h>
74 #include <sys/fs/ufs_inode.h>
76 #if !defined(AFS_DARWIN_ENV)
77 #include <ufs/inode.h>
80 #else /* AFS_VFSINCL_ENV */
82 #include <ufs/inode.h>
83 #else /* AFS_OSF_ENV */
84 #include <sys/inode.h>
86 #endif /* AFS_VFSINCL_ENV */
87 #endif /* AFS_SGI_ENV */
88 #include <afs/osi_inode.h>
91 #include <afs/afsint.h>
93 #include <afs/afssyscalls.h>
94 #include "viceinode.h"
95 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
99 #include <rx/rx_queue.h>
105 #include "volinodes.h"
106 #include "partition.h"
108 #include "volume_inline.h"
110 /* Notice: parts of this module have been cribbed from vfsck.c */
113 static char *partition
;
118 #include <jfs/filsys.h>
121 #define FSBSIZE (4096) /* filesystem block size */
122 #define FSBSHIFT (12) /* log2(FSBSIZE) */
123 #define FSBMASK (FSBSIZE - 1) /* FSBSIZE mask */
125 #define MIN_FSIZE DISKMAP_B /* minimum fs size (FSblocks) */
126 #define LAST_RSVD_I 15 /* last reserved inode */
131 * This will hopefully eventually make it into the system include files
133 #define INOPB (FSBSIZE / sizeof (struct dinode))
141 #endif /* AFS_AIX41_ENV */
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
149 * itoo - inode number to offset within disk block
152 #define itoo(x) (int) ((unsigned)(x) % INOPB)
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 */
158 static struct superblock fs
;
159 struct dinode
*ginode();
163 ListViceInodes(char *devname
, char *mountedOn
, FD_t inodeFile
,
164 int (*judgeInode
) (), VolumeId judgeParam
, int *forcep
, int forceR
,
165 char *wpath
, void *rock
)
167 char dev
[50], rdev
[51];
170 struct ViceInodeInfo info
;
171 struct stat root_inode
;
172 int ninodes
= 0, err
= 0;
174 pfd
= INVALID_FD
; /* initialize so we don't close on error output below. */
177 sleep(1); /* simulate operator */
183 partition
= mountedOn
;
184 sprintf(dev
, "/dev/%s", devname
);
185 sprintf(rdev
, "/dev/r%s", devname
);
187 if (stat(mountedOn
, &root_inode
) < 0) {
188 Log("cannot stat: %s\n", mountedOn
);
192 if (root_inode
.st_ino
!= ROOTDIR_I
) {
193 Log("%s is not root of a filesystem\n", mountedOn
);
199 * done with the superblock, now try to read the raw device.
201 if (ReadSuper(&fs
, dev
) < 0)
206 case FM_CLEAN
: /* clean and unmounted */
207 Log("Most peculiar - Super blk in FM_CLEAN state!\n");
209 case FM_MOUNT
: /* mounted cleanly */
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");
219 if (IsBigFilesFileSystem(&fs
, (char *)0)) {
220 Log("%s is a big files filesystem, can't salvage.\n", mountedOn
);
224 if (strncmp(fs
.s_magic
, fsv3magic
, strlen(fsv3magic
)) != 0) {
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
);
232 Log("Super block doesn't have the problem magic (%s vs v3magic %s)\n",
233 fs
.s_magic
, fsv3magic
);
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 */
246 fmax
= fs
.s_fsize
/ (FSBSIZE
/ 512); /* first invalid blk num */
248 pfd
= OS_OPEN(rdev
, O_RDONLY
, 0666);
249 if (pfd
== INVALID_FD
) {
250 Log("Unable to open `%s' inode for reading\n", rdev
);
255 * calculate the maximum number of inodes possible
258 imax
= iagsize
* (fs
.s_fsize
/ ag512
) - 1;
259 #else /* AFS_AIX41_ENV */
261 ((fmax
/ fs
.s_agsize
+
262 ((fmax
% fs
.s_agsize
) >= fs
.s_agsize
/ INOPB
? 1 : 0))
264 #endif /* AFS_AIX41_ENV */
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.
271 opr_Verify(p
= ginode(LAST_RSVD_I
));
273 if (p
->di_vicemagic
== VICEMAGIC
&& p
->di_vicep1
== 0xdeadbeef
274 && p
->di_nlink
== 2) {
276 idec(root_inode
.st_dev
, LAST_RSVD_I
, 0xdeadbeef);
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
)
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
;
292 if (judgeInode
&& (*judgeInode
) (&info
, judgeParam
, rock
) == 0)
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
);
304 if (inodeFile
!= INVALID_FD
) {
305 if (OS_SYNC(inodeFile
) == -1) {
306 Log("Unable to successfully fsync inode file for %s\n", partition
);
312 * Paranoia: check that the file is really the right size
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
),
328 if (pfd
!= INVALID_FD
)
334 /* Read in the superblock for devName */
336 ReadSuper(struct superblock
*fs
, char *devName
)
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
);
346 if (bread(pfd
, fs
, SUPER_B
, sizeof(struct superblock
)) < 0) {
347 Log("Unable to read superblock on %s.\n", devName
);
355 /* IsBigFilesFileSystem returns 1 if it's a big files filesystem, 0 otherwise. */
357 IsBigFilesFileSystem(struct superblock
*sb
)
359 if ((strncmp(sb
->s_magic
, fsv3pmagic
, 4) == 0)
360 && (sb
->s_version
== fsbigfile
)
374 static char buf
[FSBSIZE
];
375 static daddr_t last_blk
= -1;
381 0) ? INODES_B
+ inum
/ INOPB
: ag
* agblocks
+ (inum
-
384 #else /* AFS_AIX41_ENV */
385 ag
= inum
/ fs
.s_agsize
;
388 0) ? INODES_B
+ inum
/ INOPB
: ag
* fs
.s_agsize
+ (inum
-
392 #endif /* AFS_AIX41_ENV */
394 if (last_blk
!= pblk
) {
395 if (bread(pfd
, buf
, pblk
, sizeof(buf
)) < 0) {
402 dp
= (struct dinode
*)buf
;
407 #else /* !AFS_AIX31_ENV */
409 #if defined(AFS_SGI_ENV)
411 /* libefs.h includes <assert.h>, which we don't want */
414 #ifdef AFS_SGI_XFS_IOPS_ENV
415 #include <afs/xfsattrs.h>
416 /* xfs_ListViceInodes
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
430 * 4) Verify uid = RW volume id and gid = XFS_VICEMAGIC.
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.
441 xfs_VerifyInode(char *dir
, uint64_t pino
, char *name
, i_list_inode_t
* info
,
448 int update_chown
= 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
,
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
));
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
);
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
,
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
);
510 /* update the tag? */
511 (void)strcat(tmpName
, ".");
512 (void)strcat(tmpName
, int_to_base64(stmp
, info
->ili_tag
));
513 if (strcmp(name
, tmpName
)) {
515 (void)strcpy(tmpName
, name
);
516 p
= strchr(tmpName
+ 1, '.');
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");
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
,
535 if (update_pino
|| update_tag
) {
536 afs_xfs_attr_t attrs
;
539 length
= SIZEOF_XFS_ATTR_T
;
540 if (attr_get(path
, AFS_XFS_ATTR
, (char *)&attrs
, &length
, ATTR_ROOT
) <
542 Log("Can't get AFS attribute for %s\n", path
);
546 attrs
.at_pino
= pino
;
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
);
566 xfs_RenameFiles(char *dir
, xfs_Rename_t
* renames
, int n_renames
)
569 char opath
[128], nbase
[128], npath
[128];
570 afs_xfs_attr_t attrs
;
571 int length
= SIZEOF_XFS_ATTR_T
;
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);
589 Log("Can't find a new name for %s\n", opath
);
592 if (rename(opath
, npath
) < 0) {
593 Log("Can't rename %s to %s\n", opath
, npath
);
596 Log("Renamed %s to %s\n", opath
, npath
);
603 xfs_ListViceInodes(char *devname
, char *mountedOn
, FD_t inodeFile
,
604 int (*judgeInode
) (), VolumeId judgeParam
, int *forcep
,
605 int forceR
, char *wpath
, void *rock
)
608 int info_size
= sizeof(i_list_inode_t
);
611 dirent64_t
*top_direntp
;
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
;
619 char vol_dirname
[1024];
622 xfs_Rename_t
*renames
= (xfs_Rename_t
*) 0;
624 #define N_RENAME_STEP 64
632 if (stat64(mountedOn
, &sdirbuf
) < 0) {
633 perror("xfs_ListViceInodes: stat64");
637 if ((top_dirp
= opendir(mountedOn
)) == NULL
) {
638 Log("Can't open directory %s to read inodes.\n", mountedOn
);
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
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.
650 (void)sprintf(vol_dirname
, "%s/%s", mountedOn
, top_direntp
->d_name
);
651 length
= SIZEOF_XFS_DATTR_T
;
653 (vol_dirname
, AFS_XFS_DATTR
, (char *)&dattrs
, &length
, ATTR_ROOT
))
656 if ((vol_dirp
= opendir(vol_dirname
)) == NULL
) {
657 if (errno
== ENOTDIR
)
659 Log("Can't open directory %s to read inodes.\n", vol_dirname
);
663 pino
= top_direntp
->d_ino
;
665 while (vol_direntp
= readdir64(vol_dirp
)) {
666 if (vol_direntp
->d_name
[1] == '\0'
667 || vol_direntp
->d_name
[1] == '.')
670 info
.ili_version
= AFS_XFS_ILI_VERSION
;
671 info_size
= sizeof(i_list_inode_t
);
673 ilistinode64(sdirbuf
.st_dev
, vol_direntp
->d_ino
, &info
,
676 /* Where possible, give more explicit messages. */
680 Log("%s (device id %d) is not on an XFS filesystem.\n",
681 vol_dirname
, sdirbuf
.st_dev
);
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");
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
));
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
);
705 if (judgeInode
&& (*judgeInode
) (&info
.ili_info
, judgeParam
, rock
) == 0)
710 (vol_dirname
, pino
, vol_direntp
->d_name
, &info
,
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
));
722 renames
= realloc(renames
,
723 n_avail
* sizeof(xfs_Rename_t
));
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
));
731 (void)strcpy(renames
[n_renames
].name
, vol_direntp
->d_name
);
732 renames
[n_renames
].uniq
= info
.ili_info
.param
[2];
736 if (inodeFile
!= INVALID_FD
) {
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
);
746 } /* end while vol_direntp */
749 vol_dirp
= (DIR *) 0;
751 Log("Renaming files.\n");
752 if (xfs_RenameFiles(vol_dirname
, renames
, n_renames
) < 0) {
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;
767 * Paranoia: check that the file is really the right size
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
),
773 return errors
? -1 : -2;
778 Log("Errors encontered listing inodes, not salvaging partition.\n");
797 ListViceInodes(char *devname
, char *mountedOn
, FD_t inodeFile
,
798 int (*judgeInode
) (), VolumeId judgeParam
, int *forcep
, int forceR
,
799 char *wpath
, void *rock
)
801 char dev
[50], rdev
[51];
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
;
809 ino_t imax
, inum
; /* total number of I-nodes in file system */
813 sleep(1); /* simulate operator */
819 if (stat(mountedOn
, &root_inode
) < 0) {
820 Log("cannot stat: %s\n", mountedOn
);
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
);
830 Log("%s is not root of a filesystem\n", mountedOn
);
835 #else /* AFS_SGI_ENV */
838 #define SPERB (MAXBSIZE / sizeof(short))
839 #define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
842 struct bufarea
*b_next
; /* must be first */
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 */
854 typedef struct bufarea BUFAREA
;
857 #define sblock sblk.b_un.b_fs
858 #endif /* AFS_HPUX_ENV */
860 extern char *afs_rawname();
862 ListViceInodes(char *devname
, char *mountedOn
, FD_t inodeFile
,
863 int (*judgeInode
) (), VolumeId judgeParam
, int *forcep
, int forceR
,
864 char *wpath
, void *rock
)
870 #else /* !AFS_AIX_ENV */
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
;
880 struct ViceInodeInfo info
;
883 partition
= mountedOn
;
884 sprintf(rdev
, "%s/%s", wpath
, devname
);
885 ptr1
= afs_rawname(rdev
);
889 /* Bletch: this is terrible; is there a better way to do this? Does this work? vfsck doesn't even sleep!! */
891 sleep(5); /* Trying a smaller one for aix */
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
);
903 if (bread(pfd
, (char *)&super
.fs
, SUPERB
, sizeof super
.fs
) == -1) {
906 if (bread(pfd
, (char *)&sblock
, SBLOCK
, SBSIZE
) == -1) {
908 if (bread(pfd
, super
.block
, SBLOCK
, SBSIZE
) == -1) {
909 #endif /* AFS_HPUX_ENV */
911 Log("Unable to read superblock, partition %s\n", partition
);
917 * char *FSlabel(), *fslabel=0;
918 * fslabel = FSlabel(&super.fs);
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
);
926 fmax
= super
.fs
.s_fsize
; /* first invalid blk num */
927 imax
= ((ino_t
) super
.fs
.s_isize
- (SUPERB
+ 1)) * INOPB
;
929 Log("Size check: imax==0!\n");
932 if (GetAuxInodeFile(partition
, &status
) == 0) {
933 Log("Can't access Aux inode file for partition %s, aborting\n",
937 for (inum
= 1; inum
<= imax
; inum
++) {
938 struct dauxinode
*auxp
;
939 if ((auxp
= IsAfsInode(inum
)) == NULL
) {
940 /* Not an afs inode, keep going */
943 if ((p
= ginode(inum
)) == NULL
)
945 /* deleted/non-existent inode when di_mode == 0 */
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)
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
);
967 * run a few consistency checks of the superblock
968 * (Cribbed from vfsck)
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
)
979 if ((sblock
.fs_magic
!= FS_MAGIC
) && (sblock
.fs_magic
!= FS_MAGIC_LFN
)) {
981 Log("There's something wrong with the superblock for partition %s; bad magic (%d) run vfsck\n", partition
, sblock
.fs_magic
);
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
);
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
);
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
);
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
);
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)
1007 || (super
.fs
.fs_cpg
< 1 || super
.fs
.fs_cpg
> MAXCPG
)
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
);
1015 #endif /* AFS_HPUX_ENV */
1018 bufsize
= sblock
.fs_ipg
* sizeof(struct dinode
);
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");
1028 Log("Scanning inodes on device %s...\n", rdev
);
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
) ==
1037 if (OS_SEEK(pfd
, dbtob(fsbtodb(&sblock
, itod(&sblock
, i
))), L_SET
) ==
1041 for (c
= 0; c
< super
.fs
.fs_ncg
; c
++) {
1043 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1045 #if defined(AFS_DARWIN_ENV)
1046 #define offset_t off_t
1047 #define llseek lseek
1050 #endif /* AFS_SUN5_ENV */
1051 i
= c
* super
.fs
.fs_ipg
;
1052 e
= i
+ super
.fs
.fs_ipg
;
1054 dblk1
= fsbtodb(&super
.fs
, itod(&super
.fs
, i
));
1055 if (OS_SEEK(pfd
, (off_t
) ((off_t
) dblk1
* DEV_BSIZE
), L_SET
) == -1) {
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) {
1062 if (OS_SEEK(pfd
, dbtob(fsbtodb(&super
.fs
, itod(&super
.fs
, i
))), L_SET
)
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",
1073 if (OS_READ(pfd
, inodes
, bufsize
) != bufsize
) {
1074 Log("Error reading inodes for partition %s; run vfsck\n",
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");
1100 for (p
= inodes
; p
< einodes
&& i
< e
; i
++, p
++) {
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
);
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
);
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
);
1119 osi_Panic("Tru64 needs AFS_3DISPARES\n");
1122 #if defined(AFS_SUN5_ENV)
1123 /* if this is a pre-sol2.6 unconverted inode, bail out */
1125 afs_uint32 p1
, p2
, p3
, p4
;
1129 q
= (quad
*) & (p
->di_ic
.ic_lsize
);
1131 p2
= p
->di_ic
.ic_flags
;
1133 p4
= p
->di_ic
.ic_uid
;
1134 p5
= p
->di_ic
.ic_gid
;
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");
1143 if (IS_DVICEMAGIC(p
) && (p
->di_mode
& IFMT
) == IFREG
) {
1144 afs_uint32 p2
= p
->di_vicep2
, p3
= DI_VICEP3(p
);
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;
1153 info
.u
.param
[1] = ((p2
>> 27) << 16) + (p3
& 0xffff);
1154 info
.u
.param
[2] = (p2
& 0x3fffff);
1156 (((p2
>> 22) & 0x1f) << 16) + (p3
>> 16);
1159 info
.u
.param
[1] = p
->di_vicep2
;
1160 info
.u
.param
[2] = DI_VICEP3(p
);
1161 info
.u
.param
[3] = p
->di_vicep4
;
1163 info
.inodeNumber
= i
;
1164 info
.byteCount
= p
->di_size
;
1165 info
.linkCount
= p
->di_nlink
;
1166 if (judgeInode
&& (*judgeInode
) (&info
, judgeParam
, rock
) == 0)
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",
1183 if (inodeFile
!= INVALID_FD
) {
1184 if (OS_SYNC(inodeFile
) == -1) {
1185 Log("Unable to successfully fsync inode file for %s\n", partition
);
1191 * Paranoia: check that the file is really the right size
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
),
1212 #endif /* !AFS_SGI_ENV */
1213 #endif /* !AFS_AIX31_ENV */
1215 #ifdef AFS_DARWIN_ENV
1217 #define dbtob(db) ((unsigned)(db) << DEV_BSHIFT)
1221 bread(FD_t fd
, char *buf
, daddr_t blk
, afs_int32 size
)
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
);
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
);
1234 #endif /* AFS_AIX41_ENV */
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
);
1240 if (OS_READ(fd
, buf
, size
) != size
) {
1241 Log("Unable to read block %d, partition %s\n", blk
, partition
);
1247 #endif /* AFS_LINUX20_ENV */
1249 convertVolumeInfo(FdHandle_t
*fdhr
, FdHandle_t
*fdhw
, VolumeId vid
)
1251 struct VolumeDiskData vd
;
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
,
1260 vd
.restoredFromId
= vd
.id
; /* remember the RO volume here */
1262 vd
.id
= vd
.parentId
;
1266 vd
.uniquifier
+= 5000; /* just in case there are still file copies
1267 from the old RW volume around */
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
;
1277 /* If copyDate is newer, just make copyDate and creationDate the same,
1278 * for consistency with other RWs */
1279 vd
.copyDate
= vd
.creationDate
;
1282 p
= strrchr(vd
.name
, '.');
1283 if (p
&& !strcmp(p
, ".readonly")) {
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
,
1297 afs_int32 inodeType
;
1304 UpdateThisVolume(struct ViceInodeInfo
*inodeinfo
, VolumeId singleVolumeNumber
,
1305 struct specino
*specinos
)
1308 if ((inodeinfo
->u
.vnode
.vnodeNumber
== INODESPECIAL
) &&
1309 (inodeinfo
->u
.vnode
.volumeId
== singleVolumeNumber
)) {
1310 specinos
[inodeinfo
->u
.special
.type
].inodeNumber
=
1311 inodeinfo
->inodeNumber
;
1313 return 0; /* We aren't using a result file, we're caching */
1317 getDevName(char *pbuffer
, char *wpath
)
1319 char pbuf
[128], *ptr
;
1320 strcpy(pbuf
, pbuffer
);
1321 ptr
= (char *)strrchr(pbuf
, OS_DIRSEPC
);
1324 strcpy(wpath
, pbuf
);
1327 ptr
= (char *)strrchr(pbuffer
, OS_DIRSEPC
);
1329 strcpy(pbuffer
, ptr
+ 1);
1335 #ifdef FSSYNC_BUILD_CLIENT
1337 inode_ConvertROtoRWvolume(char *pname
, VolumeId volumeId
)
1339 char dir_name
[512], oldpath
[512], newpath
[512];
1341 char headername
[16];
1343 int fd
, err
, forcep
, j
;
1344 ssize_t len
, nBytes
;
1346 struct DiskPartition64
*partP
;
1347 struct ViceInodeInfo info
;
1348 struct VolumeDiskHeader h
;
1349 IHandle_t
*ih
, *ih2
;
1350 FdHandle_t
*fdP
, *fdP2
;
1353 char tmpDevName
[100];
1355 struct specino specinos
[VI_LINKTABLE
+1];
1356 Inode nearInode
= 0;
1357 # ifdef AFS_DEMAND_ATTACH_FS
1359 # endif /* AFS_DEMAND_ATTACH_FS */
1362 memset(&specinos
, 0, sizeof(specinos
));
1364 /* now do the work */
1366 for (partP
= DiskPartitionList
; partP
&& strcmp(partP
->name
, pname
);
1367 partP
= partP
->next
);
1369 Log("1 inode_ConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname
);
1374 #ifdef AFS_DEMAND_ATTACH_FS
1375 locktype
= VVolLockType(V_VOLUPD
, 1);
1376 code
= VLockVolumeByIdNB(volumeId
, partP
, locktype
);
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
));
1390 FSYNC_VolOp(volumeId
, pname
, FSYNC_VOL_BREAKCBKS
, 0, NULL
);
1392 strcpy(tmpDevName
, partP
->devName
);
1393 name
= getDevName(tmpDevName
, wpath
);
1395 if ((err
= ListViceInodes(name
, VPartitionPath(partP
),
1396 NULL
, UpdateThisVolume
, volumeId
,
1397 &forcep
, 0, wpath
, &specinos
)) < 0)
1399 Log("1 inode_ConvertROtoRWvolume: Couldn't get special inodes\n");
1404 #if defined(NEARINODE_HINT)
1405 nearInodeHash(volumeId
, nearInode
);
1406 nearInode
%= partP
->f_files
;
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
);
1418 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j
, volumeId
);
1423 IH_INIT(ih2
, partP
->device
, h
.parent
, specinos
[j
].ninodeNumber
);
1424 fdP2
= IH_OPEN(ih2
);
1426 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j
, h
.parent
);
1431 if (j
== VI_VOLINFO
)
1432 convertVolumeInfo(fdP
, fdP2
, ih2
->ih_vid
);
1436 len
= FDH_PREAD(fdP
, buffer
, sizeof(buffer
), offset
);
1441 nBytes
= FDH_PWRITE(fdP2
, buffer
, len
, offset
);
1442 if (nBytes
!= len
) {
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) {
1457 Log("IH_DEC failed: %x, %s, %u errno %d\n", ih
,
1458 PrintInode(stmp
, specinos
[j
].inodeNumber
), volumeId
, errno
);
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;
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
;
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
));
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
));
1499 FSYNC_VolOp(volumeId
, pname
, FSYNC_VOL_DONE
, 0, NULL
);
1500 FSYNC_VolOp(h
.id
, pname
, FSYNC_VOL_ON
, 0, NULL
);
1503 # ifdef AFS_DEMAND_ATTACH_FS
1505 VUnlockVolumeById(volumeId
, partP
);
1507 # endif /* AFS_DEMAND_ATTACH_FS */
1510 #endif /* FSSYNC_BUILD_CLIENT */
1511 #endif /* AFS_NAMEI_ENV */