readufs_lfs.c revision 1.5 1 /* $NetBSD: readufs_lfs.c,v 1.5 2003/10/22 14:18:27 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 (itohy (at) netbsd.org).
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 __P((ino_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()
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(ino, dibuf)
159 ino_t ino;
160 union ufs_dinode *dibuf;
161 {
162 struct ufs_info *ufsinfo = &ufs_info;
163 daddr_t daddr;
164 char *buf = alloca(fsi.bsize);
165 struct ufs1_dinode *di, *diend;
166 int i;
167
168 /* Get fs block which contains the specified inode. */
169 if (ino == LFS_IFILE_INUM)
170 daddr = fsi_lfs.idaddr;
171 else {
172 #ifdef DEBUG_WITH_STDIO
173 printf("LFS: ino: %d\nifpb: %d, bsize: %d\n",
174 ino, fsi_lfs.ifpb, fsi.bsize);
175 #endif
176 ufs_read((union ufs_dinode *) &ifile_dinode, buf,
177 ino / fsi_lfs.ifpb + fsi_lfs.ioffset,
178 fsi.bsize);
179 i = ino % fsi_lfs.ifpb;
180 daddr = (fsi_lfs.version == 1) ?
181 ((IFILE_V1 *) buf + i)->if_daddr
182 : ((IFILE *) buf + i)->if_daddr;
183 }
184 #ifdef DEBUG_WITH_STDIO
185 printf("LFS(%d): daddr: %d\n", ino, (int) daddr);
186 #endif
187
188 if (daddr == LFS_UNUSED_DADDR)
189 return 1;
190
191 /* Read the inode block. */
192 RAW_READ(buf, daddr << fsi.fsbtodb,
193 #if 0
194 fsi_lfs.ibsize
195 #else /* simplify calculation to reduce code size */
196 fsi.bsize
197 #endif
198 );
199
200 /* Search for the inode. */
201 di = (struct ufs1_dinode *) buf;
202 diend = di + fsi_lfs.inopb;
203
204 for ( ; di < diend; di++)
205 if (di->di_inumber == ino)
206 goto found;
207 /* not found */
208 return 1;
209
210 found:
211 #ifdef DEBUG_WITH_STDIO
212 printf("LFS: dinode(%d): mode 0%o, nlink %d, inumber %d, size %d, uid %d, db[0] %d\n",
213 ino, di->di_mode, di->di_nlink, di->di_inumber,
214 (int) di->di_size, di->di_uid, di->di_db[0]);
215 #endif
216
217 #if 0 /* currently UFS1 only */
218 #if defined(USE_UFS1) && defined(USE_UFS2)
219 /* XXX for DI_SIZE() macro */
220 if (ufsinfo->ufstype != UFSTYPE_UFS1)
221 di->di1.di_size = di->si2.di_size;
222 #endif
223 #endif
224
225 dibuf->di1 = *di;
226
227 return 0;
228 }
229