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