summaryrefslogtreecommitdiff
path: root/fs/ceph/mds_client.c
diff options
context:
space:
mode:
authorSage Weil <sage@newdream.net>2010-05-11 20:56:31 -0700
committerSage Weil <sage@newdream.net>2010-05-11 20:56:31 -0700
commitf818a73674c5d197f66b636a46d7d578d7258129 (patch)
tree90c485b5ca0a211b84ad8feddfce4f301de3d5c9 /fs/ceph/mds_client.c
parent45c6ceb547ad2d98215351974a4686bf8cb13e14 (diff)
downloadlwn-f818a73674c5d197f66b636a46d7d578d7258129.tar.gz
lwn-f818a73674c5d197f66b636a46d7d578d7258129.zip
ceph: fix cap removal races
The iterate_session_caps helper traverses the session caps list and tries to grab an inode reference. However, the __ceph_remove_cap was clearing the inode backpointer _before_ removing itself from the session list, causing a null pointer dereference. Clear cap->ci under protection of s_cap_lock to avoid the race, and to tightly couple the list and backpointer state. Use a local flag to indicate whether we are releasing the cap, as cap->session may be modified by a racing thread in iterate_session_caps. Signed-off-by: Sage Weil <sage@newdream.net>
Diffstat (limited to 'fs/ceph/mds_client.c')
-rw-r--r--fs/ceph/mds_client.c5
1 files changed, 3 insertions, 2 deletions
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)
}
/*
- * Helper to safely iterate over all caps associated with a session.
+ * Helper to safely iterate over all caps associated with a session, with
+ * special care taken to handle a racing __ceph_remove_cap().
*
- * caller must hold session s_mutex
+ * Caller must hold session s_mutex.
*/
static int iterate_session_caps(struct ceph_mds_session *session,
int (*cb)(struct inode *, struct ceph_cap *,