Skip to content

Commit

Permalink
NFS: nfs_delegation_find_inode_server must first reference the superb…
Browse files Browse the repository at this point in the history
…lock

Before referencing the inode, we must ensure that the superblock can be
referenced. Otherwise, we can end up with iput() calling superblock
operations that are no longer valid or accessible.

Fixes: e39d8a1 ("NFSv4: Fix an Oops during delegation callbacks")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
  • Loading branch information
Trond Myklebust committed Jan 10, 2021
1 parent cb2856c commit 113aac6
Showing 1 changed file with 7 additions and 5 deletions.
12 changes: 7 additions & 5 deletions fs/nfs/delegation.c
Original file line number Diff line number Diff line change
Expand Up @@ -1011,22 +1011,24 @@ nfs_delegation_find_inode_server(struct nfs_server *server,
const struct nfs_fh *fhandle)
{
struct nfs_delegation *delegation;
struct inode *freeme, *res = NULL;
struct super_block *freeme = NULL;
struct inode *res = NULL;

list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
spin_lock(&delegation->lock);
if (delegation->inode != NULL &&
!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) &&
nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
freeme = igrab(delegation->inode);
if (freeme && nfs_sb_active(freeme->i_sb))
res = freeme;
if (nfs_sb_active(server->super)) {
freeme = server->super;
res = igrab(delegation->inode);
}
spin_unlock(&delegation->lock);
if (res != NULL)
return res;
if (freeme) {
rcu_read_unlock();
iput(freeme);
nfs_sb_deactive(freeme);
rcu_read_lock();
}
return ERR_PTR(-EAGAIN);
Expand Down

0 comments on commit 113aac6

Please sign in to comment.