xref: /netbsd-src/sys/arch/x68k/stand/boot_ufs/readufs_lfs.c (revision 6b664a713479c31d4f17b38b42182a5d5fa21802)
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
try_lfs(void)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
get_lfs_inode(ino32_t ino,union ufs_dinode * dibuf)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