diff options
-rw-r--r-- | fs/ocfs2/file.c | 2 | ||||
-rw-r--r-- | fs/ocfs2/inode.c | 7 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.c | 36 | ||||
-rw-r--r-- | fs/ocfs2/refcounttree.h | 3 | ||||
-rw-r--r-- | fs/ocfs2/xattr.c | 23 | ||||
-rw-r--r-- | fs/ocfs2/xattr.h | 2 |
6 files changed, 73 insertions, 0 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 75f5b81805b5..2effac5d030e 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -531,6 +531,8 @@ bail_unlock_sem: | |||
531 | up_write(&OCFS2_I(inode)->ip_alloc_sem); | 531 | up_write(&OCFS2_I(inode)->ip_alloc_sem); |
532 | 532 | ||
533 | bail: | 533 | bail: |
534 | if (!status && OCFS2_I(inode)->ip_clusters == 0) | ||
535 | status = ocfs2_try_remove_refcount_tree(inode, di_bh); | ||
534 | 536 | ||
535 | mlog_exit(status); | 537 | mlog_exit(status); |
536 | return status; | 538 | return status; |
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index e82ceb31cc83..0297fb8982b8 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include "sysfile.h" | 53 | #include "sysfile.h" |
54 | #include "uptodate.h" | 54 | #include "uptodate.h" |
55 | #include "xattr.h" | 55 | #include "xattr.h" |
56 | #include "refcounttree.h" | ||
56 | 57 | ||
57 | #include "buffer_head_io.h" | 58 | #include "buffer_head_io.h" |
58 | 59 | ||
@@ -782,6 +783,12 @@ static int ocfs2_wipe_inode(struct inode *inode, | |||
782 | goto bail_unlock_dir; | 783 | goto bail_unlock_dir; |
783 | } | 784 | } |
784 | 785 | ||
786 | status = ocfs2_remove_refcount_tree(inode, di_bh); | ||
787 | if (status < 0) { | ||
788 | mlog_errno(status); | ||
789 | goto bail_unlock_dir; | ||
790 | } | ||
791 | |||
785 | status = ocfs2_remove_inode(inode, di_bh, orphan_dir_inode, | 792 | status = ocfs2_remove_inode(inode, di_bh, orphan_dir_inode, |
786 | orphan_dir_bh); | 793 | orphan_dir_bh); |
787 | if (status < 0) | 794 | if (status < 0) |
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index a85c01c6629d..5656c68a2cae 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
@@ -927,6 +927,42 @@ out: | |||
927 | } | 927 | } |
928 | 928 | ||
929 | /* | 929 | /* |
930 | * Try to remove refcount tree. The mechanism is: | ||
931 | * 1) Check whether i_clusters == 0, if no, exit. | ||
932 | * 2) check whether we have i_xattr_loc in dinode. if yes, exit. | ||
933 | * 3) Check whether we have inline xattr stored outside, if yes, exit. | ||
934 | * 4) Remove the tree. | ||
935 | */ | ||
936 | int ocfs2_try_remove_refcount_tree(struct inode *inode, | ||
937 | struct buffer_head *di_bh) | ||
938 | { | ||
939 | int ret; | ||
940 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | ||
941 | struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; | ||
942 | |||
943 | down_write(&oi->ip_xattr_sem); | ||
944 | down_write(&oi->ip_alloc_sem); | ||
945 | |||
946 | if (oi->ip_clusters) | ||
947 | goto out; | ||
948 | |||
949 | if ((oi->ip_dyn_features & OCFS2_HAS_XATTR_FL) && di->i_xattr_loc) | ||
950 | goto out; | ||
951 | |||
952 | if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL && | ||
953 | ocfs2_has_inline_xattr_value_outside(inode, di)) | ||
954 | goto out; | ||
955 | |||
956 | ret = ocfs2_remove_refcount_tree(inode, di_bh); | ||
957 | if (ret) | ||
958 | mlog_errno(ret); | ||
959 | out: | ||
960 | up_write(&oi->ip_alloc_sem); | ||
961 | up_write(&oi->ip_xattr_sem); | ||
962 | return 0; | ||
963 | } | ||
964 | |||
965 | /* | ||
930 | * Given a cpos and len, try to find the refcount record which contains cpos. | 966 | * Given a cpos and len, try to find the refcount record which contains cpos. |
931 | * 1. If cpos can be found in one refcount record, return the record. | 967 | * 1. If cpos can be found in one refcount record, return the record. |
932 | * 2. If cpos can't be found, return a fake record which start from cpos | 968 | * 2. If cpos can't be found, return a fake record which start from cpos |
diff --git a/fs/ocfs2/refcounttree.h b/fs/ocfs2/refcounttree.h index 7d6900c904d4..1e3446a655dd 100644 --- a/fs/ocfs2/refcounttree.h +++ b/fs/ocfs2/refcounttree.h | |||
@@ -90,4 +90,7 @@ int ocfs2_add_refcount_flag(struct inode *inode, | |||
90 | u32 cpos, u32 p_cluster, u32 num_clusters, | 90 | u32 cpos, u32 p_cluster, u32 num_clusters, |
91 | struct ocfs2_cached_dealloc_ctxt *dealloc, | 91 | struct ocfs2_cached_dealloc_ctxt *dealloc, |
92 | struct ocfs2_post_refcount *post); | 92 | struct ocfs2_post_refcount *post); |
93 | int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh); | ||
94 | int ocfs2_try_remove_refcount_tree(struct inode *inode, | ||
95 | struct buffer_head *di_bh); | ||
93 | #endif /* OCFS2_REFCOUNTTREE_H */ | 96 | #endif /* OCFS2_REFCOUNTTREE_H */ |
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 501539a733f4..6660f1c6149e 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c | |||
@@ -840,6 +840,23 @@ static int ocfs2_xattr_list_entries(struct inode *inode, | |||
840 | return result; | 840 | return result; |
841 | } | 841 | } |
842 | 842 | ||
843 | int ocfs2_has_inline_xattr_value_outside(struct inode *inode, | ||
844 | struct ocfs2_dinode *di) | ||
845 | { | ||
846 | struct ocfs2_xattr_header *xh; | ||
847 | int i; | ||
848 | |||
849 | xh = (struct ocfs2_xattr_header *) | ||
850 | ((void *)di + inode->i_sb->s_blocksize - | ||
851 | le16_to_cpu(di->i_xattr_inline_size)); | ||
852 | |||
853 | for (i = 0; i < le16_to_cpu(xh->xh_count); i++) | ||
854 | if (!ocfs2_xattr_is_local(&xh->xh_entries[i])) | ||
855 | return 1; | ||
856 | |||
857 | return 0; | ||
858 | } | ||
859 | |||
843 | static int ocfs2_xattr_ibody_list(struct inode *inode, | 860 | static int ocfs2_xattr_ibody_list(struct inode *inode, |
844 | struct ocfs2_dinode *di, | 861 | struct ocfs2_dinode *di, |
845 | char *buffer, | 862 | char *buffer, |
@@ -2898,10 +2915,16 @@ int ocfs2_xattr_set(struct inode *inode, | |||
2898 | if (ocfs2_dealloc_has_cluster(&ctxt.dealloc)) | 2915 | if (ocfs2_dealloc_has_cluster(&ctxt.dealloc)) |
2899 | ocfs2_schedule_truncate_log_flush(osb, 1); | 2916 | ocfs2_schedule_truncate_log_flush(osb, 1); |
2900 | ocfs2_run_deallocs(osb, &ctxt.dealloc); | 2917 | ocfs2_run_deallocs(osb, &ctxt.dealloc); |
2918 | |||
2901 | cleanup: | 2919 | cleanup: |
2902 | if (ref_tree) | 2920 | if (ref_tree) |
2903 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); | 2921 | ocfs2_unlock_refcount_tree(osb, ref_tree, 1); |
2904 | up_write(&OCFS2_I(inode)->ip_xattr_sem); | 2922 | up_write(&OCFS2_I(inode)->ip_xattr_sem); |
2923 | if (!value && !ret) { | ||
2924 | ret = ocfs2_try_remove_refcount_tree(inode, di_bh); | ||
2925 | if (ret) | ||
2926 | mlog_errno(ret); | ||
2927 | } | ||
2905 | ocfs2_inode_unlock(inode, 1); | 2928 | ocfs2_inode_unlock(inode, 1); |
2906 | cleanup_nolock: | 2929 | cleanup_nolock: |
2907 | brelse(di_bh); | 2930 | brelse(di_bh); |
diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h index a3295d705cea..e74703f56dca 100644 --- a/fs/ocfs2/xattr.h +++ b/fs/ocfs2/xattr.h | |||
@@ -55,6 +55,8 @@ int ocfs2_xattr_set_handle(handle_t *, struct inode *, struct buffer_head *, | |||
55 | int, const char *, const void *, size_t, int, | 55 | int, const char *, const void *, size_t, int, |
56 | struct ocfs2_alloc_context *, | 56 | struct ocfs2_alloc_context *, |
57 | struct ocfs2_alloc_context *); | 57 | struct ocfs2_alloc_context *); |
58 | int ocfs2_has_inline_xattr_value_outside(struct inode *inode, | ||
59 | struct ocfs2_dinode *di); | ||
58 | int ocfs2_xattr_remove(struct inode *, struct buffer_head *); | 60 | int ocfs2_xattr_remove(struct inode *, struct buffer_head *); |
59 | int ocfs2_init_security_get(struct inode *, struct inode *, | 61 | int ocfs2_init_security_get(struct inode *, struct inode *, |
60 | struct ocfs2_security_xattr_info *); | 62 | struct ocfs2_security_xattr_info *); |