2 * Copyright (c) 2010-2012 Semihalf.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/queue.h>
32 #include <sys/stdint.h>
33 #include <ufs/ufs/dinode.h>
34 #include <fs/nandfs/nandfs_fs.h>
42 #define NANDFS_DEBUG(fmt, args...) do { \
43 printf("NANDFS_DEBUG:" fmt "\n", ##args); } while (0)
45 #define NANDFS_DEBUG(fmt, args...)
49 uint32_t entries_per_block
;
50 uint32_t entries_per_group
;
51 uint32_t blocks_per_group
;
52 uint32_t groups_per_desc_block
; /* desc is super group */
53 uint32_t blocks_per_desc_block
; /* desc is super group */
57 LIST_ENTRY(bmap_buf
) list
;
63 struct nandfs_inode
*inode
;
64 LIST_HEAD(, bmap_buf
) bmap_bufs
;
71 struct open_file
*nf_file
;
72 struct nandfs_node
*nf_opened_node
;
77 struct nandfs_fsdata
*nf_fsdata
;
78 struct nandfs_super_block
*nf_sb
;
79 struct nandfs_segment_summary nf_segsum
;
80 struct nandfs_checkpoint nf_checkpoint
;
81 struct nandfs_super_root nf_sroot
;
82 struct nandfs_node nf_ifile
;
83 struct nandfs_node nf_datfile
;
84 struct nandfs_node nf_cpfile
;
85 struct nandfs_mdt nf_datfile_mdt
;
86 struct nandfs_mdt nf_ifile_mdt
;
88 int nf_nindir
[NIADDR
];
91 static int nandfs_open(const char *, struct open_file
*);
92 static int nandfs_close(struct open_file
*);
93 static int nandfs_read(struct open_file
*, void *, size_t, size_t *);
94 static off_t
nandfs_seek(struct open_file
*, off_t
, int);
95 static int nandfs_stat(struct open_file
*, struct stat
*);
96 static int nandfs_readdir(struct open_file
*, struct dirent
*);
98 static int nandfs_buf_read(struct nandfs
*, void **, size_t *);
99 static struct nandfs_node
*nandfs_lookup_path(struct nandfs
*, const char *);
100 static int nandfs_read_inode(struct nandfs
*, struct nandfs_node
*,
101 nandfs_lbn_t
, u_int
, void *, int);
102 static int nandfs_read_blk(struct nandfs
*, nandfs_daddr_t
, void *, int);
103 static int nandfs_bmap_lookup(struct nandfs
*, struct nandfs_node
*,
104 nandfs_lbn_t
, nandfs_daddr_t
*, int);
105 static int nandfs_get_checkpoint(struct nandfs
*, uint64_t,
106 struct nandfs_checkpoint
*);
107 static nandfs_daddr_t
nandfs_vtop(struct nandfs
*, nandfs_daddr_t
);
108 static void nandfs_calc_mdt_consts(int, struct nandfs_mdt
*, int);
109 static void nandfs_mdt_trans(struct nandfs_mdt
*, uint64_t,
110 nandfs_daddr_t
*, uint32_t *);
111 static int ioread(struct open_file
*, off_t
, void *, u_int
);
112 static int nandfs_probe_sectorsize(struct open_file
*);
114 struct fs_ops nandfs_fsops
= {
125 #define NINDIR(fs) ((fs)->nf_blocksize / sizeof(nandfs_daddr_t))
127 /* from NetBSD's src/sys/net/if_ethersubr.c */
129 nandfs_crc32(uint32_t crc
, const uint8_t *buf
, size_t len
)
131 static const uint32_t crctab
[] = {
132 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
133 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
134 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
135 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
140 for (i
= 0; i
< len
; i
++) {
142 crc
= (crc
>> 4) ^ crctab
[crc
& 0xf];
143 crc
= (crc
>> 4) ^ crctab
[crc
& 0xf];
149 nandfs_check_fsdata_crc(struct nandfs_fsdata
*fsdata
)
151 uint32_t fsdata_crc
, comp_crc
;
153 if (fsdata
->f_magic
!= NANDFS_FSDATA_MAGIC
)
157 fsdata_crc
= fsdata
->f_sum
;
161 comp_crc
= nandfs_crc32(0, (uint8_t *)fsdata
, fsdata
->f_bytes
);
164 fsdata
->f_sum
= fsdata_crc
;
167 return (fsdata_crc
== comp_crc
);
171 nandfs_check_superblock_crc(struct nandfs_fsdata
*fsdata
,
172 struct nandfs_super_block
*super
)
174 uint32_t super_crc
, comp_crc
;
176 /* Check super block magic */
177 if (super
->s_magic
!= NANDFS_SUPER_MAGIC
)
181 super_crc
= super
->s_sum
;
185 comp_crc
= nandfs_crc32(0, (uint8_t *)super
, fsdata
->f_sbbytes
);
188 super
->s_sum
= super_crc
;
191 return (super_crc
== comp_crc
);
195 nandfs_find_super_block(struct nandfs
*fs
, struct open_file
*f
)
197 struct nandfs_super_block
*sb
;
199 int sectors_to_read
, error
;
201 sb
= malloc(fs
->nf_sectorsize
);
205 memset(fs
->nf_sb
, 0, sizeof(*fs
->nf_sb
));
207 sectors_to_read
= (NANDFS_NFSAREAS
* fs
->nf_fsdata
->f_erasesize
) /
209 for (i
= 0; i
< sectors_to_read
; i
++) {
210 NANDFS_DEBUG("reading i %d offset %d\n", i
,
211 i
* fs
->nf_sectorsize
);
212 error
= ioread(f
, i
* fs
->nf_sectorsize
, (char *)sb
,
215 NANDFS_DEBUG("error %d\n", error
);
218 n
= fs
->nf_sectorsize
/ sizeof(struct nandfs_super_block
);
220 if ((i
* fs
->nf_sectorsize
) % fs
->nf_fsdata
->f_erasesize
== 0) {
221 if (fs
->nf_sectorsize
== sizeof(struct nandfs_fsdata
))
224 s
+= (sizeof(struct nandfs_fsdata
) /
225 sizeof(struct nandfs_super_block
));
229 for (j
= s
; j
< n
; j
++) {
230 if (!nandfs_check_superblock_crc(fs
->nf_fsdata
, &sb
[j
]))
232 NANDFS_DEBUG("magic %x wtime %jd, lastcp 0x%jx\n",
233 sb
[j
].s_magic
, sb
[j
].s_wtime
, sb
[j
].s_last_cno
);
234 if (sb
[j
].s_last_cno
> fs
->nf_sb
->s_last_cno
)
235 memcpy(fs
->nf_sb
, &sb
[j
], sizeof(*fs
->nf_sb
));
241 return (fs
->nf_sb
->s_magic
!= 0 ? 0 : EINVAL
);
245 nandfs_find_fsdata(struct nandfs
*fs
, struct open_file
*f
)
247 int offset
, error
, i
;
249 NANDFS_DEBUG("starting\n");
252 for (i
= 0; i
< 64 * NANDFS_NFSAREAS
; i
++) {
253 error
= ioread(f
, offset
, (char *)fs
->nf_fsdata
,
254 sizeof(struct nandfs_fsdata
));
257 if (fs
->nf_fsdata
->f_magic
== NANDFS_FSDATA_MAGIC
) {
258 NANDFS_DEBUG("found at %x, volume %s\n", offset
,
259 fs
->nf_fsdata
->f_volume_name
);
260 if (nandfs_check_fsdata_crc(fs
->nf_fsdata
))
263 offset
+= fs
->nf_sectorsize
;
270 nandfs_read_structures(struct nandfs
*fs
, struct open_file
*f
)
274 error
= nandfs_find_fsdata(fs
, f
);
278 error
= nandfs_find_super_block(fs
, f
);
281 NANDFS_DEBUG("selected sb with w_time %jd last_pseg %jx\n",
282 fs
->nf_sb
->s_wtime
, fs
->nf_sb
->s_last_pseg
);
288 nandfs_mount(struct nandfs
*fs
, struct open_file
*f
)
293 fs
->nf_fsdata
= malloc(sizeof(struct nandfs_fsdata
));
294 fs
->nf_sb
= malloc(sizeof(struct nandfs_super_block
));
296 err
= nandfs_read_structures(fs
, f
);
303 fs
->nf_blocksize
= 1 << (fs
->nf_fsdata
->f_log_block_size
+ 10);
305 NANDFS_DEBUG("using superblock with wtime %jd\n", fs
->nf_sb
->s_wtime
);
307 fs
->nf_cpno
= fs
->nf_sb
->s_last_cno
;
308 last_pseg
= fs
->nf_sb
->s_last_pseg
;
311 * Calculate indirect block levels.
316 for (level
= 0; level
< NIADDR
; level
++) {
318 fs
->nf_nindir
[level
] = mult
;
321 nandfs_calc_mdt_consts(fs
->nf_blocksize
, &fs
->nf_datfile_mdt
,
322 fs
->nf_fsdata
->f_dat_entry_size
);
324 nandfs_calc_mdt_consts(fs
->nf_blocksize
, &fs
->nf_ifile_mdt
,
325 fs
->nf_fsdata
->f_inode_size
);
327 err
= ioread(f
, last_pseg
* fs
->nf_blocksize
, &fs
->nf_segsum
,
328 sizeof(struct nandfs_segment_summary
));
335 err
= ioread(f
, (last_pseg
+ fs
->nf_segsum
.ss_nblocks
- 1) *
336 fs
->nf_blocksize
, &fs
->nf_sroot
, sizeof(struct nandfs_super_root
));
343 fs
->nf_datfile
.inode
= &fs
->nf_sroot
.sr_dat
;
344 LIST_INIT(&fs
->nf_datfile
.bmap_bufs
);
345 fs
->nf_cpfile
.inode
= &fs
->nf_sroot
.sr_cpfile
;
346 LIST_INIT(&fs
->nf_cpfile
.bmap_bufs
);
348 err
= nandfs_get_checkpoint(fs
, fs
->nf_cpno
, &fs
->nf_checkpoint
);
355 NANDFS_DEBUG("checkpoint cp_cno=%lld\n", fs
->nf_checkpoint
.cp_cno
);
356 NANDFS_DEBUG("checkpoint cp_inodes_count=%lld\n",
357 fs
->nf_checkpoint
.cp_inodes_count
);
358 NANDFS_DEBUG("checkpoint cp_ifile_inode.i_blocks=%lld\n",
359 fs
->nf_checkpoint
.cp_ifile_inode
.i_blocks
);
361 fs
->nf_ifile
.inode
= &fs
->nf_checkpoint
.cp_ifile_inode
;
362 LIST_INIT(&fs
->nf_ifile
.bmap_bufs
);
366 #define NINDIR(fs) ((fs)->nf_blocksize / sizeof(nandfs_daddr_t))
369 nandfs_open(const char *path
, struct open_file
*f
)
372 struct nandfs_node
*node
;
373 int err
, bsize
, level
;
375 NANDFS_DEBUG("nandfs_open('%s', %p)\n", path
, f
);
377 fs
= malloc(sizeof(struct nandfs
));
381 bsize
= nandfs_probe_sectorsize(f
);
383 printf("Cannot probe medium sector size\n");
387 fs
->nf_sectorsize
= bsize
;
390 * Calculate indirect block levels.
395 for (level
= 0; level
< NIADDR
; level
++) {
397 fs
->nf_nindir
[level
] = mult
;
400 NANDFS_DEBUG("fs %p nf_sectorsize=%x\n", fs
, fs
->nf_sectorsize
);
402 err
= nandfs_mount(fs
, f
);
404 NANDFS_DEBUG("Cannot mount nandfs: %s\n", strerror(err
));
408 node
= nandfs_lookup_path(fs
, path
);
414 fs
->nf_buf_blknr
= -1;
415 fs
->nf_opened_node
= node
;
416 LIST_INIT(&fs
->nf_opened_node
->bmap_bufs
);
421 nandfs_free_node(struct nandfs_node
*node
)
423 struct bmap_buf
*bmap
, *tmp
;
426 LIST_FOREACH_SAFE(bmap
, &node
->bmap_bufs
, list
, tmp
) {
427 LIST_REMOVE(bmap
, list
);
435 nandfs_close(struct open_file
*f
)
437 struct nandfs
*fs
= f
->f_fsdata
;
439 NANDFS_DEBUG("nandfs_close(%p)\n", f
);
441 if (fs
->nf_buf
!= NULL
)
444 nandfs_free_node(fs
->nf_opened_node
);
451 nandfs_read(struct open_file
*f
, void *addr
, size_t size
, size_t *resid
)
453 struct nandfs
*fs
= (struct nandfs
*)f
->f_fsdata
;
454 size_t csize
, buf_size
;
458 NANDFS_DEBUG("nandfs_read(file=%p, addr=%p, size=%d)\n", f
, addr
, size
);
461 if (fs
->nf_offset
>= fs
->nf_opened_node
->inode
->i_size
)
464 error
= nandfs_buf_read(fs
, &buf
, &buf_size
);
469 if (csize
> buf_size
)
472 bcopy(buf
, addr
, csize
);
474 fs
->nf_offset
+= csize
;
475 addr
= (char *)addr
+ csize
;
485 nandfs_seek(struct open_file
*f
, off_t offset
, int where
)
487 struct nandfs
*fs
= f
->f_fsdata
;
491 NANDFS_DEBUG("nandfs_seek(file=%p, offset=%lld, where=%d)\n", f
,
494 size
= fs
->nf_opened_node
->inode
->i_size
;
512 if (off
< 0 || off
> size
) {
517 fs
->nf_offset
= (u_int
)off
;
523 nandfs_stat(struct open_file
*f
, struct stat
*sb
)
525 struct nandfs
*fs
= f
->f_fsdata
;
527 NANDFS_DEBUG("nandfs_stat(file=%p, stat=%p)\n", f
, sb
);
529 sb
->st_size
= fs
->nf_opened_node
->inode
->i_size
;
530 sb
->st_mode
= fs
->nf_opened_node
->inode
->i_mode
;
531 sb
->st_uid
= fs
->nf_opened_node
->inode
->i_uid
;
532 sb
->st_gid
= fs
->nf_opened_node
->inode
->i_gid
;
537 nandfs_readdir(struct open_file
*f
, struct dirent
*d
)
539 struct nandfs
*fs
= f
->f_fsdata
;
540 struct nandfs_dir_entry
*dirent
;
544 NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)\n", f
, d
);
546 if (fs
->nf_offset
>= fs
->nf_opened_node
->inode
->i_size
) {
547 NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) ENOENT\n",
552 if (nandfs_buf_read(fs
, &buf
, &buf_size
)) {
553 NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p)"
554 "buf_read failed\n", f
, d
);
558 NANDFS_DEBUG("nandfs_readdir(file=%p, dirent=%p) moving forward\n",
561 dirent
= (struct nandfs_dir_entry
*)buf
;
562 fs
->nf_offset
+= dirent
->rec_len
;
563 strncpy(d
->d_name
, dirent
->name
, dirent
->name_len
);
564 d
->d_name
[dirent
->name_len
] = '\0';
565 d
->d_type
= dirent
->file_type
;
570 nandfs_buf_read(struct nandfs
*fs
, void **buf_p
, size_t *size_p
)
572 nandfs_daddr_t blknr
, blkoff
;
574 blknr
= fs
->nf_offset
/ fs
->nf_blocksize
;
575 blkoff
= fs
->nf_offset
% fs
->nf_blocksize
;
577 if (blknr
!= fs
->nf_buf_blknr
) {
578 if (fs
->nf_buf
== NULL
)
579 fs
->nf_buf
= malloc(fs
->nf_blocksize
);
581 if (nandfs_read_inode(fs
, fs
->nf_opened_node
, blknr
, 1,
585 fs
->nf_buf_blknr
= blknr
;
588 *buf_p
= fs
->nf_buf
+ blkoff
;
589 *size_p
= fs
->nf_blocksize
- blkoff
;
591 NANDFS_DEBUG("nandfs_buf_read buf_p=%p size_p=%d\n", *buf_p
, *size_p
);
593 if (*size_p
> fs
->nf_opened_node
->inode
->i_size
- fs
->nf_offset
)
594 *size_p
= fs
->nf_opened_node
->inode
->i_size
- fs
->nf_offset
;
599 static struct nandfs_node
*
600 nandfs_lookup_node(struct nandfs
*fs
, uint64_t ino
)
604 struct nandfs_inode
*buffer
;
605 struct nandfs_node
*node
;
606 struct nandfs_inode
*inode
;
608 NANDFS_DEBUG("nandfs_lookup_node ino=%lld\n", ino
);
611 printf("nandfs_lookup_node: invalid inode requested\n");
615 buffer
= malloc(fs
->nf_blocksize
);
616 inode
= malloc(sizeof(struct nandfs_inode
));
617 node
= malloc(sizeof(struct nandfs_node
));
619 nandfs_mdt_trans(&fs
->nf_ifile_mdt
, ino
, &blocknr
, &entrynr
);
621 if (nandfs_read_inode(fs
, &fs
->nf_ifile
, blocknr
, 1, buffer
, 0))
624 memcpy(inode
, &buffer
[entrynr
], sizeof(struct nandfs_inode
));
630 static struct nandfs_node
*
631 nandfs_lookup_path(struct nandfs
*fs
, const char *path
)
633 struct nandfs_node
*node
;
634 struct nandfs_dir_entry
*dirent
;
636 uint64_t i
, done
, pinode
, inode
;
637 int nlinks
= 0, counter
, len
, link_len
, nameidx
;
638 uint8_t *buffer
, *orig
;
641 buffer
= malloc(fs
->nf_blocksize
);
644 namebuf
= malloc(2 * MAXPATHLEN
+ 2);
645 strncpy(namebuf
, path
, MAXPATHLEN
);
646 namebuf
[MAXPATHLEN
] = '\0';
650 /* Get the root inode */
651 node
= nandfs_lookup_node(fs
, NANDFS_ROOT_INO
);
652 inode
= NANDFS_ROOT_INO
;
654 while ((strp
= strsep(&lpath
, "/")) != NULL
) {
657 if ((node
->inode
->i_mode
& IFMT
) != IFDIR
) {
658 nandfs_free_node(node
);
664 NANDFS_DEBUG("%s: looking for %s\n", __func__
, strp
);
665 for (i
= 0; i
< node
->inode
->i_blocks
; i
++) {
666 if (nandfs_read_inode(fs
, node
, i
, 1, orig
, 0)) {
675 (struct nandfs_dir_entry
*)(void *)buffer
;
676 NANDFS_DEBUG("%s: dirent.name = %s\n",
677 __func__
, dirent
->name
);
678 NANDFS_DEBUG("%s: dirent.rec_len = %d\n",
679 __func__
, dirent
->rec_len
);
680 NANDFS_DEBUG("%s: dirent.inode = %lld\n",
681 __func__
, dirent
->inode
);
682 if (len
== dirent
->name_len
&&
683 (strncmp(strp
, dirent
->name
, len
) == 0) &&
684 dirent
->inode
!= 0) {
685 nandfs_free_node(node
);
686 node
= nandfs_lookup_node(fs
,
689 inode
= dirent
->inode
;
694 counter
+= dirent
->rec_len
;
695 buffer
+= dirent
->rec_len
;
697 if (counter
== fs
->nf_blocksize
)
710 NANDFS_DEBUG("%s: %.*s has mode %o\n", __func__
,
711 dirent
->name_len
, dirent
->name
, node
->inode
->i_mode
);
713 if ((node
->inode
->i_mode
& IFMT
) == IFLNK
) {
714 NANDFS_DEBUG("%s: %.*s is symlink\n",
715 __func__
, dirent
->name_len
, dirent
->name
);
716 link_len
= node
->inode
->i_size
;
718 if (++nlinks
> MAXSYMLINKS
) {
719 nandfs_free_node(node
);
724 if (nandfs_read_inode(fs
, node
, 0, 1, orig
, 0)) {
725 nandfs_free_node(node
);
730 NANDFS_DEBUG("%s: symlink is %.*s\n",
731 __func__
, link_len
, (char *)orig
);
733 nameidx
= (nameidx
== 0) ? MAXPATHLEN
+ 1 : 0;
734 bcopy((char *)orig
, namebuf
+ nameidx
,
737 namebuf
[nameidx
+ link_len
++] = '/';
738 strncpy(namebuf
+ nameidx
+ link_len
, lpath
,
739 MAXPATHLEN
- link_len
);
740 namebuf
[nameidx
+ MAXPATHLEN
] = '\0';
742 namebuf
[nameidx
+ link_len
] = '\0';
744 NANDFS_DEBUG("%s: strp=%s, lpath=%s, namebuf0=%s, "
745 "namebuf1=%s, idx=%d\n", __func__
, strp
, lpath
,
746 namebuf
+ 0, namebuf
+ MAXPATHLEN
+ 1, nameidx
);
748 lpath
= namebuf
+ nameidx
;
750 nandfs_free_node(node
);
753 * If absolute pathname, restart at root. Otherwise
754 * continue with out parent inode.
756 inode
= (orig
[0] == '/') ? NANDFS_ROOT_INO
: pinode
;
757 node
= nandfs_lookup_node(fs
, inode
);
768 nandfs_read_inode(struct nandfs
*fs
, struct nandfs_node
*node
,
769 nandfs_daddr_t blknr
, u_int nblks
, void *buf
, int raw
)
776 pblks
= malloc(nblks
* sizeof(uint64_t));
777 vblks
= malloc(nblks
* sizeof(uint64_t));
779 NANDFS_DEBUG("nandfs_read_inode fs=%p node=%p blknr=%lld nblks=%d\n",
780 fs
, node
, blknr
, nblks
);
781 for (i
= 0; i
< nblks
; i
++) {
782 error
= nandfs_bmap_lookup(fs
, node
, blknr
+ i
, &vblks
[i
], raw
);
789 pblks
[i
] = nandfs_vtop(fs
, vblks
[i
]);
794 for (i
= 0; i
< nblks
; i
++) {
795 if (ioread(fs
->nf_file
, pblks
[i
] * fs
->nf_blocksize
, buf
,
802 buf
= (void *)((uintptr_t)buf
+ fs
->nf_blocksize
);
811 nandfs_read_blk(struct nandfs
*fs
, nandfs_daddr_t blknr
, void *buf
, int phys
)
815 pblknr
= (phys
? blknr
: nandfs_vtop(fs
, blknr
));
817 return (ioread(fs
->nf_file
, pblknr
* fs
->nf_blocksize
, buf
,
822 nandfs_get_checkpoint(struct nandfs
*fs
, uint64_t cpno
,
823 struct nandfs_checkpoint
*cp
)
826 int blockoff
, cp_per_block
, dlen
;
829 NANDFS_DEBUG("nandfs_get_checkpoint(fs=%p cpno=%lld)\n", fs
, cpno
);
831 buf
= malloc(fs
->nf_blocksize
);
833 cpno
+= NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET
- 1;
834 dlen
= fs
->nf_fsdata
->f_checkpoint_size
;
835 cp_per_block
= fs
->nf_blocksize
/ dlen
;
836 blocknr
= cpno
/ cp_per_block
;
837 blockoff
= (cpno
% cp_per_block
) * dlen
;
839 if (nandfs_read_inode(fs
, &fs
->nf_cpfile
, blocknr
, 1, buf
, 0)) {
844 memcpy(cp
, buf
+ blockoff
, sizeof(struct nandfs_checkpoint
));
851 nandfs_get_map(struct nandfs
*fs
, struct nandfs_node
*node
, nandfs_daddr_t blknr
,
854 struct bmap_buf
*bmap
;
857 LIST_FOREACH(bmap
, &node
->bmap_bufs
, list
) {
858 if (bmap
->blknr
== blknr
)
862 map
= malloc(fs
->nf_blocksize
);
863 if (nandfs_read_blk(fs
, blknr
, map
, phys
)) {
868 bmap
= malloc(sizeof(struct bmap_buf
));
872 LIST_INSERT_HEAD(&node
->bmap_bufs
, bmap
, list
);
874 NANDFS_DEBUG("%s:(node=%p, map=%p)\n", __func__
, node
, map
);
879 nandfs_bmap_lookup(struct nandfs
*fs
, struct nandfs_node
*node
,
880 nandfs_lbn_t lblknr
, nandfs_daddr_t
*vblknr
, int phys
)
882 struct nandfs_inode
*ino
;
883 nandfs_daddr_t ind_block_num
;
890 if (lblknr
< NDADDR
) {
891 *vblknr
= ino
->i_db
[lblknr
];
899 * nindir[1] = NINDIR**2
900 * nindir[2] = NINDIR**3
903 for (level
= 0; level
< NIADDR
; level
++) {
904 NANDFS_DEBUG("lblknr=%jx fs->nf_nindir[%d]=%d\n", lblknr
, level
, fs
->nf_nindir
[level
]);
905 if (lblknr
< fs
->nf_nindir
[level
])
907 lblknr
-= fs
->nf_nindir
[level
];
910 if (level
== NIADDR
) {
911 /* Block number too high */
912 NANDFS_DEBUG("lblknr %jx too high\n", lblknr
);
916 ind_block_num
= ino
->i_ib
[level
];
918 for (; level
>= 0; level
--) {
919 if (ind_block_num
== 0) {
920 *vblknr
= 0; /* missing */
925 NANDFS_DEBUG("calling get_map with %jx\n", ind_block_num
);
926 map
= nandfs_get_map(fs
, node
, ind_block_num
, phys
);
931 idx
= lblknr
/ fs
->nf_nindir
[level
- 1];
932 lblknr
%= fs
->nf_nindir
[level
- 1];
936 ind_block_num
= ((nandfs_daddr_t
*)map
)[idx
];
939 *vblknr
= ind_block_num
;
944 static nandfs_daddr_t
945 nandfs_vtop(struct nandfs
*fs
, nandfs_daddr_t vblocknr
)
947 nandfs_lbn_t blocknr
;
948 nandfs_daddr_t pblocknr
;
950 struct nandfs_dat_entry
*dat
;
952 dat
= malloc(fs
->nf_blocksize
);
953 nandfs_mdt_trans(&fs
->nf_datfile_mdt
, vblocknr
, &blocknr
, &entrynr
);
955 if (nandfs_read_inode(fs
, &fs
->nf_datfile
, blocknr
, 1, dat
, 1)) {
960 NANDFS_DEBUG("nandfs_vtop entrynr=%d vblocknr=%lld pblocknr=%lld\n",
961 entrynr
, vblocknr
, dat
[entrynr
].de_blocknr
);
963 pblocknr
= dat
[entrynr
].de_blocknr
;
969 nandfs_calc_mdt_consts(int blocksize
, struct nandfs_mdt
*mdt
, int entry_size
)
972 mdt
->entries_per_group
= blocksize
* 8; /* bits in sector */
973 mdt
->entries_per_block
= blocksize
/ entry_size
;
974 mdt
->blocks_per_group
=
975 (mdt
->entries_per_group
-1) / mdt
->entries_per_block
+ 1 + 1;
976 mdt
->groups_per_desc_block
=
977 blocksize
/ sizeof(struct nandfs_block_group_desc
);
978 mdt
->blocks_per_desc_block
=
979 mdt
->groups_per_desc_block
* mdt
->blocks_per_group
+ 1;
983 nandfs_mdt_trans(struct nandfs_mdt
*mdt
, uint64_t index
,
984 nandfs_daddr_t
*blocknr
, uint32_t *entry_in_block
)
986 nandfs_daddr_t blknr
;
987 uint64_t group
, group_offset
, blocknr_in_group
;
988 uint64_t desc_block
, desc_offset
;
990 /* Calculate our offset in the file */
991 group
= index
/ mdt
->entries_per_group
;
992 group_offset
= index
% mdt
->entries_per_group
;
993 desc_block
= group
/ mdt
->groups_per_desc_block
;
994 desc_offset
= group
% mdt
->groups_per_desc_block
;
995 blocknr_in_group
= group_offset
/ mdt
->entries_per_block
;
997 /* To descgroup offset */
998 blknr
= 1 + desc_block
* mdt
->blocks_per_desc_block
;
1000 /* To group offset */
1001 blknr
+= desc_offset
* mdt
->blocks_per_group
;
1003 /* To actual file block */
1004 blknr
+= 1 + blocknr_in_group
;
1007 *entry_in_block
= group_offset
% mdt
->entries_per_block
;
1011 ioread(struct open_file
*f
, off_t pos
, void *buf
, u_int length
)
1015 int bsize
= ((struct nandfs
*)f
->f_fsdata
)->nf_sectorsize
;
1020 nsec
= howmany(length
, bsize
);
1022 NANDFS_DEBUG("pos=%lld length=%d off=%d nsec=%d\n", pos
, length
,
1025 buffer
= malloc(nsec
* bsize
);
1027 err
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
, pos
, 0,
1028 nsec
* bsize
, buffer
, NULL
);
1030 memcpy(buf
, (void *)((uintptr_t)buffer
+ off
), length
);
1037 nandfs_probe_sectorsize(struct open_file
*f
)
1042 buffer
= malloc(16 * 1024);
1044 NANDFS_DEBUG("probing for sector size: ");
1046 for (i
= 512; i
< (16 * 1024); i
<<= 1) {
1047 NANDFS_DEBUG("%d ", i
);
1048 err
= (f
->f_dev
->dv_strategy
)(f
->f_devdata
, F_READ
, 0, 0, i
,
1052 NANDFS_DEBUG("found");
1059 NANDFS_DEBUG("not found\n");