1 /* $NetBSD: readufs_lfs.c,v 1.12 2011/02/21 02:31:58 itohy Exp $ */ 2 /* from Id: readufs_lfs.c,v 1.7 2003/10/15 14:16:58 itohy Exp */ 3 4 /* 5 * FS specific support for 4.4BSD Log-structured Filesystem 6 * 7 * Written in 1999, 2002, 2003 by ITOH Yasufumi. 8 * Public domain. 9 * 10 * Intended to be used for boot programs (first stage). 11 * DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT. 12 */ 13 14 #include "readufs.h" 15 16 #include <sys/mount.h> 17 #include <ufs/lfs/lfs.h> 18 19 #ifndef USE_UFS1 20 #error LFS currently requires USE_UFS1 21 #endif 22 23 static int get_lfs_inode(ino32_t ino, union ufs_dinode *dibuf); 24 25 static struct ufs1_dinode ifile_dinode; 26 27 #define fsi (*ufsinfo) 28 #define fsi_lfs fsi.fs_u.u_lfs 29 30 /* 31 * Read and check superblock. 32 * If it is an LFS, save information from the superblock. 33 */ 34 int 35 try_lfs(void) 36 { 37 struct ufs_info *ufsinfo = &ufs_info; 38 struct dlfs sblk, sblk2; 39 struct dlfs *s = &sblk; 40 daddr_t sbpos; 41 int fsbshift; 42 43 #ifdef DEBUG_WITH_STDIO 44 printf("trying LFS\n"); 45 #endif 46 sbpos = btodb(LFS_LABELPAD); 47 48 /* read primary superblock */ 49 for (;;) { 50 #ifdef DEBUG_WITH_STDIO 51 printf("LFS: reading primary sblk at: 0x%x\n", (unsigned)sbpos); 52 #endif 53 RAW_READ(&sblk, sbpos, sizeof sblk); 54 55 #ifdef DEBUG_WITH_STDIO 56 printf("LFS: sblk: magic: 0x%x, version: %d\n", 57 sblk.dlfs_magic, sblk.dlfs_version); 58 #endif 59 60 if (sblk.dlfs_magic != LFS_MAGIC) 61 return 1; 62 63 #ifdef DEBUG_WITH_STDIO 64 printf("LFS: bsize %d, fsize %d, bshift %d, blktodb %d, fsbtodb %d, inopf %d, inopb %d\n", 65 sblk.dlfs_bsize, sblk.dlfs_fsize, 66 sblk.dlfs_bshift, sblk.dlfs_blktodb, sblk.dlfs_fsbtodb, 67 sblk.dlfs_inopf, sblk.dlfs_inopb); 68 #endif 69 if ((fsi_lfs.version = sblk.dlfs_version) == 1) { 70 fsbshift = 0; 71 break; 72 } else { 73 daddr_t sbpos1; 74 #if 0 75 fsbshift = sblk.dlfs_bshift - sblk.dlfs_blktodb + sblk.dlfs_fsbtodb - DEV_BSHIFT; 76 #endif 77 fsbshift = sblk.dlfs_fsbtodb; 78 sbpos1 = sblk.dlfs_sboffs[0] << fsbshift; 79 if (sbpos == sbpos1) 80 break; 81 #ifdef DEBUG_WITH_STDIO 82 printf("LFS: correcting primary sblk location\n"); 83 #endif 84 sbpos = sbpos1; 85 } 86 } 87 88 #ifdef DEBUG_WITH_STDIO 89 printf("fsbshift: %d\n", fsbshift); 90 printf("sboff[1]: %d\n", sblk.dlfs_sboffs[1]); 91 #endif 92 93 if (sblk.dlfs_sboffs[1] > 0) { 94 #ifdef DEBUG_WITH_STDIO 95 printf("LFS: reading secondary sblk at: 0x%x\n", 96 sblk.dlfs_sboffs[1] << fsbshift); 97 #endif 98 /* read secondary superblock */ 99 RAW_READ(&sblk2, (daddr_t) sblk.dlfs_sboffs[1] << fsbshift, 100 sizeof sblk2); 101 102 #ifdef DEBUG_WITH_STDIO 103 printf("LFS: sblk2: magic: 0x%x, version: %d\n", 104 sblk2.dlfs_magic, sblk2.dlfs_version); 105 #endif 106 107 if (sblk2.dlfs_magic == LFS_MAGIC) { 108 if (fsi_lfs.version == 1) { 109 if (sblk.dlfs_otstamp > sblk2.dlfs_otstamp) 110 s = &sblk2; 111 } else { 112 if (sblk.dlfs_serial > sblk2.dlfs_serial) 113 s = &sblk2; 114 } 115 } 116 } 117 118 /* This partition looks like an LFS. */ 119 fsi.get_inode = get_lfs_inode; 120 /* 121 * version 1: disk addr is in disk sector --- no shifting 122 * version 2: disk addr is in fragment 123 */ 124 fsi.fsbtodb = fsbshift; 125 126 /* Get information from the superblock. */ 127 fsi.bsize = s->dlfs_bsize; 128 fsi.nindir = s->dlfs_nindir; 129 fsi_lfs.idaddr = s->dlfs_idaddr; 130 #if 0 131 fsi_lfs.ibsize = (fsi_lfs.version == 1) ? s->dlfs_bsize : s->dlfs_fsize; 132 #else /* simplify calculation to reduce code size */ 133 /* use fsi.bsize (larger then needed for v2, but probably no harm) */ 134 #endif 135 136 /* 137 * version 1: number of inode per block 138 * version 2: number of inode per fragment (but in dlfs_inopb) 139 */ 140 fsi_lfs.inopb = s->dlfs_inopb; 141 142 fsi_lfs.ifpb = s->dlfs_ifpb; 143 fsi_lfs.ioffset = s->dlfs_cleansz + s->dlfs_segtabsz; 144 145 /* ifile is always used to look-up other inodes, so keep its inode. */ 146 if (get_lfs_inode(LFS_IFILE_INUM, (union ufs_dinode *)&ifile_dinode)) 147 return 1; /* OOPS, failed to find inode of ifile! */ 148 149 fsi.fstype = UFSTYPE_LFS; 150 151 return 0; 152 } 153 154 /* 155 * Get inode from disk. 156 */ 157 static int 158 get_lfs_inode(ino32_t ino, union ufs_dinode *dibuf) 159 { 160 struct ufs_info *ufsinfo = &ufs_info; 161 daddr_t daddr; 162 char *buf = alloca(fsi.bsize); 163 struct ufs1_dinode *di, *diend; 164 int i; 165 166 /* Get fs block which contains the specified inode. */ 167 if (ino == LFS_IFILE_INUM) 168 daddr = fsi_lfs.idaddr; 169 else { 170 #ifdef DEBUG_WITH_STDIO 171 printf("LFS: ino: %d\nifpb: %d, bsize: %d\n", 172 ino, fsi_lfs.ifpb, fsi.bsize); 173 #endif 174 ufs_read((union ufs_dinode *) &ifile_dinode, buf, 175 ino / fsi_lfs.ifpb + fsi_lfs.ioffset, 176 fsi.bsize); 177 i = ino % fsi_lfs.ifpb; 178 daddr = (fsi_lfs.version == 1) ? 179 ((IFILE_V1 *) buf + i)->if_daddr 180 : ((IFILE *) buf + i)->if_daddr; 181 } 182 #ifdef DEBUG_WITH_STDIO 183 printf("LFS(%d): daddr: %d\n", ino, (int) daddr); 184 #endif 185 186 if (daddr == LFS_UNUSED_DADDR) 187 return 1; 188 189 /* Read the inode block. */ 190 RAW_READ(buf, daddr << fsi.fsbtodb, 191 #if 0 192 fsi_lfs.ibsize 193 #else /* simplify calculation to reduce code size */ 194 fsi.bsize 195 #endif 196 ); 197 198 /* Search for the inode. */ 199 di = (struct ufs1_dinode *) buf; 200 diend = di + fsi_lfs.inopb; 201 202 for ( ; di < diend; di++) 203 if (di->di_inumber == ino) 204 goto found; 205 /* not found */ 206 return 1; 207 208 found: 209 #ifdef DEBUG_WITH_STDIO 210 printf("LFS: dinode(%d): mode 0%o, nlink %d, inumber %d, size %d, uid %d, db[0] %d\n", 211 ino, di->di_mode, di->di_nlink, di->di_inumber, 212 (int) di->di_size, di->di_uid, di->di_db[0]); 213 #endif 214 215 #if 0 /* currently UFS1 only */ 216 #if defined(USE_UFS1) && defined(USE_UFS2) 217 /* XXX for DI_SIZE() macro */ 218 if (ufsinfo->ufstype != UFSTYPE_UFS1) 219 di->di1.di_size = di->si2.di_size; 220 #endif 221 #endif 222 223 dibuf->di1 = *di; 224 225 return 0; 226 } 227