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>
27 #if defined(AFS_LINUX20_ENV) || defined(AFS_SUN4_ENV)
32 * -1 - Unable to read the inodes.
33 * -2 - Unable to completely write temp file. Produces warning message in log.
36 ListViceInodes(char *devname
, char *mountedOn
, FILE *inodeFile
,
37 afs_uint32 (*judgeInode
) (), afs_uint32 judgeParam
, int *forcep
, int forceR
,
38 char *wpath
, void *rock
)
40 Log("ListViceInodes not implemented for this platform!\n");
45 #include <sys/param.h>
46 #if defined(AFS_SGI_ENV)
50 #else /* AFS_OSF_ENV */
51 #ifdef AFS_VFSINCL_ENV
54 #include <sys/fs/ufs_fs.h>
56 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
57 #include <ufs/ufs/dinode.h>
58 #include <ufs/ffs/fs.h>
59 #define itod ino_to_fsba
64 #else /* AFS_VFSINCL_ENV */
66 #include <sys/filsys.h>
70 #endif /* AFS_VFSINCL_ENV */
71 #endif /* AFS_OSF_ENV */
73 #ifdef AFS_VFSINCL_ENV
74 #include <sys/vnode.h>
76 #include <sys/fs/ufs_inode.h>
78 #if !defined(AFS_DARWIN_ENV)
79 #include <ufs/inode.h>
82 #else /* AFS_VFSINCL_ENV */
84 #include <ufs/inode.h>
85 #else /* AFS_OSF_ENV */
86 #include <sys/inode.h>
88 #endif /* AFS_VFSINCL_ENV */
89 #endif /* AFS_SGI_ENV */
90 #include <afs/osi_inode.h>
94 #include <afs/afsint.h>
96 #include <afs/afssyscalls.h>
97 #include "viceinode.h"
99 #if defined (AFS_AIX_ENV) || defined (AFS_HPUX_ENV)
102 #include <afs/afs_assert.h>
103 #if defined(AFS_HPUX101_ENV)
110 #include "volinodes.h"
111 #include "partition.h"
113 #include "volume_inline.h"
115 /*@+fcnmacros +macrofcndecl@*/
118 extern off64_t
afs_lseek(int FD
, off64_t O
, int F
);
119 #endif /*S_SPLINT_S */
120 #define afs_lseek(FD, O, F) lseek64(FD, (off64_t) (O), F)
121 #define afs_stat stat64
122 #define afs_fstat fstat64
123 #define afs_open open64
124 #define afs_fopen fopen64
125 #else /* !O_LARGEFILE */
127 extern off_t
afs_lseek(int FD
, off_t O
, int F
);
128 #endif /*S_SPLINT_S */
129 #define afs_lseek(FD, O, F) lseek(FD, (off_t) (O), F)
130 #define afs_stat stat
131 #define afs_fstat fstat
132 #define afs_open open
133 #define afs_fopen fopen
134 #endif /* !O_LARGEFILE */
135 /*@=fcnmacros =macrofcndecl@*/
137 /* Notice: parts of this module have been cribbed from vfsck.c */
140 static char *partition
;
145 #include <jfs/filsys.h>
148 #define FSBSIZE (4096) /* filesystem block size */
149 #define FSBSHIFT (12) /* log2(FSBSIZE) */
150 #define FSBMASK (FSBSIZE - 1) /* FSBSIZE mask */
152 #define MIN_FSIZE DISKMAP_B /* minimum fs size (FSblocks) */
153 #define LAST_RSVD_I 15 /* last reserved inode */
158 * This will hopefully eventually make it into the system include files
160 #define INOPB (FSBSIZE / sizeof (struct dinode))
168 #endif /* AFS_AIX41_ENV */
171 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
172 XX This was lifted from some `com/cmd/fs/fshlpr_aix3/Fs.h', which indicated X
173 XX a longing to see it make it into a readily accessible include file. XXXXXX
174 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
176 * itoo - inode number to offset within disk block
179 #define itoo(x) (int) ((unsigned)(x) % INOPB)
181 int Bsize
= FSBSIZE
; /* block size for this system */
182 daddr_t fmax
; /* total number of blocks n file system */
183 ino_t imax
, inum
; /* total number of I-nodes in file system */
185 static struct superblock fs
;
186 struct dinode
*ginode();
190 ListViceInodes(char *devname
, char *mountedOn
, FILE *inodeFile
,
191 int (*judgeInode
) (), afs_uint32 judgeParam
, int *forcep
, int forceR
,
192 char *wpath
, void *rock
)
194 char dev
[50], rdev
[51];
197 struct ViceInodeInfo info
;
198 struct stat root_inode
;
199 int ninodes
= 0, err
= 0;
201 pfd
= -1; /* initialize so we don't close on error output below. */
204 sleep(1); /* simulate operator */
210 partition
= mountedOn
;
211 sprintf(dev
, "/dev/%s", devname
);
212 sprintf(rdev
, "/dev/r%s", devname
);
214 if (stat(mountedOn
, &root_inode
) < 0) {
215 Log("cannot stat: %s\n", mountedOn
);
219 if (root_inode
.st_ino
!= ROOTDIR_I
) {
220 Log("%s is not root of a filesystem\n", mountedOn
);
226 * done with the superblock, now try to read the raw device.
228 if (ReadSuper(&fs
, dev
) < 0)
233 case FM_CLEAN
: /* clean and unmounted */
234 Log("Most peculiar - Super blk in FM_CLEAN state!\n");
236 case FM_MOUNT
: /* mounted cleanly */
239 case FM_MDIRTY
: /* dirty when mounted or commit fail */
240 case FM_LOGREDO
: /* log redo attempted but failed */
241 Log("File system %s is in a bad state.\n", rdev
);
242 Log("Call your IBM representative.\n");
246 if (IsBigFilesFileSystem(&fs
, (char *)0)) {
247 Log("%s is a big files filesystem, can't salvage.\n", mountedOn
);
251 if (strncmp(fs
.s_magic
, fsv3magic
, strlen(fsv3magic
)) != 0) {
253 if ((strncmp(fs
.s_magic
, fsv3pmagic
, strlen(fsv3pmagic
)) != 0)
254 || (fs
.s_version
!= fsv3pvers
)) {
255 Log("Super block doesn't have the problem magic (%s vs v3magic %s v3pmagic %s)\n", fs
.s_magic
, fsv3magic
, fsv3pmagic
);
259 Log("Super block doesn't have the problem magic (%s vs v3magic %s)\n",
260 fs
.s_magic
, fsv3magic
);
267 fragsize
= (fs
.s_fragsize
) ? fs
.s_fragsize
: FSBSIZE
;
268 iagsize
= (fs
.s_iagsize
) ? fs
.s_iagsize
: fs
.s_agsize
;
269 ag512
= fragsize
* fs
.s_agsize
/ 512;
270 agblocks
= fragsize
* fs
.s_agsize
>> BSHIFT
;
271 #endif /* AFS_AIX41_ENV */
273 fmax
= fs
.s_fsize
/ (FSBSIZE
/ 512); /* first invalid blk num */
275 pfd
= afs_open(rdev
, O_RDONLY
);
277 Log("Unable to open `%s' inode for reading\n", rdev
);
282 * calculate the maximum number of inodes possible
285 imax
= iagsize
* (fs
.s_fsize
/ ag512
) - 1;
286 #else /* AFS_AIX41_ENV */
288 ((fmax
/ fs
.s_agsize
+
289 ((fmax
% fs
.s_agsize
) >= fs
.s_agsize
/ INOPB
? 1 : 0))
291 #endif /* AFS_AIX41_ENV */
294 * check for "FORCESALVAGE" equivalent:
295 * LAST_RSVD_I is a vice inode, with dead beef, and
296 * di_nlink == 2 to indicate the FORCE.
298 osi_Assert(p
= ginode(LAST_RSVD_I
));
300 if (p
->di_vicemagic
== VICEMAGIC
&& p
->di_vicep1
== 0xdeadbeef
301 && p
->di_nlink
== 2) {
303 idec(root_inode
.st_dev
, LAST_RSVD_I
, 0xdeadbeef);
306 for (inum
= LAST_RSVD_I
+ 1; inum
<= imax
; ++inum
) {
307 if ((p
= ginode(inum
)) == NULL
|| p
->di_vicemagic
!= VICEMAGIC
308 || (p
->di_mode
& IFMT
) != IFREG
)
311 info
.inodeNumber
= inum
;
312 info
.byteCount
= p
->di_size
;
313 info
.linkCount
= p
->di_nlink
;
314 info
.u
.param
[0] = p
->di_vicep1
;
315 info
.u
.param
[1] = p
->di_vicep2
;
316 info
.u
.param
[2] = p
->di_vicep3
;
317 info
.u
.param
[3] = p
->di_vicep4
;
319 if (judgeInode
&& (*judgeInode
) (&info
, judgeParam
, rock
) == 0)
323 if (fwrite(&info
, sizeof info
, 1, inodeFile
) != 1) {
324 Log("Error writing inode file for partition %s\n", partition
);
332 if (fflush(inodeFile
) == EOF
) {
333 Log("Unable to successfully flush inode file for %s\n", partition
);
337 if (fsync(fileno(inodeFile
)) == -1) {
338 Log("Unable to successfully fsync inode file for %s\n", partition
);
344 * Paranoia: check that the file is really the right size
346 if (fstat(fileno(inodeFile
), &status
) == -1) {
347 Log("Unable to successfully stat inode file for %s\n", partition
);
351 if (status
.st_size
!= ninodes
* sizeof(struct ViceInodeInfo
)) {
352 Log("Wrong size (%d instead of %d) in inode file for %s\n",
353 status
.st_size
, ninodes
* sizeof(struct ViceInodeInfo
),
371 /* Read in the superblock for devName */
373 ReadSuper(struct superblock
*fs
, char *devName
)
377 pfd
= afs_open(devName
, O_RDONLY
);
379 Log("Unable to open inode on %s for reading superblock.\n", devName
);
383 if (bread(pfd
, fs
, SUPER_B
, sizeof(struct superblock
)) < 0) {
384 Log("Unable to read superblock on %s.\n", devName
);
392 /* IsBigFilesFileSystem returns 1 if it's a big files filesystem, 0 otherwise. */
394 IsBigFilesFileSystem(struct superblock
*sb
)
396 if ((strncmp(sb
->s_magic
, fsv3pmagic
, 4) == 0)
397 && (sb
->s_version
== fsbigfile
)
411 static char buf
[FSBSIZE
];
412 static daddr_t last_blk
= -1;
418 0) ? INODES_B
+ inum
/ INOPB
: ag
* agblocks
+ (inum
-
421 #else /* AFS_AIX41_ENV */
422 ag
= inum
/ fs
.s_agsize
;
425 0) ? INODES_B
+ inum
/ INOPB
: ag
* fs
.s_agsize
+ (inum
-
429 #endif /* AFS_AIX41_ENV */
431 if (last_blk
!= pblk
) {
432 if (bread(pfd
, buf
, pblk
, sizeof(buf
)) < 0) {
439 dp
= (struct dinode
*)buf
;
444 #else /* !AFS_AIX31_ENV */
446 #if defined(AFS_SGI_ENV)
448 /* libefs.h includes <assert.h>, which we don't want */
451 #ifdef AFS_SGI_XFS_IOPS_ENV
453 #include <afs/xfsattrs.h>
454 /* xfs_ListViceInodes
456 * xfs_ListViceInodes verifies and correct the XFS namespace as it collects
457 * the inode information. The name is required for the idec operation to work.
458 * Steps 2 and 3 below are for the AFS_XFS_NAME_VERS == 1. If the name space
459 * changes, the algorithm will need to change.
460 * 1) If the parent inode number does not match the directory's inod number,
461 * change it in the attribute.
462 * 2) If the unqifier in the attribute does not match the name, rename the
463 * file. This is done by doing an exclusive open, incrementing the tag
464 * number until a file can be created. If the tag changes, then the
465 * attribute will need updating.
466 * 3) If the tag in the attribute does not match the name, change the
468 * 4) Verify uid = RW volume id and gid = XFS_VICEMAGIC.
474 * Does the verifications listed above.
475 * We can't change the names until the readdir is complete, so we set the
476 * rename flag if the file needs renaming.
479 xfs_VerifyInode(char *dir
, uint64_t pino
, char *name
, i_list_inode_t
* info
,
486 int update_chown
= 0;
493 (void)sprintf(path
, "%s/%s", dir
, name
);
494 /* Verify uid and gid fields */
495 if (info
->ili_magic
!= XFS_VICEMAGIC
) {
496 Log("%s magic for %s/%s (inode %s) from %d to %d\n",
497 Testing
? "Would have changed" : "Changing", dir
, name
,
498 PrintInode(stmp
, info
->ili_info
.inodeNumber
), info
->ili_magic
,
504 vno
= info
->ili_info
.param
[0];
505 if (info
->ili_vno
!= AFS_XFS_VNO_CLIP(vno
)) {
506 Log("%s volume id for %s/%s (inode %s) from %d to %d\n",
507 Testing
? "Would have changed" : "Changing", dir
, name
,
508 PrintInode(stmp
, info
->ili_info
.inodeNumber
), info
->ili_vno
,
509 AFS_XFS_VNO_CLIP(vno
));
515 if (chown(path
, AFS_XFS_VNO_CLIP(vno
), XFS_VICEMAGIC
) < 0) {
516 Log("Can't chown %s to uid=%d, gid=0x%x\n", path
,
517 AFS_XFS_VNO_CLIP(vno
), XFS_VICEMAGIC
);
522 /* Check Parent inode number. */
523 if (info
->ili_pino
!= pino
) {
524 afs_ino_str_t sino
, sipino
, spino
;
525 (void)PrintInode(sino
, info
->ili_info
.inodeNumber
);
526 (void)PrintInode(sipino
, info
->ili_pino
);
527 (void)PrintInode(spino
, pino
);
528 Log("%s parent ino for %s (inode %s) from %s to %s.\n",
529 Testing
? "Would have changed" : "Changing", path
, sino
, sipino
,
535 /* Verify the file name. */
536 (void)strcpy(tmpName
, ".");
537 (void)strcat(tmpName
, int_to_base64(stmp
, info
->ili_info
.param
[2]));
538 if (strncmp(name
, tmpName
, strlen(tmpName
))) {
539 Log("%s name %s (inode %s) in directory %s, unique=%d, tag=%d\n",
540 Testing
? "Would have returned bad" : "Bad", name
,
541 PrintInode(stmp
, info
->ili_info
.inodeNumber
), dir
,
542 info
->ili_info
.param
[2], info
->ili_tag
);
548 /* update the tag? */
549 (void)strcat(tmpName
, ".");
550 (void)strcat(tmpName
, int_to_base64(stmp
, info
->ili_tag
));
551 if (strcmp(name
, tmpName
)) {
553 (void)strcpy(tmpName
, name
);
554 p
= strchr(tmpName
+ 1, '.');
556 Log("No tag found on name %s (inode %s)in directory, %s.\n",
557 name
, PrintInode(stmp
, info
->ili_info
.inodeNumber
), dir
,
558 Testing
? "would have renamed" : "will rename");
562 tag
= base64_to_int(p
+ 1);
563 Log("%s the tag for %s (inode %s) from %d to %d.\n",
564 Testing
? "Would have changed" : "Will change", path
,
565 PrintInode(stmp
, info
->ili_info
.inodeNumber
), dir
, tag
,
573 if (update_pino
|| update_tag
) {
574 afs_xfs_attr_t attrs
;
577 length
= SIZEOF_XFS_ATTR_T
;
578 if (attr_get(path
, AFS_XFS_ATTR
, (char *)&attrs
, &length
, ATTR_ROOT
) <
580 Log("Can't get AFS attribute for %s\n", path
);
584 attrs
.at_pino
= pino
;
588 (path
, AFS_XFS_ATTR
, (char *)&attrs
, length
,
589 ATTR_ROOT
| ATTR_REPLACE
) < 0) {
590 Log("Can't set AFS attribute into %s\n", path
);
604 xfs_RenameFiles(char *dir
, xfs_Rename_t
* renames
, int n_renames
)
607 char opath
[128], nbase
[128], npath
[128];
608 afs_xfs_attr_t attrs
;
609 int length
= SIZEOF_XFS_ATTR_T
;
614 for (i
= 0; i
< n_renames
; i
++) {
615 (void)sprintf(opath
, "%s/%s", dir
, renames
[i
].name
);
616 (void)sprintf(nbase
, "%s/.%s", dir
,
617 int_to_base64(stmp
, renames
[i
].uniq
));
618 for (tag
= 2, j
= 0; j
< 64; tag
++, j
++) {
619 (void)sprintf(npath
, "%s.%s", nbase
, int_to_base64(stmp
, tag
));
620 fd
= afs_open(npath
, O_CREAT
| O_EXCL
| O_RDWR
, 0);
627 Log("Can't find a new name for %s\n", opath
);
630 if (rename(opath
, npath
) < 0) {
631 Log("Can't rename %s to %s\n", opath
, npath
);
634 Log("Renamed %s to %s\n", opath
, npath
);
641 xfs_ListViceInodes(char *devname
, char *mountedOn
, FILE *inodeFile
,
642 int (*judgeInode
) (), afs_uint32 judgeParam
, int *forcep
,
643 int forceR
, char *wpath
, void *rock
)
646 int info_size
= sizeof(i_list_inode_t
);
649 dirent64_t
*top_direntp
;
651 dirent64_t
*vol_direntp
;
652 struct stat64 sdirbuf
;
653 struct stat64 sfilebuf
;
654 afs_xfs_attr_t attrs
;
655 afs_xfs_dattr_t dattrs
;
657 char vol_dirname
[1024];
660 xfs_Rename_t
*renames
= (xfs_Rename_t
*) 0;
662 #define N_RENAME_STEP 64
671 if (stat64(mountedOn
, &sdirbuf
) < 0) {
672 perror("xfs_ListViceInodes: stat64");
676 if ((top_dirp
= opendir(mountedOn
)) == NULL
) {
677 Log("Can't open directory %s to read inodes.\n", mountedOn
);
681 while (top_direntp
= readdir64(top_dirp
)) {
682 /* Only descend directories with the AFSDIR attribute set.
683 * Could also verify the contents of the atribute, but currently
685 * Performance could be improved for single volume salvages by
686 * only going through the directory containing the volume's inodes.
687 * But I'm being complete as a first pass.
689 (void)sprintf(vol_dirname
, "%s/%s", mountedOn
, top_direntp
->d_name
);
690 length
= SIZEOF_XFS_DATTR_T
;
692 (vol_dirname
, AFS_XFS_DATTR
, (char *)&dattrs
, &length
, ATTR_ROOT
))
695 if ((vol_dirp
= opendir(vol_dirname
)) == NULL
) {
696 if (errno
== ENOTDIR
)
698 Log("Can't open directory %s to read inodes.\n", vol_dirname
);
702 pino
= top_direntp
->d_ino
;
704 while (vol_direntp
= readdir64(vol_dirp
)) {
705 if (vol_direntp
->d_name
[1] == '\0'
706 || vol_direntp
->d_name
[1] == '.')
709 info
.ili_version
= AFS_XFS_ILI_VERSION
;
710 info_size
= sizeof(i_list_inode_t
);
712 ilistinode64(sdirbuf
.st_dev
, vol_direntp
->d_ino
, &info
,
715 /* Where possible, give more explicit messages. */
719 Log("%s (device id %d) is not on an XFS filesystem.\n",
720 vol_dirname
, sdirbuf
.st_dev
);
725 if (info_size
!= sizeof(i_list_inode_t
)
726 || info
.ili_version
!= AFS_XFS_ILI_VERSION
) {
727 Log("Version skew between kernel and salvager.\n");
732 /* Continue, so we collect all the errors in the first pass. */
733 Log("Error listing inode named %s/%s: %s\n", vol_dirname
,
734 vol_direntp
->d_name
, strerror(errno
));
739 if (info
.ili_attr_version
!= AFS_XFS_ATTR_VERS
) {
740 Log("Unrecognized XFS attribute version %d in %s/%s. Upgrade salvager\n", info
.ili_attr_version
, vol_dirname
, vol_direntp
->d_name
);
744 if (judgeInode
&& (*judgeInode
) (&info
.ili_info
, judgeParam
, rock
) == 0)
749 (vol_dirname
, pino
, vol_direntp
->d_name
, &info
,
755 /* Add this name to the list of items to rename. */
756 if (n_renames
>= n_avail
) {
757 n_avail
+= N_RENAME_STEP
;
758 if (n_avail
== N_RENAME_STEP
)
759 renames
= (xfs_Rename_t
*)
760 malloc(n_avail
* sizeof(xfs_Rename_t
));
762 renames
= (xfs_Rename_t
*)
763 realloc((char *)renames
,
764 n_avail
* sizeof(xfs_Rename_t
));
766 Log("Can't %salloc %lu bytes for rename list.\n",
767 (n_avail
== N_RENAME_STEP
) ? "m" : "re",
768 n_avail
* sizeof(xfs_Rename_t
));
772 (void)strcpy(renames
[n_renames
].name
, vol_direntp
->d_name
);
773 renames
[n_renames
].uniq
= info
.ili_info
.param
[2];
779 (&info
.ili_info
, sizeof(vice_inode_info_t
), 1, inodeFile
)
781 Log("Error writing inode file for partition %s\n", mountedOn
);
787 } /* end while vol_direntp */
790 vol_dirp
= (DIR *) 0;
792 Log("Renaming files.\n");
793 if (xfs_RenameFiles(vol_dirname
, renames
, n_renames
) < 0) {
801 free((char *)renames
);
803 if (fflush(inodeFile
) == EOF
) {
804 ("Unable to successfully flush inode file for %s\n", mountedOn
);
805 return errors
? -1 : -2;
807 if (fsync(fileno(inodeFile
)) == -1) {
808 Log("Unable to successfully fsync inode file for %s\n", mountedOn
);
809 return errors
? -1 : -2;
812 * Paranoia: check that the file is really the right size
814 if (fstat(fileno(inodeFile
), &status
) == -1) {
815 Log("Unable to successfully stat inode file for %s\n", partition
);
816 return errors
? -1 : -2;
818 if (status
.st_size
!= ninodes
* sizeof(struct ViceInodeInfo
)) {
819 Log("Wrong size (%d instead of %d) in inode file for %s\n",
820 status
.st_size
, ninodes
* sizeof(struct ViceInodeInfo
),
822 return errors
? -1 : -2;
827 Log("Errors encontered listing inodes, not salvaging partition.\n");
839 free((char *)renames
);
846 ListViceInodes(char *devname
, char *mountedOn
, FILE *inodeFile
,
847 int (*judgeInode
) (), afs_uint32 judgeParam
, int *forcep
, int forceR
,
848 char *wpath
, void *rock
)
850 char dev
[50], rdev
[51];
852 struct efs_dinode
*p
;
853 struct ViceInodeInfo info
;
854 struct stat root_inode
;
855 int ninodes
= 0, err
= 0;
856 struct efs_dinode
*dinodeBuf
= NULL
;
858 ino_t imax
, inum
; /* total number of I-nodes in file system */
862 sleep(1); /* simulate operator */
868 if (stat(mountedOn
, &root_inode
) < 0) {
869 Log("cannot stat: %s\n", mountedOn
);
872 #ifdef AFS_SGI_XFS_IOPS_ENV
873 if (!strcmp("xfs", root_inode
.st_fstype
)) {
874 return xfs_ListViceInodes(devname
, mountedOn
, inodeFile
, judgeInode
,
875 judgeParam
, forcep
, forceR
, wpath
, rock
);
879 Log("%s is not root of a filesystem\n", mountedOn
);
884 #else /* AFS_SGI_ENV */
887 #define SPERB (MAXBSIZE / sizeof(short))
888 #define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
891 struct bufarea
*b_next
; /* must be first */
895 char b_buf
[MAXBSIZE
]; /* buffer space */
896 short b_lnks
[SPERB
]; /* link counts */
897 daddr_t b_indir
[MAXNINDIR
]; /* indirect block */
898 struct fs b_fs
; /* super block */
899 struct cg b_cg
; /* cylinder group */
903 typedef struct bufarea BUFAREA
;
906 #define sblock sblk.b_un.b_fs
907 #endif /* AFS_HPUX_ENV */
909 extern char *afs_rawname();
911 ListViceInodes(char *devname
, char *mountedOn
, FILE *inodeFile
,
912 int (*judgeInode
) (), afs_uint32 judgeParam
, int *forcep
, int forceR
,
913 char *wpath
, void *rock
)
919 #else /* !AFS_AIX_ENV */
924 int i
, c
, e
, bufsize
, code
, err
= 0;
925 char dev
[50], rdev
[100], err1
[512], *ptr1
;
926 struct dinode
*inodes
= NULL
, *einodes
, *dptr
;
930 struct ViceInodeInfo info
;
933 partition
= mountedOn
;
934 sprintf(rdev
, "%s/%s", wpath
, devname
);
935 ptr1
= afs_rawname(rdev
);
939 /* Bletch: this is terrible; is there a better way to do this? Does this work? vfsck doesn't even sleep!! */
941 sleep(5); /* Trying a smaller one for aix */
946 pfd
= afs_open(rdev
, O_RDONLY
);
948 sprintf(err1
, "Could not open device %s to get inode list\n", rdev
);
953 if (bread(pfd
, (char *)&super
.fs
, SUPERB
, sizeof super
.fs
) == -1) {
956 if (bread(pfd
, (char *)&sblock
, SBLOCK
, SBSIZE
) == -1) {
958 if (bread(pfd
, super
.block
, SBLOCK
, SBSIZE
) == -1) {
959 #endif /* AFS_HPUX_ENV */
961 Log("Unable to read superblock, partition %s\n", partition
);
967 * char *FSlabel(), *fslabel=0;
968 * fslabel = FSlabel(&super.fs);
970 if (super
.fs
.s_bsize
== 0)
971 super
.fs
.s_bsize
= 512;
972 if (super
.fs
.s_bsize
!= BSIZE
) {
973 Log("SuperBlk: Cluster size not %d; run vfsck\n", BSIZE
);
976 fmax
= super
.fs
.s_fsize
; /* first invalid blk num */
977 imax
= ((ino_t
) super
.fs
.s_isize
- (SUPERB
+ 1)) * INOPB
;
979 Log("Size check: imax==0!\n");
982 if (GetAuxInodeFile(partition
, &status
) == 0) {
983 Log("Can't access Aux inode file for partition %s, aborting\n",
987 for (inum
= 1; inum
<= imax
; inum
++) {
988 struct dauxinode
*auxp
;
989 if ((auxp
= IsAfsInode(inum
)) == NULL
) {
990 /* Not an afs inode, keep going */
993 if ((p
= ginode(inum
)) == NULL
)
995 /* deleted/non-existent inode when di_mode == 0 */
998 info
.inodeNumber
= (int)inum
;
999 info
.byteCount
= p
->di_size
;
1000 info
.linkCount
= p
->di_nlink
;
1001 info
.u
.param
[0] = auxp
->aux_param1
;
1002 info
.u
.param
[1] = auxp
->aux_param2
;
1003 info
.u
.param
[2] = auxp
->aux_param3
;
1004 info
.u
.param
[3] = auxp
->aux_param4
;
1005 if (judgeInode
&& (*judgeInode
) (&info
, judgeParam
, rock
) == 0)
1008 if (fwrite(&info
, sizeof info
, 1, inodeFile
) != 1) {
1009 Log("Error writing inode file for partition %s\n", partition
);
1017 * run a few consistency checks of the superblock
1018 * (Cribbed from vfsck)
1021 #if defined(FD_FSMAGIC)
1022 if ((sblock
.fs_magic
!= FS_MAGIC
) && (sblock
.fs_magic
!= FS_MAGIC_LFN
)
1023 && (sblock
.fs_magic
!= FD_FSMAGIC
)
1024 #if defined(AFS_HPUX101_ENV)
1025 && (sblock
.fs_magic
!= FD_FSMAGIC_2
)
1029 if ((sblock
.fs_magic
!= FS_MAGIC
) && (sblock
.fs_magic
!= FS_MAGIC_LFN
)) {
1031 Log("There's something wrong with the superblock for partition %s; bad magic (%d) run vfsck\n", partition
, sblock
.fs_magic
);
1034 if (sblock
.fs_ncg
< 1) {
1035 Log("There's something wrong with the superblock for partition %s; NCG OUT OF RANGE (%d) run vfsck\n", partition
, sblock
.fs_ncg
);
1038 if (sblock
.fs_cpg
< 1 || sblock
.fs_cpg
> MAXCPG
) {
1039 Log("There's something wrong with the superblock for partition %s; CPG OUT OF RANGE (%d) run vfsck\n", partition
, sblock
.fs_cpg
);
1042 if (sblock
.fs_ncg
* sblock
.fs_cpg
< sblock
.fs_ncyl
1043 || (sblock
.fs_ncg
- 1) * sblock
.fs_cpg
>= sblock
.fs_ncyl
) {
1044 Log("There's something wrong with the superblock for partition %s; NCYL LESS THAN NCG*CPG run vfsck\n", partition
);
1047 if (sblock
.fs_sbsize
> SBSIZE
) {
1048 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
);
1052 if ((super
.fs
.fs_magic
!= FS_MAGIC
)
1053 || (super
.fs
.fs_ncg
< 1)
1054 #if defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
1055 || (super
.fs
.fs_cpg
< 1)
1057 || (super
.fs
.fs_cpg
< 1 || super
.fs
.fs_cpg
> MAXCPG
)
1059 || (super
.fs
.fs_ncg
* super
.fs
.fs_cpg
< super
.fs
.fs_ncyl
1060 || (super
.fs
.fs_ncg
- 1) * super
.fs
.fs_cpg
>= super
.fs
.fs_ncyl
)
1061 || (super
.fs
.fs_sbsize
> SBSIZE
)) {
1062 Log("There's something wrong with the superblock for partition %s; run vfsck\n", partition
);
1065 #endif /* AFS_HPUX_ENV */
1068 bufsize
= sblock
.fs_ipg
* sizeof(struct dinode
);
1070 bufsize
= super
.fs
.fs_ipg
* sizeof(struct dinode
);
1071 #endif /* AFS_HPUX_ENV */
1072 inodes
= (struct dinode
*)malloc(bufsize
);
1073 einodes
= (struct dinode
*)(((char *)inodes
) + bufsize
);
1074 if (inodes
== NULL
) {
1075 Log("Unable to allocate enough memory to scan inodes; help!\n");
1078 Log("Scanning inodes on device %s...\n", rdev
);
1080 for (c
= 0; c
< sblock
.fs_ncg
; c
++) {
1081 i
= c
* sblock
.fs_ipg
;
1082 e
= i
+ sblock
.fs_ipg
;
1083 #if defined(AFS_HPUX102_ENV)
1084 if (afs_lseek(pfd
, dbtoo(fsbtodb(&sblock
, itod(&sblock
, i
))), L_SET
) ==
1087 if (afs_lseek(pfd
, dbtob(fsbtodb(&sblock
, itod(&sblock
, i
))), L_SET
) ==
1091 for (c
= 0; c
< super
.fs
.fs_ncg
; c
++) {
1093 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1095 #if defined(AFS_DARWIN_ENV)
1096 #define offset_t off_t
1097 #define llseek lseek
1100 #endif /* AFS_SUN5_ENV */
1101 i
= c
* super
.fs
.fs_ipg
;
1102 e
= i
+ super
.fs
.fs_ipg
;
1104 dblk1
= fsbtodb(&super
.fs
, itod(&super
.fs
, i
));
1105 if (afs_lseek(pfd
, (off_t
) ((off_t
) dblk1
* DEV_BSIZE
), L_SET
) == -1) {
1107 #if defined(AFS_SUN5_ENV) || defined(AFS_DARWIN_ENV)
1108 f1
= fsbtodb(&super
.fs
, itod(&super
.fs
, i
));
1109 off
= (offset_t
) f1
<< DEV_BSHIFT
;
1110 if (llseek(pfd
, off
, L_SET
) == -1) {
1112 if (afs_lseek(pfd
, dbtob(fsbtodb(&super
.fs
, itod(&super
.fs
, i
))), L_SET
)
1114 #endif /* AFS_SUN5_ENV */
1115 #endif /* AFS_OSF_ENV */
1116 #endif /* AFS_HPUX_ENV */
1117 Log("Error reading inodes for partition %s; run vfsck\n",
1123 if (read(pfd
, inodes
, bufsize
) != bufsize
) {
1124 Log("Error reading inodes for partition %s; run vfsck\n",
1131 for (bj
= bk
= 0; bj
< bufsize
; bj
= bj
+ 512, bk
++) {
1132 if ((code
= read(pfd
, dptr
, 512)) != 512) {
1133 Log("Error reading inode %d? for partition %s (errno = %d); run vfsck\n", bk
+ i
, partition
, errno
);
1134 if (afs_lseek(pfd
, 512, L_SET
) == -1) {
1135 Log("Lseek failed\n");
1150 for (p
= inodes
; p
< einodes
&& i
< e
; i
++, p
++) {
1152 Log("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1153 i
, p
->di_vicep1
, p
->di_vicep2
, p
->di_vicep3
, p
->di_mode
,
1154 p
->di_size
, p
->di_nlink
);
1156 ("Ino=%d, v1=%x, v2=%x, v3=%x, mode=%x size=%d, lcnt=%d\n",
1157 i
, p
->di_vicep1
, p
->di_vicep2
, p
->di_vicep3
, p
->di_mode
,
1158 p
->di_size
, p
->di_nlink
);
1161 #ifdef AFS_3DISPARES
1162 /* Check to see if this inode is a pre-"OSF1 4.0D" inode */
1163 if ((p
->di_uid
|| p
->di_gid
)
1164 && !(p
->di_flags
& (IC_XUID
| IC_XGID
))) {
1165 Log("Found unconverted inode %d: Use 'fs_conv_dux40D convert' on partition %s\n", i
, partition
);
1169 osi_Panic("Tru64 needs AFS_3DISPARES\n");
1172 #if defined(AFS_SUN56_ENV)
1173 /* if this is a pre-sol2.6 unconverted inode, bail out */
1175 afs_uint32 p1
, p2
, p3
, p4
;
1179 q
= (quad
*) & (p
->di_ic
.ic_lsize
);
1181 p2
= p
->di_ic
.ic_flags
;
1183 p4
= p
->di_ic
.ic_uid
;
1184 p5
= p
->di_ic
.ic_gid
;
1186 if ((p2
|| p3
) && !p4
&& (p5
== -2)) {
1187 Log("Found unconverted inode %d\n", i
);
1188 Log("You should run the AFS file conversion utility\n");
1193 if (IS_DVICEMAGIC(p
) && (p
->di_mode
& IFMT
) == IFREG
) {
1194 afs_uint32 p2
= p
->di_vicep2
, p3
= DI_VICEP3(p
);
1196 info
.u
.param
[0] = p
->di_vicep1
;
1197 #ifdef AFS_3DISPARES
1198 if (((p2
>> 3) == INODESPECIAL
) && (p2
& 0x3)) {
1199 info
.u
.param
[1] = INODESPECIAL
;
1200 info
.u
.param
[2] = p3
;
1201 info
.u
.param
[3] = p2
& 0x3;
1203 info
.u
.param
[1] = ((p2
>> 27) << 16) + (p3
& 0xffff);
1204 info
.u
.param
[2] = (p2
& 0x3fffff);
1206 (((p2
>> 22) & 0x1f) << 16) + (p3
>> 16);
1209 info
.u
.param
[1] = p
->di_vicep2
;
1210 info
.u
.param
[2] = DI_VICEP3(p
);
1211 info
.u
.param
[3] = p
->di_vicep4
;
1213 info
.inodeNumber
= i
;
1214 info
.byteCount
= p
->di_size
;
1215 info
.linkCount
= p
->di_nlink
;
1216 if (judgeInode
&& (*judgeInode
) (&info
, judgeParam
, rock
) == 0)
1219 if (fwrite(&info
, sizeof info
, 1, inodeFile
) != 1) {
1220 Log("Error writing inode file for partition %s\n",
1234 if (fflush(inodeFile
) == EOF
) {
1235 Log("Unable to successfully flush inode file for %s\n", partition
);
1239 if (fsync(fileno(inodeFile
)) == -1) {
1240 Log("Unable to successfully fsync inode file for %s\n", partition
);
1246 * Paranoia: check that the file is really the right size
1248 if (fstat(fileno(inodeFile
), &status
) == -1) {
1249 Log("Unable to successfully stat inode file for %s\n", partition
);
1253 if (status
.st_size
!= ninodes
* sizeof(struct ViceInodeInfo
)) {
1254 Log("Wrong size (%d instead of %d) in inode file for %s\n",
1255 status
.st_size
, ninodes
* sizeof(struct ViceInodeInfo
),
1272 #endif /* !AFS_SGI_ENV */
1273 #endif /* !AFS_AIX31_ENV */
1275 #ifdef AFS_DARWIN_ENV
1277 #define dbtob(db) ((unsigned)(db) << DEV_BSHIFT)
1281 bread(int fd
, char *buf
, daddr_t blk
, afs_int32 size
)
1284 #ifdef AFS_AIX41_ENV
1285 offset_t off
= (offset_t
) blk
<< FSBSHIFT
;
1286 if (llseek(fd
, off
, 0) < 0) {
1287 Log("Unable to seek to offset %llu for block %u\n", off
, blk
);
1290 #else /* AFS_AIX41_ENV */
1291 if (afs_lseek(fd
, blk
* Bsize
, 0) < 0) {
1292 Log("Unable to seek to offset %u for block %u\n", blk
* Bsize
, blk
);
1294 #endif /* AFS_AIX41_ENV */
1296 if (afs_lseek(fd
, (off_t
) dbtob(blk
), L_SET
) < 0) {
1297 Log("Unable to seek to offset %u for block %u\n", dbtob(blk
), blk
);
1300 if (read(fd
, buf
, size
) != size
) {
1301 Log("Unable to read block %d, partition %s\n", blk
, partition
);
1307 #endif /* AFS_LINUX20_ENV */
1309 convertVolumeInfo(FdHandle_t
*fdhr
, FdHandle_t
*fdhw
, afs_uint32 vid
)
1311 struct VolumeDiskData vd
;
1314 if (FDH_PREAD(fdhr
, &vd
, sizeof(struct VolumeDiskData
), 0) !=
1315 sizeof(struct VolumeDiskData
)) {
1316 Log("1 convertiVolumeInfo: read failed for %lu with code %d\n", vid
,
1320 vd
.restoredFromId
= vd
.id
; /* remember the RO volume here */
1322 vd
.id
= vd
.parentId
;
1326 vd
.uniquifier
+= 5000; /* just in case there are still file copies
1327 from the old RW volume around */
1329 /* For ROs, the copyDate contains the time that the RO volume was actually
1330 * created, and the creationDate just contains the last time the RO was
1331 * copied from the RW data. So, make the new RW creationDate more accurate
1332 * by setting it to copyDate, if copyDate is older. Since, we know the
1333 * volume is at least as old as copyDate. */
1334 if (vd
.copyDate
< vd
.creationDate
) {
1335 vd
.creationDate
= vd
.copyDate
;
1337 /* If copyDate is newer, just make copyDate and creationDate the same,
1338 * for consistency with other RWs */
1339 vd
.copyDate
= vd
.creationDate
;
1342 p
= strrchr(vd
.name
, '.');
1343 if (p
&& !strcmp(p
, ".readonly")) {
1347 if (FDH_PWRITE(fdhw
, &vd
, sizeof(struct VolumeDiskData
), 0) !=
1348 sizeof(struct VolumeDiskData
)) {
1349 Log("1 convertiVolumeInfo: write failed for %lu with code %d\n", vid
,
1357 afs_int32 inodeType
;
1364 UpdateThisVolume(struct ViceInodeInfo
*inodeinfo
, VolumeId singleVolumeNumber
,
1365 struct specino
*specinos
)
1368 if ((inodeinfo
->u
.vnode
.vnodeNumber
== INODESPECIAL
) &&
1369 (inodeinfo
->u
.vnode
.volumeId
== singleVolumeNumber
)) {
1370 specinos
[inodeinfo
->u
.special
.type
].inodeNumber
=
1371 inodeinfo
->inodeNumber
;
1373 return 0; /* We aren't using a result file, we're caching */
1377 getDevName(char *pbuffer
, char *wpath
)
1379 char pbuf
[128], *ptr
;
1380 strcpy(pbuf
, pbuffer
);
1381 ptr
= (char *)strrchr(pbuf
, OS_DIRSEPC
);
1384 strcpy(wpath
, pbuf
);
1387 ptr
= (char *)strrchr(pbuffer
, OS_DIRSEPC
);
1389 strcpy(pbuffer
, ptr
+ 1);
1395 #ifdef FSSYNC_BUILD_CLIENT
1397 inode_ConvertROtoRWvolume(char *pname
, afs_uint32 volumeId
)
1399 char dir_name
[512], oldpath
[512], newpath
[512];
1401 char headername
[16];
1403 int fd
, err
, forcep
, j
;
1404 ssize_t len
, nBytes
;
1406 struct DiskPartition64
*partP
;
1407 struct ViceInodeInfo info
;
1408 struct VolumeDiskHeader h
;
1409 IHandle_t
*ih
, *ih2
;
1410 FdHandle_t
*fdP
, *fdP2
;
1413 char tmpDevName
[100];
1415 struct specino specinos
[VI_LINKTABLE
+1];
1416 Inode nearInode
= 0;
1417 # ifdef AFS_DEMAND_ATTACH_FS
1419 # endif /* AFS_DEMAND_ATTACH_FS */
1422 memset(&specinos
, 0, sizeof(specinos
));
1424 /* now do the work */
1426 for (partP
= DiskPartitionList
; partP
&& strcmp(partP
->name
, pname
);
1427 partP
= partP
->next
);
1429 Log("1 inode_ConvertROtoRWvolume: Couldn't find DiskPartition for %s\n", pname
);
1434 #ifdef AFS_DEMAND_ATTACH_FS
1435 locktype
= VVolLockType(V_VOLUPD
, 1);
1436 code
= VLockVolumeByIdNB(volumeId
, partP
, locktype
);
1444 if (VReadVolumeDiskHeader(volumeId
, partP
, &h
)) {
1445 Log("1 inode_ConvertROtoRWvolume: Couldn't read header for RO-volume %lu.\n",
1446 afs_printable_uint32_lu(volumeId
));
1450 FSYNC_VolOp(volumeId
, pname
, FSYNC_VOL_BREAKCBKS
, 0, NULL
);
1452 strcpy(tmpDevName
, partP
->devName
);
1453 name
= getDevName(tmpDevName
, wpath
);
1455 if ((err
= ListViceInodes(name
, VPartitionPath(partP
),
1456 NULL
, UpdateThisVolume
, volumeId
,
1457 &forcep
, 0, wpath
, &specinos
)) < 0)
1459 Log("1 inode_ConvertROtoRWvolume: Couldn't get special inodes\n");
1464 #if defined(NEARINODE_HINT)
1465 nearInodeHash(volumeId
, nearInode
);
1466 nearInode
%= partP
->f_files
;
1469 for (j
= VI_VOLINFO
; j
< VI_LINKTABLE
+1; j
++) {
1470 if (specinos
[j
].inodeNumber
> 0) {
1471 specinos
[j
].ninodeNumber
=
1472 IH_CREATE(NULL
, partP
->device
, VPartitionPath(partP
),
1473 nearInode
, h
.parent
, INODESPECIAL
, j
, h
.parent
);
1474 IH_INIT(ih
, partP
->device
, volumeId
,
1475 specinos
[j
].inodeNumber
);
1478 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j
, volumeId
);
1483 IH_INIT(ih2
, partP
->device
, h
.parent
, specinos
[j
].ninodeNumber
);
1484 fdP2
= IH_OPEN(ih2
);
1486 Log("1 inode_ConvertROtoRWvolume: Couldn't find special inode %d for %d\n", j
, h
.parent
);
1491 if (j
== VI_VOLINFO
)
1492 convertVolumeInfo(fdP
, fdP2
, ih2
->ih_vid
);
1496 len
= FDH_PREAD(fdP
, buffer
, sizeof(buffer
), offset
);
1501 nBytes
= FDH_PWRITE(fdP2
, buffer
, len
, offset
);
1502 if (nBytes
!= len
) {
1513 /* Unlink the old special inode; otherwise we will get duplicate
1514 * special inodes if we recreate the RO again */
1515 if (IH_DEC(ih
, specinos
[j
].inodeNumber
, volumeId
) == -1) {
1517 Log("IH_DEC failed: %x, %s, %u errno %d\n", ih
,
1518 PrintInode(stmp
, specinos
[j
].inodeNumber
), volumeId
, errno
);
1527 #ifdef AFS_64BIT_IOPS_ENV
1528 h
.volumeInfo_lo
= (afs_int32
)specinos
[VI_VOLINFO
].ninodeNumber
& 0xffffffff;
1529 h
.volumeInfo_hi
= (afs_int32
)(specinos
[VI_VOLINFO
].ninodeNumber
>> 32) && 0xffffffff;
1530 h
.smallVnodeIndex_lo
= (afs_int32
)specinos
[VI_SMALLINDEX
].ninodeNumber
& 0xffffffff;
1531 h
.smallVnodeIndex_hi
= (afs_int32
)(specinos
[VI_SMALLINDEX
].ninodeNumber
>> 32) & 0xffffffff;
1532 h
.largeVnodeIndex_lo
= (afs_int32
)specinos
[VI_LARGEINDEX
].ninodeNumber
& 0xffffffff;
1533 h
.largeVnodeIndex_hi
= (afs_int32
)(specinos
[VI_LARGEINDEX
].ninodeNumber
>> 32) & 0xffffffff;
1534 if (specinos
[VI_LINKTABLE
].ninodeNumber
) {
1535 h
.linkTable_lo
= (afs_int32
)specinos
[VI_LINKTABLE
].ninodeNumber
& 0xffffffff;
1536 h
.linkTable_hi
= (afs_int32
)specinos
[VI_LINKTABLE
].ninodeNumber
& 0xffffffff;
1539 h
.volumeInfo_lo
= specinos
[VI_VOLINFO
].ninodeNumber
;
1540 h
.smallVnodeIndex_lo
= specinos
[VI_SMALLINDEX
].ninodeNumber
;
1541 h
.largeVnodeIndex_lo
= specinos
[VI_LARGEINDEX
].ninodeNumber
;
1542 if (specinos
[VI_LINKTABLE
].ninodeNumber
) {
1543 h
.linkTable_lo
= specinos
[VI_LINKTABLE
].ninodeNumber
;
1547 if (VCreateVolumeDiskHeader(&h
, partP
)) {
1548 Log("1 inode_ConvertROtoRWvolume: Couldn't write header for RW-volume %lu\n",
1549 afs_printable_uint32_lu(h
.id
));
1554 if (VDestroyVolumeDiskHeader(partP
, volumeId
, h
.parent
)) {
1555 Log("1 inode_ConvertROtoRWvolume: Couldn't unlink header for RO-volume %lu\n",
1556 afs_printable_uint32_lu(volumeId
));
1559 FSYNC_VolOp(volumeId
, pname
, FSYNC_VOL_DONE
, 0, NULL
);
1560 FSYNC_VolOp(h
.id
, pname
, FSYNC_VOL_ON
, 0, NULL
);
1563 # ifdef AFS_DEMAND_ATTACH_FS
1565 VUnlockVolumeById(volumeId
, partP
);
1567 # endif /* AFS_DEMAND_ATTACH_FS */
1570 #endif /* FSSYNC_BUILD_CLIENT */
1571 #endif /* AFS_NAMEI_ENV */