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
nandfs_crc32(uint32_t crc,const uint8_t * buf,size_t len)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
nandfs_check_fsdata_crc(struct nandfs_fsdata * fsdata)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
nandfs_check_superblock_crc(struct nandfs_fsdata * fsdata,struct nandfs_super_block * super)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
nandfs_find_super_block(struct nandfs * fs,struct open_file * f)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
nandfs_find_fsdata(struct nandfs * fs,struct open_file * f)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
nandfs_read_structures(struct nandfs * fs,struct open_file * f)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
nandfs_mount(struct nandfs * fs,struct open_file * f)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
nandfs_open(const char * path,struct open_file * f)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
nandfs_free_node(struct nandfs_node * node)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
nandfs_close(struct open_file * f)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
nandfs_read(struct open_file * f,void * addr,size_t size,size_t * resid)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
nandfs_seek(struct open_file * f,off_t offset,int where)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
nandfs_stat(struct open_file * f,struct stat * sb)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
nandfs_readdir(struct open_file * f,struct dirent * d)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
nandfs_buf_read(struct nandfs * fs,void ** buf_p,size_t * size_p)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 *
nandfs_lookup_node(struct nandfs * fs,uint64_t ino)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 *
nandfs_lookup_path(struct nandfs * fs,const char * path)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
nandfs_read_inode(struct nandfs * fs,struct nandfs_node * node,nandfs_daddr_t blknr,u_int nblks,void * buf,int raw)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
nandfs_read_blk(struct nandfs * fs,nandfs_daddr_t blknr,void * buf,int phys)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
nandfs_get_checkpoint(struct nandfs * fs,uint64_t cpno,struct nandfs_checkpoint * cp)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 *
nandfs_get_map(struct nandfs * fs,struct nandfs_node * node,nandfs_daddr_t blknr,int phys)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
nandfs_bmap_lookup(struct nandfs * fs,struct nandfs_node * node,nandfs_lbn_t lblknr,nandfs_daddr_t * vblknr,int phys)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
nandfs_vtop(struct nandfs * fs,nandfs_daddr_t vblocknr)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
nandfs_calc_mdt_consts(int blocksize,struct nandfs_mdt * mdt,int entry_size)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
nandfs_mdt_trans(struct nandfs_mdt * mdt,uint64_t index,nandfs_daddr_t * blocknr,uint32_t * entry_in_block)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
ioread(struct open_file * f,off_t pos,void * buf,u_int length)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
nandfs_probe_sectorsize(struct open_file * f)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