xref: /netbsd-src/sys/arch/x68k/stand/boot_ufs/readufs_lfs.c (revision a5847cc334d9a7029f6352b847e9e8d71a0f9e0c)
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