Skip to content

Commit

Permalink
Issue openzfs#4243 - Handling negative dentries in a CI file system.
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
RichardSharpe committed Jan 26, 2016
1 parent d93b45a commit 4ebdc05
Showing 1 changed file with 32 additions and 2 deletions.
34 changes: 32 additions & 2 deletions module/zfs/zpl_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <sys/dmu_objset.h>
#include <sys/vfs.h>
#include <sys/zpl.h>
#include <sys/file.h>


static struct dentry *
Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 4ebdc05

Please sign in to comment.