diff options
Diffstat (limited to 'fs/jffs2/readinode.c')
-rw-r--r-- | fs/jffs2/readinode.c | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index a1980a9da531..ef552477c813 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.118 2005/02/27 23:01:33 dwmw2 Exp $ | 10 | * $Id: readinode.c,v 1.119 2005/03/01 10:34:03 dedekind Exp $ |
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
@@ -623,6 +623,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
623 | case. */ | 623 | case. */ |
624 | if (!je32_to_cpu(latest_node->isize)) | 624 | if (!je32_to_cpu(latest_node->isize)) |
625 | latest_node->isize = latest_node->dsize; | 625 | latest_node->isize = latest_node->dsize; |
626 | |||
627 | if (f->inocache->state != INO_STATE_CHECKING) { | ||
628 | /* Symlink's inode data is the target path. Read it and | ||
629 | * keep in RAM to facilitate quick follow symlink operation. | ||
630 | * We use f->dents field to store the target path, which | ||
631 | * is somewhat ugly. */ | ||
632 | f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); | ||
633 | if (!f->dents) { | ||
634 | printk(KERN_WARNING "Can't allocate %d bytes of memory " | ||
635 | "for the symlink target path cache\n", | ||
636 | je32_to_cpu(latest_node->csize)); | ||
637 | up(&f->sem); | ||
638 | jffs2_do_clear_inode(c, f); | ||
639 | return -ENOMEM; | ||
640 | } | ||
641 | |||
642 | ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), | ||
643 | je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); | ||
644 | |||
645 | if (ret || retlen != je32_to_cpu(latest_node->csize)) { | ||
646 | if (retlen != je32_to_cpu(latest_node->csize)) | ||
647 | ret = -EIO; | ||
648 | kfree(f->dents); | ||
649 | f->dents = NULL; | ||
650 | up(&f->sem); | ||
651 | jffs2_do_clear_inode(c, f); | ||
652 | return -ret; | ||
653 | } | ||
654 | |||
655 | ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; | ||
656 | D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", | ||
657 | (char *)f->dents)); | ||
658 | } | ||
659 | |||
626 | /* fall through... */ | 660 | /* fall through... */ |
627 | 661 | ||
628 | case S_IFBLK: | 662 | case S_IFBLK: |
@@ -683,12 +717,20 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) | |||
683 | 717 | ||
684 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); | 718 | jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); |
685 | 719 | ||
686 | fds = f->dents; | 720 | /* For symlink inodes we us f->dents to store the target path name */ |
721 | if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { | ||
722 | if (f->dents) { | ||
723 | kfree(f->dents); | ||
724 | f->dents = NULL; | ||
725 | } | ||
726 | } else { | ||
727 | fds = f->dents; | ||
687 | 728 | ||
688 | while(fds) { | 729 | while(fds) { |
689 | fd = fds; | 730 | fd = fds; |
690 | fds = fd->next; | 731 | fds = fd->next; |
691 | jffs2_free_full_dirent(fd); | 732 | jffs2_free_full_dirent(fd); |
733 | } | ||
692 | } | 734 | } |
693 | 735 | ||
694 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { | 736 | if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { |