diff options
Diffstat (limited to 'fs/jffs2/readinode.c')
-rw-r--r-- | fs/jffs2/readinode.c | 103 |
1 files changed, 87 insertions, 16 deletions
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index aca4a0b17bcd..5b2a83599d73 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * | 7 | * |
8 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
9 | * | 9 | * |
10 | * $Id: readinode.c,v 1.117 2004/11/20 18:06:54 dwmw2 Exp $ | 10 | * $Id: readinode.c,v 1.125 2005/07/10 13:13:55 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -151,6 +151,9 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in | |||
151 | 151 | ||
152 | D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); | 152 | D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); |
153 | 153 | ||
154 | if (unlikely(!fn->size)) | ||
155 | return 0; | ||
156 | |||
154 | newfrag = jffs2_alloc_node_frag(); | 157 | newfrag = jffs2_alloc_node_frag(); |
155 | if (unlikely(!newfrag)) | 158 | if (unlikely(!newfrag)) |
156 | return -ENOMEM; | 159 | return -ENOMEM; |
@@ -158,11 +161,6 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in | |||
158 | D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", | 161 | D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", |
159 | fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); | 162 | fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); |
160 | 163 | ||
161 | if (unlikely(!fn->size)) { | ||
162 | jffs2_free_node_frag(newfrag); | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | newfrag->ofs = fn->ofs; | 164 | newfrag->ofs = fn->ofs; |
167 | newfrag->size = fn->size; | 165 | newfrag->size = fn->size; |
168 | newfrag->node = fn; | 166 | newfrag->node = fn; |
@@ -500,7 +498,9 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
500 | struct jffs2_inode_info *f, | 498 | struct jffs2_inode_info *f, |
501 | struct jffs2_raw_inode *latest_node) | 499 | struct jffs2_raw_inode *latest_node) |
502 | { | 500 | { |
503 | struct jffs2_tmp_dnode_info *tn_list, *tn; | 501 | struct jffs2_tmp_dnode_info *tn = NULL; |
502 | struct rb_root tn_list; | ||
503 | struct rb_node *rb, *repl_rb; | ||
504 | struct jffs2_full_dirent *fd_list; | 504 | struct jffs2_full_dirent *fd_list; |
505 | struct jffs2_full_dnode *fn = NULL; | 505 | struct jffs2_full_dnode *fn = NULL; |
506 | uint32_t crc; | 506 | uint32_t crc; |
@@ -522,9 +522,10 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
522 | } | 522 | } |
523 | f->dents = fd_list; | 523 | f->dents = fd_list; |
524 | 524 | ||
525 | while (tn_list) { | 525 | rb = rb_first(&tn_list); |
526 | tn = tn_list; | ||
527 | 526 | ||
527 | while (rb) { | ||
528 | tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb); | ||
528 | fn = tn->fn; | 529 | fn = tn->fn; |
529 | 530 | ||
530 | if (f->metadata) { | 531 | if (f->metadata) { |
@@ -556,7 +557,29 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
556 | mdata_ver = tn->version; | 557 | mdata_ver = tn->version; |
557 | } | 558 | } |
558 | next_tn: | 559 | next_tn: |
559 | tn_list = tn->next; | 560 | BUG_ON(rb->rb_left); |
561 | if (rb->rb_parent && rb->rb_parent->rb_left == rb) { | ||
562 | /* We were then left-hand child of our parent. We need | ||
563 | to move our own right-hand child into our place. */ | ||
564 | repl_rb = rb->rb_right; | ||
565 | if (repl_rb) | ||
566 | repl_rb->rb_parent = rb->rb_parent; | ||
567 | } else | ||
568 | repl_rb = NULL; | ||
569 | |||
570 | rb = rb_next(rb); | ||
571 | |||
572 | /* Remove the spent tn from the tree; don't bother rebalancing | ||
573 | but put our right-hand child in our own place. */ | ||
574 | if (tn->rb.rb_parent) { | ||
575 | if (tn->rb.rb_parent->rb_left == &tn->rb) | ||
576 | tn->rb.rb_parent->rb_left = repl_rb; | ||
577 | else if (tn->rb.rb_parent->rb_right == &tn->rb) | ||
578 | tn->rb.rb_parent->rb_right = repl_rb; | ||
579 | else BUG(); | ||
580 | } else if (tn->rb.rb_right) | ||
581 | tn->rb.rb_right->rb_parent = NULL; | ||
582 | |||
560 | jffs2_free_tmp_dnode_info(tn); | 583 | jffs2_free_tmp_dnode_info(tn); |
561 | } | 584 | } |
562 | D1(jffs2_sanitycheck_fragtree(f)); | 585 | D1(jffs2_sanitycheck_fragtree(f)); |
@@ -623,6 +646,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
623 | case. */ | 646 | case. */ |
624 | if (!je32_to_cpu(latest_node->isize)) | 647 | if (!je32_to_cpu(latest_node->isize)) |
625 | latest_node->isize = latest_node->dsize; | 648 | latest_node->isize = latest_node->dsize; |
649 | |||
650 | if (f->inocache->state != INO_STATE_CHECKING) { | ||
651 | /* Symlink's inode data is the target path. Read it and | ||
652 | * keep in RAM to facilitate quick follow symlink operation. | ||
653 | * We use f->dents field to store the target path, which | ||
654 | * is somewhat ugly. */ | ||
655 | f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); | ||
656 | if (!f->dents) { | ||
657 | printk(KERN_WARNING "Can't allocate %d bytes of memory " | ||
658 | "for the symlink target path cache\n", | ||
659 | je32_to_cpu(latest_node->csize)); | ||
660 | up(&f->sem); | ||
661 | jffs2_do_clear_inode(c, f); | ||
662 | return -ENOMEM; | ||
663 | } | ||
664 | |||
665 | ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), | ||
666 | je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); | ||
667 | |||
668 | if (ret || retlen != je32_to_cpu(latest_node->csize)) { | ||
669 | if (retlen != je32_to_cpu(latest_node->csize)) | ||
670 | ret = -EIO; | ||
671 | kfree(f->dents); | ||
672 | f->dents = NULL; | ||
673 | up(&f->sem); | ||
674 | jffs2_do_clear_inode(c, f); | ||
675 | return -ret; | ||
676 | } | ||
677 | |||
678 | ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; | ||
679 | D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", | ||
680 | (char *)f->dents)); | ||
681 | } | ||
682 | |||
626 | /* fall through... */ | 683 | /* fall through... */ |
627 | 684 | ||
628 | case S_IFBLK: | 685 | case S_IFBLK: |
@@ -672,6 +729,9 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
672 | down(&f->sem); | 729 | down(&f->sem); |
673 | deleted = f->inocache && !f->inocache->nlink; | 730 | deleted = f->inocache && !f->inocache->nlink; |
674 | 731 | ||
732 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) | ||
733 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING); | ||
734 | |||
675 | if (f->metadata) { | 735 | if (f->metadata) { |
676 | if (deleted) | 736 | if (deleted) |
677 | jffs2_mark_node_obsolete(c, f->metadata->raw); | 737 | jffs2_mark_node_obsolete(c, f->metadata->raw); |
@@ -680,16 +740,27 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
680 | 740 | ||
681 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); | 741 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); |
682 | 742 | ||
683 | fds = f->dents; | 743 | /* For symlink inodes we us f->dents to store the target path name */ |
744 | if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { | ||
745 | if (f->dents) { | ||
746 | kfree(f->dents); | ||
747 | f->dents = NULL; | ||
748 | } | ||
749 | } else { | ||
750 | fds = f->dents; | ||
684 | 751 | ||
685 | while(fds) { | 752 | while(fds) { |
686 | fd = fds; | 753 | fd = fds; |
687 | fds = fd->next; | 754 | fds = fd->next; |
688 | jffs2_free_full_dirent(fd); | 755 | jffs2_free_full_dirent(fd); |
756 | } | ||
689 | } | 757 | } |
690 | 758 | ||
691 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) | 759 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { |
692 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); | 760 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); |
761 | if (f->inocache->nodes == (void *)f->inocache) | ||
762 | jffs2_del_ino_cache(c, f->inocache); | ||
763 | } | ||
693 | 764 | ||
694 | up(&f->sem); | 765 | up(&f->sem); |
695 | } | 766 | } |