aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2/readinode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jffs2/readinode.c')
-rw-r--r--fs/jffs2/readinode.c103
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}