1235537Sgber/*-
2235537Sgber * Copyright (c) 2010-2012 Semihalf.
3235537Sgber * All rights reserved.
4235537Sgber *
5235537Sgber * Redistribution and use in source and binary forms, with or without
6235537Sgber * modification, are permitted provided that the following conditions
7235537Sgber * are met:
8235537Sgber * 1. Redistributions of source code must retain the above copyright
9235537Sgber *    notice, this list of conditions and the following disclaimer.
10235537Sgber * 2. Redistributions in binary form must reproduce the above copyright
11235537Sgber *    notice, this list of conditions and the following disclaimer in the
12235537Sgber *    documentation and/or other materials provided with the distribution.
13235537Sgber *
14235537Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15235537Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16235537Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17235537Sgber * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18235537Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19235537Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20235537Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21235537Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22235537Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23235537Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24235537Sgber * SUCH DAMAGE.
25235537Sgber */
26235537Sgber
27235537Sgber#include <sys/cdefs.h>
28235537Sgber__FBSDID("$FreeBSD: stable/11/stand/libsa/nandfs.c 329132 2018-02-11 19:51:29Z kevans $");
29235537Sgber
30235537Sgber#include <sys/param.h>
31235537Sgber#include <sys/queue.h>
32235537Sgber#include <sys/stdint.h>
33235537Sgber#include <ufs/ufs/dinode.h>
34235537Sgber#include <fs/nandfs/nandfs_fs.h>
35235537Sgber#include "stand.h"
36235537Sgber#include "string.h"
37235537Sgber#include "zlib.h"
38235537Sgber
39235537Sgber#define DEBUG
40235537Sgber#undef DEBUG
41235537Sgber#ifdef DEBUG
42235537Sgber#define NANDFS_DEBUG(fmt, args...) do { \
43235537Sgber    printf("NANDFS_DEBUG:" fmt "\n", ##args); } while (0)
44235537Sgber#else
45235537Sgber#define NANDFS_DEBUG(fmt, args...)
46235537Sgber#endif
47235537Sgber
48235537Sgberstruct nandfs_mdt {
49235537Sgber	uint32_t	entries_per_block;
50235537Sgber	uint32_t	entries_per_group;
51235537Sgber	uint32_t	blocks_per_group;
52235537Sgber	uint32_t	groups_per_desc_block;	/* desc is super group */
53235537Sgber	uint32_t	blocks_per_desc_block;	/* desc is super group */
54235537Sgber};
55235537Sgber
56235537Sgberstruct bmap_buf {
57235537Sgber	LIST_ENTRY(bmap_buf)	list;
58235537Sgber	nandfs_daddr_t		blknr;
59235537Sgber	uint64_t		*map;
60235537Sgber};
61235537Sgber
62235537Sgberstruct nandfs_node {
63235537Sgber	struct nandfs_inode	*inode;
64235537Sgber	LIST_HEAD(, bmap_buf)	bmap_bufs;
65235537Sgber};
66235537Sgberstruct nandfs {
67235537Sgber	int	nf_blocksize;
68235537Sgber	int	nf_sectorsize;
69235537Sgber	int	nf_cpno;
70235537Sgber
71235537Sgber	struct open_file	*nf_file;
72235537Sgber	struct nandfs_node	*nf_opened_node;
73235537Sgber	u_int			nf_offset;
74235537Sgber	uint8_t			*nf_buf;
75235537Sgber	int64_t			nf_buf_blknr;
76235537Sgber
77235537Sgber	struct nandfs_fsdata		*nf_fsdata;
78235537Sgber	struct nandfs_super_block	*nf_sb;
79235537Sgber	struct nandfs_segment_summary	nf_segsum;
80235537Sgber	struct nandfs_checkpoint	nf_checkpoint;
81235537Sgber	struct nandfs_super_root	nf_sroot;
82235537Sgber	struct nandfs_node		nf_ifile;
83235537Sgber	struct nandfs_node		nf_datfile;
84235537Sgber	struct nandfs_node		nf_cpfile;
85235537Sgber	struct nandfs_mdt		nf_datfile_mdt;
86235537Sgber	struct nandfs_mdt		nf_ifile_mdt;
87235537Sgber
88235537Sgber	int nf_nindir[NIADDR];
89235537Sgber};
90235537Sgber
91235537Sgberstatic int nandfs_open(const char *, struct open_file *);
92235537Sgberstatic int nandfs_close(struct open_file *);
93235537Sgberstatic int nandfs_read(struct open_file *, void *, size_t, size_t *);
94235537Sgberstatic off_t nandfs_seek(struct open_file *, off_t, int);
95235537Sgberstatic int nandfs_stat(struct open_file *, struct stat *);
96235537Sgberstatic int nandfs_readdir(struct open_file *, struct dirent *);
97235537Sgber
98247613Smarcelstatic int nandfs_buf_read(struct nandfs *, void **, size_t *);
99235537Sgberstatic struct nandfs_node *nandfs_lookup_path(struct nandfs *, const char *);
100235537Sgberstatic int nandfs_read_inode(struct nandfs *, struct nandfs_node *,
101235537Sgber    nandfs_lbn_t, u_int, void *, int);
102235537Sgberstatic int nandfs_read_blk(struct nandfs *, nandfs_daddr_t, void *, int);
103235537Sgberstatic int nandfs_bmap_lookup(struct nandfs *, struct nandfs_node *,
104235537Sgber    nandfs_lbn_t, nandfs_daddr_t *, int);
105235537Sgberstatic int nandfs_get_checkpoint(struct nandfs *, uint64_t,
106235537Sgber    struct nandfs_checkpoint *);
107235537Sgberstatic nandfs_daddr_t nandfs_vtop(struct nandfs *, nandfs_daddr_t);
108235537Sgberstatic void nandfs_calc_mdt_consts(int, struct nandfs_mdt *, int);
109235537Sgberstatic void nandfs_mdt_trans(struct nandfs_mdt *, uint64_t,
110235537Sgber    nandfs_daddr_t *, uint32_t *);
111235537Sgberstatic int ioread(struct open_file *, off_t, void *, u_int);
112235537Sgberstatic int nandfs_probe_sectorsize(struct open_file *);
113235537Sgber
114235537Sgberstruct fs_ops nandfs_fsops = {
115235537Sgber	"nandfs",
116235537Sgber	nandfs_open,
117235537Sgber	nandfs_close,
118235537Sgber	nandfs_read,
119235537Sgber	null_write,
120235537Sgber	nandfs_seek,
121235537Sgber	nandfs_stat,
122235537Sgber	nandfs_readdir
123235537Sgber};
124235537Sgber
125235537Sgber#define	NINDIR(fs)	((fs)->nf_blocksize / sizeof(nandfs_daddr_t))
126235537Sgber
127247611Smarcel/* from NetBSD's src/sys/net/if_ethersubr.c */
128247611Smarcelstatic uint32_t
129247611Smarcelnandfs_crc32(uint32_t crc, const uint8_t *buf, size_t len)
130247611Smarcel{
131247611Smarcel	static const uint32_t crctab[] = {
132247611Smarcel		0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
133247611Smarcel		0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
134247611Smarcel		0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
135247611Smarcel		0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
136247611Smarcel	};
137247611Smarcel	size_t i;
138247611Smarcel
139247611Smarcel	crc = crc ^ ~0U;
140247611Smarcel	for (i = 0; i < len; i++) {
141247611Smarcel		crc ^= buf[i];
142247611Smarcel		crc = (crc >> 4) ^ crctab[crc & 0xf];
143247611Smarcel		crc = (crc >> 4) ^ crctab[crc & 0xf];
144247611Smarcel	}
145247611Smarcel	return (crc ^ ~0U);
146247611Smarcel}
147247611Smarcel
148235537Sgberstatic int
149235537Sgbernandfs_check_fsdata_crc(struct nandfs_fsdata *fsdata)
150235537Sgber{
151235537Sgber	uint32_t fsdata_crc, comp_crc;
152235537Sgber
153235537Sgber	if (fsdata->f_magic != NANDFS_FSDATA_MAGIC)
154235537Sgber		return (0);
155235537Sgber
156235537Sgber	/* Preserve crc */
157235537Sgber	fsdata_crc = fsdata->f_sum;
158235537Sgber
159235537Sgber	/* Calculate */
160235537Sgber	fsdata->f_sum = (0);
161247611Smarcel	comp_crc = nandfs_crc32(0, (uint8_t *)fsdata, fsdata->f_bytes);
162235537Sgber
163235537Sgber	/* Restore */
164235537Sgber	fsdata->f_sum = fsdata_crc;
165235537Sgber
166235537Sgber	/* Check CRC */
167235537Sgber	return (fsdata_crc == comp_crc);
168235537Sgber}
169235537Sgber
170235537Sgberstatic int
171235537Sgbernandfs_check_superblock_crc(struct nandfs_fsdata *fsdata,
172235537Sgber    struct nandfs_super_block *super)
173235537Sgber{
174235537Sgber	uint32_t super_crc, comp_crc;
175235537Sgber
176235537Sgber	/* Check super block magic */
177235537Sgber	if (super->s_magic != NANDFS_SUPER_MAGIC)
178235537Sgber		return (0);
179235537Sgber
180235537Sgber	/* Preserve CRC */
181235537Sgber	super_crc = super->s_sum;
182235537Sgber
183235537Sgber	/* Calculate */
184235537Sgber	super->s_sum = (0);
185247611Smarcel	comp_crc = nandfs_crc32(0, (uint8_t *)super, fsdata->f_sbbytes);
186235537Sgber
187235537Sgber	/* Restore */
188235537Sgber	super->s_sum = super_crc;
189235537Sgber
190235537Sgber	/* Check CRC */
191235537Sgber	return (super_crc == comp_crc);
192235537Sgber}
193235537Sgber
194235537Sgberstatic int
195235537Sgbernandfs_find_super_block(struct nandfs *fs, struct open_file *f)
196235537Sgber{
197235537Sgber	struct nandfs_super_block *sb;
198241157Sgber	int i, j, n, s;
199235537Sgber	int sectors_to_read, error;
200235537Sgber
201235537Sgber	sb = malloc(fs->nf_sectorsize);
202235537Sgber	if (sb == NULL)
203235537Sgber		return (ENOMEM);
204235537Sgber
205235537Sgber	memset(fs->nf_sb, 0, sizeof(*fs->nf_sb));
206235537Sgber
207235537Sgber	sectors_to_read = (NANDFS_NFSAREAS * fs->nf_fsdata->f_erasesize) /
208235537Sgber	    fs->nf_sectorsize;
209235537Sgber	for (i = 0; i < sectors_to_read; i++) {
210235537Sgber		NANDFS_DEBUG("reading i %d offset %d\n", i,
211235537Sgber		    i * fs->nf_sectorsize);
212235537Sgber		error = ioread(f, i * fs->nf_sectorsize, (char *)sb,
213235537Sgber		    fs->nf_sectorsize);
214235537Sgber		if (error) {
215235537Sgber			NANDFS_DEBUG("error %d\n", error);
216235537Sgber			continue;
217235537Sgber		}
218235537Sgber		n = fs->nf_sectorsize / sizeof(struct nandfs_super_block);
219241157Sgber		s = 0;
220235537Sgber		if ((i * fs->nf_sectorsize) % fs->nf_fsdata->f_erasesize == 0) {
221235537Sgber			if (fs->nf_sectorsize == sizeof(struct nandfs_fsdata))
222235537Sgber				continue;
223235537Sgber			else {
224241157Sgber				s += (sizeof(struct nandfs_fsdata) /
225235537Sgber				    sizeof(struct nandfs_super_block));
226235537Sgber			}
227235537Sgber		}
228235537Sgber
229241157Sgber		for (j = s; j < n; j++) {
230235537Sgber			if (!nandfs_check_superblock_crc(fs->nf_fsdata, &sb[j]))
231235537Sgber				continue;
232241157Sgber			NANDFS_DEBUG("magic %x wtime %jd, lastcp 0x%jx\n",
233241157Sgber			    sb[j].s_magic, sb[j].s_wtime, sb[j].s_last_cno);
234241157Sgber			if (sb[j].s_last_cno > fs->nf_sb->s_last_cno)
235235537Sgber				memcpy(fs->nf_sb, &sb[j], sizeof(*fs->nf_sb));
236235537Sgber		}
237235537Sgber	}
238235537Sgber
239235537Sgber	free(sb);
240235537Sgber
241235537Sgber	return (fs->nf_sb->s_magic != 0 ? 0 : EINVAL);
242235537Sgber}
243235537Sgber
244235537Sgberstatic int
245235537Sgbernandfs_find_fsdata(struct nandfs *fs, struct open_file *f)
246235537Sgber{
247235537Sgber	int offset, error, i;
248235537Sgber
249235537Sgber	NANDFS_DEBUG("starting\n");
250235537Sgber
251235537Sgber	offset = 0;
252235537Sgber	for (i = 0; i < 64 * NANDFS_NFSAREAS; i++) {
253235537Sgber		error = ioread(f, offset, (char *)fs->nf_fsdata,
254235537Sgber		    sizeof(struct nandfs_fsdata));
255235537Sgber		if (error)
256235537Sgber			return (error);
257235537Sgber		if (fs->nf_fsdata->f_magic == NANDFS_FSDATA_MAGIC) {
258235537Sgber			NANDFS_DEBUG("found at %x, volume %s\n", offset,
259235537Sgber			    fs->nf_fsdata->f_volume_name);
260235537Sgber			if (nandfs_check_fsdata_crc(fs->nf_fsdata))
261235537Sgber				break;
262235537Sgber		}
263235537Sgber		offset += fs->nf_sectorsize;
264235537Sgber	}
265235537Sgber
266235537Sgber	return (error);
267235537Sgber}
268235537Sgber
269235537Sgberstatic int
270235537Sgbernandfs_read_structures(struct nandfs *fs, struct open_file *f)
271235537Sgber{
272235537Sgber	int error;
273235537Sgber
274235537Sgber	error = nandfs_find_fsdata(fs, f);
275235537Sgber	if (error)
276235537Sgber		return (error);
277235537Sgber
278235537Sgber	error = nandfs_find_super_block(fs, f);
279235537Sgber
280235537Sgber	if (error == 0)
281235537Sgber		NANDFS_DEBUG("selected sb with w_time %jd last_pseg %jx\n",
282235537Sgber		    fs->nf_sb->s_wtime, fs->nf_sb->s_last_pseg);
283235537Sgber
284235537Sgber	return (error);
285235537Sgber}
286235537Sgber
287235537Sgberstatic int
288235537Sgbernandfs_mount(struct nandfs *fs, struct open_file *f)
289235537Sgber{
290235537Sgber	int err = 0, level;
291235537Sgber	uint64_t last_pseg;
292235537Sgber
293235537Sgber	fs->nf_fsdata = malloc(sizeof(struct nandfs_fsdata));
294235537Sgber	fs->nf_sb = malloc(sizeof(struct nandfs_super_block));
295235537Sgber
296235537Sgber	err = nandfs_read_structures(fs, f);
297235537Sgber	if (err) {
298235537Sgber		free(fs->nf_fsdata);
299235537Sgber		free(fs->nf_sb);
300235537Sgber		return (err);
301235537Sgber	}
302235537Sgber
303235537Sgber	fs->nf_blocksize = 1 << (fs->nf_fsdata->f_log_block_size + 10);
304235537Sgber
305235537Sgber	NANDFS_DEBUG("using superblock with wtime %jd\n", fs->nf_sb->s_wtime);
306235537Sgber
307235537Sgber	fs->nf_cpno = fs->nf_sb->s_last_cno;
308235537Sgber	last_pseg = fs->nf_sb->s_last_pseg;
309235537Sgber
310235537Sgber	/*
311235537Sgber	 * Calculate indirect block levels.
312235537Sgber	 */
313235537Sgber	nandfs_daddr_t mult;
314235537Sgber
315235537Sgber	mult = 1;
316235537Sgber	for (level = 0; level < NIADDR; level++) {
317235537Sgber		mult *= NINDIR(fs);
318235537Sgber		fs->nf_nindir[level] = mult;
319235537Sgber	}
320235537Sgber
321235537Sgber	nandfs_calc_mdt_consts(fs->nf_blocksize, &fs->nf_datfile_mdt,
322235537Sgber	    fs->nf_fsdata->f_dat_entry_size);
323235537Sgber
324235537Sgber	nandfs_calc_mdt_consts(fs->nf_blocksize, &fs->nf_ifile_mdt,
325235537Sgber	    fs->nf_fsdata->f_inode_size);
326235537Sgber
327235537Sgber	err = ioread(f, last_pseg * fs->nf_blocksize, &fs->nf_segsum,
328235537Sgber	    sizeof(struct nandfs_segment_summary));
329235537Sgber	if (err) {
330235537Sgber		free(fs->nf_sb);
331235537Sgber		free(fs->nf_fsdata);
332235537Sgber		return (err);
333235537Sgber	}
334235537Sgber
335235537Sgber	err = ioread(f, (last_pseg + fs->nf_segsum.ss_nblocks - 1) *
336235537Sgber	    fs->nf_blocksize, &fs->nf_sroot, sizeof(struct nandfs_super_root));
337235537Sgber	if (err) {
338235537Sgber		free(fs->nf_sb);
339235537Sgber		free(fs->nf_fsdata);
340235537Sgber		return (err);
341235537Sgber	}
342235537Sgber
343235537Sgber	fs->nf_datfile.inode = &fs->nf_sroot.sr_dat;
344235537Sgber	LIST_INIT(&fs->nf_datfile.bmap_bufs);
345235537Sgber	fs->nf_cpfile.inode = &fs->nf_sroot.sr_cpfile;
346235537Sgber	LIST_INIT(&fs->nf_cpfile.bmap_bufs);
347235537Sgber
348235537Sgber	err = nandfs_get_checkpoint(fs, fs->nf_cpno, &fs->nf_checkpoint);
349235537Sgber	if (err) {
350235537Sgber		free(fs->nf_sb);
351235537Sgber		free(fs->nf_fsdata);
352235537Sgber		return (err);
353235537Sgber	}
354235537Sgber
355235537Sgber	NANDFS_DEBUG("checkpoint cp_cno=%lld\n", fs->nf_checkpoint.cp_cno);
356235537Sgber	NANDFS_DEBUG("checkpoint cp_inodes_count=%lld\n",
357235537Sgber	    fs->nf_checkpoint.cp_inodes_count);
358235537Sgber	NANDFS_DEBUG("checkpoint cp_ifile_inode.i_blocks=%lld\n",
359235537Sgber	    fs->nf_checkpoint.cp_ifile_inode.i_blocks);
360235537Sgber
361235537Sgber	fs->nf_ifile.inode = &fs->nf_checkpoint.cp_ifile_inode;
362235537Sgber	LIST_INIT(&fs->nf_ifile.bmap_bufs);
363235537Sgber	return (0);
364235537Sgber}
365235537Sgber
366235537Sgber#define NINDIR(fs)	((fs)->nf_blocksize / sizeof(nandfs_daddr_t))
367235537Sgber
368235537Sgberstatic int
369235537Sgbernandfs_open(const char *path, struct open_file *f)
370235537Sgber{
371235537Sgber	struct nandfs *fs;
372235537Sgber	struct nandfs_node *node;
373235537Sgber	int err, bsize, level;
374235537Sgber
375235537Sgber	NANDFS_DEBUG("nandfs_open('%s', %p)\n", path, f);
376235537Sgber
377235537Sgber	fs = malloc(sizeof(struct nandfs));
378235537Sgber	f->f_fsdata = fs;
379235537Sgber	fs->nf_file = f;
380235537Sgber
381235537Sgber	bsize = nandfs_probe_sectorsize(f);
382235537Sgber	if (bsize < 0) {
383235537Sgber		printf("Cannot probe medium sector size\n");
384235537Sgber		return (EINVAL);
385235537Sgber	}
386235537Sgber
387235537Sgber	fs->nf_sectorsize = bsize;
388235537Sgber
389235537Sgber	/*
390235537Sgber	 * Calculate indirect block levels.
391235537Sgber	 */
392235537Sgber	nandfs_daddr_t mult;
393235537Sgber
394235537Sgber	mult = 1;
395235537Sgber	for (level = 0; level < NIADDR; level++) {
396235537Sgber		mult *= NINDIR(fs);
397235537Sgber		fs->nf_nindir[level] = mult;
398235537Sgber	}
399235537Sgber
400235537Sgber	NANDFS_DEBUG("fs %p nf_sectorsize=%x\n", fs, fs->nf_sectorsize);
401235537Sgber
402235537Sgber	err = nandfs_mount(fs, f);
403235537Sgber	if (err) {
404235537Sgber		NANDFS_DEBUG("Cannot mount nandfs: %s\n", strerror(err));
405235537Sgber		return (err);
406235537Sgber	}
407235537Sgber
408235537Sgber	node = nandfs_lookup_path(fs, path);
409235537Sgber	if (node == NULL)
410235537Sgber		return (EINVAL);
411235537Sgber
412235537Sgber	fs->nf_offset = 0;
413235537Sgber	fs->nf_buf = NULL;
414235537Sgber	fs->nf_buf_blknr = -1;
415235537Sgber	fs->nf_opened_node = node;
416235537Sgber	LIST_INIT(&fs->nf_opened_node->bmap_bufs);
417235537Sgber	return (0);
418235537Sgber}
419235537Sgber
420247612Smarcelstatic void
421235537Sgbernandfs_free_node(struct nandfs_node *node)
422235537Sgber{
423235537Sgber	struct bmap_buf *bmap, *tmp;
424235537Sgber
425235537Sgber	free(node->inode);
426235537Sgber	LIST_FOREACH_SAFE(bmap, &node->bmap_bufs, list, tmp) {
427235537Sgber		LIST_REMOVE(bmap, list);
428235537Sgber		free(bmap->map);
429235537Sgber		free(bmap);
430235537Sgber	}
431235537Sgber	free(node);
432235537Sgber}
433235537Sgber
434235537Sgberstatic int
435235537Sgbernandfs_close(struct open_file *f)
436235537Sgber{
437235537Sgber	struct nandfs *fs = f->f_fsdata;
438235537Sgber
439235537Sgber	NANDFS_DEBUG("nandfs_close(%p)\n", f);
440235537Sgber
441235537Sgber	if (fs->nf_buf != NULL)
442235537Sgber		free(fs->nf_buf);
443235537Sgber
444235537Sgber	nandfs_free_node(fs->nf_opened_node);
445235537Sgber	free(fs->nf_sb);
446235537Sgber	free(fs);
447247612Smarcel	return (0);
448235537Sgber}
449235537Sgber
450235537Sgberstatic int
451235537Sgbernandfs_read(struct open_file *f, void *addr, size_t size, size_t *resid)
452235537Sgber{
453235537Sgber	struct nandfs *fs = (struct nandfs *)f->f_fsdata;
454235537Sgber	size_t csize, buf_size;
455247613Smarcel	void *buf;
456235537Sgber	int error = 0;
457235537Sgber
458235537Sgber	NANDFS_DEBUG("nandfs_read(file=%p, addr=%p, size=%d)\n", f, addr, size);
459235537Sgber
460235537Sgber	while (size != 0) {
461235537Sgber		if (fs->nf_offset >= fs->nf_opened_node->inode->i_size)
462235537Sgber			break;
463235537Sgber
464247613Smarcel		error = nandfs_buf_read(fs, &buf, &buf_size);
465235537Sgber		if (error)
466235537Sgber			break;
467235537Sgber
468235537Sgber		csize = size;
469235537Sgber		if (csize > buf_size)
470235537Sgber			csize = buf_size;
471235537Sgber
472235537Sgber		bcopy(buf, addr, csize);
473235537Sgber
474235537Sgber		fs->nf_offset += csize;
475235537Sgber		addr = (char *)addr + csize;
476235537Sgber		size -= csize;
477235537Sgber	}
478235537Sgber
479235537Sgber	if (resid)
480235537Sgber		*resid = size;
481235537Sgber	return (error);
482235537Sgber}
483235537Sgber
484235537Sgberstatic off_t
485235537Sgbernandfs_seek(struct open_file *f, off_t offset, int where)
486235537Sgber{
487235537Sgber	struct nandfs *fs = f->f_fsdata;
488235537Sgber	off_t off;
489235537Sgber	u_int size;
490235537Sgber
491235537Sgber	NANDFS_DEBUG("nandfs_seek(file=%p, offset=%lld, where=%d)\n", f,
492235537Sgber	    offset, where);
493235537Sgber
494235537Sgber	size = fs->nf_opened_node->inode->i_size;
495235537Sgber
496235537Sgber	switch (where) {
497235537Sgber	case SEEK_SET:
498235537Sgber		off = 0;
499235537Sgber		break;
500235537Sgber	case SEEK_CUR:
501235537Sgber		off = fs->nf_offset;
502235537Sgber		break;
503235537Sgber	case SEEK_END:
504235537Sgber		off = size;
505235537Sgber		break;
506235537Sgber	default:
507235537Sgber		errno = EINVAL;
508235537Sgber		return (-1);
509235537Sgber	}
510235537Sgber
511235537Sgber	off += offset;
512235537Sgber	if (off < 0 || off > size) {
513235537Sgber		errno = EINVAL;
514235537Sgber		return(-1);
515235537Sgber	}
516235537Sgber
517235537Sgber	fs->nf_offset = (u_int)off;
518235537Sgber
519235537Sgber	return (off);
520235537Sgber}
521235537Sgber
522235537Sgberstatic int
523235537Sgbernandfs_stat(struct open_file *f, struct stat *sb)
524235537Sgber{
525235537Sgber	struct nandfs *fs = f->f_fsdata;
526235537Sgber
527235537Sgber	NANDFS_DEBUG("nandfs_stat(file=%p, stat=%p)\n", f, sb);
528235537Sgber
529235537Sgber	sb->st_size = fs->nf_opened_node->inode->i_size;
530235537Sgber	sb->st_mode = fs->nf_opened_node->inode->i_mode;
531235537Sgber	sb->st_uid = fs->nf_opened_node->inode->i_uid;
532235537Sgber	sb->st_gid = fs->nf_opened_node->inode->i_gid;
533235537Sgber	return (0);
534235537Sgber}
535235537Sgber
536235537Sgberstatic int
537235537Sgbernandfs_readdir(struct open_file *f, struct dirent *d)
538235537Sgber{
539235537Sgber	struct nandfs *fs = f->f_fsdata;
540235537Sgber	struct nandfs_dir_entry *dirent;
541247613Smarcel	void *buf;
542235537Sgber	size_t buf_size;
543235537Sgber
544235537Sgber	NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)\n", f, d);
545235537Sgber
546235537Sgber	if (fs->nf_offset >= fs->nf_opened_node->inode->i_size) {
547235537Sgber		NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) ENOENT\n",
548235537Sgber		    f, d);
549235537Sgber		return (ENOENT);
550235537Sgber	}
551235537Sgber
552247613Smarcel	if (nandfs_buf_read(fs, &buf, &buf_size)) {
553235537Sgber		NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)"
554235537Sgber		    "buf_read failed\n", f, d);
555235537Sgber		return (EIO);
556235537Sgber	}
557235537Sgber
558235537Sgber	NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) moving forward\n",
559235537Sgber	    f, d);
560235537Sgber
561235537Sgber	dirent = (struct nandfs_dir_entry *)buf;
562235537Sgber	fs->nf_offset += dirent->rec_len;
563235537Sgber	strncpy(d->d_name, dirent->name, dirent->name_len);
564235537Sgber	d->d_name[dirent->name_len] = '\0';
565235537Sgber	d->d_type = dirent->file_type;
566235537Sgber	return (0);
567235537Sgber}
568235537Sgber
569235537Sgberstatic int
570247613Smarcelnandfs_buf_read(struct nandfs *fs, void **buf_p, size_t *size_p)
571235537Sgber{
572235537Sgber	nandfs_daddr_t blknr, blkoff;
573235537Sgber
574235537Sgber	blknr = fs->nf_offset / fs->nf_blocksize;
575235537Sgber	blkoff = fs->nf_offset % fs->nf_blocksize;
576235537Sgber
577235537Sgber	if (blknr != fs->nf_buf_blknr) {
578235537Sgber		if (fs->nf_buf == NULL)
579235537Sgber			fs->nf_buf = malloc(fs->nf_blocksize);
580235537Sgber
581235537Sgber		if (nandfs_read_inode(fs, fs->nf_opened_node, blknr, 1,
582235537Sgber		    fs->nf_buf, 0))
583235537Sgber			return (EIO);
584235537Sgber
585235537Sgber		fs->nf_buf_blknr = blknr;
586235537Sgber	}
587235537Sgber
588235537Sgber	*buf_p = fs->nf_buf + blkoff;
589235537Sgber	*size_p = fs->nf_blocksize - blkoff;
590235537Sgber
591235537Sgber	NANDFS_DEBUG("nandfs_buf_read buf_p=%p size_p=%d\n", *buf_p, *size_p);
592235537Sgber
593235537Sgber	if (*size_p > fs->nf_opened_node->inode->i_size - fs->nf_offset)
594235537Sgber		*size_p = fs->nf_opened_node->inode->i_size - fs->nf_offset;
595235537Sgber
596235537Sgber	return (0);
597235537Sgber}
598235537Sgber
599235537Sgberstatic struct nandfs_node *
600235537Sgbernandfs_lookup_node(struct nandfs *fs, uint64_t ino)
601235537Sgber{
602235537Sgber	uint64_t blocknr;
603235537Sgber	int entrynr;
604235537Sgber	struct nandfs_inode *buffer;
605235537Sgber	struct nandfs_node *node;
606235537Sgber	struct nandfs_inode *inode;
607235537Sgber
608235537Sgber	NANDFS_DEBUG("nandfs_lookup_node ino=%lld\n", ino);
609235537Sgber
610235537Sgber	if (ino == 0) {
611235537Sgber		printf("nandfs_lookup_node: invalid inode requested\n");
612235537Sgber		return (NULL);
613235537Sgber	}
614235537Sgber
615235537Sgber	buffer = malloc(fs->nf_blocksize);
616235537Sgber	inode = malloc(sizeof(struct nandfs_inode));
617235537Sgber	node = malloc(sizeof(struct nandfs_node));
618235537Sgber
619235537Sgber	nandfs_mdt_trans(&fs->nf_ifile_mdt, ino, &blocknr, &entrynr);
620235537Sgber
621235537Sgber	if (nandfs_read_inode(fs, &fs->nf_ifile, blocknr, 1, buffer, 0))
622235537Sgber		return (NULL);
623235537Sgber
624235537Sgber	memcpy(inode, &buffer[entrynr], sizeof(struct nandfs_inode));
625235537Sgber	node->inode = inode;
626235537Sgber	free(buffer);
627235537Sgber	return (node);
628235537Sgber}
629235537Sgber
630235537Sgberstatic struct nandfs_node *
631235537Sgbernandfs_lookup_path(struct nandfs *fs, const char *path)
632235537Sgber{
633235537Sgber	struct nandfs_node *node;
634235537Sgber	struct nandfs_dir_entry *dirent;
635235537Sgber	char *namebuf;
636247613Smarcel	uint64_t i, done, pinode, inode;
637247613Smarcel	int nlinks = 0, counter, len, link_len, nameidx;
638235537Sgber	uint8_t *buffer, *orig;
639235537Sgber	char *strp, *lpath;
640235537Sgber
641235537Sgber	buffer = malloc(fs->nf_blocksize);
642235537Sgber	orig = buffer;
643235537Sgber
644235537Sgber	namebuf = malloc(2 * MAXPATHLEN + 2);
645235537Sgber	strncpy(namebuf, path, MAXPATHLEN);
646235537Sgber	namebuf[MAXPATHLEN] = '\0';
647235537Sgber	done = nameidx = 0;
648235537Sgber	lpath = namebuf;
649235537Sgber
650235537Sgber	/* Get the root inode */
651235537Sgber	node = nandfs_lookup_node(fs, NANDFS_ROOT_INO);
652235537Sgber	inode = NANDFS_ROOT_INO;
653235537Sgber
654235537Sgber	while ((strp = strsep(&lpath, "/")) != NULL) {
655235537Sgber		if (*strp == '\0')
656235537Sgber			continue;
657235537Sgber		if ((node->inode->i_mode & IFMT) != IFDIR) {
658235537Sgber			nandfs_free_node(node);
659235537Sgber			node = NULL;
660235537Sgber			goto out;
661235537Sgber		}
662235537Sgber
663235537Sgber		len = strlen(strp);
664235537Sgber		NANDFS_DEBUG("%s: looking for %s\n", __func__, strp);
665235537Sgber		for (i = 0; i < node->inode->i_blocks; i++) {
666235537Sgber			if (nandfs_read_inode(fs, node, i, 1, orig, 0)) {
667235537Sgber				node = NULL;
668235537Sgber				goto out;
669235537Sgber			}
670235537Sgber
671235537Sgber			buffer = orig;
672235537Sgber			done = counter = 0;
673235537Sgber			while (1) {
674247613Smarcel				dirent =
675247613Smarcel				    (struct nandfs_dir_entry *)(void *)buffer;
676235537Sgber				NANDFS_DEBUG("%s: dirent.name = %s\n",
677235537Sgber				    __func__, dirent->name);
678235537Sgber				NANDFS_DEBUG("%s: dirent.rec_len = %d\n",
679235537Sgber				    __func__, dirent->rec_len);
680235537Sgber				NANDFS_DEBUG("%s: dirent.inode = %lld\n",
681235537Sgber				    __func__, dirent->inode);
682235537Sgber				if (len == dirent->name_len &&
683235537Sgber				    (strncmp(strp, dirent->name, len) == 0) &&
684235537Sgber				    dirent->inode != 0) {
685235537Sgber					nandfs_free_node(node);
686235537Sgber					node = nandfs_lookup_node(fs,
687235537Sgber					    dirent->inode);
688235537Sgber					pinode = inode;
689235537Sgber					inode = dirent->inode;
690235537Sgber					done = 1;
691235537Sgber					break;
692235537Sgber				}
693235537Sgber
694235537Sgber				counter += dirent->rec_len;
695235537Sgber				buffer += dirent->rec_len;
696235537Sgber
697235537Sgber				if (counter == fs->nf_blocksize)
698235537Sgber					break;
699235537Sgber			}
700235537Sgber
701235537Sgber			if (done)
702235537Sgber				break;
703235537Sgber		}
704235537Sgber
705235537Sgber		if (!done) {
706235537Sgber			node = NULL;
707235537Sgber			goto out;
708235537Sgber		}
709235537Sgber
710235537Sgber		NANDFS_DEBUG("%s: %.*s has mode %o\n", __func__,
711235537Sgber		    dirent->name_len, dirent->name, node->inode->i_mode);
712235537Sgber
713235537Sgber		if ((node->inode->i_mode & IFMT) == IFLNK) {
714235537Sgber			NANDFS_DEBUG("%s: %.*s is symlink\n",
715235537Sgber			    __func__, dirent->name_len, dirent->name);
716235537Sgber			link_len = node->inode->i_size;
717235537Sgber
718235537Sgber			if (++nlinks > MAXSYMLINKS) {
719235537Sgber				nandfs_free_node(node);
720235537Sgber				node = NULL;
721235537Sgber				goto out;
722235537Sgber			}
723235537Sgber
724235537Sgber			if (nandfs_read_inode(fs, node, 0, 1, orig, 0)) {
725235537Sgber				nandfs_free_node(node);
726235537Sgber				node = NULL;
727235537Sgber				goto out;
728235537Sgber			}
729235537Sgber
730235537Sgber			NANDFS_DEBUG("%s: symlink is  %.*s\n",
731235537Sgber			    __func__, link_len, (char *)orig);
732235537Sgber
733235537Sgber			nameidx = (nameidx == 0) ? MAXPATHLEN + 1 : 0;
734235537Sgber			bcopy((char *)orig, namebuf + nameidx,
735235537Sgber			    (unsigned)link_len);
736235537Sgber			if (lpath != NULL) {
737235537Sgber				namebuf[nameidx + link_len++] = '/';
738235537Sgber				strncpy(namebuf + nameidx + link_len, lpath,
739235537Sgber				    MAXPATHLEN - link_len);
740235537Sgber				namebuf[nameidx + MAXPATHLEN] = '\0';
741235537Sgber			} else
742235537Sgber				namebuf[nameidx + link_len] = '\0';
743235537Sgber
744235537Sgber			NANDFS_DEBUG("%s: strp=%s, lpath=%s, namebuf0=%s, "
745235537Sgber			    "namebuf1=%s, idx=%d\n", __func__, strp, lpath,
746235537Sgber			    namebuf + 0, namebuf + MAXPATHLEN + 1, nameidx);
747235537Sgber
748235537Sgber			lpath = namebuf + nameidx;
749235537Sgber
750235537Sgber			nandfs_free_node(node);
751235537Sgber
752235537Sgber			/*
753235537Sgber			 * If absolute pathname, restart at root. Otherwise
754235537Sgber			 * continue with out parent inode.
755235537Sgber			 */
756235537Sgber			inode = (orig[0] == '/') ? NANDFS_ROOT_INO : pinode;
757235537Sgber			node = nandfs_lookup_node(fs, inode);
758235537Sgber		}
759235537Sgber	}
760235537Sgber
761235537Sgberout:
762235537Sgber	free(namebuf);
763235537Sgber	free(orig);
764235537Sgber	return (node);
765235537Sgber}
766235537Sgber
767235537Sgberstatic int
768235537Sgbernandfs_read_inode(struct nandfs *fs, struct nandfs_node *node,
769235537Sgber    nandfs_daddr_t blknr, u_int nblks, void *buf, int raw)
770235537Sgber{
771235537Sgber	uint64_t *pblks;
772235537Sgber	uint64_t *vblks;
773247613Smarcel	u_int i;
774235537Sgber	int error;
775235537Sgber
776235537Sgber	pblks = malloc(nblks * sizeof(uint64_t));
777235537Sgber	vblks = malloc(nblks * sizeof(uint64_t));
778235537Sgber
779235537Sgber	NANDFS_DEBUG("nandfs_read_inode fs=%p node=%p blknr=%lld nblks=%d\n",
780235537Sgber	    fs, node, blknr, nblks);
781235537Sgber	for (i = 0; i < nblks; i++) {
782235537Sgber		error = nandfs_bmap_lookup(fs, node, blknr + i, &vblks[i], raw);
783235537Sgber		if (error) {
784235537Sgber			free(pblks);
785235537Sgber			free(vblks);
786235537Sgber			return (error);
787235537Sgber		}
788235537Sgber		if (raw == 0)
789235537Sgber			pblks[i] = nandfs_vtop(fs, vblks[i]);
790235537Sgber		else
791235537Sgber			pblks[i] = vblks[i];
792235537Sgber	}
793235537Sgber
794235537Sgber	for (i = 0; i < nblks; i++) {
795235537Sgber		if (ioread(fs->nf_file, pblks[i] * fs->nf_blocksize, buf,
796235537Sgber		    fs->nf_blocksize)) {
797235537Sgber			free(pblks);
798235537Sgber			free(vblks);
799235537Sgber			return (EIO);
800235537Sgber		}
801235537Sgber
802247613Smarcel		buf = (void *)((uintptr_t)buf + fs->nf_blocksize);
803235537Sgber	}
804235537Sgber
805235537Sgber	free(pblks);
806235537Sgber	free(vblks);
807235537Sgber	return (0);
808235537Sgber}
809235537Sgber
810235537Sgberstatic int
811235537Sgbernandfs_read_blk(struct nandfs *fs, nandfs_daddr_t blknr, void *buf, int phys)
812235537Sgber{
813235537Sgber	uint64_t pblknr;
814235537Sgber
815235537Sgber	pblknr = (phys ? blknr : nandfs_vtop(fs, blknr));
816235537Sgber
817235537Sgber	return (ioread(fs->nf_file, pblknr * fs->nf_blocksize, buf,
818235537Sgber	    fs->nf_blocksize));
819235537Sgber}
820235537Sgber
821235537Sgberstatic int
822235537Sgbernandfs_get_checkpoint(struct nandfs *fs, uint64_t cpno,
823235537Sgber    struct nandfs_checkpoint *cp)
824235537Sgber{
825235537Sgber	uint64_t blocknr;
826235537Sgber	int blockoff, cp_per_block, dlen;
827235537Sgber	uint8_t *buf;
828235537Sgber
829235537Sgber	NANDFS_DEBUG("nandfs_get_checkpoint(fs=%p cpno=%lld)\n", fs, cpno);
830235537Sgber
831235537Sgber	buf = malloc(fs->nf_blocksize);
832235537Sgber
833235537Sgber	cpno += NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1;
834235537Sgber	dlen = fs->nf_fsdata->f_checkpoint_size;
835235537Sgber	cp_per_block = fs->nf_blocksize / dlen;
836235537Sgber	blocknr = cpno / cp_per_block;
837235537Sgber	blockoff = (cpno % cp_per_block) * dlen;
838235537Sgber
839235537Sgber	if (nandfs_read_inode(fs, &fs->nf_cpfile, blocknr, 1, buf, 0)) {
840235537Sgber		free(buf);
841235537Sgber		return (EINVAL);
842235537Sgber	}
843235537Sgber
844235537Sgber	memcpy(cp, buf + blockoff, sizeof(struct nandfs_checkpoint));
845235537Sgber	free(buf);
846235537Sgber
847235537Sgber	return (0);
848235537Sgber}
849235537Sgber
850235537Sgberstatic uint64_t *
851235537Sgbernandfs_get_map(struct nandfs *fs, struct nandfs_node *node, nandfs_daddr_t blknr,
852235537Sgber    int phys)
853235537Sgber{
854235537Sgber	struct bmap_buf *bmap;
855235537Sgber	uint64_t *map;
856235537Sgber
857235537Sgber	LIST_FOREACH(bmap, &node->bmap_bufs, list) {
858235537Sgber		if (bmap->blknr == blknr)
859235537Sgber			return (bmap->map);
860235537Sgber	}
861235537Sgber
862235537Sgber	map = malloc(fs->nf_blocksize);
863235537Sgber	if (nandfs_read_blk(fs, blknr, map, phys)) {
864235537Sgber		free(map);
865235537Sgber		return (NULL);
866235537Sgber	}
867235537Sgber
868235537Sgber	bmap = malloc(sizeof(struct bmap_buf));
869235537Sgber	bmap->blknr = blknr;
870235537Sgber	bmap->map = map;
871235537Sgber
872235537Sgber	LIST_INSERT_HEAD(&node->bmap_bufs, bmap, list);
873235537Sgber
874235537Sgber	NANDFS_DEBUG("%s:(node=%p, map=%p)\n", __func__, node, map);
875235537Sgber	return (map);
876235537Sgber}
877235537Sgber
878235537Sgberstatic int
879235537Sgbernandfs_bmap_lookup(struct nandfs *fs, struct nandfs_node *node,
880235537Sgber    nandfs_lbn_t lblknr, nandfs_daddr_t *vblknr, int phys)
881235537Sgber{
882235537Sgber	struct nandfs_inode *ino;
883235537Sgber	nandfs_daddr_t ind_block_num;
884247613Smarcel	uint64_t *map;
885235537Sgber	int idx;
886235537Sgber	int level;
887235537Sgber
888235537Sgber	ino = node->inode;
889235537Sgber
890235537Sgber	if (lblknr < NDADDR) {
891235537Sgber		*vblknr = ino->i_db[lblknr];
892235537Sgber		return (0);
893235537Sgber	}
894235537Sgber
895235537Sgber	lblknr -= NDADDR;
896235537Sgber
897235537Sgber	/*
898235537Sgber	 * nindir[0] = NINDIR
899235537Sgber	 * nindir[1] = NINDIR**2
900235537Sgber	 * nindir[2] = NINDIR**3
901235537Sgber	 *	etc
902235537Sgber	 */
903235537Sgber	for (level = 0; level < NIADDR; level++) {
904235537Sgber		NANDFS_DEBUG("lblknr=%jx fs->nf_nindir[%d]=%d\n", lblknr, level, fs->nf_nindir[level]);
905235537Sgber		if (lblknr < fs->nf_nindir[level])
906235537Sgber			break;
907235537Sgber		lblknr -= fs->nf_nindir[level];
908235537Sgber	}
909235537Sgber
910235537Sgber	if (level == NIADDR) {
911235537Sgber		/* Block number too high */
912235537Sgber		NANDFS_DEBUG("lblknr %jx too high\n", lblknr);
913235537Sgber		return (EFBIG);
914235537Sgber	}
915235537Sgber
916235537Sgber	ind_block_num = ino->i_ib[level];
917235537Sgber
918235537Sgber	for (; level >= 0; level--) {
919235537Sgber		if (ind_block_num == 0) {
920235537Sgber			*vblknr = 0;	/* missing */
921235537Sgber			return (0);
922235537Sgber		}
923235537Sgber
924276079Sian		twiddle(1);
925235537Sgber		NANDFS_DEBUG("calling get_map with %jx\n", ind_block_num);
926235537Sgber		map = nandfs_get_map(fs, node, ind_block_num, phys);
927235537Sgber		if (map == NULL)
928235537Sgber			return (EIO);
929235537Sgber
930235537Sgber		if (level > 0) {
931235537Sgber			idx = lblknr / fs->nf_nindir[level - 1];
932235537Sgber			lblknr %= fs->nf_nindir[level - 1];
933235537Sgber		} else
934235537Sgber			idx = lblknr;
935235537Sgber
936235537Sgber		ind_block_num = ((nandfs_daddr_t *)map)[idx];
937235537Sgber	}
938235537Sgber
939235537Sgber	*vblknr = ind_block_num;
940235537Sgber
941235537Sgber	return (0);
942235537Sgber}
943235537Sgber
944235537Sgberstatic nandfs_daddr_t
945235537Sgbernandfs_vtop(struct nandfs *fs, nandfs_daddr_t vblocknr)
946235537Sgber{
947235537Sgber	nandfs_lbn_t blocknr;
948235537Sgber	nandfs_daddr_t pblocknr;
949235537Sgber	int entrynr;
950235537Sgber	struct nandfs_dat_entry *dat;
951235537Sgber
952235537Sgber	dat = malloc(fs->nf_blocksize);
953235537Sgber	nandfs_mdt_trans(&fs->nf_datfile_mdt, vblocknr, &blocknr, &entrynr);
954235537Sgber
955235537Sgber	if (nandfs_read_inode(fs, &fs->nf_datfile, blocknr, 1, dat, 1)) {
956235537Sgber		free(dat);
957235537Sgber		return (0);
958235537Sgber	}
959235537Sgber
960235537Sgber	NANDFS_DEBUG("nandfs_vtop entrynr=%d vblocknr=%lld pblocknr=%lld\n",
961235537Sgber	    entrynr, vblocknr, dat[entrynr].de_blocknr);
962235537Sgber
963235537Sgber	pblocknr = dat[entrynr].de_blocknr;
964235537Sgber	free(dat);
965235537Sgber	return (pblocknr);
966235537Sgber}
967235537Sgber
968235537Sgberstatic void
969235537Sgbernandfs_calc_mdt_consts(int blocksize, struct nandfs_mdt *mdt, int entry_size)
970235537Sgber{
971235537Sgber
972235537Sgber	mdt->entries_per_group = blocksize * 8;	   /* bits in sector */
973235537Sgber	mdt->entries_per_block = blocksize / entry_size;
974235537Sgber	mdt->blocks_per_group  =
975235537Sgber	    (mdt->entries_per_group -1) / mdt->entries_per_block + 1 + 1;
976235537Sgber	mdt->groups_per_desc_block =
977235537Sgber	    blocksize / sizeof(struct nandfs_block_group_desc);
978235537Sgber	mdt->blocks_per_desc_block =
979235537Sgber	    mdt->groups_per_desc_block * mdt->blocks_per_group + 1;
980235537Sgber}
981235537Sgber
982235537Sgberstatic void
983235537Sgbernandfs_mdt_trans(struct nandfs_mdt *mdt, uint64_t index,
984235537Sgber    nandfs_daddr_t *blocknr, uint32_t *entry_in_block)
985235537Sgber{
986235537Sgber	nandfs_daddr_t blknr;
987235537Sgber	uint64_t group, group_offset, blocknr_in_group;
988235537Sgber	uint64_t desc_block, desc_offset;
989235537Sgber
990235537Sgber	/* Calculate our offset in the file */
991235537Sgber	group = index / mdt->entries_per_group;
992235537Sgber	group_offset = index % mdt->entries_per_group;
993235537Sgber	desc_block = group / mdt->groups_per_desc_block;
994235537Sgber	desc_offset = group % mdt->groups_per_desc_block;
995235537Sgber	blocknr_in_group = group_offset / mdt->entries_per_block;
996235537Sgber
997235537Sgber	/* To descgroup offset */
998235537Sgber	blknr = 1 + desc_block * mdt->blocks_per_desc_block;
999235537Sgber
1000235537Sgber	/* To group offset */
1001235537Sgber	blknr += desc_offset * mdt->blocks_per_group;
1002235537Sgber
1003235537Sgber	/* To actual file block */
1004235537Sgber	blknr += 1 + blocknr_in_group;
1005235537Sgber
1006235537Sgber	*blocknr        = blknr;
1007235537Sgber	*entry_in_block = group_offset % mdt->entries_per_block;
1008235537Sgber}
1009235537Sgber
1010235537Sgberstatic int
1011235537Sgberioread(struct open_file *f, off_t pos, void *buf, u_int length)
1012235537Sgber{
1013235537Sgber	void *buffer;
1014235537Sgber	int err;
1015235537Sgber	int bsize = ((struct nandfs *)f->f_fsdata)->nf_sectorsize;
1016235537Sgber	u_int off, nsec;
1017235537Sgber
1018235537Sgber	off = pos % bsize;
1019235537Sgber	pos /= bsize;
1020298601Spfg	nsec = howmany(length, bsize);
1021235537Sgber
1022235537Sgber	NANDFS_DEBUG("pos=%lld length=%d off=%d nsec=%d\n", pos, length,
1023235537Sgber	    off, nsec);
1024235537Sgber
1025235537Sgber	buffer = malloc(nsec * bsize);
1026235537Sgber
1027313355Stsoome	err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, pos,
1028235537Sgber	    nsec * bsize, buffer, NULL);
1029235537Sgber
1030247613Smarcel	memcpy(buf, (void *)((uintptr_t)buffer + off), length);
1031235537Sgber	free(buffer);
1032235537Sgber
1033235537Sgber	return (err);
1034235537Sgber}
1035235537Sgber
1036235537Sgberstatic int
1037235537Sgbernandfs_probe_sectorsize(struct open_file *f)
1038235537Sgber{
1039235537Sgber	void *buffer;
1040235537Sgber	int i, err;
1041235537Sgber
1042235537Sgber	buffer = malloc(16 * 1024);
1043235537Sgber
1044235537Sgber	NANDFS_DEBUG("probing for sector size: ");
1045235537Sgber
1046235537Sgber	for (i = 512; i < (16 * 1024); i <<= 1) {
1047235537Sgber		NANDFS_DEBUG("%d ", i);
1048313355Stsoome		err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 0, i,
1049235537Sgber		    buffer, NULL);
1050235537Sgber
1051235537Sgber		if (err == 0) {
1052235537Sgber			NANDFS_DEBUG("found");
1053235537Sgber			free(buffer);
1054235537Sgber			return (i);
1055235537Sgber		}
1056235537Sgber	}
1057235537Sgber
1058235537Sgber	free(buffer);
1059235537Sgber	NANDFS_DEBUG("not found\n");
1060235537Sgber	return (-1);
1061235537Sgber}
1062