1156608Sdeischen/* $NetBSD: readufs_lfs.c,v 1.18 2024/01/07 07:58:33 isaki Exp $ */ 2156608Sdeischen/* from Id: readufs_lfs.c,v 1.7 2003/10/15 14:16:58 itohy Exp */ 3156608Sdeischen 4156608Sdeischen/* 5156608Sdeischen * FS specific support for 4.4BSD Log-structured Filesystem 6156608Sdeischen * 7156608Sdeischen * Written in 1999, 2002, 2003 by ITOH Yasufumi. 8156608Sdeischen * Public domain. 9156608Sdeischen * 10156608Sdeischen * Intended to be used for boot programs (first stage). 11156608Sdeischen * DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT. 12156608Sdeischen */ 13156608Sdeischen 14156608Sdeischen#include "readufs.h" 15156608Sdeischen 16156608Sdeischen#include <sys/mount.h> 17156608Sdeischen 18156608Sdeischen#ifndef USE_UFS1 19156608Sdeischen #error LFS currently requires USE_UFS1 20156608Sdeischen#endif 21156608Sdeischen 22156608Sdeischenstatic int get_lfs_inode(ino32_t ino, union ufs_dinode *dibuf); 23156608Sdeischen 24static 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 */ 33int 34try_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 */ 156static int 157get_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 207found: 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