summaryrefslogtreecommitdiffstats
path: root/module/zfs
diff options
context:
space:
mode:
authorRichard Sharpe <[email protected]>2016-01-24 11:36:51 -0800
committerBrian Behlendorf <[email protected]>2016-03-22 17:54:07 -0700
commit82ff8810718b0e8fe840e070893c8cd5371853ad (patch)
tree3310d411a2a37d0eb2d42165e2f18e170fde7fa8 /module/zfs
parenta99c845fdcaa0ac41c44930fdb384a0a3244af68 (diff)
Handling negative dentries in a CI file system.
For a Case Insensitive file system we must avoid creating negative entries in the dentry cache. We must also pass the FIGNORECASE into zfs_lookup so that special files are handled correctly. We must also prevent negative dentries from being created when files are unlinked. Tested by running fsstress from LTP (10 loops, 10 processes, 10,000 ops.) Also tested with printks (now removed) to ensure that lookups come to zpl_lookup when negative should not exist. Tests: 1. ls Some-file.txt; touch some-file.txt; ls Some-file.txt and ensure no errors. 2. touch Some-file.txt; rm some-file.txt; ls Some-file.txt and ensure that the last ls shows log messages showing the lookup went all the way to zpl_lookup. Thanks to tuxoko for helping me get this correct. Signed-off-by: Richard Sharpe <[email protected]> Signed-off-by: Chunwei Chen <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #4243
Diffstat (limited to 'module/zfs')
-rw-r--r--module/zfs/zpl_inode.c34
1 files changed, 32 insertions, 2 deletions
diff --git a/module/zfs/zpl_inode.c b/module/zfs/zpl_inode.c
index c4233959b..cbdab7d30 100644
--- a/module/zfs/zpl_inode.c
+++ b/module/zfs/zpl_inode.c
@@ -31,6 +31,7 @@
#include <sys/dmu_objset.h>
#include <sys/vfs.h>
#include <sys/zpl.h>
+#include <sys/file.h>
static struct dentry *
@@ -46,6 +47,7 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
fstrans_cookie_t cookie;
pathname_t *ppn = NULL;
pathname_t pn;
+ int zfs_flags = 0;
zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
if (dlen(dentry) > ZFS_MAXNAMELEN)
@@ -56,12 +58,13 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
/* If we are a case insensitive fs, we need the real name */
if (zsb->z_case == ZFS_CASE_INSENSITIVE) {
+ zfs_flags = FIGNORECASE;
pn.pn_bufsize = ZFS_MAXNAMELEN;
pn.pn_buf = kmem_zalloc(ZFS_MAXNAMELEN, KM_SLEEP);
ppn = &pn;
}
- error = -zfs_lookup(dir, dname(dentry), &ip, 0, cr, NULL, ppn);
+ error = -zfs_lookup(dir, dname(dentry), &ip, zfs_flags, cr, NULL, ppn);
spl_fstrans_unmark(cookie);
ASSERT3S(error, <=, 0);
crfree(cr);
@@ -74,8 +77,17 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
spin_unlock(&dentry->d_lock);
if (error) {
- if (ppn)
+ /*
+ * If we have a case sensitive fs, we do not want to
+ * insert negative entries, so return NULL for ENOENT.
+ * Fall through if the error is not ENOENT. Also free memory.
+ */
+ if (ppn) {
kmem_free(pn.pn_buf, ZFS_MAXNAMELEN);
+ if (error == -ENOENT)
+ return (NULL);
+ }
+
if (error == -ENOENT)
return (d_splice_alias(NULL, dentry));
else
@@ -205,10 +217,19 @@ zpl_unlink(struct inode *dir, struct dentry *dentry)
cred_t *cr = CRED();
int error;
fstrans_cookie_t cookie;
+ zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
crhold(cr);
cookie = spl_fstrans_mark();
error = -zfs_remove(dir, dname(dentry), cr);
+
+ /*
+ * For a CI FS we must invalidate the dentry to prevent the
+ * creation of negative entries.
+ */
+ if (error == 0 && zsb->z_case == ZFS_CASE_INSENSITIVE)
+ d_invalidate(dentry);
+
spl_fstrans_unmark(cookie);
crfree(cr);
ASSERT3S(error, <=, 0);
@@ -256,10 +277,19 @@ zpl_rmdir(struct inode * dir, struct dentry *dentry)
cred_t *cr = CRED();
int error;
fstrans_cookie_t cookie;
+ zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
crhold(cr);
cookie = spl_fstrans_mark();
error = -zfs_rmdir(dir, dname(dentry), NULL, cr, 0);
+
+ /*
+ * For a CI FS we must invalidate the dentry to prevent the
+ * creation of negative entries.
+ */
+ if (error == 0 && zsb->z_case == ZFS_CASE_INSENSITIVE)
+ d_invalidate(dentry);
+
spl_fstrans_unmark(cookie);
crfree(cr);
ASSERT3S(error, <=, 0);