Message ID | 20201125185240.295065-1-trondmy@kernel.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | NFSv4: Fix a pNFS layout related use-after-free race when freeing the inode | expand |
Hi, I love your patch! Yet something to improve: [auto build test ERROR on nfs/linux-next] [also build test ERROR on v5.10-rc5 next-20201125] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/trondmy-kernel-org/NFSv4-Fix-a-pNFS-layout-related-use-after-free-race-when-freeing-the-inode/20201126-025547 base: git://git.linux-nfs.org/projects/trondmy/linux-nfs.git linux-next config: i386-randconfig-s001-20201125 (attached as .config) compiler: gcc-9 (Debian 9.3.0-15) 9.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.3-151-g540c2c4b-dirty # https://github.com/0day-ci/linux/commit/1152b7349ba4ede4340756f56f5f21808d987a86 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review trondmy-kernel-org/NFSv4-Fix-a-pNFS-layout-related-use-after-free-race-when-freeing-the-inode/20201126-025547 git checkout 1152b7349ba4ede4340756f56f5f21808d987a86 # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=i386 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): fs/nfs/nfs4super.c: In function 'nfs4_evict_inode': >> fs/nfs/nfs4super.c:70:2: error: implicit declaration of function 'pnfs_destroy_layout_final'; did you mean 'pnfs_destroy_layout'? [-Werror=implicit-function-declaration] 70 | pnfs_destroy_layout_final(NFS_I(inode)); | ^~~~~~~~~~~~~~~~~~~~~~~~~ | pnfs_destroy_layout cc1: some warnings being treated as errors vim +70 fs/nfs/nfs4super.c 56 57 /* 58 * Clean out any remaining NFSv4 state that might be left over due 59 * to open() calls that passed nfs_atomic_lookup, but failed to call 60 * nfs_open(). 61 */ 62 static void nfs4_evict_inode(struct inode *inode) 63 { 64 truncate_inode_pages_final(&inode->i_data); 65 clear_inode(inode); 66 /* If we are holding a delegation, return and free it */ 67 nfs_inode_evict_delegation(inode); 68 /* Note that above delegreturn would trigger pnfs return-on-close */ 69 pnfs_return_layout(inode); > 70 pnfs_destroy_layout_final(NFS_I(inode)); 71 /* First call standard NFS clear_inode() code */ 72 nfs_clear_inode(inode); 73 nfs4_xattr_cache_zap(inode); 74 } 75 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index 93f5c1678ec2..984cc42ee54d 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c @@ -67,7 +67,7 @@ static void nfs4_evict_inode(struct inode *inode) nfs_inode_evict_delegation(inode); /* Note that above delegreturn would trigger pnfs return-on-close */ pnfs_return_layout(inode); - pnfs_destroy_layout(NFS_I(inode)); + pnfs_destroy_layout_final(NFS_I(inode)); /* First call standard NFS clear_inode() code */ nfs_clear_inode(inode); nfs4_xattr_cache_zap(inode); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 0e50b9d45c32..b4cc2059a5ba 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -294,6 +294,7 @@ void pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) { struct inode *inode; + unsigned long i_state; if (!lo) return; @@ -304,8 +305,12 @@ pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo) if (!list_empty(&lo->plh_segs)) WARN_ONCE(1, "NFS: BUG unfreed layout segments.\n"); pnfs_detach_layout_hdr(lo); + i_state = inode->i_state; spin_unlock(&inode->i_lock); 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); } } @@ -734,8 +739,7 @@ pnfs_free_lseg_list(struct list_head *free_me) } } -void -pnfs_destroy_layout(struct nfs_inode *nfsi) +static struct pnfs_layout_hdr *__pnfs_destroy_layout(struct nfs_inode *nfsi) { struct pnfs_layout_hdr *lo; LIST_HEAD(tmp_list); @@ -753,9 +757,23 @@ pnfs_destroy_layout(struct nfs_inode *nfsi) pnfs_put_layout_hdr(lo); } else 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); +void pnfs_destroy_layout_final(struct nfs_inode *nfsi) +{ + struct pnfs_layout_hdr *lo = __pnfs_destroy_layout(nfsi); + + if (lo) + wait_var_event(lo, nfsi->layout != lo); +} + static bool pnfs_layout_add_bulk_destroy_list(struct inode *inode, struct list_head *layout_list) diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index f618c49697bb..ef19499e1e0f 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -268,6 +268,7 @@ struct pnfs_layout_segment *pnfs_layout_process(struct nfs4_layoutget *lgp); void pnfs_layoutget_free(struct nfs4_layoutget *lgp); void pnfs_free_lseg_list(struct list_head *tmp_list); void pnfs_destroy_layout(struct nfs_inode *); +void pnfs_destroy_layout_final(struct nfs_inode *); void pnfs_destroy_all_layouts(struct nfs_client *); int pnfs_destroy_layouts_byfsid(struct nfs_client *clp, struct nfs_fsid *fsid,