diff options
author | David Howells <dhowells@redhat.com> | 2019-05-13 16:14:32 +0100 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-05-16 22:23:21 +0100 |
commit | f642404a0436a50912c218009ccc7856d48d784c (patch) | |
tree | ddf39d1741f07866333581e66f1abc0e6709d453 /fs/afs/callback.c | |
parent | c925bd0ac4741badb567f594c41c8cba5e9e9732 (diff) |
afs: Make vnode->cb_interest RCU safe
Use RCU-based freeing for afs_cb_interest struct objects and use RCU on
vnode->cb_interest. Use that change to allow afs_check_validity() to use
read_seqbegin_or_lock() instead of read_seqlock_excl().
This also requires the caller of afs_check_validity() to hold the RCU read
lock across the call.
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs/callback.c')
-rw-r--r-- | fs/afs/callback.c | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 4876079aa643..d441bef72163 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c @@ -94,15 +94,15 @@ int afs_register_server_cb_interest(struct afs_vnode *vnode, struct afs_server *server = entry->server; again: - if (vnode->cb_interest && - likely(vnode->cb_interest == entry->cb_interest)) + vcbi = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->io_lock)); + if (vcbi && likely(vcbi == entry->cb_interest)) return 0; read_lock(&slist->lock); cbi = afs_get_cb_interest(entry->cb_interest); read_unlock(&slist->lock); - vcbi = vnode->cb_interest; if (vcbi) { if (vcbi == cbi) { afs_put_cb_interest(afs_v2net(vnode), cbi); @@ -114,8 +114,9 @@ again: */ if (cbi && vcbi->server == cbi->server) { write_seqlock(&vnode->cb_lock); - old = vnode->cb_interest; - vnode->cb_interest = cbi; + old = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->cb_lock.lock)); + rcu_assign_pointer(vnode->cb_interest, cbi); write_sequnlock(&vnode->cb_lock); afs_put_cb_interest(afs_v2net(vnode), old); return 0; @@ -160,8 +161,9 @@ again: */ write_seqlock(&vnode->cb_lock); - old = vnode->cb_interest; - vnode->cb_interest = cbi; + old = rcu_dereference_protected(vnode->cb_interest, + lockdep_is_held(&vnode->cb_lock.lock)); + rcu_assign_pointer(vnode->cb_interest, cbi); vnode->cb_s_break = cbi->server->cb_s_break; vnode->cb_v_break = vnode->volume->cb_v_break; clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); @@ -191,10 +193,11 @@ void afs_put_cb_interest(struct afs_net *net, struct afs_cb_interest *cbi) vi = NULL; write_unlock(&cbi->server->cb_break_lock); - kfree(vi); + if (vi) + kfree_rcu(vi, rcu); afs_put_server(net, cbi->server); } - kfree(cbi); + kfree_rcu(cbi, rcu); } } |