From 6ca8c0eec2f5ca6b6b33161c634f14d1bdfebc23 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 8 Sep 2021 14:56:46 -0700 Subject: [PATCH] Consistently initialize dentry info Unfortunately, we're back in kernels that don't yet have d_op->d_init. We allocate our dentry info manually as we're given dentries. The recent verification work forgot to consistently make sure the info was allocated before using it. Fix that up, and while we're at it be a bit more robust in how we check to see that it's been initialized without grabbing the d_lock. Signed-off-by: Zach Brown --- kmod/src/dir.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/kmod/src/dir.c b/kmod/src/dir.c index dc95c360..a1a58500 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -135,8 +135,8 @@ static int alloc_dentry_info(struct dentry *dentry) { struct dentry_info *di; - /* XXX read mb? */ - if (dentry->d_fsdata) + smp_rmb(); + if (dentry->d_op == &scoutfs_dentry_ops) return 0; di = kmem_cache_zalloc(dentry_info_cache, GFP_NOFS); @@ -148,6 +148,7 @@ static int alloc_dentry_info(struct dentry *dentry) spin_lock(&dentry->d_lock); if (!dentry->d_fsdata) { dentry->d_fsdata = di; + smp_wmb(); d_set_d_op(dentry, &scoutfs_dentry_ops); } spin_unlock(&dentry->d_lock); @@ -903,10 +904,6 @@ static int scoutfs_link(struct dentry *old_dentry, if (ret) return ret; - ret = verify_entry(sb, scoutfs_ino(dir), dentry, dir_lock); - if (ret < 0) - goto out_unlock; - if (inode->i_nlink >= SCOUTFS_LINK_MAX) { ret = -EMLINK; goto out_unlock; @@ -916,6 +913,10 @@ static int scoutfs_link(struct dentry *old_dentry, if (ret) goto out_unlock; + ret = verify_entry(sb, scoutfs_ino(dir), dentry, dir_lock); + if (ret < 0) + goto out_unlock; + dir_size = i_size_read(dir) + dentry->d_name.len; if (inode->i_nlink == 0) { @@ -1016,6 +1017,10 @@ static int scoutfs_unlink(struct inode *dir, struct dentry *dentry) if (ret) return ret; + ret = alloc_dentry_info(dentry); + if (ret) + goto unlock; + ret = verify_entry(sb, scoutfs_ino(dir), dentry, dir_lock); if (ret < 0) goto unlock; @@ -1676,7 +1681,9 @@ static int scoutfs_rename(struct inode *old_dir, struct dentry *old_dentry, } /* make sure that the entries assumed by the argument still exist */ - ret = verify_entry(sb, scoutfs_ino(old_dir), old_dentry, old_dir_lock) ?: + ret = alloc_dentry_info(old_dentry) ?: + alloc_dentry_info(new_dentry) ?: + verify_entry(sb, scoutfs_ino(old_dir), old_dentry, old_dir_lock) ?: verify_entry(sb, scoutfs_ino(new_dir), new_dentry, new_dir_lock); if (ret) goto out_unlock;