From fb3b7a385f1e39881455b8cb90a08c27b7739fde Mon Sep 17 00:00:00 2001 From: Adam Moss Date: Sun, 7 Mar 2021 13:10:42 -0700 Subject: [PATCH] Linux: always check or verify return of igrab() Signed-off-by: Adam Moss --- include/os/linux/zfs/sys/zfs_znode_impl.h | 8 +++++++- module/os/linux/zfs/zfs_ctldir.c | 3 ++- module/os/linux/zfs/zfs_vfsops.c | 6 +++++- module/os/linux/zfs/zpl_inode.c | 3 ++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/os/linux/zfs/sys/zfs_znode_impl.h b/include/os/linux/zfs/sys/zfs_znode_impl.h index b1a91f6667a6..f89f0976dea6 100644 --- a/include/os/linux/zfs/sys/zfs_znode_impl.h +++ b/include/os/linux/zfs/sys/zfs_znode_impl.h @@ -73,7 +73,13 @@ extern "C" { #define zn_has_cached_data(zp) ((zp)->z_is_mapped) #define zn_rlimit_fsize(zp, uio) (0) -#define zhold(zp) igrab(ZTOI((zp))) +/* + * zhold() wraps igrab() on Linux, and igrab() may fail when the + * inode is in the process of being deleted. As zhold() must only be + * called when a ref already exists - so the inode cannot be + * mid-deletion - we VERIFY() this. + */ +#define zhold(zp) VERIFY3P(igrab(ZTOI((zp))), !=, NULL) #define zrele(zp) iput(ZTOI((zp))) /* Called on entry to each ZFS inode and vfs operation. */ diff --git a/module/os/linux/zfs/zfs_ctldir.c b/module/os/linux/zfs/zfs_ctldir.c index a1668e46e4f9..d33188f3822c 100644 --- a/module/os/linux/zfs/zfs_ctldir.c +++ b/module/os/linux/zfs/zfs_ctldir.c @@ -590,7 +590,8 @@ struct inode * zfsctl_root(znode_t *zp) { ASSERT(zfs_has_ctldir(zp)); - igrab(ZTOZSB(zp)->z_ctldir); + /* Must have an existing ref, so igrab() cannot return NULL */ + VERIFY3P(igrab(ZTOZSB(zp)->z_ctldir), !=, NULL); return (ZTOZSB(zp)->z_ctldir); } diff --git a/module/os/linux/zfs/zfs_vfsops.c b/module/os/linux/zfs/zfs_vfsops.c index cc77bd451125..bf329c9495c9 100644 --- a/module/os/linux/zfs/zfs_vfsops.c +++ b/module/os/linux/zfs/zfs_vfsops.c @@ -1734,7 +1734,11 @@ zfs_vget(struct super_block *sb, struct inode **ipp, fid_t *fidp) VERIFY(zfsctl_root_lookup(*ipp, "snapshot", ipp, 0, kcred, NULL, NULL) == 0); } else { - igrab(*ipp); + /* + * Must have an existing ref, so igrab() + * cannot return NULL + */ + VERIFY3P(igrab(*ipp), !=, NULL); } ZFS_EXIT(zfsvfs); return (0); diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index e79d334edc9b..117963f44af3 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -593,7 +593,8 @@ zpl_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) crhold(cr); ip->i_ctime = current_time(ip); - igrab(ip); /* Use ihold() if available */ + /* Must have an existing ref, so igrab() cannot return NULL */ + VERIFY3P(igrab(ip), !=, NULL); cookie = spl_fstrans_mark(); error = -zfs_link(ITOZ(dir), ITOZ(ip), dname(dentry), cr, 0);