diff options
| -rw-r--r-- | fs/ceph/caps.c | 19 | ||||
| -rw-r--r-- | fs/ceph/mds_client.c | 5 |
2 files changed, 15 insertions, 9 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index 0c1681806867..d9400534b279 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 | */ |
| @@ -866,15 +868,10 @@ void __ceph_remove_cap(struct ceph_cap *cap) | |||
| 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 = &ceph_client(ci->vfs_inode.i_sb)->mdsc; |
| 871 | int removed = 0; | ||
| 869 | 872 | ||
| 870 | dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode); | 873 | dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode); |
| 871 | 874 | ||
| 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 */ | 875 | /* remove from session list */ |
| 879 | spin_lock(&session->s_cap_lock); | 876 | spin_lock(&session->s_cap_lock); |
| 880 | if (session->s_cap_iterator == cap) { | 877 | if (session->s_cap_iterator == cap) { |
| @@ -885,10 +882,18 @@ void __ceph_remove_cap(struct ceph_cap *cap) | |||
| 885 | list_del_init(&cap->session_caps); | 882 | list_del_init(&cap->session_caps); |
| 886 | session->s_nr_caps--; | 883 | session->s_nr_caps--; |
| 887 | cap->session = NULL; | 884 | cap->session = NULL; |
| 885 | removed = 1; | ||
| 888 | } | 886 | } |
| 887 | /* protect backpointer with s_cap_lock: see iterate_session_caps */ | ||
| 888 | cap->ci = NULL; | ||
| 889 | spin_unlock(&session->s_cap_lock); | 889 | spin_unlock(&session->s_cap_lock); |
| 890 | 890 | ||
| 891 | if (cap->session == NULL) | 891 | /* remove from inode list */ |
| 892 | rb_erase(&cap->ci_node, &ci->i_caps); | ||
| 893 | if (ci->i_auth_cap == cap) | ||
| 894 | ci->i_auth_cap = NULL; | ||
| 895 | |||
| 896 | if (removed) | ||
| 892 | ceph_put_cap(cap); | 897 | ceph_put_cap(cap); |
| 893 | 898 | ||
| 894 | if (!__ceph_is_any_caps(ci) && ci->i_snap_realm) { | 899 | if (!__ceph_is_any_caps(ci) && ci->i_snap_realm) { |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index eccc0ecad1a2..24561a557e01 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
| @@ -736,9 +736,10 @@ static void cleanup_cap_releases(struct ceph_mds_session *session) | |||
| 736 | } | 736 | } |
| 737 | 737 | ||
| 738 | /* | 738 | /* |
| 739 | * Helper to safely iterate over all caps associated with a session. | 739 | * Helper to safely iterate over all caps associated with a session, with |
| 740 | * special care taken to handle a racing __ceph_remove_cap(). | ||
| 740 | * | 741 | * |
| 741 | * caller must hold session s_mutex | 742 | * Caller must hold session s_mutex. |
| 742 | */ | 743 | */ |
| 743 | static int iterate_session_caps(struct ceph_mds_session *session, | 744 | static int iterate_session_caps(struct ceph_mds_session *session, |
| 744 | int (*cb)(struct inode *, struct ceph_cap *, | 745 | int (*cb)(struct inode *, struct ceph_cap *, |
