diff options
| author | Tao Ma <tao.ma@oracle.com> | 2009-08-17 23:43:49 -0400 |
|---|---|---|
| committer | Joel Becker <joel.becker@oracle.com> | 2009-09-22 23:09:44 -0400 |
| commit | 8b2c0dba5159570af5721d40490f6c529d721500 (patch) | |
| tree | faca76fab3c9a65ba8e7be3aa93d02e4ff53f0cf /fs | |
| parent | 0129241e2b3b90ff83a8c774353e5612d84bd493 (diff) | |
ocfs2: Call refcount tree remove process properly.
Now with xattr refcount support, we need to check whether
we have xattr refcounted before we remove the refcount tree.
Now the mechanism is:
1) Check whether i_clusters == 0, if no, exit.
2) check whether we have i_xattr_loc in dinode. if yes, exit.
2) Check whether we have inline xattr stored outside, if yes, exit.
4) Remove the tree.
Signed-off-by: Tao Ma <tao.ma@oracle.com>
Diffstat (limited to 'fs')
| -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 *); |
