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