@@ -761,8 +761,15 @@ static inline int d_revalidate(struct dentry *dentry, unsigned int flags)
{
if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE))
return dentry->d_op->d_revalidate(dentry, flags);
- else
- return 1;
+
+ /* Completely ignore negative dentries
+ for LOOKUP_CASEFOLD. */
+ if (unlikely(flags & LOOKUP_CASEFOLD)) {
+ if (d_is_negative(dentry))
+ return 0;
+ }
+
+ return 1;
}
/**
@@ -1159,6 +1166,15 @@ static int follow_automount(struct path *path, struct nameidata *nd,
}
+static void set_casefold_lookup(struct nameidata *nd, struct path *path)
+{
+ if (path && path->mnt &&
+ path->mnt->mnt_flags & MNT_CASEFOLD)
+ nd->flags |= LOOKUP_CASEFOLD;
+ else
+ nd->flags &= ~LOOKUP_CASEFOLD;
+}
+
/*
* Handle a dentry that is managed in some way.
* - Flagged for transit management (autofs)
@@ -1202,6 +1218,7 @@ static int follow_managed(struct path *path, struct nameidata *nd)
path->mnt = mounted;
path->dentry = dget(mounted->mnt_root);
need_mntput = true;
+ set_casefold_lookup(nd, path);
continue;
}
@@ -1288,6 +1305,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
path->mnt = &mounted->mnt;
path->dentry = mounted->mnt.mnt_root;
nd->flags |= LOOKUP_JUMPED;
+ set_casefold_lookup(nd, path);
*seqp = read_seqcount_begin(&path->dentry->d_seq);
/*
* Update the inode too. We don't need to re-check the
@@ -1336,6 +1354,7 @@ static int follow_dotdot_rcu(struct nameidata *nd)
nd->path.mnt = &mparent->mnt;
inode = inode2;
nd->seq = seq;
+ set_casefold_lookup(nd, &nd->path);
}
}
while (unlikely(d_mountpoint(nd->path.dentry))) {
@@ -1350,6 +1369,7 @@ static int follow_dotdot_rcu(struct nameidata *nd)
inode = nd->path.dentry->d_inode;
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
}
+ set_casefold_lookup(nd, &nd->path);
nd->inode = inode;
return 0;
}
@@ -2143,6 +2163,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
} else {
path_get(&nd->path);
}
+ set_casefold_lookup(nd, &nd->path);
return s;
}
@@ -2177,6 +2198,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
get_fs_pwd(current->fs, &nd->path);
nd->inode = nd->path.dentry->d_inode;
}
+ set_casefold_lookup(nd, &nd->path);
return s;
} else {
/* Caller must check execute permissions on the starting path component */
@@ -2205,6 +2227,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
nd->inode = nd->path.dentry->d_inode;
}
fdput(f);
+ set_casefold_lookup(nd, &nd->path);
return s;
}
}
@@ -2509,6 +2509,12 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
if (!type)
return -ENODEV;
+ if (mnt_flags & MNT_CASEFOLD &&
+ !(type->fs_flags & FS_HAS_CASEFOLD)) {
+ put_filesystem(type);
+ return -EINVAL;
+ }
+
mnt = vfs_kern_mount(type, sb_flags, name, data);
if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
!mnt->mnt_sb->s_subtype)
@@ -2809,6 +2815,8 @@ long do_mount(const char *dev_name, const char __user *dir_name,
mnt_flags |= MNT_NODIRATIME;
if (flags & MS_STRICTATIME)
mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
+ if (flags & MS_CASEFOLD)
+ mnt_flags |= MNT_CASEFOLD;
if (flags & SB_RDONLY)
mnt_flags |= MNT_READONLY;
@@ -2827,7 +2835,8 @@ long do_mount(const char *dev_name, const char __user *dir_name,
SB_SILENT |
SB_POSIXACL |
SB_LAZYTIME |
- SB_I_VERSION);
+ SB_I_VERSION |
+ SB_CASEFOLD);
if (flags & MS_REMOUNT)
retval = do_remount(&path, flags, sb_flags, mnt_flags,
@@ -1287,6 +1287,7 @@ extern int send_sigurg(struct fown_struct *fown);
#define SB_SYNCHRONOUS 16 /* Writes are synced at once */
#define SB_MANDLOCK 64 /* Allow mandatory locks on an FS */
#define SB_DIRSYNC 128 /* Directory modifications are synchronous */
+#define SB_CASEFOLD 256 /* Directory lookups are case-insensitive */
#define SB_NOATIME 1024 /* Do not update access times. */
#define SB_NODIRATIME 2048 /* Do not update directory access times */
#define SB_SILENT 32768
@@ -2069,6 +2070,7 @@ struct file_system_type {
#define FS_BINARY_MOUNTDATA 2
#define FS_HAS_SUBTYPE 4
#define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */
+#define FS_HAS_CASEFOLD 16
#define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */
struct dentry *(*mount) (struct file_system_type *, int,
const char *, void *);
@@ -52,6 +52,7 @@ struct mnt_namespace;
MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED)
#define MNT_INTERNAL 0x4000
+#define MNT_CASEFOLD 0x8000
#define MNT_LOCK_ATIME 0x040000
#define MNT_LOCK_NOEXEC 0x080000
@@ -46,6 +46,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_ROOT 0x2000
#define LOOKUP_EMPTY 0x4000
#define LOOKUP_DOWN 0x8000
+#define LOOKUP_CASEFOLD 0x010000
extern int path_pts(struct path *path);
@@ -113,6 +113,7 @@ struct inodes_stat_t {
#define MS_REMOUNT 32 /* Alter flags of a mounted FS */
#define MS_MANDLOCK 64 /* Allow mandatory locks on an FS */
#define MS_DIRSYNC 128 /* Directory modifications are synchronous */
+#define MS_CASEFOLD 256 /* Directory lookups are case-insensitive */
#define MS_NOATIME 1024 /* Do not update access times. */
#define MS_NODIRATIME 2048 /* Do not update directory access times */
#define MS_BIND 4096
At this point, negative dentries are ignored for LOOKUP_CASEFOLD. This will be addressed later in the series. Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk> --- fs/namei.c | 27 +++++++++++++++++++++++++-- fs/namespace.c | 11 ++++++++++- include/linux/fs.h | 2 ++ include/linux/mount.h | 1 + include/linux/namei.h | 1 + include/uapi/linux/fs.h | 1 + 6 files changed, 40 insertions(+), 3 deletions(-)