readufs_lfs.c revision 1.3 1 /* from Id: readufs_lfs.c,v 1.5 2002/01/26 16:26:44 itohy Exp */
2
3 /*
4 * FS specific support for 4.4BSD Log-structured Filesystem
5 *
6 * Written by ITOH, Yasufumi (itohy (at) netbsd.org).
7 * Public domain.
8 *
9 * Intended to be used for boot programs (first stage).
10 * DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT.
11 */
12
13 #include <sys/types.h>
14 #include <sys/param.h>
15 #include <sys/mount.h>
16 #include <ufs/ufs/dinode.h>
17 #include <ufs/lfs/lfs.h>
18
19 #include "readufs.h"
20
21 static int get_lfs_inode __P((ino_t ino, struct dinode *dibuf));
22
23 static struct dinode ifile_dinode;
24
25 #define fsi (*ufsinfo)
26 #define fsi_lfs fsi.fs_u.u_lfs
27
28 /*
29 * Read and check superblock.
30 * If it is an LFS, save information from the superblock.
31 */
32 int
33 try_lfs()
34 {
35 struct ufs_info *ufsinfo = &ufs_info;
36 struct dlfs sblk, sblk2;
37 struct dlfs *s = &sblk;
38 daddr_t sbpos;
39 int fsbshift;
40
41 #ifdef DEBUG_WITH_STDIO
42 printf("trying LFS\n");
43 #endif
44 sbpos = btodb(LFS_LABELPAD);
45
46 /* read primary superblock */
47 for (;;) {
48 #ifdef DEBUG_WITH_STDIO
49 printf("LFS: reading primary sblk at: 0x%x\n", sbpos);
50 #endif
51 RAW_READ(&sblk, sbpos, sizeof sblk);
52
53 #ifdef DEBUG_WITH_STDIO
54 printf("LFS: sblk: magic: 0x%x, version: %d\n",
55 sblk.dlfs_magic, sblk.dlfs_version);
56 #endif
57
58 if (sblk.dlfs_magic != LFS_MAGIC)
59 return 1;
60
61 #ifdef DEBUG_WITH_STDIO
62 printf("LFS: bsize %d, fsize %d, bshift %d, blktodb %d, fsbtodb %d, inopf %d, inopb %d\n",
63 sblk.dlfs_bsize, sblk.dlfs_fsize,
64 sblk.dlfs_bshift, sblk.dlfs_blktodb, sblk.dlfs_fsbtodb,
65 sblk.dlfs_inopf, sblk.dlfs_inopb);
66 #endif
67 if ((fsi_lfs.version = sblk.dlfs_version) == 1) {
68 fsbshift = 0;
69 break;
70 } else {
71 daddr_t sbpos1;
72 #if 0
73 fsbshift = sblk.dlfs_bshift - sblk.dlfs_blktodb + sblk.dlfs_fsbtodb - DEV_BSHIFT;
74 #endif
75 fsbshift = sblk.dlfs_fsbtodb;
76 sbpos1 = sblk.dlfs_sboffs[0] << fsbshift;
77 if (sbpos == sbpos1)
78 break;
79 #ifdef DEBUG_WITH_STDIO
80 printf("LFS: correcting primary sblk location\n");
81 #endif
82 sbpos = sbpos1;
83 }
84 }
85
86 #ifdef DEBUG_WITH_STDIO
87 printf("fsbshift: %d\n", fsbshift);
88 printf("sboff[1]: %d\n", sblk.dlfs_sboffs[1]);
89 #endif
90
91 if (sblk.dlfs_sboffs[1] > 0) {
92 #ifdef DEBUG_WITH_STDIO
93 printf("LFS: reading secondary sblk at: 0x%x\n",
94 sblk.dlfs_sboffs[1] << fsbshift);
95 #endif
96 /* read secondary superblock */
97 RAW_READ(&sblk2, sblk.dlfs_sboffs[1] << fsbshift, sizeof sblk2);
98
99 #ifdef DEBUG_WITH_STDIO
100 printf("LFS: sblk2: magic: 0x%x, version: %d\n",
101 sblk2.dlfs_magic, sblk2.dlfs_version);
102 #endif
103
104 if (sblk2.dlfs_magic == LFS_MAGIC) {
105 if (fsi_lfs.version == 1) {
106 if (sblk.dlfs_otstamp > sblk2.dlfs_otstamp)
107 s = &sblk2;
108 } else {
109 if (sblk.dlfs_serial > sblk2.dlfs_serial)
110 s = &sblk2;
111 }
112 }
113 }
114
115 /* This partition looks like an LFS. */
116 fsi.get_inode = get_lfs_inode;
117 /*
118 * version 1: disk addr is in disk sector --- no shifting
119 * version 2: disk addr is in fragment
120 */
121 fsi.fsbtodb = fsbshift;
122
123 /* Get information from the superblock. */
124 fsi.bsize = s->dlfs_bsize;
125 fsi.nindir = s->dlfs_nindir;
126 fsi_lfs.idaddr = s->dlfs_idaddr;
127 #if 0
128 fsi_lfs.ibsize = (fsi_lfs.version == 1) ? s->dlfs_bsize : s->dlfs_fsize;
129 #else /* simplify calculation to reduce code size */
130 /* use fsi.bsize (larger then needed for v2, but probably no harm) */
131 #endif
132
133 /*
134 * version 1: number of inode per block
135 * version 2: number of inode per fragment (but in dlfs_inopb)
136 */
137 fsi_lfs.inopb = s->dlfs_inopb;
138
139 fsi_lfs.ifpb = s->dlfs_ifpb;
140 fsi_lfs.ioffset = s->dlfs_cleansz + s->dlfs_segtabsz;
141
142 /* ifile is always used to look-up other inodes, so keep its inode. */
143 if (get_lfs_inode(LFS_IFILE_INUM, &ifile_dinode))
144 return 1; /* OOPS, failed to find inode of ifile! */
145
146 fsi.fstype = UFSTYPE_LFS;
147
148 return 0;
149 }
150
151 /*
152 * Get inode from disk.
153 */
154 static int
155 get_lfs_inode(ino, dibuf)
156 ino_t ino;
157 struct dinode *dibuf;
158 {
159 struct ufs_info *ufsinfo = &ufs_info;
160 daddr_t daddr;
161 char *buf = alloca(fsi.bsize);
162 struct 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(&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 : ((IFILE *) buf + i)->if_daddr;
180 }
181 #ifdef DEBUG_WITH_STDIO
182 printf("LFS(%d): daddr: %lld\n", ino, (long long)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 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, gid %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_gid, di->di_db[0]);
212 #endif
213
214 *dibuf = *di;
215
216 return 0;
217 }
218