aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ocfs2/file.c2
-rw-r--r--fs/ocfs2/inode.c7
-rw-r--r--fs/ocfs2/refcounttree.c36
-rw-r--r--fs/ocfs2/refcounttree.h3
-rw-r--r--fs/ocfs2/xattr.c23
-rw-r--r--fs/ocfs2/xattr.h2
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
533bail: 533bail:
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 */
936int 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);
959out:
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);
93int ocfs2_remove_refcount_tree(struct inode *inode, struct buffer_head *di_bh);
94int 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
843int 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
843static int ocfs2_xattr_ibody_list(struct inode *inode, 860static 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
2901cleanup: 2919cleanup:
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);
2906cleanup_nolock: 2929cleanup_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 *);
58int ocfs2_has_inline_xattr_value_outside(struct inode *inode,
59 struct ocfs2_dinode *di);
58int ocfs2_xattr_remove(struct inode *, struct buffer_head *); 60int ocfs2_xattr_remove(struct inode *, struct buffer_head *);
59int ocfs2_init_security_get(struct inode *, struct inode *, 61int ocfs2_init_security_get(struct inode *, struct inode *,
60 struct ocfs2_security_xattr_info *); 62 struct ocfs2_security_xattr_info *);