提交 d57908da 编写于 作者: T Trond Myklebust 提交者: Yang Yingliang

NFSv4: Fix a pNFS layout related use-after-free race when freeing the inode

stable inclusion
from linux-4.19.165
commit 05a0aec6787885a335a9d3cec7e1cfffee253b84

--------------------------------

[ Upstream commit b6d49ecd ]

When returning the layout in nfs4_evict_inode(), we need to ensure that
the layout is actually done being freed before we can proceed to free the
inode itself.
Signed-off-by: NTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: NCheng Jian <cj.chengjian@huawei.com>
上级 f58f6391
...@@ -95,7 +95,7 @@ static void nfs4_evict_inode(struct inode *inode) ...@@ -95,7 +95,7 @@ static void nfs4_evict_inode(struct inode *inode)
nfs_inode_return_delegation_noreclaim(inode); nfs_inode_return_delegation_noreclaim(inode);
/* Note that above delegreturn would trigger pnfs return-on-close */ /* Note that above delegreturn would trigger pnfs return-on-close */
pnfs_return_layout(inode); pnfs_return_layout(inode);
pnfs_destroy_layout(NFS_I(inode)); pnfs_destroy_layout_final(NFS_I(inode));
/* First call standard NFS clear_inode() code */ /* First call standard NFS clear_inode() code */
nfs_clear_inode(inode); nfs_clear_inode(inode);
} }
......
...@@ -294,6 +294,7 @@ void ...@@ -294,6 +294,7 @@ void
pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
{ {
struct inode *inode; struct inode *inode;
unsigned long i_state;
if (!lo) if (!lo)
return; return;
...@@ -304,8 +305,12 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) ...@@ -304,8 +305,12 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
if (!list_empty(&lo->plh_segs)) if (!list_empty(&lo->plh_segs))
WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n"); WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n");
pnfs_detach_layout_hdr(lo); pnfs_detach_layout_hdr(lo);
i_state = inode->i_state;
spin_unlock(&inode->i_lock); spin_unlock(&inode->i_lock);
pnfs_free_layout_hdr(lo); pnfs_free_layout_hdr(lo);
/* Notify pnfs_destroy_layout_final() that we're done */
if (i_state & (I_FREEING | I_CLEAR))
wake_up_var(lo);
} }
} }
...@@ -713,8 +718,7 @@ pnfs_free_lseg_list(struct list_head *free_me) ...@@ -713,8 +718,7 @@ pnfs_free_lseg_list(struct list_head *free_me)
} }
} }
void static struct pnfs_layout_hdr *__pnfs_destroy_layout(struct nfs_inode *nfsi)
pnfs_destroy_layout(struct nfs_inode *nfsi)
{ {
struct pnfs_layout_hdr *lo; struct pnfs_layout_hdr *lo;
LIST_HEAD(tmp_list); LIST_HEAD(tmp_list);
...@@ -732,9 +736,34 @@ pnfs_destroy_layout(struct nfs_inode *nfsi) ...@@ -732,9 +736,34 @@ pnfs_destroy_layout(struct nfs_inode *nfsi)
pnfs_put_layout_hdr(lo); pnfs_put_layout_hdr(lo);
} else } else
spin_unlock(&nfsi->vfs_inode.i_lock); spin_unlock(&nfsi->vfs_inode.i_lock);
return lo;
}
void pnfs_destroy_layout(struct nfs_inode *nfsi)
{
__pnfs_destroy_layout(nfsi);
} }
EXPORT_SYMBOL_GPL(pnfs_destroy_layout); EXPORT_SYMBOL_GPL(pnfs_destroy_layout);
static bool pnfs_layout_removed(struct nfs_inode *nfsi,
struct pnfs_layout_hdr *lo)
{
bool ret;
spin_lock(&nfsi->vfs_inode.i_lock);
ret = nfsi->layout != lo;
spin_unlock(&nfsi->vfs_inode.i_lock);
return ret;
}
void pnfs_destroy_layout_final(struct nfs_inode *nfsi)
{
struct pnfs_layout_hdr *lo = __pnfs_destroy_layout(nfsi);
if (lo)
wait_var_event(lo, pnfs_layout_removed(nfsi, lo));
}
static bool static bool
pnfs_layout_add_bulk_destroy_list(struct inode *inode, pnfs_layout_add_bulk_destroy_list(struct inode *inode,
struct list_head *layout_list) struct list_head *layout_list)
......
...@@ -253,6 +253,7 @@ struct pnfs_layout_segment *pnfs_layout_process(struct nfs4_layoutget *lgp); ...@@ -253,6 +253,7 @@ struct pnfs_layout_segment *pnfs_layout_process(struct nfs4_layoutget *lgp);
void pnfs_layoutget_free(struct nfs4_layoutget *lgp); void pnfs_layoutget_free(struct nfs4_layoutget *lgp);
void pnfs_free_lseg_list(struct list_head *tmp_list); void pnfs_free_lseg_list(struct list_head *tmp_list);
void pnfs_destroy_layout(struct nfs_inode *); void pnfs_destroy_layout(struct nfs_inode *);
void pnfs_destroy_layout_final(struct nfs_inode *);
void pnfs_destroy_all_layouts(struct nfs_client *); void pnfs_destroy_all_layouts(struct nfs_client *);
int pnfs_destroy_layouts_byfsid(struct nfs_client *clp, int pnfs_destroy_layouts_byfsid(struct nfs_client *clp,
struct nfs_fsid *fsid, struct nfs_fsid *fsid,
...@@ -644,6 +645,10 @@ static inline void pnfs_destroy_layout(struct nfs_inode *nfsi) ...@@ -644,6 +645,10 @@ static inline void pnfs_destroy_layout(struct nfs_inode *nfsi)
{ {
} }
static inline void pnfs_destroy_layout_final(struct nfs_inode *nfsi)
{
}
static inline struct pnfs_layout_segment * static inline struct pnfs_layout_segment *
pnfs_get_lseg(struct pnfs_layout_segment *lseg) pnfs_get_lseg(struct pnfs_layout_segment *lseg)
{ {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册