diff options
author | Mark Fasheh <mark.fasheh@oracle.com> | 2007-09-24 17:25:27 -0400 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2007-10-12 14:54:41 -0400 |
commit | e7b34019606ab1dd06196635e931b0c302799228 (patch) | |
tree | c5fc9393ddd817b3e577e6df755e924015d3c06e | |
parent | 5b6a3a2b4a5f071d170f8122038dd647a84810a8 (diff) |
ocfs2: Optionally return filldir errors
Modify ocfs2_dir_foreach_blk() to optionally return any error from the
filldir callback. This way ocfs2_dirforeach() can terminate early, as
opposed to always passing through the entire directory. This fixes a bug
introduced during a previous code refactor where ocfs2_empty_dir() would
loop infinitely.
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
-rw-r--r-- | fs/ocfs2/dir.c | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index e15351338417..7453b70c1a19 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -588,7 +588,7 @@ bail: | |||
588 | static int ocfs2_dir_foreach_blk_id(struct inode *inode, | 588 | static int ocfs2_dir_foreach_blk_id(struct inode *inode, |
589 | unsigned long *f_version, | 589 | unsigned long *f_version, |
590 | loff_t *f_pos, void *priv, | 590 | loff_t *f_pos, void *priv, |
591 | filldir_t filldir) | 591 | filldir_t filldir, int *filldir_err) |
592 | { | 592 | { |
593 | int ret, i, filldir_ret; | 593 | int ret, i, filldir_ret; |
594 | unsigned long offset = *f_pos; | 594 | unsigned long offset = *f_pos; |
@@ -659,8 +659,11 @@ revalidate: | |||
659 | *f_pos, | 659 | *f_pos, |
660 | le64_to_cpu(de->inode), | 660 | le64_to_cpu(de->inode), |
661 | d_type); | 661 | d_type); |
662 | if (filldir_ret) | 662 | if (filldir_ret) { |
663 | if (filldir_err) | ||
664 | *filldir_err = filldir_ret; | ||
663 | break; | 665 | break; |
666 | } | ||
664 | if (version != *f_version) | 667 | if (version != *f_version) |
665 | goto revalidate; | 668 | goto revalidate; |
666 | } | 669 | } |
@@ -676,7 +679,7 @@ out: | |||
676 | static int ocfs2_dir_foreach_blk_el(struct inode *inode, | 679 | static int ocfs2_dir_foreach_blk_el(struct inode *inode, |
677 | unsigned long *f_version, | 680 | unsigned long *f_version, |
678 | loff_t *f_pos, void *priv, | 681 | loff_t *f_pos, void *priv, |
679 | filldir_t filldir) | 682 | filldir_t filldir, int *filldir_err) |
680 | { | 683 | { |
681 | int error = 0; | 684 | int error = 0; |
682 | unsigned long offset, blk, last_ra_blk = 0; | 685 | unsigned long offset, blk, last_ra_blk = 0; |
@@ -775,8 +778,11 @@ revalidate: | |||
775 | *f_pos, | 778 | *f_pos, |
776 | le64_to_cpu(de->inode), | 779 | le64_to_cpu(de->inode), |
777 | d_type); | 780 | d_type); |
778 | if (error) | 781 | if (error) { |
782 | if (filldir_err) | ||
783 | *filldir_err = error; | ||
779 | break; | 784 | break; |
785 | } | ||
780 | if (version != *f_version) | 786 | if (version != *f_version) |
781 | goto revalidate; | 787 | goto revalidate; |
782 | stored ++; | 788 | stored ++; |
@@ -793,13 +799,15 @@ out: | |||
793 | } | 799 | } |
794 | 800 | ||
795 | static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version, | 801 | static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version, |
796 | loff_t *f_pos, void *priv, filldir_t filldir) | 802 | loff_t *f_pos, void *priv, filldir_t filldir, |
803 | int *filldir_err) | ||
797 | { | 804 | { |
798 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) | 805 | if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) |
799 | return ocfs2_dir_foreach_blk_id(inode, f_version, f_pos, priv, | 806 | return ocfs2_dir_foreach_blk_id(inode, f_version, f_pos, priv, |
800 | filldir); | 807 | filldir, filldir_err); |
801 | 808 | ||
802 | return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir); | 809 | return ocfs2_dir_foreach_blk_el(inode, f_version, f_pos, priv, filldir, |
810 | filldir_err); | ||
803 | } | 811 | } |
804 | 812 | ||
805 | /* | 813 | /* |
@@ -809,16 +817,19 @@ static int ocfs2_dir_foreach_blk(struct inode *inode, unsigned long *f_version, | |||
809 | int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, | 817 | int ocfs2_dir_foreach(struct inode *inode, loff_t *f_pos, void *priv, |
810 | filldir_t filldir) | 818 | filldir_t filldir) |
811 | { | 819 | { |
812 | int ret = 0; | 820 | int ret = 0, filldir_err = 0; |
813 | unsigned long version = inode->i_version; | 821 | unsigned long version = inode->i_version; |
814 | 822 | ||
815 | while (*f_pos < i_size_read(inode)) { | 823 | while (*f_pos < i_size_read(inode)) { |
816 | ret = ocfs2_dir_foreach_blk(inode, &version, f_pos, priv, | 824 | ret = ocfs2_dir_foreach_blk(inode, &version, f_pos, priv, |
817 | filldir); | 825 | filldir, &filldir_err); |
818 | if (ret) | 826 | if (ret || filldir_err) |
819 | break; | 827 | break; |
820 | } | 828 | } |
821 | 829 | ||
830 | if (ret > 0) | ||
831 | ret = -EIO; | ||
832 | |||
822 | return 0; | 833 | return 0; |
823 | } | 834 | } |
824 | 835 | ||
@@ -852,7 +863,7 @@ int ocfs2_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
852 | } | 863 | } |
853 | 864 | ||
854 | error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos, | 865 | error = ocfs2_dir_foreach_blk(inode, &filp->f_version, &filp->f_pos, |
855 | dirent, filldir); | 866 | dirent, filldir, NULL); |
856 | 867 | ||
857 | ocfs2_meta_unlock(inode, lock_level); | 868 | ocfs2_meta_unlock(inode, lock_level); |
858 | 869 | ||