aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam D. Moss <[email protected]>2021-03-16 16:33:34 -0700
committerGitHub <[email protected]>2021-03-16 16:33:34 -0700
commit1daad98176d18a785d116d9666dadc866f631f98 (patch)
treead4a4bb806f02a98f3ceb3f6f7ada1639620689e
parent5f9d61d06b5a2df87d8d5733429cf4eba66f0acb (diff)
Linux: always check or verify return of igrab()
zhold() wraps igrab() on Linux, and igrab() may fail when the inode is in the process of being deleted. This means zhold() must only be called when a reference exists and therefore it cannot be deleted. This is the case for all existing consumers so add a VERIFY and a comment explaining this requirement. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Adam Moss <[email protected]> Closes #11704
-rw-r--r--include/os/linux/zfs/sys/zfs_znode_impl.h8
-rw-r--r--module/os/linux/zfs/zfs_ctldir.c3
-rw-r--r--module/os/linux/zfs/zfs_vfsops.c6
-rw-r--r--module/os/linux/zfs/zpl_inode.c3
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 b1b3aec4c..be211c5b5 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 a1668e46e..d33188f38 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 3cc4b560e..5d672af0e 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 e79d334ed..117963f44 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);