diff options
Diffstat (limited to 'fs/jffs2/readinode.c')
-rw-r--r-- | fs/jffs2/readinode.c | 96 |
1 files changed, 85 insertions, 11 deletions
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index aca4a0b17bcd..081656c1d49e 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.120 2005/07/05 21:03:07 dwmw2 Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -500,7 +500,9 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
500 | struct jffs2_inode_info *f, | 500 | struct jffs2_inode_info *f, |
501 | struct jffs2_raw_inode *latest_node) | 501 | struct jffs2_raw_inode *latest_node) |
502 | { | 502 | { |
503 | struct jffs2_tmp_dnode_info *tn_list, *tn; | 503 | struct jffs2_tmp_dnode_info *tn = NULL; |
504 | struct rb_root tn_list; | ||
505 | struct rb_node *rb, *repl_rb; | ||
504 | struct jffs2_full_dirent *fd_list; | 506 | struct jffs2_full_dirent *fd_list; |
505 | struct jffs2_full_dnode *fn = NULL; | 507 | struct jffs2_full_dnode *fn = NULL; |
506 | uint32_t crc; | 508 | uint32_t crc; |
@@ -522,9 +524,10 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
522 | } | 524 | } |
523 | f->dents = fd_list; | 525 | f->dents = fd_list; |
524 | 526 | ||
525 | while (tn_list) { | 527 | rb = rb_first(&tn_list); |
526 | tn = tn_list; | ||
527 | 528 | ||
529 | while (rb) { | ||
530 | tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb); | ||
528 | fn = tn->fn; | 531 | fn = tn->fn; |
529 | 532 | ||
530 | if (f->metadata) { | 533 | if (f->metadata) { |
@@ -556,7 +559,30 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
556 | mdata_ver = tn->version; | 559 | mdata_ver = tn->version; |
557 | } | 560 | } |
558 | next_tn: | 561 | next_tn: |
559 | tn_list = tn->next; | 562 | BUG_ON(rb->rb_left); |
563 | repl_rb = NULL; | ||
564 | if (rb->rb_parent && rb->rb_parent->rb_left == rb) { | ||
565 | /* We were then left-hand child of our parent. We need | ||
566 | to move our own right-hand child into our place. */ | ||
567 | repl_rb = rb->rb_right; | ||
568 | if (repl_rb) | ||
569 | repl_rb->rb_parent = rb->rb_parent; | ||
570 | } else | ||
571 | repl_rb = NULL; | ||
572 | |||
573 | rb = rb_next(rb); | ||
574 | |||
575 | /* Remove the spent tn from the tree; don't bother rebalancing | ||
576 | but put our right-hand child in our own place. */ | ||
577 | if (tn->rb.rb_parent) { | ||
578 | if (tn->rb.rb_parent->rb_left == &tn->rb) | ||
579 | tn->rb.rb_parent->rb_left = repl_rb; | ||
580 | else if (tn->rb.rb_parent->rb_right == &tn->rb) | ||
581 | tn->rb.rb_parent->rb_right = repl_rb; | ||
582 | else BUG(); | ||
583 | } else if (tn->rb.rb_right) | ||
584 | tn->rb.rb_right->rb_parent = NULL; | ||
585 | |||
560 | jffs2_free_tmp_dnode_info(tn); | 586 | jffs2_free_tmp_dnode_info(tn); |
561 | } | 587 | } |
562 | D1(jffs2_sanitycheck_fragtree(f)); | 588 | D1(jffs2_sanitycheck_fragtree(f)); |
@@ -623,6 +649,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
623 | case. */ | 649 | case. */ |
624 | if (!je32_to_cpu(latest_node->isize)) | 650 | if (!je32_to_cpu(latest_node->isize)) |
625 | latest_node->isize = latest_node->dsize; | 651 | latest_node->isize = latest_node->dsize; |
652 | |||
653 | if (f->inocache->state != INO_STATE_CHECKING) { | ||
654 | /* Symlink's inode data is the target path. Read it and | ||
655 | * keep in RAM to facilitate quick follow symlink operation. | ||
656 | * We use f->dents field to store the target path, which | ||
657 | * is somewhat ugly. */ | ||
658 | f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); | ||
659 | if (!f->dents) { | ||
660 | printk(KERN_WARNING "Can't allocate %d bytes of memory " | ||
661 | "for the symlink target path cache\n", | ||
662 | je32_to_cpu(latest_node->csize)); | ||
663 | up(&f->sem); | ||
664 | jffs2_do_clear_inode(c, f); | ||
665 | return -ENOMEM; | ||
666 | } | ||
667 | |||
668 | ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), | ||
669 | je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); | ||
670 | |||
671 | if (ret || retlen != je32_to_cpu(latest_node->csize)) { | ||
672 | if (retlen != je32_to_cpu(latest_node->csize)) | ||
673 | ret = -EIO; | ||
674 | kfree(f->dents); | ||
675 | f->dents = NULL; | ||
676 | up(&f->sem); | ||
677 | jffs2_do_clear_inode(c, f); | ||
678 | return -ret; | ||
679 | } | ||
680 | |||
681 | ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; | ||
682 | D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", | ||
683 | (char *)f->dents)); | ||
684 | } | ||
685 | |||
626 | /* fall through... */ | 686 | /* fall through... */ |
627 | 687 | ||
628 | case S_IFBLK: | 688 | case S_IFBLK: |
@@ -672,6 +732,9 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
672 | down(&f->sem); | 732 | down(&f->sem); |
673 | deleted = f->inocache && !f->inocache->nlink; | 733 | deleted = f->inocache && !f->inocache->nlink; |
674 | 734 | ||
735 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) | ||
736 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING); | ||
737 | |||
675 | if (f->metadata) { | 738 | if (f->metadata) { |
676 | if (deleted) | 739 | if (deleted) |
677 | jffs2_mark_node_obsolete(c, f->metadata->raw); | 740 | jffs2_mark_node_obsolete(c, f->metadata->raw); |
@@ -680,16 +743,27 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
680 | 743 | ||
681 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); | 744 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); |
682 | 745 | ||
683 | fds = f->dents; | 746 | /* For symlink inodes we us f->dents to store the target path name */ |
747 | if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { | ||
748 | if (f->dents) { | ||
749 | kfree(f->dents); | ||
750 | f->dents = NULL; | ||
751 | } | ||
752 | } else { | ||
753 | fds = f->dents; | ||
684 | 754 | ||
685 | while(fds) { | 755 | while(fds) { |
686 | fd = fds; | 756 | fd = fds; |
687 | fds = fd->next; | 757 | fds = fd->next; |
688 | jffs2_free_full_dirent(fd); | 758 | jffs2_free_full_dirent(fd); |
759 | } | ||
689 | } | 760 | } |
690 | 761 | ||
691 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) | 762 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { |
692 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); | 763 | jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); |
764 | if (f->inocache->nodes == (void *)f->inocache) | ||
765 | jffs2_del_ino_cache(c, f->inocache); | ||
766 | } | ||
693 | 767 | ||
694 | up(&f->sem); | 768 | up(&f->sem); |
695 | } | 769 | } |