aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ocfs2/xattr.c
diff options
context:
space:
mode:
authorTao Ma <tao.ma@oracle.com>2010-05-13 10:49:05 -0400
committerJoel Becker <joel.becker@oracle.com>2010-05-18 19:41:39 -0400
commit5f5261acb059f43c7fb9a2fac9d32c6ef4df2ed5 (patch)
treec4f7e8f4b774ff3bb7b0e60f4bb956729e51d5b6 /fs/ocfs2/xattr.c
parentd9ef75221a6247b758e1d7e18edb661996e4b7cf (diff)
ocfs2: Don't retry xattr set in case value extension fails.
In normal xattr set, the set sequence is inode, xattr block and finally xattr bucket if we meet with a ENOSPC. But there is a corner case. So consider we will set a xattr whose value will be stored in a cluster, and there is no xattr block by now. So we will reserve 1 xattr block and 1 cluster for setting it. Now if we fail in value extension(in case the volume is almost full and we can't allocate the cluster because the check in ocfs2_test_bg_bit_allocatable), ENOSPC will be returned. So we will try to create a bucket(this time there is a chance that the reserved cluster will be used), and when we try value extension again, kernel bug happens. We did meet with it. Check the bug below. http://oss.oracle.com/bugzilla/show_bug.cgi?id=1251 This patch just try to avoid this by adding a set_abort in ocfs2_xattr_set_ctxt, so in case ENOSPC happens in value extension, we will check whether it is caused by the real ENOSPC or just the full of inode or xattr block. If it is the first case, we set set_abort so that we don't try any further. we are safe to exit directly here ince it is really ENOSPC. Signed-off-by: Tao Ma <tao.ma@oracle.com> Signed-off-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs/ocfs2/xattr.c')
-rw-r--r--fs/ocfs2/xattr.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index e87130f44cb7..98ee6c44102d 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -79,6 +79,7 @@ struct ocfs2_xattr_set_ctxt {
79 struct ocfs2_alloc_context *meta_ac; 79 struct ocfs2_alloc_context *meta_ac;
80 struct ocfs2_alloc_context *data_ac; 80 struct ocfs2_alloc_context *data_ac;
81 struct ocfs2_cached_dealloc_ctxt dealloc; 81 struct ocfs2_cached_dealloc_ctxt dealloc;
82 int set_abort;
82}; 83};
83 84
84#define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root)) 85#define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root))
@@ -2135,6 +2136,7 @@ alloc_value:
2135 orig_clusters = ocfs2_xa_value_clusters(loc); 2136 orig_clusters = ocfs2_xa_value_clusters(loc);
2136 rc = ocfs2_xa_value_truncate(loc, xi->xi_value_len, ctxt); 2137 rc = ocfs2_xa_value_truncate(loc, xi->xi_value_len, ctxt);
2137 if (rc < 0) { 2138 if (rc < 0) {
2139 ctxt->set_abort = 1;
2138 ocfs2_xa_cleanup_value_truncate(loc, "growing", 2140 ocfs2_xa_cleanup_value_truncate(loc, "growing",
2139 orig_clusters); 2141 orig_clusters);
2140 /* 2142 /*
@@ -2946,7 +2948,7 @@ static int ocfs2_xattr_block_set(struct inode *inode,
2946 ret = ocfs2_xa_set(&loc, xi, ctxt); 2948 ret = ocfs2_xa_set(&loc, xi, ctxt);
2947 if (!ret) 2949 if (!ret)
2948 xs->here = loc.xl_entry; 2950 xs->here = loc.xl_entry;
2949 else if (ret != -ENOSPC) 2951 else if ((ret != -ENOSPC) || ctxt->set_abort)
2950 goto end; 2952 goto end;
2951 else { 2953 else {
2952 ret = ocfs2_xattr_create_index_block(inode, xs, ctxt); 2954 ret = ocfs2_xattr_create_index_block(inode, xs, ctxt);
@@ -3308,7 +3310,7 @@ static int __ocfs2_xattr_set_handle(struct inode *inode,
3308 goto out; 3310 goto out;
3309 } 3311 }
3310 ret = ocfs2_xattr_block_set(inode, xi, xbs, ctxt); 3312 ret = ocfs2_xattr_block_set(inode, xi, xbs, ctxt);
3311 } else if (ret == -ENOSPC) { 3313 } else if ((ret == -ENOSPC) && !ctxt->set_abort) {
3312 if (di->i_xattr_loc && !xbs->xattr_bh) { 3314 if (di->i_xattr_loc && !xbs->xattr_bh) {
3313 ret = ocfs2_xattr_block_find(inode, 3315 ret = ocfs2_xattr_block_find(inode,
3314 xi->xi_name_index, 3316 xi->xi_name_index,