diff options
Diffstat (limited to 'fs/ceph/xattr.c')
-rw-r--r-- | fs/ceph/xattr.c | 19 |
1 files changed, 14 insertions, 5 deletions
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 37b458a9af3a..939eab7aa219 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c | |||
@@ -754,12 +754,15 @@ static int __get_required_blob_size(struct ceph_inode_info *ci, int name_size, | |||
754 | 754 | ||
755 | /* | 755 | /* |
756 | * If there are dirty xattrs, reencode xattrs into the prealloc_blob | 756 | * If there are dirty xattrs, reencode xattrs into the prealloc_blob |
757 | * and swap into place. | 757 | * and swap into place. It returns the old i_xattrs.blob (or NULL) so |
758 | * that it can be freed by the caller as the i_ceph_lock is likely to be | ||
759 | * held. | ||
758 | */ | 760 | */ |
759 | void __ceph_build_xattrs_blob(struct ceph_inode_info *ci) | 761 | struct ceph_buffer *__ceph_build_xattrs_blob(struct ceph_inode_info *ci) |
760 | { | 762 | { |
761 | struct rb_node *p; | 763 | struct rb_node *p; |
762 | struct ceph_inode_xattr *xattr = NULL; | 764 | struct ceph_inode_xattr *xattr = NULL; |
765 | struct ceph_buffer *old_blob = NULL; | ||
763 | void *dest; | 766 | void *dest; |
764 | 767 | ||
765 | dout("__build_xattrs_blob %p\n", &ci->vfs_inode); | 768 | dout("__build_xattrs_blob %p\n", &ci->vfs_inode); |
@@ -790,12 +793,14 @@ void __ceph_build_xattrs_blob(struct ceph_inode_info *ci) | |||
790 | dest - ci->i_xattrs.prealloc_blob->vec.iov_base; | 793 | dest - ci->i_xattrs.prealloc_blob->vec.iov_base; |
791 | 794 | ||
792 | if (ci->i_xattrs.blob) | 795 | if (ci->i_xattrs.blob) |
793 | ceph_buffer_put(ci->i_xattrs.blob); | 796 | old_blob = ci->i_xattrs.blob; |
794 | ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob; | 797 | ci->i_xattrs.blob = ci->i_xattrs.prealloc_blob; |
795 | ci->i_xattrs.prealloc_blob = NULL; | 798 | ci->i_xattrs.prealloc_blob = NULL; |
796 | ci->i_xattrs.dirty = false; | 799 | ci->i_xattrs.dirty = false; |
797 | ci->i_xattrs.version++; | 800 | ci->i_xattrs.version++; |
798 | } | 801 | } |
802 | |||
803 | return old_blob; | ||
799 | } | 804 | } |
800 | 805 | ||
801 | static inline int __get_request_mask(struct inode *in) { | 806 | static inline int __get_request_mask(struct inode *in) { |
@@ -1036,6 +1041,7 @@ int __ceph_setxattr(struct inode *inode, const char *name, | |||
1036 | struct ceph_inode_info *ci = ceph_inode(inode); | 1041 | struct ceph_inode_info *ci = ceph_inode(inode); |
1037 | struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; | 1042 | struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; |
1038 | struct ceph_cap_flush *prealloc_cf = NULL; | 1043 | struct ceph_cap_flush *prealloc_cf = NULL; |
1044 | struct ceph_buffer *old_blob = NULL; | ||
1039 | int issued; | 1045 | int issued; |
1040 | int err; | 1046 | int err; |
1041 | int dirty = 0; | 1047 | int dirty = 0; |
@@ -1109,13 +1115,15 @@ retry: | |||
1109 | struct ceph_buffer *blob; | 1115 | struct ceph_buffer *blob; |
1110 | 1116 | ||
1111 | spin_unlock(&ci->i_ceph_lock); | 1117 | spin_unlock(&ci->i_ceph_lock); |
1112 | dout(" preaallocating new blob size=%d\n", required_blob_size); | 1118 | ceph_buffer_put(old_blob); /* Shouldn't be required */ |
1119 | dout(" pre-allocating new blob size=%d\n", required_blob_size); | ||
1113 | blob = ceph_buffer_new(required_blob_size, GFP_NOFS); | 1120 | blob = ceph_buffer_new(required_blob_size, GFP_NOFS); |
1114 | if (!blob) | 1121 | if (!blob) |
1115 | goto do_sync_unlocked; | 1122 | goto do_sync_unlocked; |
1116 | spin_lock(&ci->i_ceph_lock); | 1123 | spin_lock(&ci->i_ceph_lock); |
1124 | /* prealloc_blob can't be released while holding i_ceph_lock */ | ||
1117 | if (ci->i_xattrs.prealloc_blob) | 1125 | if (ci->i_xattrs.prealloc_blob) |
1118 | ceph_buffer_put(ci->i_xattrs.prealloc_blob); | 1126 | old_blob = ci->i_xattrs.prealloc_blob; |
1119 | ci->i_xattrs.prealloc_blob = blob; | 1127 | ci->i_xattrs.prealloc_blob = blob; |
1120 | goto retry; | 1128 | goto retry; |
1121 | } | 1129 | } |
@@ -1131,6 +1139,7 @@ retry: | |||
1131 | } | 1139 | } |
1132 | 1140 | ||
1133 | spin_unlock(&ci->i_ceph_lock); | 1141 | spin_unlock(&ci->i_ceph_lock); |
1142 | ceph_buffer_put(old_blob); | ||
1134 | if (lock_snap_rwsem) | 1143 | if (lock_snap_rwsem) |
1135 | up_read(&mdsc->snap_rwsem); | 1144 | up_read(&mdsc->snap_rwsem); |
1136 | if (dirty) | 1145 | if (dirty) |