mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	NFSv4: Fix an Oops during delegation callbacks
If the server sends a CB_GETATTR or a CB_RECALL while the filesystem is being unmounted, then we can Oops when releasing the inode in nfs4_callback_getattr() and nfs4_callback_recall(). Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
		
							parent
							
								
									e3d5e573a5
								
							
						
					
					
						commit
						e39d8a186e
					
				
					 2 changed files with 11 additions and 4 deletions
				
			
		| 
						 | 
				
			
			@ -66,7 +66,7 @@ __be32 nfs4_callback_getattr(void *argp, void *resp,
 | 
			
		|||
out_iput:
 | 
			
		||||
	rcu_read_unlock();
 | 
			
		||||
	trace_nfs4_cb_getattr(cps->clp, &args->fh, inode, -ntohl(res->status));
 | 
			
		||||
	iput(inode);
 | 
			
		||||
	nfs_iput_and_deactive(inode);
 | 
			
		||||
out:
 | 
			
		||||
	dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status));
 | 
			
		||||
	return res->status;
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +108,7 @@ __be32 nfs4_callback_recall(void *argp, void *resp,
 | 
			
		|||
	}
 | 
			
		||||
	trace_nfs4_cb_recall(cps->clp, &args->fh, inode,
 | 
			
		||||
			&args->stateid, -ntohl(res));
 | 
			
		||||
	iput(inode);
 | 
			
		||||
	nfs_iput_and_deactive(inode);
 | 
			
		||||
out:
 | 
			
		||||
	dprintk("%s: exit with status = %d\n", __func__, ntohl(res));
 | 
			
		||||
	return res;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -850,16 +850,23 @@ nfs_delegation_find_inode_server(struct nfs_server *server,
 | 
			
		|||
				 const struct nfs_fh *fhandle)
 | 
			
		||||
{
 | 
			
		||||
	struct nfs_delegation *delegation;
 | 
			
		||||
	struct inode *res = NULL;
 | 
			
		||||
	struct inode *freeme, *res = NULL;
 | 
			
		||||
 | 
			
		||||
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
 | 
			
		||||
		spin_lock(&delegation->lock);
 | 
			
		||||
		if (delegation->inode != NULL &&
 | 
			
		||||
		    nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
 | 
			
		||||
			res = igrab(delegation->inode);
 | 
			
		||||
			freeme = igrab(delegation->inode);
 | 
			
		||||
			if (freeme && nfs_sb_active(freeme->i_sb))
 | 
			
		||||
				res = freeme;
 | 
			
		||||
			spin_unlock(&delegation->lock);
 | 
			
		||||
			if (res != NULL)
 | 
			
		||||
				return res;
 | 
			
		||||
			if (freeme) {
 | 
			
		||||
				rcu_read_unlock();
 | 
			
		||||
				iput(freeme);
 | 
			
		||||
				rcu_read_lock();
 | 
			
		||||
			}
 | 
			
		||||
			return ERR_PTR(-EAGAIN);
 | 
			
		||||
		}
 | 
			
		||||
		spin_unlock(&delegation->lock);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue