Skip to content

Commit 5085607

Browse files
author
Trond Myklebust
committed
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: fd9a8d7 ("NFSv4.1: Fix bulk recall and destroy of layouts") Signed-off-by: Trond Myklebust <[email protected]>
1 parent 6f9449b commit 5085607

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

fs/nfs/pnfs.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -758,22 +758,35 @@ static int
758758
pnfs_layout_bulk_destroy_byserver_locked(struct nfs_client *clp,
759759
struct nfs_server *server,
760760
struct list_head *layout_list)
761+
__must_hold(&clp->cl_lock)
762+
__must_hold(RCU)
761763
{
762764
struct pnfs_layout_hdr *lo, *next;
763765
struct inode *inode;
764766

765767
list_for_each_entry_safe(lo, next, &server->layouts, plh_layouts) {
766-
if (test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags))
768+
if (test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) ||
769+
test_bit(NFS_LAYOUT_INODE_FREEING, &lo->plh_flags) ||
770+
!list_empty(&lo->plh_bulk_destroy))
767771
continue;
772+
/* If the sb is being destroyed, just bail */
773+
if (!nfs_sb_active(server->super))
774+
break;
768775
inode = igrab(lo->plh_inode);
769-
if (inode == NULL)
770-
continue;
771-
list_del_init(&lo->plh_layouts);
772-
if (pnfs_layout_add_bulk_destroy_list(inode, layout_list))
773-
continue;
774-
rcu_read_unlock();
775-
spin_unlock(&clp->cl_lock);
776-
iput(inode);
776+
if (inode != NULL) {
777+
list_del_init(&lo->plh_layouts);
778+
if (pnfs_layout_add_bulk_destroy_list(inode,
779+
layout_list))
780+
continue;
781+
rcu_read_unlock();
782+
spin_unlock(&clp->cl_lock);
783+
iput(inode);
784+
} else {
785+
rcu_read_unlock();
786+
spin_unlock(&clp->cl_lock);
787+
set_bit(NFS_LAYOUT_INODE_FREEING, &lo->plh_flags);
788+
}
789+
nfs_sb_deactive(server->super);
777790
spin_lock(&clp->cl_lock);
778791
rcu_read_lock();
779792
return -EAGAIN;
@@ -811,7 +824,7 @@ pnfs_layout_free_bulk_destroy_list(struct list_head *layout_list,
811824
/* Free all lsegs that are attached to commit buckets */
812825
nfs_commit_inode(inode, 0);
813826
pnfs_put_layout_hdr(lo);
814-
iput(inode);
827+
nfs_iput_and_deactive(inode);
815828
}
816829
return ret;
817830
}

fs/nfs/pnfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ enum {
104104
NFS_LAYOUT_RETURN_REQUESTED, /* Return this layout ASAP */
105105
NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */
106106
NFS_LAYOUT_FIRST_LAYOUTGET, /* Serialize first layoutget */
107+
NFS_LAYOUT_INODE_FREEING, /* The inode is being freed */
107108
};
108109

109110
enum layoutdriver_policy_flags {

0 commit comments

Comments
 (0)