NFS/pnfs: Bulk destroy of layouts needs to be safe w.r.t. umount

If a bulk layout recall or a metadata server reboot coincides with a
umount, then holding a reference to an inode is unsafe unless we
also hold a reference to the super block.

Fixes: fd9a8d7160 ("NFSv4.1: Fix bulk recall and destroy of layouts")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
Trond Myklebust 2019-02-22 14:20:27 -05:00
parent 6f9449be53
commit 5085607d20
2 changed files with 24 additions and 10 deletions

View File

@ -758,22 +758,35 @@ static int
pnfs_layout_bulk_destroy_byserver_locked(struct nfs_client *clp, pnfs_layout_bulk_destroy_byserver_locked(struct nfs_client *clp,
struct nfs_server *server, struct nfs_server *server,
struct list_head *layout_list) struct list_head *layout_list)
__must_hold(&clp->cl_lock)
__must_hold(RCU)
{ {
struct pnfs_layout_hdr *lo, *next; struct pnfs_layout_hdr *lo, *next;
struct inode *inode; struct inode *inode;
list_for_each_entry_safe(lo, next, &server->layouts, plh_layouts) { list_for_each_entry_safe(lo, next, &server->layouts, plh_layouts) {
if (test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags)) if (test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) ||
test_bit(NFS_LAYOUT_INODE_FREEING, &lo->plh_flags) ||
!list_empty(&lo->plh_bulk_destroy))
continue; continue;
/* If the sb is being destroyed, just bail */
if (!nfs_sb_active(server->super))
break;
inode = igrab(lo->plh_inode); inode = igrab(lo->plh_inode);
if (inode == NULL) if (inode != NULL) {
continue;
list_del_init(&lo->plh_layouts); list_del_init(&lo->plh_layouts);
if (pnfs_layout_add_bulk_destroy_list(inode, layout_list)) if (pnfs_layout_add_bulk_destroy_list(inode,
layout_list))
continue; continue;
rcu_read_unlock(); rcu_read_unlock();
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
iput(inode); iput(inode);
} else {
rcu_read_unlock();
spin_unlock(&clp->cl_lock);
set_bit(NFS_LAYOUT_INODE_FREEING, &lo->plh_flags);
}
nfs_sb_deactive(server->super);
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
rcu_read_lock(); rcu_read_lock();
return -EAGAIN; return -EAGAIN;
@ -811,7 +824,7 @@ pnfs_layout_free_bulk_destroy_list(struct list_head *layout_list,
/* Free all lsegs that are attached to commit buckets */ /* Free all lsegs that are attached to commit buckets */
nfs_commit_inode(inode, 0); nfs_commit_inode(inode, 0);
pnfs_put_layout_hdr(lo); pnfs_put_layout_hdr(lo);
iput(inode); nfs_iput_and_deactive(inode);
} }
return ret; return ret;
} }

View File

@ -104,6 +104,7 @@ enum {
NFS_LAYOUT_RETURN_REQUESTED, /* Return this layout ASAP */ NFS_LAYOUT_RETURN_REQUESTED, /* Return this layout ASAP */
NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */ NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */
NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */ NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */
NFS_LAYOUT_INODE_FREEING, /* The inode is being freed */
}; };
enum layoutdriver_policy_flags { enum layoutdriver_policy_flags {