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