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