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