diff options
author | Sage Weil <sage@newdream.net> | 2009-12-22 04:40:34 (GMT) |
---|---|---|
committer | Sage Weil <sage@newdream.net> | 2009-12-23 16:17:14 (GMT) |
commit | 5dacf09121ffb2e5fc7d15b78cae0b77042a1935 (patch) | |
tree | 8a4ec2fde459f93936a91644d024673d37347408 | |
parent | 7067f797b8409f1e10ec95ac2c1e17a200173d13 (diff) | |
download | linux-5dacf09121ffb2e5fc7d15b78cae0b77042a1935.tar.xz |
ceph: do not touch_caps while iterating over caps list
Avoid confusing iterate_session_caps(), flag the session while we are
iterating so that __touch_cap does not rearrange items on the list.
All other modifiers of session->s_caps do so under the protection of
s_mutex.
Signed-off-by: Sage Weil <sage@newdream.net>
-rw-r--r-- | fs/ceph/caps.c | 11 | ||||
-rw-r--r-- | fs/ceph/mds_client.c | 14 | ||||
-rw-r--r-- | fs/ceph/mds_client.h | 1 |
3 files changed, 19 insertions, 7 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index dfb509f..93c1afe 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -697,10 +697,15 @@ static void __touch_cap(struct ceph_cap *cap) { struct ceph_mds_session *s = cap->session; - dout("__touch_cap %p cap %p mds%d\n", &cap->ci->vfs_inode, cap, - s->s_mds); spin_lock(&s->s_cap_lock); - list_move_tail(&cap->session_caps, &s->s_caps); + if (!s->s_iterating_caps) { + dout("__touch_cap %p cap %p mds%d\n", &cap->ci->vfs_inode, cap, + s->s_mds); + list_move_tail(&cap->session_caps, &s->s_caps); + } else { + dout("__touch_cap %p cap %p mds%d NOP, iterating over caps\n", + &cap->ci->vfs_inode, cap, s->s_mds); + } spin_unlock(&s->s_cap_lock); } diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index d7cecc3..63ca3b1 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -337,10 +337,12 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc, s->s_renew_seq = 0; INIT_LIST_HEAD(&s->s_caps); s->s_nr_caps = 0; + s->s_trim_caps = 0; atomic_set(&s->s_ref, 1); INIT_LIST_HEAD(&s->s_waiting); INIT_LIST_HEAD(&s->s_unsafe); s->s_num_cap_releases = 0; + s->s_iterating_caps = false; INIT_LIST_HEAD(&s->s_cap_releases); INIT_LIST_HEAD(&s->s_cap_releases_done); INIT_LIST_HEAD(&s->s_cap_flushing); @@ -699,6 +701,7 @@ static int iterate_session_caps(struct ceph_mds_session *session, dout("iterate_session_caps %p mds%d\n", session, session->s_mds); spin_lock(&session->s_cap_lock); + session->s_iterating_caps = true; list_for_each_entry_safe(cap, ncap, &session->s_caps, session_caps) { inode = igrab(&cap->ci->vfs_inode); if (!inode) @@ -706,13 +709,15 @@ static int iterate_session_caps(struct ceph_mds_session *session, spin_unlock(&session->s_cap_lock); ret = cb(inode, cap, arg); iput(inode); - if (ret < 0) - return ret; spin_lock(&session->s_cap_lock); + if (ret < 0) + goto out; } + ret = 0; +out: + session->s_iterating_caps = false; spin_unlock(&session->s_cap_lock); - - return 0; + return ret; } static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, @@ -935,6 +940,7 @@ static int trim_caps(struct ceph_mds_client *mdsc, dout("trim_caps mds%d done: %d / %d, trimmed %d\n", session->s_mds, session->s_nr_caps, max_caps, trim_caps - session->s_trim_caps); + session->s_trim_caps = 0; } return 0; } diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 41af5ca..b1c2025 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -114,6 +114,7 @@ struct ceph_mds_session { int s_num_cap_releases; struct list_head s_cap_releases; /* waiting cap_release messages */ struct list_head s_cap_releases_done; /* ready to send */ + bool s_iterating_caps; /* protected by mutex */ struct list_head s_cap_flushing; /* inodes w/ flushing caps */ |