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