1/* $NetBSD: chfs_readinode.c,v 1.1 2011/11/24 15:51:31 ahoka Exp $ */ 2 3/*- 4 * Copyright (c) 2010 Department of Software Engineering, 5 * University of Szeged, Hungary 6 * Copyright (C) 2010 David Tengeri <dtengeri@inf.u-szeged.hu> 7 * Copyright (C) 2010 Tamas Toth <ttoth@inf.u-szeged.hu> 8 * Copyright (C) 2010 Adam Hoka <ahoka@NetBSD.org> 9 * All rights reserved. 10 * 11 * This code is derived from software contributed to The NetBSD Foundation 12 * by the Department of Software Engineering, University of Szeged, Hungary 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36/* 37 * chfs_readinode.c 38 * 39 * Created on: 2010.05.31. 40 * Author: dtengeri 41 */ 42 43#include <sys/buf.h> 44 45#include "chfs.h" 46 47/* tmp node operations */ 48int chfs_check_td_data(struct chfs_mount *, 49 struct chfs_tmp_dnode *); 50int chfs_check_td_node(struct chfs_mount *, 51 struct chfs_tmp_dnode *); 52struct chfs_node_ref *chfs_first_valid_data_ref(struct chfs_node_ref *); 53int chfs_add_tmp_dnode_to_tree(struct chfs_mount *, 54 struct chfs_readinode_info *, 55 struct chfs_tmp_dnode *); 56void chfs_add_tmp_dnode_to_tdi(struct chfs_tmp_dnode_info *, 57 struct chfs_tmp_dnode *); 58void chfs_remove_tmp_dnode_from_tdi(struct chfs_tmp_dnode_info *, 59 struct chfs_tmp_dnode *); 60static void chfs_kill_td(struct chfs_mount *, 61 struct chfs_tmp_dnode *); 62static void chfs_kill_tdi(struct chfs_mount *, 63 struct chfs_tmp_dnode_info *); 64/* frag node operations */ 65struct chfs_node_frag *new_fragment(struct chfs_full_dnode *, 66 uint32_t, 67 uint32_t); 68int no_overlapping_node(struct rb_tree *, struct chfs_node_frag *, 69 struct chfs_node_frag *, uint32_t); 70int chfs_add_frag_to_fragtree(struct chfs_mount *, 71 struct rb_tree *, 72 struct chfs_node_frag *); 73void chfs_obsolete_node_frag(struct chfs_mount *, 74 struct chfs_node_frag *); 75/* general node operations */ 76int chfs_get_data_nodes(struct chfs_mount *, 77 struct chfs_inode *, 78 struct chfs_readinode_info *); 79int chfs_build_fragtree(struct chfs_mount *, 80 struct chfs_inode *, 81 struct chfs_readinode_info *); 82 83 84 85/* 86 * -------------------------- 87 * tmp node rbtree operations 88 * -------------------------- 89 */ 90static signed int 91tmp_node_compare_nodes(void *ctx, const void *n1, const void *n2) 92{ 93 const struct chfs_tmp_dnode_info *tdi1 = n1; 94 const struct chfs_tmp_dnode_info *tdi2 = n2; 95 96 return (tdi1->tmpnode->node->ofs - tdi2->tmpnode->node->ofs); 97} 98 99static signed int 100tmp_node_compare_key(void *ctx, const void *n, const void *key) 101{ 102 const struct chfs_tmp_dnode_info *tdi = n; 103 uint64_t ofs = *(const uint64_t *)key; 104 105 return (tdi->tmpnode->node->ofs - ofs); 106} 107 108const rb_tree_ops_t tmp_node_rbtree_ops = { 109 .rbto_compare_nodes = tmp_node_compare_nodes, 110 .rbto_compare_key = tmp_node_compare_key, 111 .rbto_node_offset = offsetof(struct chfs_tmp_dnode_info, rb_node), 112 .rbto_context = NULL 113}; 114 115 116/* 117 * --------------------------- 118 * frag node rbtree operations 119 * --------------------------- 120 */ 121static signed int 122frag_compare_nodes(void *ctx, const void *n1, const void *n2) 123{ 124 const struct chfs_node_frag *frag1 = n1; 125 const struct chfs_node_frag *frag2 = n2; 126 127 return (frag1->ofs - frag2->ofs); 128} 129 130static signed int 131frag_compare_key(void *ctx, const void *n, const void *key) 132{ 133 const struct chfs_node_frag *frag = n; 134 uint64_t ofs = *(const uint64_t *)key; 135 136 return (frag->ofs - ofs); 137} 138 139const rb_tree_ops_t frag_rbtree_ops = { 140 .rbto_compare_nodes = frag_compare_nodes, 141 .rbto_compare_key = frag_compare_key, 142 .rbto_node_offset = offsetof(struct chfs_node_frag, rb_node), 143 .rbto_context = NULL 144}; 145 146 147/* 148 * ------------------- 149 * tmp node operations 150 * ------------------- 151 */ 152/* 153 * Check the data CRC of the node. 154 * 155 * Returns: 0 - if everything OK; 156 * 1 - if CRC is incorrect; 157 * 2 - else; 158 * error code if an error occured. 159 */ 160int 161chfs_check_td_data(struct chfs_mount *chmp, 162 struct chfs_tmp_dnode *td) 163{ 164 int err; 165 size_t retlen, len, totlen; 166 uint32_t crc; 167 uint64_t ofs; 168 char *buf; 169 struct chfs_node_ref *nref = td->node->nref; 170 171 KASSERT(mutex_owned(&chmp->chm_lock_mountfields)); 172 KASSERT(!mutex_owned(&chmp->chm_lock_sizes)); 173 174 ofs = CHFS_GET_OFS(nref->nref_offset) + sizeof(struct chfs_flash_data_node); 175 len = td->node->size; 176 if (!len) 177 return 0; 178 179 buf = kmem_alloc(len, KM_SLEEP); 180 if (!buf) { 181 dbg("allocating error\n"); 182 return 2; 183 } 184 err = chfs_read_leb(chmp, nref->nref_lnr, buf, ofs, len, &retlen); 185 if (err) { 186 dbg("error wile reading: %d\n", err); 187 err = 2; 188 goto out; 189 } 190 191 if (len != retlen) { 192 dbg("len:%zu, retlen:%zu\n", len, retlen); 193 err = 2; 194 goto out; 195 } 196 crc = crc32(0, (uint8_t *)buf, len); 197 198 if (crc != td->data_crc) { 199 dbg("crc failed, calculated: 0x%x, orig: 0x%x\n", crc, td->data_crc); 200 kmem_free(buf, len); 201 return 1; 202 } 203 204 nref->nref_offset = CHFS_GET_OFS(nref->nref_offset) | CHFS_NORMAL_NODE_MASK; 205 totlen = CHFS_PAD(sizeof(struct chfs_flash_data_node) + len); 206 207 mutex_enter(&chmp->chm_lock_sizes); 208 chfs_change_size_unchecked(chmp, &chmp->chm_blocks[nref->nref_lnr], -totlen); 209 chfs_change_size_used(chmp, &chmp->chm_blocks[nref->nref_lnr], totlen); 210 mutex_exit(&chmp->chm_lock_sizes); 211 KASSERT(chmp->chm_blocks[nref->nref_lnr].used_size <= chmp->chm_ebh->eb_size); 212 213 err = 0; 214out: 215 kmem_free(buf, len); 216 return err; 217} 218 219int 220chfs_check_td_node(struct chfs_mount *chmp, struct chfs_tmp_dnode *td) 221{ 222 int ret; 223 224 if (CHFS_REF_FLAGS(td->node->nref) != CHFS_UNCHECKED_NODE_MASK) 225 return 0; 226 227 ret = chfs_check_td_data(chmp, td); 228 if (ret == 1) { 229 chfs_mark_node_obsolete(chmp, td->node->nref); 230 } 231 return ret; 232} 233 234 235struct chfs_node_ref * 236chfs_first_valid_data_ref(struct chfs_node_ref *nref) 237{ 238 while (nref) { 239 if (!CHFS_REF_OBSOLETE(nref)) { 240#ifdef DGB_MSG_GC 241 if (nref->nref_lnr == REF_EMPTY_NODE) { 242 dbg("FIRST VALID IS EMPTY!\n"); 243 } 244#endif 245 return nref; 246 } 247 248 if (nref->nref_next) { 249 nref = nref->nref_next; 250 } else 251 break; 252 } 253 return NULL; 254} 255 256void 257chfs_add_tmp_dnode_to_tdi(struct chfs_tmp_dnode_info *tdi, 258 struct chfs_tmp_dnode *td) 259{ 260 if (!tdi->tmpnode) { 261 tdi->tmpnode = td; 262 } else { 263 struct chfs_tmp_dnode *tmp = tdi->tmpnode; 264 while (tmp->next) { 265 tmp = tmp->next; 266 } 267 tmp->next = td; 268 } 269} 270 271void 272chfs_remove_tmp_dnode_from_tdi(struct chfs_tmp_dnode_info *tdi, 273 struct chfs_tmp_dnode *td) 274{ 275 if (tdi->tmpnode == td) { 276 tdi->tmpnode = tdi->tmpnode->next; 277 } else { 278 struct chfs_tmp_dnode *tmp = tdi->tmpnode->next; 279 while (tmp->next && tmp->next != td) { 280 tmp = tmp->next; 281 } 282 if (tmp->next) { 283 tmp->next = td->next; 284 } 285 } 286} 287 288static void 289chfs_kill_td(struct chfs_mount *chmp, 290 struct chfs_tmp_dnode *td) 291{ 292 /* check if we need to mark as obsolete, to avoid double mark */ 293 if (!CHFS_REF_OBSOLETE(td->node->nref)) { 294 chfs_mark_node_obsolete(chmp, td->node->nref); 295 } 296 297 chfs_free_tmp_dnode(td); 298} 299 300static void 301chfs_kill_tdi(struct chfs_mount *chmp, 302 struct chfs_tmp_dnode_info *tdi) 303{ 304 struct chfs_tmp_dnode *next, *tmp = tdi->tmpnode; 305 306 while (tmp) { 307 next = tmp->next; 308 chfs_kill_td(chmp, tmp); 309 tmp = next; 310 } 311 312 chfs_free_tmp_dnode_info(tdi); 313} 314 315int 316chfs_add_tmp_dnode_to_tree(struct chfs_mount *chmp, 317 struct chfs_readinode_info *rii, 318 struct chfs_tmp_dnode *newtd) 319{ 320 uint64_t end_ofs = newtd->node->ofs + newtd->node->size; 321 struct chfs_tmp_dnode_info *this; 322 struct rb_node *node, *prev_node; 323 struct chfs_tmp_dnode_info *newtdi; 324 325 node = rb_tree_find_node(&rii->tdi_root, &newtd->node->ofs); 326 if (node) { 327 this = (struct chfs_tmp_dnode_info *)node; 328 while (this->tmpnode->overlapped) { 329 prev_node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_LEFT); 330 if (!prev_node) { 331 this->tmpnode->overlapped = 0; 332 break; 333 } 334 node = prev_node; 335 this = (struct chfs_tmp_dnode_info *)node; 336 } 337 } 338 while (node) { 339 this = (struct chfs_tmp_dnode_info *)node; 340 if (this->tmpnode->node->ofs > end_ofs) 341 break; 342 343 struct chfs_tmp_dnode *tmp_td = this->tmpnode; 344 while (tmp_td) { 345 if (tmp_td->version == newtd->version) { 346 if (!chfs_check_td_node(chmp, tmp_td)) { 347 dbg("calling kill td 0\n"); 348 chfs_kill_td(chmp, newtd); 349 return 0; 350 } else { 351 chfs_remove_tmp_dnode_from_tdi(this, tmp_td); 352 chfs_kill_td(chmp, tmp_td); 353 chfs_add_tmp_dnode_to_tdi(this, newtd); 354 return 0; 355 } 356 } 357 if (tmp_td->version < newtd->version && 358 tmp_td->node->ofs >= newtd->node->ofs && 359 tmp_td->node->ofs + tmp_td->node->size <= end_ofs) { 360 /* New node entirely overlaps 'this' */ 361 if (chfs_check_td_node(chmp, newtd)) { 362 dbg("calling kill td 2\n"); 363 chfs_kill_td(chmp, newtd); 364 return 0; 365 } 366 /* ... and is good. Kill 'this' and any subsequent nodes which are also overlapped */ 367 while (tmp_td && tmp_td->node->ofs + tmp_td->node->size <= end_ofs) { 368 struct rb_node *next = rb_tree_iterate(&rii->tdi_root, this, RB_DIR_RIGHT); 369 struct chfs_tmp_dnode_info *next_tdi = (struct chfs_tmp_dnode_info *)next; 370 struct chfs_tmp_dnode *next_td = NULL; 371 if (tmp_td->next) { 372 next_td = tmp_td->next; 373 } else if (next_tdi) { 374 next_td = next_tdi->tmpnode; 375 } 376 if (tmp_td->version < newtd->version) { 377 chfs_remove_tmp_dnode_from_tdi(this, tmp_td); 378 chfs_kill_td(chmp, tmp_td); 379 if (!this->tmpnode) { 380 rb_tree_remove_node(&rii->tdi_root, this); 381 chfs_kill_tdi(chmp, this); 382 this = next_tdi; 383 } 384 } 385 tmp_td = next_td; 386 } 387 continue; 388 } 389 if (tmp_td->version > newtd->version && 390 tmp_td->node->ofs <= newtd->node->ofs && 391 tmp_td->node->ofs + tmp_td->node->size >= end_ofs) { 392 /* New node entirely overlapped by 'this' */ 393 if (!chfs_check_td_node(chmp, tmp_td)) { 394 dbg("this version: %llu\n", 395 (unsigned long long)tmp_td->version); 396 dbg("this ofs: %llu, size: %u\n", 397 (unsigned long long)tmp_td->node->ofs, 398 tmp_td->node->size); 399 dbg("calling kill td 4\n"); 400 chfs_kill_td(chmp, newtd); 401 return 0; 402 } 403 /* ... but 'this' was bad. Replace it... */ 404 chfs_remove_tmp_dnode_from_tdi(this, tmp_td); 405 chfs_kill_td(chmp, tmp_td); 406 if (!this->tmpnode) { 407 rb_tree_remove_node(&rii->tdi_root, this); 408 chfs_kill_tdi(chmp, this); 409 } 410 dbg("calling kill td 5\n"); 411 chfs_kill_td(chmp, newtd); 412 break; 413 } 414 tmp_td = tmp_td->next; 415 } 416 node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_RIGHT); 417 } 418 419 newtdi = chfs_alloc_tmp_dnode_info(); 420 chfs_add_tmp_dnode_to_tdi(newtdi, newtd); 421 /* We neither completely obsoleted nor were completely 422 obsoleted by an earlier node. Insert into the tree */ 423 struct chfs_tmp_dnode_info *tmp_tdi = rb_tree_insert_node(&rii->tdi_root, newtdi); 424 if (tmp_tdi != newtdi) { 425 chfs_add_tmp_dnode_to_tdi(tmp_tdi, newtd); 426 newtdi->tmpnode = NULL; 427 chfs_kill_tdi(chmp, newtdi); 428 } 429 430 /* If there's anything behind that overlaps us, note it */ 431 node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_LEFT); 432 if (node) { 433 while (1) { 434 this = (struct chfs_tmp_dnode_info *)node; 435 if (this->tmpnode->node->ofs + this->tmpnode->node->size > newtd->node->ofs) { 436 newtd->overlapped = 1; 437 } 438 if (!this->tmpnode->overlapped) 439 break; 440 441 prev_node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_LEFT); 442 if (!prev_node) { 443 this->tmpnode->overlapped = 0; 444 break; 445 } 446 node = prev_node; 447 } 448 } 449 450 /* If the new node overlaps anything ahead, note it */ 451 node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_RIGHT); 452 this = (struct chfs_tmp_dnode_info *)node; 453 while (this && this->tmpnode->node->ofs < end_ofs) { 454 this->tmpnode->overlapped = 1; 455 node = rb_tree_iterate(&rii->tdi_root, node, RB_DIR_RIGHT); 456 this = (struct chfs_tmp_dnode_info *)node; 457 } 458 return 0; 459} 460 461 462/* 463 * -------------------- 464 * frag node operations 465 * -------------------- 466 */ 467struct chfs_node_frag * 468new_fragment(struct chfs_full_dnode *fdn, uint32_t ofs, uint32_t size) 469{ 470 struct chfs_node_frag *newfrag; 471 newfrag = chfs_alloc_node_frag(); 472 if (newfrag) { 473 newfrag->ofs = ofs; 474 newfrag->size = size; 475 newfrag->node = fdn; 476 } else { 477 chfs_err("cannot allocate a chfs_node_frag object\n"); 478 } 479 return newfrag; 480} 481 482int 483no_overlapping_node(struct rb_tree *fragtree, 484 struct chfs_node_frag *newfrag, 485 struct chfs_node_frag *this, uint32_t lastend) 486{ 487 if (lastend < newfrag->node->ofs) { 488 struct chfs_node_frag *holefrag; 489 490 holefrag = new_fragment(NULL, lastend, newfrag->node->ofs - lastend); 491 if (!holefrag) { 492 chfs_free_node_frag(newfrag); 493 return ENOMEM; 494 } 495 496 rb_tree_insert_node(fragtree, holefrag); 497 this = holefrag; 498 } 499 500 rb_tree_insert_node(fragtree, newfrag); 501 502 return 0; 503} 504 505int 506chfs_add_frag_to_fragtree(struct chfs_mount *chmp, 507 struct rb_tree *fragtree, 508 struct chfs_node_frag *newfrag) 509{ 510 struct chfs_node_frag *this; 511 uint32_t lastend; 512 KASSERT(mutex_owned(&chmp->chm_lock_mountfields)); 513 514 this = (struct chfs_node_frag *)rb_tree_find_node_leq(fragtree, &newfrag->ofs); 515 516 if (this) { 517 lastend = this->ofs + this->size; 518 } else { 519 lastend = 0; 520 } 521 522 if (lastend <= newfrag->ofs) { 523 //dbg("no overlapping node\n"); 524 if (lastend && (lastend - 1) >> PAGE_SHIFT == newfrag->ofs >> PAGE_SHIFT) { 525 if (this->node) 526 CHFS_MARK_REF_NORMAL(this->node->nref); 527 CHFS_MARK_REF_NORMAL(newfrag->node->nref); 528 } 529 return no_overlapping_node(fragtree, newfrag, this, lastend); 530 } 531 532 if (newfrag->ofs > this->ofs) { 533 534 CHFS_MARK_REF_NORMAL(newfrag->node->nref); 535 if (this->node) 536 CHFS_MARK_REF_NORMAL(this->node->nref); 537 538 if (this->ofs + this->size > newfrag->ofs + newfrag->size) { 539 /* newfrag is inside of this */ 540 //dbg("newfrag is inside of this\n"); 541 struct chfs_node_frag *newfrag2; 542 543 newfrag2 = new_fragment(this->node, newfrag->ofs + newfrag->size, 544 this->ofs + this->size - newfrag->ofs - newfrag->size); 545 if (!newfrag2) 546 return ENOMEM; 547 if (this->node) 548 this->node->frags++; 549 550 this->size = newfrag->ofs - this->ofs; 551 552 rb_tree_insert_node(fragtree, newfrag); 553 rb_tree_insert_node(fragtree, newfrag2); 554 555 return 0; 556 } 557 /* newfrag is bottom of this */ 558 //dbg("newfrag is bottom of this\n"); 559 this->size = newfrag->ofs - this->ofs; 560 rb_tree_insert_node(fragtree, newfrag); 561 } else { 562 /* newfrag start at same point */ 563 //dbg("newfrag start at same point\n"); 564 //TODO replace instead of remove and insert 565 rb_tree_remove_node(fragtree, this); 566 rb_tree_insert_node(fragtree, newfrag); 567 568 if (newfrag->ofs + newfrag->size >= this->ofs+this->size) { 569 chfs_obsolete_node_frag(chmp, this); 570 } else { 571 this->ofs += newfrag->size; 572 this->size -= newfrag->size; 573 574 rb_tree_insert_node(fragtree, this); 575 return 0; 576 } 577 } 578 /* OK, now we have newfrag added in the correct place in the tree, but 579 frag_next(newfrag) may be a fragment which is overlapped by it 580 */ 581 while ((this = frag_next(fragtree, newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) { 582 rb_tree_remove_node(fragtree, this); 583 chfs_obsolete_node_frag(chmp, this); 584 } 585 586 if (!this || newfrag->ofs + newfrag->size == this->ofs) 587 return 0; 588 589 this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); 590 this->ofs = newfrag->ofs + newfrag->size; 591 592 if (this->node) 593 CHFS_MARK_REF_NORMAL(this->node->nref); 594 CHFS_MARK_REF_NORMAL(newfrag->node->nref); 595 596 return 0; 597} 598 599void 600chfs_kill_fragtree(struct rb_tree *fragtree) 601{ 602 struct chfs_node_frag *this, *next; 603 //dbg("start\n"); 604 605 this = (struct chfs_node_frag *)RB_TREE_MIN(fragtree); 606 while (this) { 607 //for (this = (struct chfs_node_frag *)RB_TREE_MIN(&fragtree); this != NULL; this = (struct chfs_node_frag *)rb_tree_iterate(&fragtree, &this->rb_node, RB_DIR_RIGHT)) { 608 next = frag_next(fragtree, this); 609 rb_tree_remove_node(fragtree, this); 610 chfs_free_node_frag(this); 611 //dbg("one frag killed\n"); 612 this = next; 613 } 614 //dbg("end\n"); 615} 616 617uint32_t 618chfs_truncate_fragtree(struct chfs_mount *chmp, 619 struct rb_tree *fragtree, uint32_t size) 620{ 621 struct chfs_node_frag *frag; 622 KASSERT(mutex_owned(&chmp->chm_lock_mountfields)); 623 624 dbg("truncate to size: %u\n", size); 625 626 frag = (struct chfs_node_frag *)rb_tree_find_node_leq(fragtree, &size); 627 628 /* Find the last frag before size and set its new size. */ 629 if (frag && frag->ofs != size) { 630 if (frag->ofs + frag->size > size) { 631 frag->size = size - frag->ofs; 632 } 633 frag = frag_next(fragtree, frag); 634 } 635 636 /* Delete frags after new size. */ 637 while (frag && frag->ofs >= size) { 638 struct chfs_node_frag *next = frag_next(fragtree, frag); 639 640 rb_tree_remove_node(fragtree, frag); 641 chfs_obsolete_node_frag(chmp, frag); 642 frag = next; 643 } 644 645 if (size == 0) { 646 return 0; 647 } 648 649 frag = frag_last(fragtree); 650 651 if (!frag) { 652 return 0; 653 } 654 655 if (frag->ofs + frag->size < size) { 656 return frag->ofs + frag->size; 657 } 658 659 /* FIXME Should we check the postion of the last node? (PAGE_CACHE size, etc.) */ 660 if (frag->node && (frag->ofs & (PAGE_SIZE - 1)) == 0) { 661 frag->node->nref->nref_offset = CHFS_GET_OFS(frag->node->nref->nref_offset) | CHFS_PRISTINE_NODE_MASK; 662 } 663 664 return size; 665} 666 667void 668chfs_obsolete_node_frag(struct chfs_mount *chmp, 669 struct chfs_node_frag *this) 670{ 671 KASSERT(mutex_owned(&chmp->chm_lock_mountfields)); 672 if (this->node) { 673 this->node->frags--; 674 if (!this->node->frags) { 675 struct chfs_vnode_cache *vc = chfs_nref_to_vc(this->node->nref); 676 chfs_mark_node_obsolete(chmp, this->node->nref); 677 678 if (vc->dnode == this->node->nref) { 679 vc->dnode = this->node->nref->nref_next; 680 } else { 681 struct chfs_node_ref *tmp = vc->dnode; 682 while (tmp->nref_next != (struct chfs_node_ref*) vc 683 && tmp->nref_next != this->node->nref) { 684 tmp = tmp->nref_next; 685 } 686 if (tmp->nref_next == this->node->nref) { 687 tmp->nref_next = this->node->nref->nref_next; 688 } 689 // FIXME should we free here the this->node->nref? 690 } 691 692 chfs_free_full_dnode(this->node); 693 } else { 694 CHFS_MARK_REF_NORMAL(this->node->nref); 695 } 696 } 697 chfs_free_node_frag(this); 698} 699 700int 701chfs_add_full_dnode_to_inode(struct chfs_mount *chmp, 702 struct chfs_inode *ip, 703 struct chfs_full_dnode *fd) 704{ 705 int ret; 706 struct chfs_node_frag *newfrag; 707 KASSERT(mutex_owned(&chmp->chm_lock_mountfields)); 708 709 if (unlikely(!fd->size)) 710 return 0; 711 712 newfrag = new_fragment(fd, fd->ofs, fd->size); 713 if (unlikely(!newfrag)) 714 return ENOMEM; 715 716 newfrag->node->frags = 1; 717 718 ret = chfs_add_frag_to_fragtree(chmp, &ip->fragtree, newfrag); 719 if (ret) 720 return ret; 721 722 if (newfrag->ofs & (PAGE_SIZE - 1)) { 723 struct chfs_node_frag *prev = frag_prev(&ip->fragtree, newfrag); 724 725 CHFS_MARK_REF_NORMAL(fd->nref); 726 if (prev->node) 727 CHFS_MARK_REF_NORMAL(prev->node->nref); 728 } 729 730 if ((newfrag->ofs+newfrag->size) & (PAGE_SIZE - 1)) { 731 struct chfs_node_frag *next = frag_next(&ip->fragtree, newfrag); 732 733 if (next) { 734 CHFS_MARK_REF_NORMAL(fd->nref); 735 if (next->node) 736 CHFS_MARK_REF_NORMAL(next->node->nref); 737 } 738 } 739 740 return 0; 741} 742 743 744/* 745 * ----------------------- 746 * general node operations 747 * ----------------------- 748 */ 749/* get tmp nodes of an inode */ 750int 751chfs_get_data_nodes(struct chfs_mount *chmp, 752 struct chfs_inode *ip, 753 struct chfs_readinode_info *rii) 754{ 755 uint32_t crc; 756 int err; 757 size_t len, retlen; 758 struct chfs_node_ref *nref; 759 struct chfs_flash_data_node *dnode; 760 struct chfs_tmp_dnode *td; 761 char* buf; 762 763 len = sizeof(struct chfs_flash_data_node); 764 buf = kmem_alloc(len, KM_SLEEP); 765 766 dnode = kmem_alloc(len, KM_SLEEP); 767 if (!dnode) 768 return ENOMEM; 769 770 nref = chfs_first_valid_data_ref(ip->chvc->dnode); 771 772 rii->highest_version = ip->chvc->highest_version; 773 774 while(nref && (struct chfs_vnode_cache *)nref != ip->chvc) { 775 err = chfs_read_leb(chmp, nref->nref_lnr, buf, CHFS_GET_OFS(nref->nref_offset), len, &retlen); 776 if (err || len != retlen) 777 goto out; 778 dnode = (struct chfs_flash_data_node*)buf; 779 780 //check header crc 781 crc = crc32(0, (uint8_t *)dnode, CHFS_NODE_HDR_SIZE - 4); 782 if (crc != le32toh(dnode->hdr_crc)) { 783 chfs_err("CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->hdr_crc)); 784 goto cont; 785 } 786 //check header magic bitmask 787 if (le16toh(dnode->magic) != CHFS_FS_MAGIC_BITMASK) { 788 chfs_err("Wrong magic bitmask.\n"); 789 goto cont; 790 } 791 //check node crc 792 crc = crc32(0, (uint8_t *)dnode, sizeof(*dnode) - 4); 793 if (crc != le32toh(dnode->node_crc)) { 794 chfs_err("Node CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->node_crc)); 795 goto cont; 796 } 797 td = chfs_alloc_tmp_dnode(); 798 if (!td) { 799 chfs_err("Can't allocate tmp dnode info.\n"); 800 err = ENOMEM; 801 goto out; 802 } 803 /* We don't check data crc here, just add nodes to tmp frag tree, because 804 * we don't want to check nodes which have been overlapped by a new node 805 * with a higher version number. 806 */ 807 td->node = chfs_alloc_full_dnode(); 808 if (!td->node) { 809 chfs_err("Can't allocate full dnode info.\n"); 810 err = ENOMEM; 811 goto out_tmp_dnode; 812 } 813 td->version = le64toh(dnode->version); 814 td->node->ofs = le64toh(dnode->offset); 815 td->data_crc = le32toh(dnode->data_crc); 816 td->node->nref = nref; 817 td->node->size = le32toh(dnode->data_length); 818 td->overlapped = 0; 819 820 if (td->version > rii->highest_version) { 821 rii->highest_version = td->version; 822 } 823 824 err = chfs_add_tmp_dnode_to_tree(chmp, rii, td); 825 if (err) 826 goto out_full_dnode; 827 828cont: 829 nref = chfs_first_valid_data_ref(nref->nref_next); 830 } 831 832 ip->chvc->highest_version = rii->highest_version; 833 return 0; 834 835/* Exit points */ 836out_full_dnode: 837 chfs_free_full_dnode(td->node); 838out_tmp_dnode: 839 chfs_free_tmp_dnode(td); 840out: 841 kmem_free(buf, len); 842 kmem_free(dnode, len); 843 return err; 844} 845 846 847/* Build final normal fragtree from tdi tree. */ 848int 849chfs_build_fragtree(struct chfs_mount *chmp, struct chfs_inode *ip, 850 struct chfs_readinode_info *rii) 851{ 852 struct chfs_tmp_dnode_info *pen, *last, *this; 853 struct rb_tree ver_tree; /* version tree */ 854 uint64_t high_ver = 0; 855 KASSERT(mutex_owned(&chmp->chm_lock_mountfields)); 856 857 rb_tree_init(&ver_tree, &tmp_node_rbtree_ops); 858 859 if (rii->mdata_tn) { 860 high_ver = rii->mdata_tn->tmpnode->version; 861 rii->latest_ref = rii->mdata_tn->tmpnode->node->nref; 862 } 863 864 pen = (struct chfs_tmp_dnode_info *)RB_TREE_MAX(&rii->tdi_root); 865 866 while((last = pen)) { 867 pen = (struct chfs_tmp_dnode_info *)rb_tree_iterate(&rii->tdi_root, last, RB_DIR_LEFT); 868 869 rb_tree_remove_node(&rii->tdi_root, last); 870 rb_tree_insert_node(&ver_tree, last); 871 872 if (last->tmpnode->overlapped) { 873 if (pen) 874 continue; 875 876 last->tmpnode->overlapped = 0; 877 } 878 879 this = (struct chfs_tmp_dnode_info *)RB_TREE_MAX(&ver_tree); 880 881 while (this) { 882 struct chfs_tmp_dnode_info *vers_next; 883 int ret; 884 885 vers_next = (struct chfs_tmp_dnode_info *)rb_tree_iterate(&ver_tree, this, RB_DIR_LEFT); 886 rb_tree_remove_node(&ver_tree, this); 887 888 struct chfs_tmp_dnode *tmp_td = this->tmpnode; 889 while (tmp_td) { 890 struct chfs_tmp_dnode *next_td = tmp_td->next; 891 892 if (chfs_check_td_node(chmp, tmp_td)) { 893 if (next_td) { 894 chfs_remove_tmp_dnode_from_tdi(this, tmp_td); 895 } else { 896 break; 897 } 898 } else { 899 if (tmp_td->version > high_ver) { 900 high_ver = tmp_td->version; 901 dbg("highver: %llu\n", (unsigned long long)high_ver); 902 rii->latest_ref = tmp_td->node->nref; 903 } 904 905 ret = chfs_add_full_dnode_to_inode(chmp, ip, tmp_td->node); 906 if (ret) { 907 while (1) { 908 vers_next = (struct chfs_tmp_dnode_info *)rb_tree_iterate(&ver_tree, this, RB_DIR_LEFT); 909 while (tmp_td) { 910 next_td = tmp_td->next; 911 if (chfs_check_td_node(chmp, tmp_td) > 1) { 912 chfs_mark_node_obsolete(chmp, 913 tmp_td->node->nref); 914 } 915 chfs_free_full_dnode(tmp_td->node); 916 chfs_remove_tmp_dnode_from_tdi(this, tmp_td); 917 chfs_free_tmp_dnode(tmp_td); 918 tmp_td = next_td; 919 } 920 chfs_free_tmp_dnode_info(this); 921 this = vers_next; 922 if (!this) 923 break; 924 rb_tree_remove_node(&ver_tree, vers_next); 925 } 926 return ret; 927 } 928 929 chfs_remove_tmp_dnode_from_tdi(this, tmp_td); 930 chfs_free_tmp_dnode(tmp_td); 931 } 932 tmp_td = next_td; 933 } 934 chfs_kill_tdi(chmp, this); 935 this = vers_next; 936 } 937 } 938 939 return 0; 940} 941 942int chfs_read_inode(struct chfs_mount *chmp, struct chfs_inode *ip) 943{ 944 struct chfs_vnode_cache *vc = ip->chvc; 945 946 KASSERT(mutex_owned(&chmp->chm_lock_mountfields)); 947 948retry: 949 /* XXX locking */ 950 //mutex_enter(&chmp->chm_lock_vnocache); 951 switch (vc->state) { 952 case VNO_STATE_UNCHECKED: 953 case VNO_STATE_CHECKEDABSENT: 954// chfs_vnode_cache_set_state(chmp, vc, VNO_STATE_READING); 955 vc->state = VNO_STATE_READING; 956 break; 957 case VNO_STATE_CHECKING: 958 case VNO_STATE_GC: 959 //sleep_on_spinunlock(&chmp->chm_lock_vnocache); 960 //KASSERT(!mutex_owned(&chmp->chm_lock_vnocache)); 961 goto retry; 962 break; 963 case VNO_STATE_PRESENT: 964 case VNO_STATE_READING: 965 chfs_err("Reading inode #%llu in state %d!\n", 966 (unsigned long long)vc->vno, vc->state); 967 chfs_err("wants to read a nonexistent ino %llu\n", 968 (unsigned long long)vc->vno); 969 return ENOENT; 970 default: 971 panic("BUG() Bad vno cache state."); 972 } 973 //mutex_exit(&chmp->chm_lock_vnocache); 974 975 return chfs_read_inode_internal(chmp, ip); 976} 977 978/* 979 * Read inode frags. 980 * Firstly get tmp nodes, 981 * secondly build fragtree from those. 982 */ 983int 984chfs_read_inode_internal(struct chfs_mount *chmp, struct chfs_inode *ip) 985{ 986 int err; 987 size_t len, retlen; 988 char* buf; 989 struct chfs_readinode_info rii; 990 struct chfs_flash_vnode *fvnode; 991 992 KASSERT(mutex_owned(&chmp->chm_lock_mountfields)); 993 994 len = sizeof(*fvnode); 995 996 memset(&rii, 0, sizeof(rii)); 997 998 rb_tree_init(&rii.tdi_root, &tmp_node_rbtree_ops); 999 1000 /* build up a temp node frag tree */ 1001 err = chfs_get_data_nodes(chmp, ip, &rii); 1002 if (err) { 1003 if (ip->chvc->state == VNO_STATE_READING) 1004 ip->chvc->state = VNO_STATE_CHECKEDABSENT; 1005 /* FIXME Should we kill fragtree or something here? */ 1006 return err; 1007 } 1008 1009 rb_tree_init(&ip->fragtree, &frag_rbtree_ops); 1010 /* 1011 * build fragtree from temp nodes 1012 */ 1013 err = chfs_build_fragtree(chmp, ip, &rii); 1014 if (err) { 1015 if (ip->chvc->state == VNO_STATE_READING) 1016 ip->chvc->state = VNO_STATE_CHECKEDABSENT; 1017 /* FIXME Should we kill fragtree or something here? */ 1018 return err; 1019 } 1020 1021 if (!rii.latest_ref) { 1022 return 0; 1023 } 1024 1025 buf = kmem_alloc(len, KM_SLEEP); 1026 if (!buf) 1027 return ENOMEM; 1028 1029 /* 1030 * set inode size from chvc->v 1031 */ 1032 err = chfs_read_leb(chmp, ip->chvc->v->nref_lnr, buf, CHFS_GET_OFS(ip->chvc->v->nref_offset), len, &retlen); 1033 if (err || retlen != len) { 1034 kmem_free(buf, len); 1035 return err?err:EIO; 1036 } 1037 1038 fvnode = (struct chfs_flash_vnode*)buf; 1039 1040 dbg("set size from v: %u\n", fvnode->dn_size); 1041 chfs_set_vnode_size(ITOV(ip), fvnode->dn_size); 1042 uint32_t retsize = chfs_truncate_fragtree(chmp, &ip->fragtree, fvnode->dn_size); 1043 if (retsize != fvnode->dn_size) { 1044 dbg("Truncating failed. It is %u instead of %u\n", retsize, fvnode->dn_size); 1045 } 1046 1047 kmem_free(buf, len); 1048 1049 if (ip->chvc->state == VNO_STATE_READING) { 1050 ip->chvc->state = VNO_STATE_PRESENT; 1051 } 1052 1053 return 0; 1054} 1055 1056int 1057chfs_read_data(struct chfs_mount* chmp, struct vnode *vp, 1058 struct buf *bp) 1059{ 1060 off_t ofs; 1061 struct chfs_node_frag *frag; 1062 char * buf; 1063 int err = 0; 1064 size_t size, retlen; 1065 uint32_t crc; 1066 struct chfs_inode *ip = VTOI(vp); 1067 struct chfs_flash_data_node *dnode; 1068 struct chfs_node_ref *nref; 1069 1070 memset(bp->b_data, 0, bp->b_bcount); 1071 1072 ofs = bp->b_blkno * PAGE_SIZE; 1073 frag = (struct chfs_node_frag *)rb_tree_find_node_leq(&ip->fragtree, &ofs); 1074 1075 if (!frag || frag->ofs > ofs || frag->ofs + frag->size <= ofs) { 1076 dbg("not found in frag tree\n"); 1077 return 0; 1078 } 1079 1080 if (!frag->node) { 1081 dbg("no node in frag\n"); 1082 return 0; 1083 } 1084 1085 nref = frag->node->nref; 1086 1087 size = sizeof(*dnode) + frag->size; 1088 1089 buf = kmem_alloc(size, KM_SLEEP); 1090 1091 dbg("reading from lnr: %u, offset: %u, size: %zu\n", nref->nref_lnr, CHFS_GET_OFS(nref->nref_offset), size); 1092 err = chfs_read_leb(chmp, nref->nref_lnr, buf, CHFS_GET_OFS(nref->nref_offset), size, &retlen); 1093 if (err) { 1094 chfs_err("error after reading: %d\n", err); 1095 goto out; 1096 } 1097 if (retlen != size) { 1098 chfs_err("retlen: %zu != size: %zu\n", retlen, size); 1099 err = EIO; 1100 goto out; 1101 } 1102 1103 dnode = (struct chfs_flash_data_node *)buf; 1104 crc = crc32(0, (uint8_t *)dnode, CHFS_NODE_HDR_SIZE - 4); 1105 if (crc != le32toh(dnode->hdr_crc)) { 1106 chfs_err("CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->hdr_crc)); 1107 err = EIO; 1108 goto out; 1109 } 1110 //check header magic bitmask 1111 if (le16toh(dnode->magic) != CHFS_FS_MAGIC_BITMASK) { 1112 chfs_err("Wrong magic bitmask.\n"); 1113 err = EIO; 1114 goto out; 1115 } 1116 //check node crc 1117 crc = crc32(0, (uint8_t *)dnode, sizeof(*dnode) - 4); 1118 if (crc != le32toh(dnode->node_crc)) { 1119 chfs_err("Node CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->node_crc)); 1120 err = EIO; 1121 goto out; 1122 } 1123 crc = crc32(0, (uint8_t *)dnode->data, dnode->data_length); 1124 if (crc != le32toh(dnode->data_crc)) { 1125 chfs_err("Data CRC check failed. calc: 0x%x orig: 0x%x\n", crc, le32toh(dnode->data_crc)); 1126 err = EIO; 1127 goto out; 1128 } 1129 1130 memcpy(bp->b_data, dnode->data, dnode->data_length); 1131 bp->b_resid = 0; 1132 1133out: 1134 kmem_free(buf, size); 1135 return err; 1136} 1137