mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
ceph: ensure prealloc_blob is in place when removing xattr
In __ceph_build_xattrs_blob(), if a ceph inode's extended attributes are marked dirty, all attributes recorded in its rb_tree index are formatted into a "blob" buffer. The target buffer is recorded in ceph_inode->i_xattrs.prealloc_blob, and it is expected to exist and be of sufficient size to hold the attributes. The extended attributes are marked dirty in two cases: when a new attribute is added to the inode; or when one is removed. In the former case work is done to ensure the prealloc_blob buffer is properly set up, but in the latter it is not. Change the logic in ceph_removexattr() so it matches what is done in ceph_setxattr(). Note that this is done in a way that keeps the two blocks of code nearly identical, in anticipation of a subsequent patch that encapsulates some of this logic into one or more helper routines. Signed-off-by: Alex Elder <elder@dreamhost.com> Signed-off-by: Sage Weil <sage@newdream.net>
This commit is contained in:
parent
0e805a1d85
commit
83eb26af0d
@ -818,6 +818,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
|
||||
struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode);
|
||||
int issued;
|
||||
int err;
|
||||
int required_blob_size;
|
||||
int dirty;
|
||||
|
||||
if (ceph_snap(inode) != CEPH_NOSNAP)
|
||||
@ -833,14 +834,34 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
err = -ENOMEM;
|
||||
spin_lock(&ci->i_ceph_lock);
|
||||
__build_xattrs(inode);
|
||||
retry:
|
||||
issued = __ceph_caps_issued(ci, NULL);
|
||||
dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued));
|
||||
|
||||
if (!(issued & CEPH_CAP_XATTR_EXCL))
|
||||
goto do_sync;
|
||||
|
||||
required_blob_size = __get_required_blob_size(ci, 0, 0);
|
||||
|
||||
if (!ci->i_xattrs.prealloc_blob ||
|
||||
required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) {
|
||||
struct ceph_buffer *blob;
|
||||
|
||||
spin_unlock(&ci->i_ceph_lock);
|
||||
dout(" preaallocating new blob size=%d\n", required_blob_size);
|
||||
blob = ceph_buffer_new(required_blob_size, GFP_NOFS);
|
||||
if (!blob)
|
||||
goto out;
|
||||
spin_lock(&ci->i_ceph_lock);
|
||||
if (ci->i_xattrs.prealloc_blob)
|
||||
ceph_buffer_put(ci->i_xattrs.prealloc_blob);
|
||||
ci->i_xattrs.prealloc_blob = blob;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
err = __remove_xattr_by_name(ceph_inode(inode), name);
|
||||
dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL);
|
||||
ci->i_xattrs.dirty = true;
|
||||
@ -853,6 +874,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
|
||||
do_sync:
|
||||
spin_unlock(&ci->i_ceph_lock);
|
||||
err = ceph_send_removexattr(dentry, name);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user