xref: /titanic_51/usr/src/boot/lib/libstand/nandfs.c (revision 4a5d661a82b942b6538acd26209d959ce98b593a)
1*4a5d661aSToomas Soome /*-
2*4a5d661aSToomas Soome  * Copyright (c) 2010-2012 Semihalf.
3*4a5d661aSToomas Soome  * All rights reserved.
4*4a5d661aSToomas Soome  *
5*4a5d661aSToomas Soome  * Redistribution and use in source and binary forms, with or without
6*4a5d661aSToomas Soome  * modification, are permitted provided that the following conditions
7*4a5d661aSToomas Soome  * are met:
8*4a5d661aSToomas Soome  * 1. Redistributions of source code must retain the above copyright
9*4a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer.
10*4a5d661aSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
11*4a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
12*4a5d661aSToomas Soome  *    documentation and/or other materials provided with the distribution.
13*4a5d661aSToomas Soome  *
14*4a5d661aSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*4a5d661aSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*4a5d661aSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*4a5d661aSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*4a5d661aSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*4a5d661aSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*4a5d661aSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*4a5d661aSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*4a5d661aSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*4a5d661aSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*4a5d661aSToomas Soome  * SUCH DAMAGE.
25*4a5d661aSToomas Soome  */
26*4a5d661aSToomas Soome 
27*4a5d661aSToomas Soome #include <sys/cdefs.h>
28*4a5d661aSToomas Soome __FBSDID("$FreeBSD$");
29*4a5d661aSToomas Soome 
30*4a5d661aSToomas Soome #include <sys/param.h>
31*4a5d661aSToomas Soome #include <sys/queue.h>
32*4a5d661aSToomas Soome #include <sys/stdint.h>
33*4a5d661aSToomas Soome #include <ufs/ufs/dinode.h>
34*4a5d661aSToomas Soome #include <fs/nandfs/nandfs_fs.h>
35*4a5d661aSToomas Soome #include "stand.h"
36*4a5d661aSToomas Soome #include "string.h"
37*4a5d661aSToomas Soome #include "zlib.h"
38*4a5d661aSToomas Soome 
39*4a5d661aSToomas Soome #define DEBUG
40*4a5d661aSToomas Soome #undef DEBUG
41*4a5d661aSToomas Soome #ifdef DEBUG
42*4a5d661aSToomas Soome #define NANDFS_DEBUG(fmt, args...) do { \
43*4a5d661aSToomas Soome     printf("NANDFS_DEBUG:" fmt "\n", ##args); } while (0)
44*4a5d661aSToomas Soome #else
45*4a5d661aSToomas Soome #define NANDFS_DEBUG(fmt, args...)
46*4a5d661aSToomas Soome #endif
47*4a5d661aSToomas Soome 
48*4a5d661aSToomas Soome struct nandfs_mdt {
49*4a5d661aSToomas Soome 	uint32_t	entries_per_block;
50*4a5d661aSToomas Soome 	uint32_t	entries_per_group;
51*4a5d661aSToomas Soome 	uint32_t	blocks_per_group;
52*4a5d661aSToomas Soome 	uint32_t	groups_per_desc_block;	/* desc is super group */
53*4a5d661aSToomas Soome 	uint32_t	blocks_per_desc_block;	/* desc is super group */
54*4a5d661aSToomas Soome };
55*4a5d661aSToomas Soome 
56*4a5d661aSToomas Soome struct bmap_buf {
57*4a5d661aSToomas Soome 	LIST_ENTRY(bmap_buf)	list;
58*4a5d661aSToomas Soome 	nandfs_daddr_t		blknr;
59*4a5d661aSToomas Soome 	uint64_t		*map;
60*4a5d661aSToomas Soome };
61*4a5d661aSToomas Soome 
62*4a5d661aSToomas Soome struct nandfs_node {
63*4a5d661aSToomas Soome 	struct nandfs_inode	*inode;
64*4a5d661aSToomas Soome 	LIST_HEAD(, bmap_buf)	bmap_bufs;
65*4a5d661aSToomas Soome };
66*4a5d661aSToomas Soome struct nandfs {
67*4a5d661aSToomas Soome 	int	nf_blocksize;
68*4a5d661aSToomas Soome 	int	nf_sectorsize;
69*4a5d661aSToomas Soome 	int	nf_cpno;
70*4a5d661aSToomas Soome 
71*4a5d661aSToomas Soome 	struct open_file	*nf_file;
72*4a5d661aSToomas Soome 	struct nandfs_node	*nf_opened_node;
73*4a5d661aSToomas Soome 	u_int			nf_offset;
74*4a5d661aSToomas Soome 	uint8_t			*nf_buf;
75*4a5d661aSToomas Soome 	int64_t			nf_buf_blknr;
76*4a5d661aSToomas Soome 
77*4a5d661aSToomas Soome 	struct nandfs_fsdata		*nf_fsdata;
78*4a5d661aSToomas Soome 	struct nandfs_super_block	*nf_sb;
79*4a5d661aSToomas Soome 	struct nandfs_segment_summary	nf_segsum;
80*4a5d661aSToomas Soome 	struct nandfs_checkpoint	nf_checkpoint;
81*4a5d661aSToomas Soome 	struct nandfs_super_root	nf_sroot;
82*4a5d661aSToomas Soome 	struct nandfs_node		nf_ifile;
83*4a5d661aSToomas Soome 	struct nandfs_node		nf_datfile;
84*4a5d661aSToomas Soome 	struct nandfs_node		nf_cpfile;
85*4a5d661aSToomas Soome 	struct nandfs_mdt		nf_datfile_mdt;
86*4a5d661aSToomas Soome 	struct nandfs_mdt		nf_ifile_mdt;
87*4a5d661aSToomas Soome 
88*4a5d661aSToomas Soome 	int nf_nindir[NIADDR];
89*4a5d661aSToomas Soome };
90*4a5d661aSToomas Soome 
91*4a5d661aSToomas Soome static int nandfs_open(const char *, struct open_file *);
92*4a5d661aSToomas Soome static int nandfs_close(struct open_file *);
93*4a5d661aSToomas Soome static int nandfs_read(struct open_file *, void *, size_t, size_t *);
94*4a5d661aSToomas Soome static off_t nandfs_seek(struct open_file *, off_t, int);
95*4a5d661aSToomas Soome static int nandfs_stat(struct open_file *, struct stat *);
96*4a5d661aSToomas Soome static int nandfs_readdir(struct open_file *, struct dirent *);
97*4a5d661aSToomas Soome 
98*4a5d661aSToomas Soome static int nandfs_buf_read(struct nandfs *, void **, size_t *);
99*4a5d661aSToomas Soome static struct nandfs_node *nandfs_lookup_path(struct nandfs *, const char *);
100*4a5d661aSToomas Soome static int nandfs_read_inode(struct nandfs *, struct nandfs_node *,
101*4a5d661aSToomas Soome     nandfs_lbn_t, u_int, void *, int);
102*4a5d661aSToomas Soome static int nandfs_read_blk(struct nandfs *, nandfs_daddr_t, void *, int);
103*4a5d661aSToomas Soome static int nandfs_bmap_lookup(struct nandfs *, struct nandfs_node *,
104*4a5d661aSToomas Soome     nandfs_lbn_t, nandfs_daddr_t *, int);
105*4a5d661aSToomas Soome static int nandfs_get_checkpoint(struct nandfs *, uint64_t,
106*4a5d661aSToomas Soome     struct nandfs_checkpoint *);
107*4a5d661aSToomas Soome static nandfs_daddr_t nandfs_vtop(struct nandfs *, nandfs_daddr_t);
108*4a5d661aSToomas Soome static void nandfs_calc_mdt_consts(int, struct nandfs_mdt *, int);
109*4a5d661aSToomas Soome static void nandfs_mdt_trans(struct nandfs_mdt *, uint64_t,
110*4a5d661aSToomas Soome     nandfs_daddr_t *, uint32_t *);
111*4a5d661aSToomas Soome static int ioread(struct open_file *, off_t, void *, u_int);
112*4a5d661aSToomas Soome static int nandfs_probe_sectorsize(struct open_file *);
113*4a5d661aSToomas Soome 
114*4a5d661aSToomas Soome struct fs_ops nandfs_fsops = {
115*4a5d661aSToomas Soome 	"nandfs",
116*4a5d661aSToomas Soome 	nandfs_open,
117*4a5d661aSToomas Soome 	nandfs_close,
118*4a5d661aSToomas Soome 	nandfs_read,
119*4a5d661aSToomas Soome 	null_write,
120*4a5d661aSToomas Soome 	nandfs_seek,
121*4a5d661aSToomas Soome 	nandfs_stat,
122*4a5d661aSToomas Soome 	nandfs_readdir
123*4a5d661aSToomas Soome };
124*4a5d661aSToomas Soome 
125*4a5d661aSToomas Soome #define	NINDIR(fs)	((fs)->nf_blocksize / sizeof(nandfs_daddr_t))
126*4a5d661aSToomas Soome 
127*4a5d661aSToomas Soome /* from NetBSD's src/sys/net/if_ethersubr.c */
128*4a5d661aSToomas Soome static uint32_t
129*4a5d661aSToomas Soome nandfs_crc32(uint32_t crc, const uint8_t *buf, size_t len)
130*4a5d661aSToomas Soome {
131*4a5d661aSToomas Soome 	static const uint32_t crctab[] = {
132*4a5d661aSToomas Soome 		0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
133*4a5d661aSToomas Soome 		0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
134*4a5d661aSToomas Soome 		0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
135*4a5d661aSToomas Soome 		0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
136*4a5d661aSToomas Soome 	};
137*4a5d661aSToomas Soome 	size_t i;
138*4a5d661aSToomas Soome 
139*4a5d661aSToomas Soome 	crc = crc ^ ~0U;
140*4a5d661aSToomas Soome 	for (i = 0; i < len; i++) {
141*4a5d661aSToomas Soome 		crc ^= buf[i];
142*4a5d661aSToomas Soome 		crc = (crc >> 4) ^ crctab[crc & 0xf];
143*4a5d661aSToomas Soome 		crc = (crc >> 4) ^ crctab[crc & 0xf];
144*4a5d661aSToomas Soome 	}
145*4a5d661aSToomas Soome 	return (crc ^ ~0U);
146*4a5d661aSToomas Soome }
147*4a5d661aSToomas Soome 
148*4a5d661aSToomas Soome static int
149*4a5d661aSToomas Soome nandfs_check_fsdata_crc(struct nandfs_fsdata *fsdata)
150*4a5d661aSToomas Soome {
151*4a5d661aSToomas Soome 	uint32_t fsdata_crc, comp_crc;
152*4a5d661aSToomas Soome 
153*4a5d661aSToomas Soome 	if (fsdata->f_magic != NANDFS_FSDATA_MAGIC)
154*4a5d661aSToomas Soome 		return (0);
155*4a5d661aSToomas Soome 
156*4a5d661aSToomas Soome 	/* Preserve crc */
157*4a5d661aSToomas Soome 	fsdata_crc = fsdata->f_sum;
158*4a5d661aSToomas Soome 
159*4a5d661aSToomas Soome 	/* Calculate */
160*4a5d661aSToomas Soome 	fsdata->f_sum = (0);
161*4a5d661aSToomas Soome 	comp_crc = nandfs_crc32(0, (uint8_t *)fsdata, fsdata->f_bytes);
162*4a5d661aSToomas Soome 
163*4a5d661aSToomas Soome 	/* Restore */
164*4a5d661aSToomas Soome 	fsdata->f_sum = fsdata_crc;
165*4a5d661aSToomas Soome 
166*4a5d661aSToomas Soome 	/* Check CRC */
167*4a5d661aSToomas Soome 	return (fsdata_crc == comp_crc);
168*4a5d661aSToomas Soome }
169*4a5d661aSToomas Soome 
170*4a5d661aSToomas Soome static int
171*4a5d661aSToomas Soome nandfs_check_superblock_crc(struct nandfs_fsdata *fsdata,
172*4a5d661aSToomas Soome     struct nandfs_super_block *super)
173*4a5d661aSToomas Soome {
174*4a5d661aSToomas Soome 	uint32_t super_crc, comp_crc;
175*4a5d661aSToomas Soome 
176*4a5d661aSToomas Soome 	/* Check super block magic */
177*4a5d661aSToomas Soome 	if (super->s_magic != NANDFS_SUPER_MAGIC)
178*4a5d661aSToomas Soome 		return (0);
179*4a5d661aSToomas Soome 
180*4a5d661aSToomas Soome 	/* Preserve CRC */
181*4a5d661aSToomas Soome 	super_crc = super->s_sum;
182*4a5d661aSToomas Soome 
183*4a5d661aSToomas Soome 	/* Calculate */
184*4a5d661aSToomas Soome 	super->s_sum = (0);
185*4a5d661aSToomas Soome 	comp_crc = nandfs_crc32(0, (uint8_t *)super, fsdata->f_sbbytes);
186*4a5d661aSToomas Soome 
187*4a5d661aSToomas Soome 	/* Restore */
188*4a5d661aSToomas Soome 	super->s_sum = super_crc;
189*4a5d661aSToomas Soome 
190*4a5d661aSToomas Soome 	/* Check CRC */
191*4a5d661aSToomas Soome 	return (super_crc == comp_crc);
192*4a5d661aSToomas Soome }
193*4a5d661aSToomas Soome 
194*4a5d661aSToomas Soome static int
195*4a5d661aSToomas Soome nandfs_find_super_block(struct nandfs *fs, struct open_file *f)
196*4a5d661aSToomas Soome {
197*4a5d661aSToomas Soome 	struct nandfs_super_block *sb;
198*4a5d661aSToomas Soome 	int i, j, n, s;
199*4a5d661aSToomas Soome 	int sectors_to_read, error;
200*4a5d661aSToomas Soome 
201*4a5d661aSToomas Soome 	sb = malloc(fs->nf_sectorsize);
202*4a5d661aSToomas Soome 	if (sb == NULL)
203*4a5d661aSToomas Soome 		return (ENOMEM);
204*4a5d661aSToomas Soome 
205*4a5d661aSToomas Soome 	memset(fs->nf_sb, 0, sizeof(*fs->nf_sb));
206*4a5d661aSToomas Soome 
207*4a5d661aSToomas Soome 	sectors_to_read = (NANDFS_NFSAREAS * fs->nf_fsdata->f_erasesize) /
208*4a5d661aSToomas Soome 	    fs->nf_sectorsize;
209*4a5d661aSToomas Soome 	for (i = 0; i < sectors_to_read; i++) {
210*4a5d661aSToomas Soome 		NANDFS_DEBUG("reading i %d offset %d\n", i,
211*4a5d661aSToomas Soome 		    i * fs->nf_sectorsize);
212*4a5d661aSToomas Soome 		error = ioread(f, i * fs->nf_sectorsize, (char *)sb,
213*4a5d661aSToomas Soome 		    fs->nf_sectorsize);
214*4a5d661aSToomas Soome 		if (error) {
215*4a5d661aSToomas Soome 			NANDFS_DEBUG("error %d\n", error);
216*4a5d661aSToomas Soome 			continue;
217*4a5d661aSToomas Soome 		}
218*4a5d661aSToomas Soome 		n = fs->nf_sectorsize / sizeof(struct nandfs_super_block);
219*4a5d661aSToomas Soome 		s = 0;
220*4a5d661aSToomas Soome 		if ((i * fs->nf_sectorsize) % fs->nf_fsdata->f_erasesize == 0) {
221*4a5d661aSToomas Soome 			if (fs->nf_sectorsize == sizeof(struct nandfs_fsdata))
222*4a5d661aSToomas Soome 				continue;
223*4a5d661aSToomas Soome 			else {
224*4a5d661aSToomas Soome 				s += (sizeof(struct nandfs_fsdata) /
225*4a5d661aSToomas Soome 				    sizeof(struct nandfs_super_block));
226*4a5d661aSToomas Soome 			}
227*4a5d661aSToomas Soome 		}
228*4a5d661aSToomas Soome 
229*4a5d661aSToomas Soome 		for (j = s; j < n; j++) {
230*4a5d661aSToomas Soome 			if (!nandfs_check_superblock_crc(fs->nf_fsdata, &sb[j]))
231*4a5d661aSToomas Soome 				continue;
232*4a5d661aSToomas Soome 			NANDFS_DEBUG("magic %x wtime %jd, lastcp 0x%jx\n",
233*4a5d661aSToomas Soome 			    sb[j].s_magic, sb[j].s_wtime, sb[j].s_last_cno);
234*4a5d661aSToomas Soome 			if (sb[j].s_last_cno > fs->nf_sb->s_last_cno)
235*4a5d661aSToomas Soome 				memcpy(fs->nf_sb, &sb[j], sizeof(*fs->nf_sb));
236*4a5d661aSToomas Soome 		}
237*4a5d661aSToomas Soome 	}
238*4a5d661aSToomas Soome 
239*4a5d661aSToomas Soome 	free(sb);
240*4a5d661aSToomas Soome 
241*4a5d661aSToomas Soome 	return (fs->nf_sb->s_magic != 0 ? 0 : EINVAL);
242*4a5d661aSToomas Soome }
243*4a5d661aSToomas Soome 
244*4a5d661aSToomas Soome static int
245*4a5d661aSToomas Soome nandfs_find_fsdata(struct nandfs *fs, struct open_file *f)
246*4a5d661aSToomas Soome {
247*4a5d661aSToomas Soome 	int offset, error, i;
248*4a5d661aSToomas Soome 
249*4a5d661aSToomas Soome 	NANDFS_DEBUG("starting\n");
250*4a5d661aSToomas Soome 
251*4a5d661aSToomas Soome 	offset = 0;
252*4a5d661aSToomas Soome 	for (i = 0; i < 64 * NANDFS_NFSAREAS; i++) {
253*4a5d661aSToomas Soome 		error = ioread(f, offset, (char *)fs->nf_fsdata,
254*4a5d661aSToomas Soome 		    sizeof(struct nandfs_fsdata));
255*4a5d661aSToomas Soome 		if (error)
256*4a5d661aSToomas Soome 			return (error);
257*4a5d661aSToomas Soome 		if (fs->nf_fsdata->f_magic == NANDFS_FSDATA_MAGIC) {
258*4a5d661aSToomas Soome 			NANDFS_DEBUG("found at %x, volume %s\n", offset,
259*4a5d661aSToomas Soome 			    fs->nf_fsdata->f_volume_name);
260*4a5d661aSToomas Soome 			if (nandfs_check_fsdata_crc(fs->nf_fsdata))
261*4a5d661aSToomas Soome 				break;
262*4a5d661aSToomas Soome 		}
263*4a5d661aSToomas Soome 		offset += fs->nf_sectorsize;
264*4a5d661aSToomas Soome 	}
265*4a5d661aSToomas Soome 
266*4a5d661aSToomas Soome 	return (error);
267*4a5d661aSToomas Soome }
268*4a5d661aSToomas Soome 
269*4a5d661aSToomas Soome static int
270*4a5d661aSToomas Soome nandfs_read_structures(struct nandfs *fs, struct open_file *f)
271*4a5d661aSToomas Soome {
272*4a5d661aSToomas Soome 	int error;
273*4a5d661aSToomas Soome 
274*4a5d661aSToomas Soome 	error = nandfs_find_fsdata(fs, f);
275*4a5d661aSToomas Soome 	if (error)
276*4a5d661aSToomas Soome 		return (error);
277*4a5d661aSToomas Soome 
278*4a5d661aSToomas Soome 	error = nandfs_find_super_block(fs, f);
279*4a5d661aSToomas Soome 
280*4a5d661aSToomas Soome 	if (error == 0)
281*4a5d661aSToomas Soome 		NANDFS_DEBUG("selected sb with w_time %jd last_pseg %jx\n",
282*4a5d661aSToomas Soome 		    fs->nf_sb->s_wtime, fs->nf_sb->s_last_pseg);
283*4a5d661aSToomas Soome 
284*4a5d661aSToomas Soome 	return (error);
285*4a5d661aSToomas Soome }
286*4a5d661aSToomas Soome 
287*4a5d661aSToomas Soome static int
288*4a5d661aSToomas Soome nandfs_mount(struct nandfs *fs, struct open_file *f)
289*4a5d661aSToomas Soome {
290*4a5d661aSToomas Soome 	int err = 0, level;
291*4a5d661aSToomas Soome 	uint64_t last_pseg;
292*4a5d661aSToomas Soome 
293*4a5d661aSToomas Soome 	fs->nf_fsdata = malloc(sizeof(struct nandfs_fsdata));
294*4a5d661aSToomas Soome 	fs->nf_sb = malloc(sizeof(struct nandfs_super_block));
295*4a5d661aSToomas Soome 
296*4a5d661aSToomas Soome 	err = nandfs_read_structures(fs, f);
297*4a5d661aSToomas Soome 	if (err) {
298*4a5d661aSToomas Soome 		free(fs->nf_fsdata);
299*4a5d661aSToomas Soome 		free(fs->nf_sb);
300*4a5d661aSToomas Soome 		return (err);
301*4a5d661aSToomas Soome 	}
302*4a5d661aSToomas Soome 
303*4a5d661aSToomas Soome 	fs->nf_blocksize = 1 << (fs->nf_fsdata->f_log_block_size + 10);
304*4a5d661aSToomas Soome 
305*4a5d661aSToomas Soome 	NANDFS_DEBUG("using superblock with wtime %jd\n", fs->nf_sb->s_wtime);
306*4a5d661aSToomas Soome 
307*4a5d661aSToomas Soome 	fs->nf_cpno = fs->nf_sb->s_last_cno;
308*4a5d661aSToomas Soome 	last_pseg = fs->nf_sb->s_last_pseg;
309*4a5d661aSToomas Soome 
310*4a5d661aSToomas Soome 	/*
311*4a5d661aSToomas Soome 	 * Calculate indirect block levels.
312*4a5d661aSToomas Soome 	 */
313*4a5d661aSToomas Soome 	nandfs_daddr_t mult;
314*4a5d661aSToomas Soome 
315*4a5d661aSToomas Soome 	mult = 1;
316*4a5d661aSToomas Soome 	for (level = 0; level < NIADDR; level++) {
317*4a5d661aSToomas Soome 		mult *= NINDIR(fs);
318*4a5d661aSToomas Soome 		fs->nf_nindir[level] = mult;
319*4a5d661aSToomas Soome 	}
320*4a5d661aSToomas Soome 
321*4a5d661aSToomas Soome 	nandfs_calc_mdt_consts(fs->nf_blocksize, &fs->nf_datfile_mdt,
322*4a5d661aSToomas Soome 	    fs->nf_fsdata->f_dat_entry_size);
323*4a5d661aSToomas Soome 
324*4a5d661aSToomas Soome 	nandfs_calc_mdt_consts(fs->nf_blocksize, &fs->nf_ifile_mdt,
325*4a5d661aSToomas Soome 	    fs->nf_fsdata->f_inode_size);
326*4a5d661aSToomas Soome 
327*4a5d661aSToomas Soome 	err = ioread(f, last_pseg * fs->nf_blocksize, &fs->nf_segsum,
328*4a5d661aSToomas Soome 	    sizeof(struct nandfs_segment_summary));
329*4a5d661aSToomas Soome 	if (err) {
330*4a5d661aSToomas Soome 		free(fs->nf_sb);
331*4a5d661aSToomas Soome 		free(fs->nf_fsdata);
332*4a5d661aSToomas Soome 		return (err);
333*4a5d661aSToomas Soome 	}
334*4a5d661aSToomas Soome 
335*4a5d661aSToomas Soome 	err = ioread(f, (last_pseg + fs->nf_segsum.ss_nblocks - 1) *
336*4a5d661aSToomas Soome 	    fs->nf_blocksize, &fs->nf_sroot, sizeof(struct nandfs_super_root));
337*4a5d661aSToomas Soome 	if (err) {
338*4a5d661aSToomas Soome 		free(fs->nf_sb);
339*4a5d661aSToomas Soome 		free(fs->nf_fsdata);
340*4a5d661aSToomas Soome 		return (err);
341*4a5d661aSToomas Soome 	}
342*4a5d661aSToomas Soome 
343*4a5d661aSToomas Soome 	fs->nf_datfile.inode = &fs->nf_sroot.sr_dat;
344*4a5d661aSToomas Soome 	LIST_INIT(&fs->nf_datfile.bmap_bufs);
345*4a5d661aSToomas Soome 	fs->nf_cpfile.inode = &fs->nf_sroot.sr_cpfile;
346*4a5d661aSToomas Soome 	LIST_INIT(&fs->nf_cpfile.bmap_bufs);
347*4a5d661aSToomas Soome 
348*4a5d661aSToomas Soome 	err = nandfs_get_checkpoint(fs, fs->nf_cpno, &fs->nf_checkpoint);
349*4a5d661aSToomas Soome 	if (err) {
350*4a5d661aSToomas Soome 		free(fs->nf_sb);
351*4a5d661aSToomas Soome 		free(fs->nf_fsdata);
352*4a5d661aSToomas Soome 		return (err);
353*4a5d661aSToomas Soome 	}
354*4a5d661aSToomas Soome 
355*4a5d661aSToomas Soome 	NANDFS_DEBUG("checkpoint cp_cno=%lld\n", fs->nf_checkpoint.cp_cno);
356*4a5d661aSToomas Soome 	NANDFS_DEBUG("checkpoint cp_inodes_count=%lld\n",
357*4a5d661aSToomas Soome 	    fs->nf_checkpoint.cp_inodes_count);
358*4a5d661aSToomas Soome 	NANDFS_DEBUG("checkpoint cp_ifile_inode.i_blocks=%lld\n",
359*4a5d661aSToomas Soome 	    fs->nf_checkpoint.cp_ifile_inode.i_blocks);
360*4a5d661aSToomas Soome 
361*4a5d661aSToomas Soome 	fs->nf_ifile.inode = &fs->nf_checkpoint.cp_ifile_inode;
362*4a5d661aSToomas Soome 	LIST_INIT(&fs->nf_ifile.bmap_bufs);
363*4a5d661aSToomas Soome 	return (0);
364*4a5d661aSToomas Soome }
365*4a5d661aSToomas Soome 
366*4a5d661aSToomas Soome #define NINDIR(fs)	((fs)->nf_blocksize / sizeof(nandfs_daddr_t))
367*4a5d661aSToomas Soome 
368*4a5d661aSToomas Soome static int
369*4a5d661aSToomas Soome nandfs_open(const char *path, struct open_file *f)
370*4a5d661aSToomas Soome {
371*4a5d661aSToomas Soome 	struct nandfs *fs;
372*4a5d661aSToomas Soome 	struct nandfs_node *node;
373*4a5d661aSToomas Soome 	int err, bsize, level;
374*4a5d661aSToomas Soome 
375*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_open('%s', %p)\n", path, f);
376*4a5d661aSToomas Soome 
377*4a5d661aSToomas Soome 	fs = malloc(sizeof(struct nandfs));
378*4a5d661aSToomas Soome 	f->f_fsdata = fs;
379*4a5d661aSToomas Soome 	fs->nf_file = f;
380*4a5d661aSToomas Soome 
381*4a5d661aSToomas Soome 	bsize = nandfs_probe_sectorsize(f);
382*4a5d661aSToomas Soome 	if (bsize < 0) {
383*4a5d661aSToomas Soome 		printf("Cannot probe medium sector size\n");
384*4a5d661aSToomas Soome 		return (EINVAL);
385*4a5d661aSToomas Soome 	}
386*4a5d661aSToomas Soome 
387*4a5d661aSToomas Soome 	fs->nf_sectorsize = bsize;
388*4a5d661aSToomas Soome 
389*4a5d661aSToomas Soome 	/*
390*4a5d661aSToomas Soome 	 * Calculate indirect block levels.
391*4a5d661aSToomas Soome 	 */
392*4a5d661aSToomas Soome 	nandfs_daddr_t mult;
393*4a5d661aSToomas Soome 
394*4a5d661aSToomas Soome 	mult = 1;
395*4a5d661aSToomas Soome 	for (level = 0; level < NIADDR; level++) {
396*4a5d661aSToomas Soome 		mult *= NINDIR(fs);
397*4a5d661aSToomas Soome 		fs->nf_nindir[level] = mult;
398*4a5d661aSToomas Soome 	}
399*4a5d661aSToomas Soome 
400*4a5d661aSToomas Soome 	NANDFS_DEBUG("fs %p nf_sectorsize=%x\n", fs, fs->nf_sectorsize);
401*4a5d661aSToomas Soome 
402*4a5d661aSToomas Soome 	err = nandfs_mount(fs, f);
403*4a5d661aSToomas Soome 	if (err) {
404*4a5d661aSToomas Soome 		NANDFS_DEBUG("Cannot mount nandfs: %s\n", strerror(err));
405*4a5d661aSToomas Soome 		return (err);
406*4a5d661aSToomas Soome 	}
407*4a5d661aSToomas Soome 
408*4a5d661aSToomas Soome 	node = nandfs_lookup_path(fs, path);
409*4a5d661aSToomas Soome 	if (node == NULL)
410*4a5d661aSToomas Soome 		return (EINVAL);
411*4a5d661aSToomas Soome 
412*4a5d661aSToomas Soome 	fs->nf_offset = 0;
413*4a5d661aSToomas Soome 	fs->nf_buf = NULL;
414*4a5d661aSToomas Soome 	fs->nf_buf_blknr = -1;
415*4a5d661aSToomas Soome 	fs->nf_opened_node = node;
416*4a5d661aSToomas Soome 	LIST_INIT(&fs->nf_opened_node->bmap_bufs);
417*4a5d661aSToomas Soome 	return (0);
418*4a5d661aSToomas Soome }
419*4a5d661aSToomas Soome 
420*4a5d661aSToomas Soome static void
421*4a5d661aSToomas Soome nandfs_free_node(struct nandfs_node *node)
422*4a5d661aSToomas Soome {
423*4a5d661aSToomas Soome 	struct bmap_buf *bmap, *tmp;
424*4a5d661aSToomas Soome 
425*4a5d661aSToomas Soome 	free(node->inode);
426*4a5d661aSToomas Soome 	LIST_FOREACH_SAFE(bmap, &node->bmap_bufs, list, tmp) {
427*4a5d661aSToomas Soome 		LIST_REMOVE(bmap, list);
428*4a5d661aSToomas Soome 		free(bmap->map);
429*4a5d661aSToomas Soome 		free(bmap);
430*4a5d661aSToomas Soome 	}
431*4a5d661aSToomas Soome 	free(node);
432*4a5d661aSToomas Soome }
433*4a5d661aSToomas Soome 
434*4a5d661aSToomas Soome static int
435*4a5d661aSToomas Soome nandfs_close(struct open_file *f)
436*4a5d661aSToomas Soome {
437*4a5d661aSToomas Soome 	struct nandfs *fs = f->f_fsdata;
438*4a5d661aSToomas Soome 
439*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_close(%p)\n", f);
440*4a5d661aSToomas Soome 
441*4a5d661aSToomas Soome 	if (fs->nf_buf != NULL)
442*4a5d661aSToomas Soome 		free(fs->nf_buf);
443*4a5d661aSToomas Soome 
444*4a5d661aSToomas Soome 	nandfs_free_node(fs->nf_opened_node);
445*4a5d661aSToomas Soome 	free(fs->nf_sb);
446*4a5d661aSToomas Soome 	free(fs);
447*4a5d661aSToomas Soome 	return (0);
448*4a5d661aSToomas Soome }
449*4a5d661aSToomas Soome 
450*4a5d661aSToomas Soome static int
451*4a5d661aSToomas Soome nandfs_read(struct open_file *f, void *addr, size_t size, size_t *resid)
452*4a5d661aSToomas Soome {
453*4a5d661aSToomas Soome 	struct nandfs *fs = (struct nandfs *)f->f_fsdata;
454*4a5d661aSToomas Soome 	size_t csize, buf_size;
455*4a5d661aSToomas Soome 	void *buf;
456*4a5d661aSToomas Soome 	int error = 0;
457*4a5d661aSToomas Soome 
458*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_read(file=%p, addr=%p, size=%d)\n", f, addr, size);
459*4a5d661aSToomas Soome 
460*4a5d661aSToomas Soome 	while (size != 0) {
461*4a5d661aSToomas Soome 		if (fs->nf_offset >= fs->nf_opened_node->inode->i_size)
462*4a5d661aSToomas Soome 			break;
463*4a5d661aSToomas Soome 
464*4a5d661aSToomas Soome 		error = nandfs_buf_read(fs, &buf, &buf_size);
465*4a5d661aSToomas Soome 		if (error)
466*4a5d661aSToomas Soome 			break;
467*4a5d661aSToomas Soome 
468*4a5d661aSToomas Soome 		csize = size;
469*4a5d661aSToomas Soome 		if (csize > buf_size)
470*4a5d661aSToomas Soome 			csize = buf_size;
471*4a5d661aSToomas Soome 
472*4a5d661aSToomas Soome 		bcopy(buf, addr, csize);
473*4a5d661aSToomas Soome 
474*4a5d661aSToomas Soome 		fs->nf_offset += csize;
475*4a5d661aSToomas Soome 		addr = (char *)addr + csize;
476*4a5d661aSToomas Soome 		size -= csize;
477*4a5d661aSToomas Soome 	}
478*4a5d661aSToomas Soome 
479*4a5d661aSToomas Soome 	if (resid)
480*4a5d661aSToomas Soome 		*resid = size;
481*4a5d661aSToomas Soome 	return (error);
482*4a5d661aSToomas Soome }
483*4a5d661aSToomas Soome 
484*4a5d661aSToomas Soome static off_t
485*4a5d661aSToomas Soome nandfs_seek(struct open_file *f, off_t offset, int where)
486*4a5d661aSToomas Soome {
487*4a5d661aSToomas Soome 	struct nandfs *fs = f->f_fsdata;
488*4a5d661aSToomas Soome 	off_t off;
489*4a5d661aSToomas Soome 	u_int size;
490*4a5d661aSToomas Soome 
491*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_seek(file=%p, offset=%lld, where=%d)\n", f,
492*4a5d661aSToomas Soome 	    offset, where);
493*4a5d661aSToomas Soome 
494*4a5d661aSToomas Soome 	size = fs->nf_opened_node->inode->i_size;
495*4a5d661aSToomas Soome 
496*4a5d661aSToomas Soome 	switch (where) {
497*4a5d661aSToomas Soome 	case SEEK_SET:
498*4a5d661aSToomas Soome 		off = 0;
499*4a5d661aSToomas Soome 		break;
500*4a5d661aSToomas Soome 	case SEEK_CUR:
501*4a5d661aSToomas Soome 		off = fs->nf_offset;
502*4a5d661aSToomas Soome 		break;
503*4a5d661aSToomas Soome 	case SEEK_END:
504*4a5d661aSToomas Soome 		off = size;
505*4a5d661aSToomas Soome 		break;
506*4a5d661aSToomas Soome 	default:
507*4a5d661aSToomas Soome 		errno = EINVAL;
508*4a5d661aSToomas Soome 		return (-1);
509*4a5d661aSToomas Soome 	}
510*4a5d661aSToomas Soome 
511*4a5d661aSToomas Soome 	off += offset;
512*4a5d661aSToomas Soome 	if (off < 0 || off > size) {
513*4a5d661aSToomas Soome 		errno = EINVAL;
514*4a5d661aSToomas Soome 		return(-1);
515*4a5d661aSToomas Soome 	}
516*4a5d661aSToomas Soome 
517*4a5d661aSToomas Soome 	fs->nf_offset = (u_int)off;
518*4a5d661aSToomas Soome 
519*4a5d661aSToomas Soome 	return (off);
520*4a5d661aSToomas Soome }
521*4a5d661aSToomas Soome 
522*4a5d661aSToomas Soome static int
523*4a5d661aSToomas Soome nandfs_stat(struct open_file *f, struct stat *sb)
524*4a5d661aSToomas Soome {
525*4a5d661aSToomas Soome 	struct nandfs *fs = f->f_fsdata;
526*4a5d661aSToomas Soome 
527*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_stat(file=%p, stat=%p)\n", f, sb);
528*4a5d661aSToomas Soome 
529*4a5d661aSToomas Soome 	sb->st_size = fs->nf_opened_node->inode->i_size;
530*4a5d661aSToomas Soome 	sb->st_mode = fs->nf_opened_node->inode->i_mode;
531*4a5d661aSToomas Soome 	sb->st_uid = fs->nf_opened_node->inode->i_uid;
532*4a5d661aSToomas Soome 	sb->st_gid = fs->nf_opened_node->inode->i_gid;
533*4a5d661aSToomas Soome 	return (0);
534*4a5d661aSToomas Soome }
535*4a5d661aSToomas Soome 
536*4a5d661aSToomas Soome static int
537*4a5d661aSToomas Soome nandfs_readdir(struct open_file *f, struct dirent *d)
538*4a5d661aSToomas Soome {
539*4a5d661aSToomas Soome 	struct nandfs *fs = f->f_fsdata;
540*4a5d661aSToomas Soome 	struct nandfs_dir_entry *dirent;
541*4a5d661aSToomas Soome 	void *buf;
542*4a5d661aSToomas Soome 	size_t buf_size;
543*4a5d661aSToomas Soome 
544*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)\n", f, d);
545*4a5d661aSToomas Soome 
546*4a5d661aSToomas Soome 	if (fs->nf_offset >= fs->nf_opened_node->inode->i_size) {
547*4a5d661aSToomas Soome 		NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) ENOENT\n",
548*4a5d661aSToomas Soome 		    f, d);
549*4a5d661aSToomas Soome 		return (ENOENT);
550*4a5d661aSToomas Soome 	}
551*4a5d661aSToomas Soome 
552*4a5d661aSToomas Soome 	if (nandfs_buf_read(fs, &buf, &buf_size)) {
553*4a5d661aSToomas Soome 		NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)"
554*4a5d661aSToomas Soome 		    "buf_read failed\n", f, d);
555*4a5d661aSToomas Soome 		return (EIO);
556*4a5d661aSToomas Soome 	}
557*4a5d661aSToomas Soome 
558*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) moving forward\n",
559*4a5d661aSToomas Soome 	    f, d);
560*4a5d661aSToomas Soome 
561*4a5d661aSToomas Soome 	dirent = (struct nandfs_dir_entry *)buf;
562*4a5d661aSToomas Soome 	fs->nf_offset += dirent->rec_len;
563*4a5d661aSToomas Soome 	strncpy(d->d_name, dirent->name, dirent->name_len);
564*4a5d661aSToomas Soome 	d->d_name[dirent->name_len] = '\0';
565*4a5d661aSToomas Soome 	d->d_type = dirent->file_type;
566*4a5d661aSToomas Soome 	return (0);
567*4a5d661aSToomas Soome }
568*4a5d661aSToomas Soome 
569*4a5d661aSToomas Soome static int
570*4a5d661aSToomas Soome nandfs_buf_read(struct nandfs *fs, void **buf_p, size_t *size_p)
571*4a5d661aSToomas Soome {
572*4a5d661aSToomas Soome 	nandfs_daddr_t blknr, blkoff;
573*4a5d661aSToomas Soome 
574*4a5d661aSToomas Soome 	blknr = fs->nf_offset / fs->nf_blocksize;
575*4a5d661aSToomas Soome 	blkoff = fs->nf_offset % fs->nf_blocksize;
576*4a5d661aSToomas Soome 
577*4a5d661aSToomas Soome 	if (blknr != fs->nf_buf_blknr) {
578*4a5d661aSToomas Soome 		if (fs->nf_buf == NULL)
579*4a5d661aSToomas Soome 			fs->nf_buf = malloc(fs->nf_blocksize);
580*4a5d661aSToomas Soome 
581*4a5d661aSToomas Soome 		if (nandfs_read_inode(fs, fs->nf_opened_node, blknr, 1,
582*4a5d661aSToomas Soome 		    fs->nf_buf, 0))
583*4a5d661aSToomas Soome 			return (EIO);
584*4a5d661aSToomas Soome 
585*4a5d661aSToomas Soome 		fs->nf_buf_blknr = blknr;
586*4a5d661aSToomas Soome 	}
587*4a5d661aSToomas Soome 
588*4a5d661aSToomas Soome 	*buf_p = fs->nf_buf + blkoff;
589*4a5d661aSToomas Soome 	*size_p = fs->nf_blocksize - blkoff;
590*4a5d661aSToomas Soome 
591*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_buf_read buf_p=%p size_p=%d\n", *buf_p, *size_p);
592*4a5d661aSToomas Soome 
593*4a5d661aSToomas Soome 	if (*size_p > fs->nf_opened_node->inode->i_size - fs->nf_offset)
594*4a5d661aSToomas Soome 		*size_p = fs->nf_opened_node->inode->i_size - fs->nf_offset;
595*4a5d661aSToomas Soome 
596*4a5d661aSToomas Soome 	return (0);
597*4a5d661aSToomas Soome }
598*4a5d661aSToomas Soome 
599*4a5d661aSToomas Soome static struct nandfs_node *
600*4a5d661aSToomas Soome nandfs_lookup_node(struct nandfs *fs, uint64_t ino)
601*4a5d661aSToomas Soome {
602*4a5d661aSToomas Soome 	uint64_t blocknr;
603*4a5d661aSToomas Soome 	int entrynr;
604*4a5d661aSToomas Soome 	struct nandfs_inode *buffer;
605*4a5d661aSToomas Soome 	struct nandfs_node *node;
606*4a5d661aSToomas Soome 	struct nandfs_inode *inode;
607*4a5d661aSToomas Soome 
608*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_lookup_node ino=%lld\n", ino);
609*4a5d661aSToomas Soome 
610*4a5d661aSToomas Soome 	if (ino == 0) {
611*4a5d661aSToomas Soome 		printf("nandfs_lookup_node: invalid inode requested\n");
612*4a5d661aSToomas Soome 		return (NULL);
613*4a5d661aSToomas Soome 	}
614*4a5d661aSToomas Soome 
615*4a5d661aSToomas Soome 	buffer = malloc(fs->nf_blocksize);
616*4a5d661aSToomas Soome 	inode = malloc(sizeof(struct nandfs_inode));
617*4a5d661aSToomas Soome 	node = malloc(sizeof(struct nandfs_node));
618*4a5d661aSToomas Soome 
619*4a5d661aSToomas Soome 	nandfs_mdt_trans(&fs->nf_ifile_mdt, ino, &blocknr, &entrynr);
620*4a5d661aSToomas Soome 
621*4a5d661aSToomas Soome 	if (nandfs_read_inode(fs, &fs->nf_ifile, blocknr, 1, buffer, 0))
622*4a5d661aSToomas Soome 		return (NULL);
623*4a5d661aSToomas Soome 
624*4a5d661aSToomas Soome 	memcpy(inode, &buffer[entrynr], sizeof(struct nandfs_inode));
625*4a5d661aSToomas Soome 	node->inode = inode;
626*4a5d661aSToomas Soome 	free(buffer);
627*4a5d661aSToomas Soome 	return (node);
628*4a5d661aSToomas Soome }
629*4a5d661aSToomas Soome 
630*4a5d661aSToomas Soome static struct nandfs_node *
631*4a5d661aSToomas Soome nandfs_lookup_path(struct nandfs *fs, const char *path)
632*4a5d661aSToomas Soome {
633*4a5d661aSToomas Soome 	struct nandfs_node *node;
634*4a5d661aSToomas Soome 	struct nandfs_dir_entry *dirent;
635*4a5d661aSToomas Soome 	char *namebuf;
636*4a5d661aSToomas Soome 	uint64_t i, done, pinode, inode;
637*4a5d661aSToomas Soome 	int nlinks = 0, counter, len, link_len, nameidx;
638*4a5d661aSToomas Soome 	uint8_t *buffer, *orig;
639*4a5d661aSToomas Soome 	char *strp, *lpath;
640*4a5d661aSToomas Soome 
641*4a5d661aSToomas Soome 	buffer = malloc(fs->nf_blocksize);
642*4a5d661aSToomas Soome 	orig = buffer;
643*4a5d661aSToomas Soome 
644*4a5d661aSToomas Soome 	namebuf = malloc(2 * MAXPATHLEN + 2);
645*4a5d661aSToomas Soome 	strncpy(namebuf, path, MAXPATHLEN);
646*4a5d661aSToomas Soome 	namebuf[MAXPATHLEN] = '\0';
647*4a5d661aSToomas Soome 	done = nameidx = 0;
648*4a5d661aSToomas Soome 	lpath = namebuf;
649*4a5d661aSToomas Soome 
650*4a5d661aSToomas Soome 	/* Get the root inode */
651*4a5d661aSToomas Soome 	node = nandfs_lookup_node(fs, NANDFS_ROOT_INO);
652*4a5d661aSToomas Soome 	inode = NANDFS_ROOT_INO;
653*4a5d661aSToomas Soome 
654*4a5d661aSToomas Soome 	while ((strp = strsep(&lpath, "/")) != NULL) {
655*4a5d661aSToomas Soome 		if (*strp == '\0')
656*4a5d661aSToomas Soome 			continue;
657*4a5d661aSToomas Soome 		if ((node->inode->i_mode & IFMT) != IFDIR) {
658*4a5d661aSToomas Soome 			nandfs_free_node(node);
659*4a5d661aSToomas Soome 			node = NULL;
660*4a5d661aSToomas Soome 			goto out;
661*4a5d661aSToomas Soome 		}
662*4a5d661aSToomas Soome 
663*4a5d661aSToomas Soome 		len = strlen(strp);
664*4a5d661aSToomas Soome 		NANDFS_DEBUG("%s: looking for %s\n", __func__, strp);
665*4a5d661aSToomas Soome 		for (i = 0; i < node->inode->i_blocks; i++) {
666*4a5d661aSToomas Soome 			if (nandfs_read_inode(fs, node, i, 1, orig, 0)) {
667*4a5d661aSToomas Soome 				node = NULL;
668*4a5d661aSToomas Soome 				goto out;
669*4a5d661aSToomas Soome 			}
670*4a5d661aSToomas Soome 
671*4a5d661aSToomas Soome 			buffer = orig;
672*4a5d661aSToomas Soome 			done = counter = 0;
673*4a5d661aSToomas Soome 			while (1) {
674*4a5d661aSToomas Soome 				dirent =
675*4a5d661aSToomas Soome 				    (struct nandfs_dir_entry *)(void *)buffer;
676*4a5d661aSToomas Soome 				NANDFS_DEBUG("%s: dirent.name = %s\n",
677*4a5d661aSToomas Soome 				    __func__, dirent->name);
678*4a5d661aSToomas Soome 				NANDFS_DEBUG("%s: dirent.rec_len = %d\n",
679*4a5d661aSToomas Soome 				    __func__, dirent->rec_len);
680*4a5d661aSToomas Soome 				NANDFS_DEBUG("%s: dirent.inode = %lld\n",
681*4a5d661aSToomas Soome 				    __func__, dirent->inode);
682*4a5d661aSToomas Soome 				if (len == dirent->name_len &&
683*4a5d661aSToomas Soome 				    (strncmp(strp, dirent->name, len) == 0) &&
684*4a5d661aSToomas Soome 				    dirent->inode != 0) {
685*4a5d661aSToomas Soome 					nandfs_free_node(node);
686*4a5d661aSToomas Soome 					node = nandfs_lookup_node(fs,
687*4a5d661aSToomas Soome 					    dirent->inode);
688*4a5d661aSToomas Soome 					pinode = inode;
689*4a5d661aSToomas Soome 					inode = dirent->inode;
690*4a5d661aSToomas Soome 					done = 1;
691*4a5d661aSToomas Soome 					break;
692*4a5d661aSToomas Soome 				}
693*4a5d661aSToomas Soome 
694*4a5d661aSToomas Soome 				counter += dirent->rec_len;
695*4a5d661aSToomas Soome 				buffer += dirent->rec_len;
696*4a5d661aSToomas Soome 
697*4a5d661aSToomas Soome 				if (counter == fs->nf_blocksize)
698*4a5d661aSToomas Soome 					break;
699*4a5d661aSToomas Soome 			}
700*4a5d661aSToomas Soome 
701*4a5d661aSToomas Soome 			if (done)
702*4a5d661aSToomas Soome 				break;
703*4a5d661aSToomas Soome 		}
704*4a5d661aSToomas Soome 
705*4a5d661aSToomas Soome 		if (!done) {
706*4a5d661aSToomas Soome 			node = NULL;
707*4a5d661aSToomas Soome 			goto out;
708*4a5d661aSToomas Soome 		}
709*4a5d661aSToomas Soome 
710*4a5d661aSToomas Soome 		NANDFS_DEBUG("%s: %.*s has mode %o\n", __func__,
711*4a5d661aSToomas Soome 		    dirent->name_len, dirent->name, node->inode->i_mode);
712*4a5d661aSToomas Soome 
713*4a5d661aSToomas Soome 		if ((node->inode->i_mode & IFMT) == IFLNK) {
714*4a5d661aSToomas Soome 			NANDFS_DEBUG("%s: %.*s is symlink\n",
715*4a5d661aSToomas Soome 			    __func__, dirent->name_len, dirent->name);
716*4a5d661aSToomas Soome 			link_len = node->inode->i_size;
717*4a5d661aSToomas Soome 
718*4a5d661aSToomas Soome 			if (++nlinks > MAXSYMLINKS) {
719*4a5d661aSToomas Soome 				nandfs_free_node(node);
720*4a5d661aSToomas Soome 				node = NULL;
721*4a5d661aSToomas Soome 				goto out;
722*4a5d661aSToomas Soome 			}
723*4a5d661aSToomas Soome 
724*4a5d661aSToomas Soome 			if (nandfs_read_inode(fs, node, 0, 1, orig, 0)) {
725*4a5d661aSToomas Soome 				nandfs_free_node(node);
726*4a5d661aSToomas Soome 				node = NULL;
727*4a5d661aSToomas Soome 				goto out;
728*4a5d661aSToomas Soome 			}
729*4a5d661aSToomas Soome 
730*4a5d661aSToomas Soome 			NANDFS_DEBUG("%s: symlink is  %.*s\n",
731*4a5d661aSToomas Soome 			    __func__, link_len, (char *)orig);
732*4a5d661aSToomas Soome 
733*4a5d661aSToomas Soome 			nameidx = (nameidx == 0) ? MAXPATHLEN + 1 : 0;
734*4a5d661aSToomas Soome 			bcopy((char *)orig, namebuf + nameidx,
735*4a5d661aSToomas Soome 			    (unsigned)link_len);
736*4a5d661aSToomas Soome 			if (lpath != NULL) {
737*4a5d661aSToomas Soome 				namebuf[nameidx + link_len++] = '/';
738*4a5d661aSToomas Soome 				strncpy(namebuf + nameidx + link_len, lpath,
739*4a5d661aSToomas Soome 				    MAXPATHLEN - link_len);
740*4a5d661aSToomas Soome 				namebuf[nameidx + MAXPATHLEN] = '\0';
741*4a5d661aSToomas Soome 			} else
742*4a5d661aSToomas Soome 				namebuf[nameidx + link_len] = '\0';
743*4a5d661aSToomas Soome 
744*4a5d661aSToomas Soome 			NANDFS_DEBUG("%s: strp=%s, lpath=%s, namebuf0=%s, "
745*4a5d661aSToomas Soome 			    "namebuf1=%s, idx=%d\n", __func__, strp, lpath,
746*4a5d661aSToomas Soome 			    namebuf + 0, namebuf + MAXPATHLEN + 1, nameidx);
747*4a5d661aSToomas Soome 
748*4a5d661aSToomas Soome 			lpath = namebuf + nameidx;
749*4a5d661aSToomas Soome 
750*4a5d661aSToomas Soome 			nandfs_free_node(node);
751*4a5d661aSToomas Soome 
752*4a5d661aSToomas Soome 			/*
753*4a5d661aSToomas Soome 			 * If absolute pathname, restart at root. Otherwise
754*4a5d661aSToomas Soome 			 * continue with out parent inode.
755*4a5d661aSToomas Soome 			 */
756*4a5d661aSToomas Soome 			inode = (orig[0] == '/') ? NANDFS_ROOT_INO : pinode;
757*4a5d661aSToomas Soome 			node = nandfs_lookup_node(fs, inode);
758*4a5d661aSToomas Soome 		}
759*4a5d661aSToomas Soome 	}
760*4a5d661aSToomas Soome 
761*4a5d661aSToomas Soome out:
762*4a5d661aSToomas Soome 	free(namebuf);
763*4a5d661aSToomas Soome 	free(orig);
764*4a5d661aSToomas Soome 	return (node);
765*4a5d661aSToomas Soome }
766*4a5d661aSToomas Soome 
767*4a5d661aSToomas Soome static int
768*4a5d661aSToomas Soome nandfs_read_inode(struct nandfs *fs, struct nandfs_node *node,
769*4a5d661aSToomas Soome     nandfs_daddr_t blknr, u_int nblks, void *buf, int raw)
770*4a5d661aSToomas Soome {
771*4a5d661aSToomas Soome 	uint64_t *pblks;
772*4a5d661aSToomas Soome 	uint64_t *vblks;
773*4a5d661aSToomas Soome 	u_int i;
774*4a5d661aSToomas Soome 	int error;
775*4a5d661aSToomas Soome 
776*4a5d661aSToomas Soome 	pblks = malloc(nblks * sizeof(uint64_t));
777*4a5d661aSToomas Soome 	vblks = malloc(nblks * sizeof(uint64_t));
778*4a5d661aSToomas Soome 
779*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_read_inode fs=%p node=%p blknr=%lld nblks=%d\n",
780*4a5d661aSToomas Soome 	    fs, node, blknr, nblks);
781*4a5d661aSToomas Soome 	for (i = 0; i < nblks; i++) {
782*4a5d661aSToomas Soome 		error = nandfs_bmap_lookup(fs, node, blknr + i, &vblks[i], raw);
783*4a5d661aSToomas Soome 		if (error) {
784*4a5d661aSToomas Soome 			free(pblks);
785*4a5d661aSToomas Soome 			free(vblks);
786*4a5d661aSToomas Soome 			return (error);
787*4a5d661aSToomas Soome 		}
788*4a5d661aSToomas Soome 		if (raw == 0)
789*4a5d661aSToomas Soome 			pblks[i] = nandfs_vtop(fs, vblks[i]);
790*4a5d661aSToomas Soome 		else
791*4a5d661aSToomas Soome 			pblks[i] = vblks[i];
792*4a5d661aSToomas Soome 	}
793*4a5d661aSToomas Soome 
794*4a5d661aSToomas Soome 	for (i = 0; i < nblks; i++) {
795*4a5d661aSToomas Soome 		if (ioread(fs->nf_file, pblks[i] * fs->nf_blocksize, buf,
796*4a5d661aSToomas Soome 		    fs->nf_blocksize)) {
797*4a5d661aSToomas Soome 			free(pblks);
798*4a5d661aSToomas Soome 			free(vblks);
799*4a5d661aSToomas Soome 			return (EIO);
800*4a5d661aSToomas Soome 		}
801*4a5d661aSToomas Soome 
802*4a5d661aSToomas Soome 		buf = (void *)((uintptr_t)buf + fs->nf_blocksize);
803*4a5d661aSToomas Soome 	}
804*4a5d661aSToomas Soome 
805*4a5d661aSToomas Soome 	free(pblks);
806*4a5d661aSToomas Soome 	free(vblks);
807*4a5d661aSToomas Soome 	return (0);
808*4a5d661aSToomas Soome }
809*4a5d661aSToomas Soome 
810*4a5d661aSToomas Soome static int
811*4a5d661aSToomas Soome nandfs_read_blk(struct nandfs *fs, nandfs_daddr_t blknr, void *buf, int phys)
812*4a5d661aSToomas Soome {
813*4a5d661aSToomas Soome 	uint64_t pblknr;
814*4a5d661aSToomas Soome 
815*4a5d661aSToomas Soome 	pblknr = (phys ? blknr : nandfs_vtop(fs, blknr));
816*4a5d661aSToomas Soome 
817*4a5d661aSToomas Soome 	return (ioread(fs->nf_file, pblknr * fs->nf_blocksize, buf,
818*4a5d661aSToomas Soome 	    fs->nf_blocksize));
819*4a5d661aSToomas Soome }
820*4a5d661aSToomas Soome 
821*4a5d661aSToomas Soome static int
822*4a5d661aSToomas Soome nandfs_get_checkpoint(struct nandfs *fs, uint64_t cpno,
823*4a5d661aSToomas Soome     struct nandfs_checkpoint *cp)
824*4a5d661aSToomas Soome {
825*4a5d661aSToomas Soome 	uint64_t blocknr;
826*4a5d661aSToomas Soome 	int blockoff, cp_per_block, dlen;
827*4a5d661aSToomas Soome 	uint8_t *buf;
828*4a5d661aSToomas Soome 
829*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_get_checkpoint(fs=%p cpno=%lld)\n", fs, cpno);
830*4a5d661aSToomas Soome 
831*4a5d661aSToomas Soome 	buf = malloc(fs->nf_blocksize);
832*4a5d661aSToomas Soome 
833*4a5d661aSToomas Soome 	cpno += NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1;
834*4a5d661aSToomas Soome 	dlen = fs->nf_fsdata->f_checkpoint_size;
835*4a5d661aSToomas Soome 	cp_per_block = fs->nf_blocksize / dlen;
836*4a5d661aSToomas Soome 	blocknr = cpno / cp_per_block;
837*4a5d661aSToomas Soome 	blockoff = (cpno % cp_per_block) * dlen;
838*4a5d661aSToomas Soome 
839*4a5d661aSToomas Soome 	if (nandfs_read_inode(fs, &fs->nf_cpfile, blocknr, 1, buf, 0)) {
840*4a5d661aSToomas Soome 		free(buf);
841*4a5d661aSToomas Soome 		return (EINVAL);
842*4a5d661aSToomas Soome 	}
843*4a5d661aSToomas Soome 
844*4a5d661aSToomas Soome 	memcpy(cp, buf + blockoff, sizeof(struct nandfs_checkpoint));
845*4a5d661aSToomas Soome 	free(buf);
846*4a5d661aSToomas Soome 
847*4a5d661aSToomas Soome 	return (0);
848*4a5d661aSToomas Soome }
849*4a5d661aSToomas Soome 
850*4a5d661aSToomas Soome static uint64_t *
851*4a5d661aSToomas Soome nandfs_get_map(struct nandfs *fs, struct nandfs_node *node, nandfs_daddr_t blknr,
852*4a5d661aSToomas Soome     int phys)
853*4a5d661aSToomas Soome {
854*4a5d661aSToomas Soome 	struct bmap_buf *bmap;
855*4a5d661aSToomas Soome 	uint64_t *map;
856*4a5d661aSToomas Soome 
857*4a5d661aSToomas Soome 	LIST_FOREACH(bmap, &node->bmap_bufs, list) {
858*4a5d661aSToomas Soome 		if (bmap->blknr == blknr)
859*4a5d661aSToomas Soome 			return (bmap->map);
860*4a5d661aSToomas Soome 	}
861*4a5d661aSToomas Soome 
862*4a5d661aSToomas Soome 	map = malloc(fs->nf_blocksize);
863*4a5d661aSToomas Soome 	if (nandfs_read_blk(fs, blknr, map, phys)) {
864*4a5d661aSToomas Soome 		free(map);
865*4a5d661aSToomas Soome 		return (NULL);
866*4a5d661aSToomas Soome 	}
867*4a5d661aSToomas Soome 
868*4a5d661aSToomas Soome 	bmap = malloc(sizeof(struct bmap_buf));
869*4a5d661aSToomas Soome 	bmap->blknr = blknr;
870*4a5d661aSToomas Soome 	bmap->map = map;
871*4a5d661aSToomas Soome 
872*4a5d661aSToomas Soome 	LIST_INSERT_HEAD(&node->bmap_bufs, bmap, list);
873*4a5d661aSToomas Soome 
874*4a5d661aSToomas Soome 	NANDFS_DEBUG("%s:(node=%p, map=%p)\n", __func__, node, map);
875*4a5d661aSToomas Soome 	return (map);
876*4a5d661aSToomas Soome }
877*4a5d661aSToomas Soome 
878*4a5d661aSToomas Soome static int
879*4a5d661aSToomas Soome nandfs_bmap_lookup(struct nandfs *fs, struct nandfs_node *node,
880*4a5d661aSToomas Soome     nandfs_lbn_t lblknr, nandfs_daddr_t *vblknr, int phys)
881*4a5d661aSToomas Soome {
882*4a5d661aSToomas Soome 	struct nandfs_inode *ino;
883*4a5d661aSToomas Soome 	nandfs_daddr_t ind_block_num;
884*4a5d661aSToomas Soome 	uint64_t *map;
885*4a5d661aSToomas Soome 	int idx;
886*4a5d661aSToomas Soome 	int level;
887*4a5d661aSToomas Soome 
888*4a5d661aSToomas Soome 	ino = node->inode;
889*4a5d661aSToomas Soome 
890*4a5d661aSToomas Soome 	if (lblknr < NDADDR) {
891*4a5d661aSToomas Soome 		*vblknr = ino->i_db[lblknr];
892*4a5d661aSToomas Soome 		return (0);
893*4a5d661aSToomas Soome 	}
894*4a5d661aSToomas Soome 
895*4a5d661aSToomas Soome 	lblknr -= NDADDR;
896*4a5d661aSToomas Soome 
897*4a5d661aSToomas Soome 	/*
898*4a5d661aSToomas Soome 	 * nindir[0] = NINDIR
899*4a5d661aSToomas Soome 	 * nindir[1] = NINDIR**2
900*4a5d661aSToomas Soome 	 * nindir[2] = NINDIR**3
901*4a5d661aSToomas Soome 	 *	etc
902*4a5d661aSToomas Soome 	 */
903*4a5d661aSToomas Soome 	for (level = 0; level < NIADDR; level++) {
904*4a5d661aSToomas Soome 		NANDFS_DEBUG("lblknr=%jx fs->nf_nindir[%d]=%d\n", lblknr, level, fs->nf_nindir[level]);
905*4a5d661aSToomas Soome 		if (lblknr < fs->nf_nindir[level])
906*4a5d661aSToomas Soome 			break;
907*4a5d661aSToomas Soome 		lblknr -= fs->nf_nindir[level];
908*4a5d661aSToomas Soome 	}
909*4a5d661aSToomas Soome 
910*4a5d661aSToomas Soome 	if (level == NIADDR) {
911*4a5d661aSToomas Soome 		/* Block number too high */
912*4a5d661aSToomas Soome 		NANDFS_DEBUG("lblknr %jx too high\n", lblknr);
913*4a5d661aSToomas Soome 		return (EFBIG);
914*4a5d661aSToomas Soome 	}
915*4a5d661aSToomas Soome 
916*4a5d661aSToomas Soome 	ind_block_num = ino->i_ib[level];
917*4a5d661aSToomas Soome 
918*4a5d661aSToomas Soome 	for (; level >= 0; level--) {
919*4a5d661aSToomas Soome 		if (ind_block_num == 0) {
920*4a5d661aSToomas Soome 			*vblknr = 0;	/* missing */
921*4a5d661aSToomas Soome 			return (0);
922*4a5d661aSToomas Soome 		}
923*4a5d661aSToomas Soome 
924*4a5d661aSToomas Soome 		twiddle(1);
925*4a5d661aSToomas Soome 		NANDFS_DEBUG("calling get_map with %jx\n", ind_block_num);
926*4a5d661aSToomas Soome 		map = nandfs_get_map(fs, node, ind_block_num, phys);
927*4a5d661aSToomas Soome 		if (map == NULL)
928*4a5d661aSToomas Soome 			return (EIO);
929*4a5d661aSToomas Soome 
930*4a5d661aSToomas Soome 		if (level > 0) {
931*4a5d661aSToomas Soome 			idx = lblknr / fs->nf_nindir[level - 1];
932*4a5d661aSToomas Soome 			lblknr %= fs->nf_nindir[level - 1];
933*4a5d661aSToomas Soome 		} else
934*4a5d661aSToomas Soome 			idx = lblknr;
935*4a5d661aSToomas Soome 
936*4a5d661aSToomas Soome 		ind_block_num = ((nandfs_daddr_t *)map)[idx];
937*4a5d661aSToomas Soome 	}
938*4a5d661aSToomas Soome 
939*4a5d661aSToomas Soome 	*vblknr = ind_block_num;
940*4a5d661aSToomas Soome 
941*4a5d661aSToomas Soome 	return (0);
942*4a5d661aSToomas Soome }
943*4a5d661aSToomas Soome 
944*4a5d661aSToomas Soome static nandfs_daddr_t
945*4a5d661aSToomas Soome nandfs_vtop(struct nandfs *fs, nandfs_daddr_t vblocknr)
946*4a5d661aSToomas Soome {
947*4a5d661aSToomas Soome 	nandfs_lbn_t blocknr;
948*4a5d661aSToomas Soome 	nandfs_daddr_t pblocknr;
949*4a5d661aSToomas Soome 	int entrynr;
950*4a5d661aSToomas Soome 	struct nandfs_dat_entry *dat;
951*4a5d661aSToomas Soome 
952*4a5d661aSToomas Soome 	dat = malloc(fs->nf_blocksize);
953*4a5d661aSToomas Soome 	nandfs_mdt_trans(&fs->nf_datfile_mdt, vblocknr, &blocknr, &entrynr);
954*4a5d661aSToomas Soome 
955*4a5d661aSToomas Soome 	if (nandfs_read_inode(fs, &fs->nf_datfile, blocknr, 1, dat, 1)) {
956*4a5d661aSToomas Soome 		free(dat);
957*4a5d661aSToomas Soome 		return (0);
958*4a5d661aSToomas Soome 	}
959*4a5d661aSToomas Soome 
960*4a5d661aSToomas Soome 	NANDFS_DEBUG("nandfs_vtop entrynr=%d vblocknr=%lld pblocknr=%lld\n",
961*4a5d661aSToomas Soome 	    entrynr, vblocknr, dat[entrynr].de_blocknr);
962*4a5d661aSToomas Soome 
963*4a5d661aSToomas Soome 	pblocknr = dat[entrynr].de_blocknr;
964*4a5d661aSToomas Soome 	free(dat);
965*4a5d661aSToomas Soome 	return (pblocknr);
966*4a5d661aSToomas Soome }
967*4a5d661aSToomas Soome 
968*4a5d661aSToomas Soome static void
969*4a5d661aSToomas Soome nandfs_calc_mdt_consts(int blocksize, struct nandfs_mdt *mdt, int entry_size)
970*4a5d661aSToomas Soome {
971*4a5d661aSToomas Soome 
972*4a5d661aSToomas Soome 	mdt->entries_per_group = blocksize * 8;	   /* bits in sector */
973*4a5d661aSToomas Soome 	mdt->entries_per_block = blocksize / entry_size;
974*4a5d661aSToomas Soome 	mdt->blocks_per_group  =
975*4a5d661aSToomas Soome 	    (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1;
976*4a5d661aSToomas Soome 	mdt->groups_per_desc_block =
977*4a5d661aSToomas Soome 	    blocksize / sizeof(struct nandfs_block_group_desc);
978*4a5d661aSToomas Soome 	mdt->blocks_per_desc_block =
979*4a5d661aSToomas Soome 	    mdt->groups_per_desc_block * mdt->blocks_per_group + 1;
980*4a5d661aSToomas Soome }
981*4a5d661aSToomas Soome 
982*4a5d661aSToomas Soome static void
983*4a5d661aSToomas Soome nandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index,
984*4a5d661aSToomas Soome     nandfs_daddr_t *blocknr, uint32_t *entry_in_block)
985*4a5d661aSToomas Soome {
986*4a5d661aSToomas Soome 	nandfs_daddr_t blknr;
987*4a5d661aSToomas Soome 	uint64_t group, group_offset, blocknr_in_group;
988*4a5d661aSToomas Soome 	uint64_t desc_block, desc_offset;
989*4a5d661aSToomas Soome 
990*4a5d661aSToomas Soome 	/* Calculate our offset in the file */
991*4a5d661aSToomas Soome 	group = index / mdt->entries_per_group;
992*4a5d661aSToomas Soome 	group_offset = index % mdt->entries_per_group;
993*4a5d661aSToomas Soome 	desc_block = group / mdt->groups_per_desc_block;
994*4a5d661aSToomas Soome 	desc_offset = group % mdt->groups_per_desc_block;
995*4a5d661aSToomas Soome 	blocknr_in_group = group_offset / mdt->entries_per_block;
996*4a5d661aSToomas Soome 
997*4a5d661aSToomas Soome 	/* To descgroup offset */
998*4a5d661aSToomas Soome 	blknr = 1 + desc_block * mdt->blocks_per_desc_block;
999*4a5d661aSToomas Soome 
1000*4a5d661aSToomas Soome 	/* To group offset */
1001*4a5d661aSToomas Soome 	blknr += desc_offset * mdt->blocks_per_group;
1002*4a5d661aSToomas Soome 
1003*4a5d661aSToomas Soome 	/* To actual file block */
1004*4a5d661aSToomas Soome 	blknr += 1 + blocknr_in_group;
1005*4a5d661aSToomas Soome 
1006*4a5d661aSToomas Soome 	*blocknr        = blknr;
1007*4a5d661aSToomas Soome 	*entry_in_block = group_offset % mdt->entries_per_block;
1008*4a5d661aSToomas Soome }
1009*4a5d661aSToomas Soome 
1010*4a5d661aSToomas Soome static int
1011*4a5d661aSToomas Soome ioread(struct open_file *f, off_t pos, void *buf, u_int length)
1012*4a5d661aSToomas Soome {
1013*4a5d661aSToomas Soome 	void *buffer;
1014*4a5d661aSToomas Soome 	int err;
1015*4a5d661aSToomas Soome 	int bsize = ((struct nandfs *)f->f_fsdata)->nf_sectorsize;
1016*4a5d661aSToomas Soome 	u_int off, nsec;
1017*4a5d661aSToomas Soome 
1018*4a5d661aSToomas Soome 	off = pos % bsize;
1019*4a5d661aSToomas Soome 	pos /= bsize;
1020*4a5d661aSToomas Soome 	nsec = (length + (bsize - 1)) / bsize;
1021*4a5d661aSToomas Soome 
1022*4a5d661aSToomas Soome 	NANDFS_DEBUG("pos=%lld length=%d off=%d nsec=%d\n", pos, length,
1023*4a5d661aSToomas Soome 	    off, nsec);
1024*4a5d661aSToomas Soome 
1025*4a5d661aSToomas Soome 	buffer = malloc(nsec * bsize);
1026*4a5d661aSToomas Soome 
1027*4a5d661aSToomas Soome 	err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, pos,
1028*4a5d661aSToomas Soome 	    nsec * bsize, buffer, NULL);
1029*4a5d661aSToomas Soome 
1030*4a5d661aSToomas Soome 	memcpy(buf, (void *)((uintptr_t)buffer + off), length);
1031*4a5d661aSToomas Soome 	free(buffer);
1032*4a5d661aSToomas Soome 
1033*4a5d661aSToomas Soome 	return (err);
1034*4a5d661aSToomas Soome }
1035*4a5d661aSToomas Soome 
1036*4a5d661aSToomas Soome static int
1037*4a5d661aSToomas Soome nandfs_probe_sectorsize(struct open_file *f)
1038*4a5d661aSToomas Soome {
1039*4a5d661aSToomas Soome 	void *buffer;
1040*4a5d661aSToomas Soome 	int i, err;
1041*4a5d661aSToomas Soome 
1042*4a5d661aSToomas Soome 	buffer = malloc(16 * 1024);
1043*4a5d661aSToomas Soome 
1044*4a5d661aSToomas Soome 	NANDFS_DEBUG("probing for sector size: ");
1045*4a5d661aSToomas Soome 
1046*4a5d661aSToomas Soome 	for (i = 512; i < (16 * 1024); i <<= 1) {
1047*4a5d661aSToomas Soome 		NANDFS_DEBUG("%d ", i);
1048*4a5d661aSToomas Soome 		err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 0, i,
1049*4a5d661aSToomas Soome 		    buffer, NULL);
1050*4a5d661aSToomas Soome 
1051*4a5d661aSToomas Soome 		if (err == 0) {
1052*4a5d661aSToomas Soome 			NANDFS_DEBUG("found");
1053*4a5d661aSToomas Soome 			free(buffer);
1054*4a5d661aSToomas Soome 			return (i);
1055*4a5d661aSToomas Soome 		}
1056*4a5d661aSToomas Soome 	}
1057*4a5d661aSToomas Soome 
1058*4a5d661aSToomas Soome 	free(buffer);
1059*4a5d661aSToomas Soome 	NANDFS_DEBUG("not found\n");
1060*4a5d661aSToomas Soome 	return (-1);
1061*4a5d661aSToomas Soome }
1062