aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/delegation.c41
1 files changed, 20 insertions, 21 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 1fd62fc49be3..521d71b81825 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -175,9 +175,9 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation
175 return inode; 175 return inode;
176} 176}
177 177
178static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, 178static struct nfs_delegation *
179 const nfs4_stateid *stateid, 179nfs_detach_delegation_locked(struct nfs_inode *nfsi,
180 struct nfs_client *clp) 180 struct nfs_client *clp)
181{ 181{
182 struct nfs_delegation *delegation = 182 struct nfs_delegation *delegation =
183 rcu_dereference_protected(nfsi->delegation, 183 rcu_dereference_protected(nfsi->delegation,
@@ -185,22 +185,29 @@ static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfs
185 185
186 if (delegation == NULL) 186 if (delegation == NULL)
187 goto nomatch; 187 goto nomatch;
188
188 spin_lock(&delegation->lock); 189 spin_lock(&delegation->lock);
189 if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data,
190 sizeof(delegation->stateid.data)) != 0)
191 goto nomatch_unlock;
192 list_del_rcu(&delegation->super_list); 190 list_del_rcu(&delegation->super_list);
193 delegation->inode = NULL; 191 delegation->inode = NULL;
194 nfsi->delegation_state = 0; 192 nfsi->delegation_state = 0;
195 rcu_assign_pointer(nfsi->delegation, NULL); 193 rcu_assign_pointer(nfsi->delegation, NULL);
196 spin_unlock(&delegation->lock); 194 spin_unlock(&delegation->lock);
197 return delegation; 195 return delegation;
198nomatch_unlock:
199 spin_unlock(&delegation->lock);
200nomatch: 196nomatch:
201 return NULL; 197 return NULL;
202} 198}
203 199
200static struct nfs_delegation *nfs_detach_delegation(struct nfs_inode *nfsi,
201 struct nfs_client *clp)
202{
203 struct nfs_delegation *delegation;
204
205 spin_lock(&clp->cl_lock);
206 delegation = nfs_detach_delegation_locked(nfsi, clp);
207 spin_unlock(&clp->cl_lock);
208 return delegation;
209}
210
204/* 211/*
205 * Set up a delegation on an inode 212 * Set up a delegation on an inode
206 */ 213 */
@@ -246,7 +253,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
246 delegation = NULL; 253 delegation = NULL;
247 goto out; 254 goto out;
248 } 255 }
249 freeme = nfs_detach_delegation_locked(nfsi, NULL, clp); 256 freeme = nfs_detach_delegation_locked(nfsi, clp);
250 } 257 }
251 list_add_rcu(&delegation->super_list, &clp->cl_delegations); 258 list_add_rcu(&delegation->super_list, &clp->cl_delegations);
252 nfsi->delegation_state = delegation->type; 259 nfsi->delegation_state = delegation->type;
@@ -307,9 +314,7 @@ restart:
307 inode = nfs_delegation_grab_inode(delegation); 314 inode = nfs_delegation_grab_inode(delegation);
308 if (inode == NULL) 315 if (inode == NULL)
309 continue; 316 continue;
310 spin_lock(&clp->cl_lock); 317 delegation = nfs_detach_delegation(NFS_I(inode), clp);
311 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp);
312 spin_unlock(&clp->cl_lock);
313 rcu_read_unlock(); 318 rcu_read_unlock();
314 if (delegation != NULL) { 319 if (delegation != NULL) {
315 filemap_flush(inode->i_mapping); 320 filemap_flush(inode->i_mapping);
@@ -338,9 +343,7 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode)
338 struct nfs_delegation *delegation; 343 struct nfs_delegation *delegation;
339 344
340 if (rcu_access_pointer(nfsi->delegation) != NULL) { 345 if (rcu_access_pointer(nfsi->delegation) != NULL) {
341 spin_lock(&clp->cl_lock); 346 delegation = nfs_detach_delegation(nfsi, clp);
342 delegation = nfs_detach_delegation_locked(nfsi, NULL, clp);
343 spin_unlock(&clp->cl_lock);
344 if (delegation != NULL) 347 if (delegation != NULL)
345 nfs_do_return_delegation(inode, delegation, 0); 348 nfs_do_return_delegation(inode, delegation, 0);
346 } 349 }
@@ -354,9 +357,7 @@ int nfs_inode_return_delegation(struct inode *inode)
354 int err = 0; 357 int err = 0;
355 358
356 if (rcu_access_pointer(nfsi->delegation) != NULL) { 359 if (rcu_access_pointer(nfsi->delegation) != NULL) {
357 spin_lock(&clp->cl_lock); 360 delegation = nfs_detach_delegation(nfsi, clp);
358 delegation = nfs_detach_delegation_locked(nfsi, NULL, clp);
359 spin_unlock(&clp->cl_lock);
360 if (delegation != NULL) { 361 if (delegation != NULL) {
361 nfs_wb_all(inode); 362 nfs_wb_all(inode);
362 err = __nfs_inode_return_delegation(inode, delegation, 1); 363 err = __nfs_inode_return_delegation(inode, delegation, 1);
@@ -530,9 +531,7 @@ restart:
530 inode = nfs_delegation_grab_inode(delegation); 531 inode = nfs_delegation_grab_inode(delegation);
531 if (inode == NULL) 532 if (inode == NULL)
532 continue; 533 continue;
533 spin_lock(&clp->cl_lock); 534 delegation = nfs_detach_delegation(NFS_I(inode), clp);
534 delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp);
535 spin_unlock(&clp->cl_lock);
536 rcu_read_unlock(); 535 rcu_read_unlock();
537 if (delegation != NULL) 536 if (delegation != NULL)
538 nfs_free_delegation(delegation); 537 nfs_free_delegation(delegation);