xref: /netbsd-src/sys/arch/hppa/stand/xxboot/readufs_lfs.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: readufs_lfs.c,v 1.1 2014/02/24 07:23:43 skrll Exp $	*/
2 /*	from Id: readufs_lfs.c,v 1.8 2003/12/16 13:54:11 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 #include <ufs/lfs/lfs.h>
18 
19 #ifndef USE_UFS1
20  #error LFS currently requires USE_UFS1
21 #endif
22 
23 static struct ulfs1_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(void)
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", (unsigned)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, (daddr_t) sblk.dlfs_sboffs[1] << fsbshift,
98 		    sizeof sblk2);
99 
100 #ifdef DEBUG_WITH_STDIO
101 		printf("LFS: sblk2: magic: 0x%x, version: %d\n",
102 			sblk2.dlfs_magic, sblk2.dlfs_version);
103 #endif
104 
105 		if (sblk2.dlfs_magic == LFS_MAGIC) {
106 			if (fsi_lfs.version == 1) {
107 				if (sblk.dlfs_otstamp > sblk2.dlfs_otstamp)
108 					s = &sblk2;
109 			} else {
110 				if (sblk.dlfs_serial > sblk2.dlfs_serial)
111 					s = &sblk2;
112 			}
113 		}
114 	}
115 
116 	/* This partition looks like an LFS. */
117 #if 0
118 	fsi.get_inode = get_lfs_inode;
119 #endif
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 	fsi_lfs.ibsize = (fsi_lfs.version == 1) ? s->dlfs_bsize : s->dlfs_fsize;
131 
132 	/*
133 	 * version 1: number of inode per block
134 	 * version 2: number of inode per fragment (but in dlfs_inopb)
135 	 */
136 	fsi_lfs.inopb = s->dlfs_inopb;
137 
138 	fsi_lfs.ifpb = s->dlfs_ifpb;
139 	fsi_lfs.ioffset = s->dlfs_cleansz + s->dlfs_segtabsz;
140 
141 	/* ifile is always used to look-up other inodes, so keep its inode. */
142 	if (get_lfs_inode(LFS_IFILE_INUM, (union ufs_dinode *)&ifile_dinode))
143 		return 1;	/* OOPS, failed to find inode of ifile! */
144 
145 	fsi.fstype = UFSTYPE_LFS;
146 
147 	return 0;
148 }
149 
150 /*
151  * Get inode from disk.
152  */
153 int
154 get_lfs_inode(ino32_t ino, union ufs_dinode *dibuf)
155 {
156 	struct ufs_info *ufsinfo = &ufs_info;
157 	daddr_t daddr;
158 	char *buf = alloca(fsi.bsize);
159 	struct ulfs1_dinode *di, *diend;
160 	int i;
161 
162 	/* Get fs block which contains the specified inode. */
163 	if (ino == LFS_IFILE_INUM)
164 		daddr = fsi_lfs.idaddr;
165 	else {
166 #ifdef DEBUG_WITH_STDIO
167 		printf("LFS: ino: %d\nifpb: %d, bsize: %d\n",
168 			ino, fsi_lfs.ifpb, fsi.bsize);
169 #endif
170 		ufs_read((union ufs_dinode *) &ifile_dinode, buf,
171 			 ino / fsi_lfs.ifpb + fsi_lfs.ioffset,
172 			 fsi.bsize);
173 		i = ino % fsi_lfs.ifpb;
174 		daddr = (fsi_lfs.version == 1) ?
175 		    ((IFILE_V1 *) buf + i)->if_daddr
176 		    : ((IFILE *) buf + i)->if_daddr;
177 	}
178 #ifdef DEBUG_WITH_STDIO
179 	printf("LFS(%d): daddr: %d\n", ino, (int) daddr);
180 #endif
181 
182 	if (daddr == LFS_UNUSED_DADDR)
183 		return 1;
184 
185 	/* Read the inode block. */
186 	RAW_READ(buf, daddr << fsi.fsbtodb, fsi_lfs.ibsize);
187 
188 	/* Search for the inode. */
189 	di = (struct ulfs1_dinode *) buf;
190 	diend = di + fsi_lfs.inopb;
191 
192 	for ( ; di < diend; di++)
193 		if (di->di_inumber == ino)
194 			goto found;
195 	/* not found */
196 	return 1;
197 
198 found:
199 #ifdef DEBUG_WITH_STDIO
200 	printf("LFS: dinode(%d): mode 0%o, nlink %d, inumber %d, size %d, uid %d, db[0] %d\n",
201 		ino, di->di_mode, di->di_nlink, di->di_inumber,
202 		(int) di->di_size, di->di_uid, di->di_db[0]);
203 #endif
204 
205 #if 0	/* currently UFS1 only */
206 #if defined(USE_UFS1) && defined(USE_UFS2)
207 	/* XXX for DI_SIZE() macro */
208 	if (ufsinfo->ufstype != UFSTYPE_UFS1)
209 		di->di1.di_size = di->si2.di_size;
210 #endif
211 #endif
212 
213 	dibuf->dil1 = *di;
214 
215 	return 0;
216 }
217