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