diff options
Diffstat (limited to 'fs/ceph/caps.c')
-rw-r--r-- | fs/ceph/caps.c | 43 |
1 files changed, 25 insertions, 18 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 0c1681806867..0dd0b81e64f7 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -858,6 +858,8 @@ static int __ceph_is_any_caps(struct ceph_inode_info *ci) | |||
858 | } | 858 | } |
859 | 859 | ||
860 | /* | 860 | /* |
861 | * Remove a cap. Take steps to deal with a racing iterate_session_caps. | ||
862 | * | ||
861 | * caller should hold i_lock. | 863 | * caller should hold i_lock. |
862 | * caller will not hold session s_mutex if called from destroy_inode. | 864 | * caller will not hold session s_mutex if called from destroy_inode. |
863 | */ | 865 | */ |
@@ -865,16 +867,12 @@ void __ceph_remove_cap(struct ceph_cap *cap) | |||
865 | { | 867 | { |
866 | struct ceph_mds_session *session = cap->session; | 868 | struct ceph_mds_session *session = cap->session; |
867 | struct ceph_inode_info *ci = cap->ci; | 869 | struct ceph_inode_info *ci = cap->ci; |
868 | struct ceph_mds_client *mdsc = &ceph_client(ci->vfs_inode.i_sb)->mdsc; | 870 | struct ceph_mds_client *mdsc = |
871 | &ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc; | ||
872 | int removed = 0; | ||
869 | 873 | ||
870 | dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode); | 874 | dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode); |
871 | 875 | ||
872 | /* remove from inode list */ | ||
873 | rb_erase(&cap->ci_node, &ci->i_caps); | ||
874 | cap->ci = NULL; | ||
875 | if (ci->i_auth_cap == cap) | ||
876 | ci->i_auth_cap = NULL; | ||
877 | |||
878 | /* remove from session list */ | 876 | /* remove from session list */ |
879 | spin_lock(&session->s_cap_lock); | 877 | spin_lock(&session->s_cap_lock); |
880 | if (session->s_cap_iterator == cap) { | 878 | if (session->s_cap_iterator == cap) { |
@@ -885,10 +883,18 @@ void __ceph_remove_cap(struct ceph_cap *cap) | |||
885 | list_del_init(&cap->session_caps); | 883 | list_del_init(&cap->session_caps); |
886 | session->s_nr_caps--; | 884 | session->s_nr_caps--; |
887 | cap->session = NULL; | 885 | cap->session = NULL; |
886 | removed = 1; | ||
888 | } | 887 | } |
888 | /* protect backpointer with s_cap_lock: see iterate_session_caps */ | ||
889 | cap->ci = NULL; | ||
889 | spin_unlock(&session->s_cap_lock); | 890 | spin_unlock(&session->s_cap_lock); |
890 | 891 | ||
891 | if (cap->session == NULL) | 892 | /* remove from inode list */ |
893 | rb_erase(&cap->ci_node, &ci->i_caps); | ||
894 | if (ci->i_auth_cap == cap) | ||
895 | ci->i_auth_cap = NULL; | ||
896 | |||
897 | if (removed) | ||
892 | ceph_put_cap(cap); | 898 | ceph_put_cap(cap); |
893 | 899 | ||
894 | if (!__ceph_is_any_caps(ci) && ci->i_snap_realm) { | 900 | if (!__ceph_is_any_caps(ci) && ci->i_snap_realm) { |
@@ -932,9 +938,9 @@ static int send_cap_msg(struct ceph_mds_session *session, | |||
932 | seq, issue_seq, mseq, follows, size, max_size, | 938 | seq, issue_seq, mseq, follows, size, max_size, |
933 | xattr_version, xattrs_buf ? (int)xattrs_buf->vec.iov_len : 0); | 939 | xattr_version, xattrs_buf ? (int)xattrs_buf->vec.iov_len : 0); |
934 | 940 | ||
935 | msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, sizeof(*fc), 0, 0, NULL); | 941 | msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPS, sizeof(*fc), GFP_NOFS); |
936 | if (IS_ERR(msg)) | 942 | if (!msg) |
937 | return PTR_ERR(msg); | 943 | return -ENOMEM; |
938 | 944 | ||
939 | msg->hdr.tid = cpu_to_le64(flush_tid); | 945 | msg->hdr.tid = cpu_to_le64(flush_tid); |
940 | 946 | ||
@@ -1293,7 +1299,8 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci) | |||
1293 | */ | 1299 | */ |
1294 | void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) | 1300 | void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) |
1295 | { | 1301 | { |
1296 | struct ceph_mds_client *mdsc = &ceph_client(ci->vfs_inode.i_sb)->mdsc; | 1302 | struct ceph_mds_client *mdsc = |
1303 | &ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc; | ||
1297 | struct inode *inode = &ci->vfs_inode; | 1304 | struct inode *inode = &ci->vfs_inode; |
1298 | int was = ci->i_dirty_caps; | 1305 | int was = ci->i_dirty_caps; |
1299 | int dirty = 0; | 1306 | int dirty = 0; |
@@ -1331,7 +1338,7 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) | |||
1331 | static int __mark_caps_flushing(struct inode *inode, | 1338 | static int __mark_caps_flushing(struct inode *inode, |
1332 | struct ceph_mds_session *session) | 1339 | struct ceph_mds_session *session) |
1333 | { | 1340 | { |
1334 | struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc; | 1341 | struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc; |
1335 | struct ceph_inode_info *ci = ceph_inode(inode); | 1342 | struct ceph_inode_info *ci = ceph_inode(inode); |
1336 | int flushing; | 1343 | int flushing; |
1337 | 1344 | ||
@@ -1658,7 +1665,7 @@ ack: | |||
1658 | static int try_flush_caps(struct inode *inode, struct ceph_mds_session *session, | 1665 | static int try_flush_caps(struct inode *inode, struct ceph_mds_session *session, |
1659 | unsigned *flush_tid) | 1666 | unsigned *flush_tid) |
1660 | { | 1667 | { |
1661 | struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc; | 1668 | struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc; |
1662 | struct ceph_inode_info *ci = ceph_inode(inode); | 1669 | struct ceph_inode_info *ci = ceph_inode(inode); |
1663 | int unlock_session = session ? 0 : 1; | 1670 | int unlock_session = session ? 0 : 1; |
1664 | int flushing = 0; | 1671 | int flushing = 0; |
@@ -1711,10 +1718,9 @@ out_unlocked: | |||
1711 | static int caps_are_flushed(struct inode *inode, unsigned tid) | 1718 | static int caps_are_flushed(struct inode *inode, unsigned tid) |
1712 | { | 1719 | { |
1713 | struct ceph_inode_info *ci = ceph_inode(inode); | 1720 | struct ceph_inode_info *ci = ceph_inode(inode); |
1714 | int dirty, i, ret = 1; | 1721 | int i, ret = 1; |
1715 | 1722 | ||
1716 | spin_lock(&inode->i_lock); | 1723 | spin_lock(&inode->i_lock); |
1717 | dirty = __ceph_caps_dirty(ci); | ||
1718 | for (i = 0; i < CEPH_CAP_BITS; i++) | 1724 | for (i = 0; i < CEPH_CAP_BITS; i++) |
1719 | if ((ci->i_flushing_caps & (1 << i)) && | 1725 | if ((ci->i_flushing_caps & (1 << i)) && |
1720 | ci->i_cap_flush_tid[i] <= tid) { | 1726 | ci->i_cap_flush_tid[i] <= tid) { |
@@ -1824,7 +1830,8 @@ int ceph_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
1824 | err = wait_event_interruptible(ci->i_cap_wq, | 1830 | err = wait_event_interruptible(ci->i_cap_wq, |
1825 | caps_are_flushed(inode, flush_tid)); | 1831 | caps_are_flushed(inode, flush_tid)); |
1826 | } else { | 1832 | } else { |
1827 | struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc; | 1833 | struct ceph_mds_client *mdsc = |
1834 | &ceph_sb_to_client(inode->i_sb)->mdsc; | ||
1828 | 1835 | ||
1829 | spin_lock(&inode->i_lock); | 1836 | spin_lock(&inode->i_lock); |
1830 | if (__ceph_caps_dirty(ci)) | 1837 | if (__ceph_caps_dirty(ci)) |
@@ -2406,7 +2413,7 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid, | |||
2406 | __releases(inode->i_lock) | 2413 | __releases(inode->i_lock) |
2407 | { | 2414 | { |
2408 | struct ceph_inode_info *ci = ceph_inode(inode); | 2415 | struct ceph_inode_info *ci = ceph_inode(inode); |
2409 | struct ceph_mds_client *mdsc = &ceph_client(inode->i_sb)->mdsc; | 2416 | struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc; |
2410 | unsigned seq = le32_to_cpu(m->seq); | 2417 | unsigned seq = le32_to_cpu(m->seq); |
2411 | int dirty = le32_to_cpu(m->dirty); | 2418 | int dirty = le32_to_cpu(m->dirty); |
2412 | int cleaned = 0; | 2419 | int cleaned = 0; |