diff options
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, | |||
94 | struct afs_server *server = entry->server; | 94 | struct afs_server *server = entry->server; |
95 | 95 | ||
96 | again: | 96 | again: |
97 | if (vnode->cb_interest && | 97 | vcbi = rcu_dereference_protected(vnode->cb_interest, |
98 | likely(vnode->cb_interest == entry->cb_interest)) | 98 | lockdep_is_held(&vnode->io_lock)); |
99 | if (vcbi && likely(vcbi == entry->cb_interest)) | ||
99 | return 0; | 100 | return 0; |
100 | 101 | ||
101 | read_lock(&slist->lock); | 102 | read_lock(&slist->lock); |
102 | cbi = afs_get_cb_interest(entry->cb_interest); | 103 | cbi = afs_get_cb_interest(entry->cb_interest); |
103 | read_unlock(&slist->lock); | 104 | read_unlock(&slist->lock); |
104 | 105 | ||
105 | vcbi = vnode->cb_interest; | ||
106 | if (vcbi) { | 106 | if (vcbi) { |
107 | if (vcbi == cbi) { | 107 | if (vcbi == cbi) { |
108 | afs_put_cb_interest(afs_v2net(vnode), cbi); | 108 | afs_put_cb_interest(afs_v2net(vnode), cbi); |
@@ -114,8 +114,9 @@ again: | |||
114 | */ | 114 | */ |
115 | if (cbi && vcbi->server == cbi->server) { | 115 | if (cbi && vcbi->server == cbi->server) { |
116 | write_seqlock(&vnode->cb_lock); | 116 | write_seqlock(&vnode->cb_lock); |
117 | old = vnode->cb_interest; | 117 | old = rcu_dereference_protected(vnode->cb_interest, |
118 | vnode->cb_interest = cbi; | 118 | lockdep_is_held(&vnode->cb_lock.lock)); |
119 | rcu_assign_pointer(vnode->cb_interest, cbi); | ||
119 | write_sequnlock(&vnode->cb_lock); | 120 | write_sequnlock(&vnode->cb_lock); |
120 | afs_put_cb_interest(afs_v2net(vnode), old); | 121 | afs_put_cb_interest(afs_v2net(vnode), old); |
121 | return 0; | 122 | return 0; |
@@ -160,8 +161,9 @@ again: | |||
160 | */ | 161 | */ |
161 | write_seqlock(&vnode->cb_lock); | 162 | write_seqlock(&vnode->cb_lock); |
162 | 163 | ||
163 | old = vnode->cb_interest; | 164 | old = rcu_dereference_protected(vnode->cb_interest, |
164 | vnode->cb_interest = cbi; | 165 | lockdep_is_held(&vnode->cb_lock.lock)); |
166 | rcu_assign_pointer(vnode->cb_interest, cbi); | ||
165 | vnode->cb_s_break = cbi->server->cb_s_break; | 167 | vnode->cb_s_break = cbi->server->cb_s_break; |
166 | vnode->cb_v_break = vnode->volume->cb_v_break; | 168 | vnode->cb_v_break = vnode->volume->cb_v_break; |
167 | clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags); | 169 | 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) | |||
191 | vi = NULL; | 193 | vi = NULL; |
192 | 194 | ||
193 | write_unlock(&cbi->server->cb_break_lock); | 195 | write_unlock(&cbi->server->cb_break_lock); |
194 | kfree(vi); | 196 | if (vi) |
197 | kfree_rcu(vi, rcu); | ||
195 | afs_put_server(net, cbi->server); | 198 | afs_put_server(net, cbi->server); |
196 | } | 199 | } |
197 | kfree(cbi); | 200 | kfree_rcu(cbi, rcu); |
198 | } | 201 | } |
199 | } | 202 | } |
200 | 203 | ||