From b7d26eb54c6ae378e17a0954881831e3dc65e42c Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 11 May 2010 20:56:31 -0700 Subject: [PATCH] --- yaml --- r: 190809 b: refs/heads/master c: f818a73674c5d197f66b636a46d7d578d7258129 h: refs/heads/master i: 190807: d6974901ad808d5698dcbe151a0ed6fd18e25dd3 v: v3 --- [refs] | 2 +- trunk/fs/ceph/caps.c | 19 ++++++++++++------- trunk/fs/ceph/mds_client.c | 5 +++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/[refs] b/[refs] index c74313387e49..dc7561875709 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 45c6ceb547ad2d98215351974a4686bf8cb13e14 +refs/heads/master: f818a73674c5d197f66b636a46d7d578d7258129 diff --git a/trunk/fs/ceph/caps.c b/trunk/fs/ceph/caps.c index 0c1681806867..d9400534b279 100644 --- a/trunk/fs/ceph/caps.c +++ b/trunk/fs/ceph/caps.c @@ -858,6 +858,8 @@ static int __ceph_is_any_caps(struct ceph_inode_info *ci) } /* + * Remove a cap. Take steps to deal with a racing iterate_session_caps. + * * caller should hold i_lock. * caller will not hold session s_mutex if called from destroy_inode. */ @@ -866,15 +868,10 @@ void __ceph_remove_cap(struct ceph_cap *cap) struct ceph_mds_session *session = cap->session; struct ceph_inode_info *ci = cap->ci; struct ceph_mds_client *mdsc = &ceph_client(ci->vfs_inode.i_sb)->mdsc; + int removed = 0; dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode); - /* remove from inode list */ - rb_erase(&cap->ci_node, &ci->i_caps); - cap->ci = NULL; - if (ci->i_auth_cap == cap) - ci->i_auth_cap = NULL; - /* remove from session list */ spin_lock(&session->s_cap_lock); if (session->s_cap_iterator == cap) { @@ -885,10 +882,18 @@ void __ceph_remove_cap(struct ceph_cap *cap) list_del_init(&cap->session_caps); session->s_nr_caps--; cap->session = NULL; + removed = 1; } + /* protect backpointer with s_cap_lock: see iterate_session_caps */ + cap->ci = NULL; spin_unlock(&session->s_cap_lock); - if (cap->session == NULL) + /* remove from inode list */ + rb_erase(&cap->ci_node, &ci->i_caps); + if (ci->i_auth_cap == cap) + ci->i_auth_cap = NULL; + + if (removed) ceph_put_cap(cap); if (!__ceph_is_any_caps(ci) && ci->i_snap_realm) { diff --git a/trunk/fs/ceph/mds_client.c b/trunk/fs/ceph/mds_client.c index eccc0ecad1a2..24561a557e01 100644 --- a/trunk/fs/ceph/mds_client.c +++ b/trunk/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 *,