diff options
author | Alex Elder <elder@dreamhost.com> | 2012-01-11 20:41:01 -0500 |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2012-01-12 14:00:51 -0500 |
commit | 83eb26af0db71f2dfe551405c55d982288fa6178 (patch) | |
tree | c7bc62a810483e328cbe2b931416e58ec655ab9b /fs/ceph/xattr.c | |
parent | 0e805a1d857799352e51e8697c0b1a30aec16913 (diff) |
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>
Diffstat (limited to 'fs/ceph/xattr.c')
-rw-r--r-- | fs/ceph/xattr.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index a5e36e4488a7..857214ae8c08 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c | |||
@@ -818,6 +818,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name) | |||
818 | struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode); | 818 | struct ceph_vxattr_cb *vxattrs = ceph_inode_vxattrs(inode); |
819 | int issued; | 819 | int issued; |
820 | int err; | 820 | int err; |
821 | int required_blob_size; | ||
821 | int dirty; | 822 | int dirty; |
822 | 823 | ||
823 | if (ceph_snap(inode) != CEPH_NOSNAP) | 824 | if (ceph_snap(inode) != CEPH_NOSNAP) |
@@ -833,14 +834,34 @@ int ceph_removexattr(struct dentry *dentry, const char *name) | |||
833 | return -EOPNOTSUPP; | 834 | return -EOPNOTSUPP; |
834 | } | 835 | } |
835 | 836 | ||
837 | err = -ENOMEM; | ||
836 | spin_lock(&ci->i_ceph_lock); | 838 | spin_lock(&ci->i_ceph_lock); |
837 | __build_xattrs(inode); | 839 | __build_xattrs(inode); |
840 | retry: | ||
838 | issued = __ceph_caps_issued(ci, NULL); | 841 | issued = __ceph_caps_issued(ci, NULL); |
839 | dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued)); | 842 | dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued)); |
840 | 843 | ||
841 | if (!(issued & CEPH_CAP_XATTR_EXCL)) | 844 | if (!(issued & CEPH_CAP_XATTR_EXCL)) |
842 | goto do_sync; | 845 | goto do_sync; |
843 | 846 | ||
847 | required_blob_size = __get_required_blob_size(ci, 0, 0); | ||
848 | |||
849 | if (!ci->i_xattrs.prealloc_blob || | ||
850 | required_blob_size > ci->i_xattrs.prealloc_blob->alloc_len) { | ||
851 | struct ceph_buffer *blob; | ||
852 | |||
853 | spin_unlock(&ci->i_ceph_lock); | ||
854 | dout(" preaallocating new blob size=%d\n", required_blob_size); | ||
855 | blob = ceph_buffer_new(required_blob_size, GFP_NOFS); | ||
856 | if (!blob) | ||
857 | goto out; | ||
858 | spin_lock(&ci->i_ceph_lock); | ||
859 | if (ci->i_xattrs.prealloc_blob) | ||
860 | ceph_buffer_put(ci->i_xattrs.prealloc_blob); | ||
861 | ci->i_xattrs.prealloc_blob = blob; | ||
862 | goto retry; | ||
863 | } | ||
864 | |||
844 | err = __remove_xattr_by_name(ceph_inode(inode), name); | 865 | err = __remove_xattr_by_name(ceph_inode(inode), name); |
845 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); | 866 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); |
846 | ci->i_xattrs.dirty = true; | 867 | ci->i_xattrs.dirty = true; |
@@ -853,6 +874,7 @@ int ceph_removexattr(struct dentry *dentry, const char *name) | |||
853 | do_sync: | 874 | do_sync: |
854 | spin_unlock(&ci->i_ceph_lock); | 875 | spin_unlock(&ci->i_ceph_lock); |
855 | err = ceph_send_removexattr(dentry, name); | 876 | err = ceph_send_removexattr(dentry, name); |
877 | out: | ||
856 | return err; | 878 | return err; |
857 | } | 879 | } |
858 | 880 | ||