diff options
Diffstat (limited to 'fs/ceph')
-rw-r--r-- | fs/ceph/caps.c | 4 | ||||
-rw-r--r-- | fs/ceph/inode.c | 15 | ||||
-rw-r--r-- | fs/ceph/xattr.c | 45 |
3 files changed, 57 insertions, 7 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index f1dbcae7c75c..900c05fd77d8 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -1413,9 +1413,11 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) | |||
1413 | ceph_cap_string(was | mask)); | 1413 | ceph_cap_string(was | mask)); |
1414 | ci->i_dirty_caps |= mask; | 1414 | ci->i_dirty_caps |= mask; |
1415 | if (was == 0) { | 1415 | if (was == 0) { |
1416 | if (!ci->i_head_snapc) | 1416 | if (!ci->i_head_snapc) { |
1417 | WARN_ON_ONCE(!rwsem_is_locked(&mdsc->snap_rwsem)); | ||
1417 | ci->i_head_snapc = ceph_get_snap_context( | 1418 | ci->i_head_snapc = ceph_get_snap_context( |
1418 | ci->i_snap_realm->cached_context); | 1419 | ci->i_snap_realm->cached_context); |
1420 | } | ||
1419 | dout(" inode %p now dirty snapc %p auth cap %p\n", | 1421 | dout(" inode %p now dirty snapc %p auth cap %p\n", |
1420 | &ci->vfs_inode, ci->i_head_snapc, ci->i_auth_cap); | 1422 | &ci->vfs_inode, ci->i_head_snapc, ci->i_auth_cap); |
1421 | BUG_ON(!list_empty(&ci->i_dirty_item)); | 1423 | BUG_ON(!list_empty(&ci->i_dirty_item)); |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 1a68c0e38a52..1c991df276c9 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -1727,6 +1727,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) | |||
1727 | int mask = 0; | 1727 | int mask = 0; |
1728 | int err = 0; | 1728 | int err = 0; |
1729 | int inode_dirty_flags = 0; | 1729 | int inode_dirty_flags = 0; |
1730 | bool lock_snap_rwsem = false; | ||
1730 | 1731 | ||
1731 | if (ceph_snap(inode) != CEPH_NOSNAP) | 1732 | if (ceph_snap(inode) != CEPH_NOSNAP) |
1732 | return -EROFS; | 1733 | return -EROFS; |
@@ -1742,6 +1743,18 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) | |||
1742 | 1743 | ||
1743 | spin_lock(&ci->i_ceph_lock); | 1744 | spin_lock(&ci->i_ceph_lock); |
1744 | issued = __ceph_caps_issued(ci, NULL); | 1745 | issued = __ceph_caps_issued(ci, NULL); |
1746 | |||
1747 | if (!ci->i_head_snapc && | ||
1748 | (issued & (CEPH_CAP_ANY_EXCL | CEPH_CAP_FILE_WR))) { | ||
1749 | lock_snap_rwsem = true; | ||
1750 | if (!down_read_trylock(&mdsc->snap_rwsem)) { | ||
1751 | spin_unlock(&ci->i_ceph_lock); | ||
1752 | down_read(&mdsc->snap_rwsem); | ||
1753 | spin_lock(&ci->i_ceph_lock); | ||
1754 | issued = __ceph_caps_issued(ci, NULL); | ||
1755 | } | ||
1756 | } | ||
1757 | |||
1745 | dout("setattr %p issued %s\n", inode, ceph_cap_string(issued)); | 1758 | dout("setattr %p issued %s\n", inode, ceph_cap_string(issued)); |
1746 | 1759 | ||
1747 | if (ia_valid & ATTR_UID) { | 1760 | if (ia_valid & ATTR_UID) { |
@@ -1890,6 +1903,8 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) | |||
1890 | 1903 | ||
1891 | release &= issued; | 1904 | release &= issued; |
1892 | spin_unlock(&ci->i_ceph_lock); | 1905 | spin_unlock(&ci->i_ceph_lock); |
1906 | if (lock_snap_rwsem) | ||
1907 | up_read(&mdsc->snap_rwsem); | ||
1893 | 1908 | ||
1894 | if (inode_dirty_flags) | 1909 | if (inode_dirty_flags) |
1895 | __mark_inode_dirty(inode, inode_dirty_flags); | 1910 | __mark_inode_dirty(inode, inode_dirty_flags); |
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index cd7ffad4041d..c6f7d9b82085 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c | |||
@@ -911,6 +911,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, | |||
911 | struct inode *inode = d_inode(dentry); | 911 | struct inode *inode = d_inode(dentry); |
912 | struct ceph_vxattr *vxattr; | 912 | struct ceph_vxattr *vxattr; |
913 | struct ceph_inode_info *ci = ceph_inode(inode); | 913 | struct ceph_inode_info *ci = ceph_inode(inode); |
914 | struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc; | ||
914 | int issued; | 915 | int issued; |
915 | int err; | 916 | int err; |
916 | int dirty = 0; | 917 | int dirty = 0; |
@@ -920,6 +921,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, | |||
920 | char *newval = NULL; | 921 | char *newval = NULL; |
921 | struct ceph_inode_xattr *xattr = NULL; | 922 | struct ceph_inode_xattr *xattr = NULL; |
922 | int required_blob_size; | 923 | int required_blob_size; |
924 | bool lock_snap_rwsem = false; | ||
923 | 925 | ||
924 | if (!ceph_is_valid_xattr(name)) | 926 | if (!ceph_is_valid_xattr(name)) |
925 | return -EOPNOTSUPP; | 927 | return -EOPNOTSUPP; |
@@ -951,9 +953,20 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, | |||
951 | spin_lock(&ci->i_ceph_lock); | 953 | spin_lock(&ci->i_ceph_lock); |
952 | retry: | 954 | retry: |
953 | issued = __ceph_caps_issued(ci, NULL); | 955 | issued = __ceph_caps_issued(ci, NULL); |
954 | dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued)); | ||
955 | if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL)) | 956 | if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL)) |
956 | goto do_sync; | 957 | goto do_sync; |
958 | |||
959 | if (!lock_snap_rwsem && !ci->i_head_snapc) { | ||
960 | lock_snap_rwsem = true; | ||
961 | if (!down_read_trylock(&mdsc->snap_rwsem)) { | ||
962 | spin_unlock(&ci->i_ceph_lock); | ||
963 | down_read(&mdsc->snap_rwsem); | ||
964 | spin_lock(&ci->i_ceph_lock); | ||
965 | goto retry; | ||
966 | } | ||
967 | } | ||
968 | |||
969 | dout("setxattr %p issued %s\n", inode, ceph_cap_string(issued)); | ||
957 | __build_xattrs(inode); | 970 | __build_xattrs(inode); |
958 | 971 | ||
959 | required_blob_size = __get_required_blob_size(ci, name_len, val_len); | 972 | required_blob_size = __get_required_blob_size(ci, name_len, val_len); |
@@ -966,7 +979,7 @@ retry: | |||
966 | dout(" preaallocating new blob size=%d\n", required_blob_size); | 979 | dout(" preaallocating new blob size=%d\n", required_blob_size); |
967 | blob = ceph_buffer_new(required_blob_size, GFP_NOFS); | 980 | blob = ceph_buffer_new(required_blob_size, GFP_NOFS); |
968 | if (!blob) | 981 | if (!blob) |
969 | goto out; | 982 | goto do_sync_unlocked; |
970 | spin_lock(&ci->i_ceph_lock); | 983 | spin_lock(&ci->i_ceph_lock); |
971 | if (ci->i_xattrs.prealloc_blob) | 984 | if (ci->i_xattrs.prealloc_blob) |
972 | ceph_buffer_put(ci->i_xattrs.prealloc_blob); | 985 | ceph_buffer_put(ci->i_xattrs.prealloc_blob); |
@@ -984,6 +997,8 @@ retry: | |||
984 | } | 997 | } |
985 | 998 | ||
986 | spin_unlock(&ci->i_ceph_lock); | 999 | spin_unlock(&ci->i_ceph_lock); |
1000 | if (lock_snap_rwsem) | ||
1001 | up_read(&mdsc->snap_rwsem); | ||
987 | if (dirty) | 1002 | if (dirty) |
988 | __mark_inode_dirty(inode, dirty); | 1003 | __mark_inode_dirty(inode, dirty); |
989 | return err; | 1004 | return err; |
@@ -991,6 +1006,8 @@ retry: | |||
991 | do_sync: | 1006 | do_sync: |
992 | spin_unlock(&ci->i_ceph_lock); | 1007 | spin_unlock(&ci->i_ceph_lock); |
993 | do_sync_unlocked: | 1008 | do_sync_unlocked: |
1009 | if (lock_snap_rwsem) | ||
1010 | up_read(&mdsc->snap_rwsem); | ||
994 | err = ceph_sync_setxattr(dentry, name, value, size, flags); | 1011 | err = ceph_sync_setxattr(dentry, name, value, size, flags); |
995 | out: | 1012 | out: |
996 | kfree(newname); | 1013 | kfree(newname); |
@@ -1044,10 +1061,12 @@ int __ceph_removexattr(struct dentry *dentry, const char *name) | |||
1044 | struct inode *inode = d_inode(dentry); | 1061 | struct inode *inode = d_inode(dentry); |
1045 | struct ceph_vxattr *vxattr; | 1062 | struct ceph_vxattr *vxattr; |
1046 | struct ceph_inode_info *ci = ceph_inode(inode); | 1063 | struct ceph_inode_info *ci = ceph_inode(inode); |
1064 | struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc; | ||
1047 | int issued; | 1065 | int issued; |
1048 | int err; | 1066 | int err; |
1049 | int required_blob_size; | 1067 | int required_blob_size; |
1050 | int dirty; | 1068 | int dirty; |
1069 | bool lock_snap_rwsem = false; | ||
1051 | 1070 | ||
1052 | if (!ceph_is_valid_xattr(name)) | 1071 | if (!ceph_is_valid_xattr(name)) |
1053 | return -EOPNOTSUPP; | 1072 | return -EOPNOTSUPP; |
@@ -1064,10 +1083,21 @@ int __ceph_removexattr(struct dentry *dentry, const char *name) | |||
1064 | spin_lock(&ci->i_ceph_lock); | 1083 | spin_lock(&ci->i_ceph_lock); |
1065 | retry: | 1084 | retry: |
1066 | issued = __ceph_caps_issued(ci, NULL); | 1085 | issued = __ceph_caps_issued(ci, NULL); |
1067 | dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued)); | ||
1068 | |||
1069 | if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL)) | 1086 | if (ci->i_xattrs.version == 0 || !(issued & CEPH_CAP_XATTR_EXCL)) |
1070 | goto do_sync; | 1087 | goto do_sync; |
1088 | |||
1089 | if (!lock_snap_rwsem && !ci->i_head_snapc) { | ||
1090 | lock_snap_rwsem = true; | ||
1091 | if (!down_read_trylock(&mdsc->snap_rwsem)) { | ||
1092 | spin_unlock(&ci->i_ceph_lock); | ||
1093 | down_read(&mdsc->snap_rwsem); | ||
1094 | spin_lock(&ci->i_ceph_lock); | ||
1095 | goto retry; | ||
1096 | } | ||
1097 | } | ||
1098 | |||
1099 | dout("removexattr %p issued %s\n", inode, ceph_cap_string(issued)); | ||
1100 | |||
1071 | __build_xattrs(inode); | 1101 | __build_xattrs(inode); |
1072 | 1102 | ||
1073 | required_blob_size = __get_required_blob_size(ci, 0, 0); | 1103 | required_blob_size = __get_required_blob_size(ci, 0, 0); |
@@ -1080,7 +1110,7 @@ retry: | |||
1080 | dout(" preaallocating new blob size=%d\n", required_blob_size); | 1110 | dout(" preaallocating new blob size=%d\n", required_blob_size); |
1081 | blob = ceph_buffer_new(required_blob_size, GFP_NOFS); | 1111 | blob = ceph_buffer_new(required_blob_size, GFP_NOFS); |
1082 | if (!blob) | 1112 | if (!blob) |
1083 | goto out; | 1113 | goto do_sync_unlocked; |
1084 | spin_lock(&ci->i_ceph_lock); | 1114 | spin_lock(&ci->i_ceph_lock); |
1085 | if (ci->i_xattrs.prealloc_blob) | 1115 | if (ci->i_xattrs.prealloc_blob) |
1086 | ceph_buffer_put(ci->i_xattrs.prealloc_blob); | 1116 | ceph_buffer_put(ci->i_xattrs.prealloc_blob); |
@@ -1094,14 +1124,17 @@ retry: | |||
1094 | ci->i_xattrs.dirty = true; | 1124 | ci->i_xattrs.dirty = true; |
1095 | inode->i_ctime = CURRENT_TIME; | 1125 | inode->i_ctime = CURRENT_TIME; |
1096 | spin_unlock(&ci->i_ceph_lock); | 1126 | spin_unlock(&ci->i_ceph_lock); |
1127 | if (lock_snap_rwsem) | ||
1128 | up_read(&mdsc->snap_rwsem); | ||
1097 | if (dirty) | 1129 | if (dirty) |
1098 | __mark_inode_dirty(inode, dirty); | 1130 | __mark_inode_dirty(inode, dirty); |
1099 | return err; | 1131 | return err; |
1100 | do_sync: | 1132 | do_sync: |
1101 | spin_unlock(&ci->i_ceph_lock); | 1133 | spin_unlock(&ci->i_ceph_lock); |
1102 | do_sync_unlocked: | 1134 | do_sync_unlocked: |
1135 | if (lock_snap_rwsem) | ||
1136 | up_read(&mdsc->snap_rwsem); | ||
1103 | err = ceph_send_removexattr(dentry, name); | 1137 | err = ceph_send_removexattr(dentry, name); |
1104 | out: | ||
1105 | return err; | 1138 | return err; |
1106 | } | 1139 | } |
1107 | 1140 | ||