* [PATCH NOMERGE 01/13] vfs: Add support for mounting with MS_CASEFOLD
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 02/13] vfs: Propagate LOOKUP_CASEFOLD after doing parent lookups Gabriel Krisman Bertazi
` (11 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
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(-)
diff --git a/fs/namei.c b/fs/namei.c
index 921ae32dbc80..ddd5c9e9ab3c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -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;
}
}
diff --git a/fs/namespace.c b/fs/namespace.c
index 9d1374ab6e06..0053e29b73cc 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -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,
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2a815560fda0..743d38876a51 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -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 *);
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 45b1f56c6c2f..05f5d6f71108 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -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
diff --git a/include/linux/namei.h b/include/linux/namei.h
index a982bb7cd480..fb74ab4c86f3 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -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);
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index d2a8313fabd7..7fa23e5f49d6 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -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
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 02/13] vfs: Propagate LOOKUP_CASEFOLD after doing parent lookups
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 01/13] vfs: Add support for mounting with MS_CASEFOLD Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 03/13] vfs: Add support for positive dentries CI lookups in the dentry cache Gabriel Krisman Bertazi
` (10 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
filename_parentat() is executed in order to quickly access a child
dentry for creation, unlinking or rename, outside the path_walk path.
Although, if the parent was accessed via a CI mount, we need to make
sure the child will also be searched in a CI manner, so the nameidata
flag from the first search needs to be propageted to the following child
__lookup_hash call.
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
fs/namei.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 54 insertions(+), 7 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index ddd5c9e9ab3c..135a9a4e676b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2369,7 +2369,7 @@ static int path_parentat(struct nameidata *nd, unsigned flags,
static struct filename *filename_parentat(int dfd, struct filename *name,
unsigned int flags, struct path *parent,
- struct qstr *last, int *type)
+ struct qstr *last, int *type, bool *foldtree)
{
int retval;
struct nameidata nd;
@@ -2385,6 +2385,7 @@ static struct filename *filename_parentat(int dfd, struct filename *name,
if (likely(!retval)) {
*last = nd.last;
*type = nd.last_type;
+ *foldtree = !!(nd.flags & LOOKUP_CASEFOLD);
audit_inode(name, parent->dentry, LOOKUP_PARENT);
} else {
putname(name);
@@ -2401,9 +2402,14 @@ struct dentry *kern_path_locked(const char *name, struct path *path)
struct dentry *d;
struct qstr last;
int type;
+ bool foldtree = false;
filename = filename_parentat(AT_FDCWD, getname_kernel(name), 0, path,
- &last, &type);
+ &last, &type, &foldtree);
+
+ /* kernel path don't care about foldtree. Root cannot be folded. */
+ WARN_ON(foldtree);
+
if (IS_ERR(filename))
return ERR_CAST(filename);
if (unlikely(type != LAST_NORM)) {
@@ -3620,6 +3626,7 @@ static struct dentry *filename_create(int dfd, struct filename *name,
int err2;
int error;
bool is_dir = (lookup_flags & LOOKUP_DIRECTORY);
+ bool foldtree = false;
/*
* Note that only LOOKUP_REVAL and LOOKUP_DIRECTORY matter here. Any
@@ -3627,7 +3634,8 @@ static struct dentry *filename_create(int dfd, struct filename *name,
*/
lookup_flags &= LOOKUP_REVAL;
- name = filename_parentat(dfd, name, lookup_flags, path, &last, &type);
+ name = filename_parentat(dfd, name, lookup_flags, path, &last,
+ &type, &foldtree);
if (IS_ERR(name))
return ERR_CAST(name);
@@ -3644,6 +3652,16 @@ static struct dentry *filename_create(int dfd, struct filename *name,
* Do the final lookup.
*/
lookup_flags |= LOOKUP_CREATE | LOOKUP_EXCL;
+
+ /* If parent is a casefold mountpoint, search for an existing
+ * dentry with LOOKUP_CASEFOLD.
+ * LOOKUP_CASEFOLD needs to be explicitly cleared in case it is
+ * doing retry. */
+ if (foldtree)
+ lookup_flags |= LOOKUP_CASEFOLD;
+ else
+ lookup_flags &= ~LOOKUP_CASEFOLD;
+
inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT);
dentry = __lookup_hash(&last, path->dentry, lookup_flags);
if (IS_ERR(dentry))
@@ -3904,9 +3922,10 @@ static long do_rmdir(int dfd, const char __user *pathname)
struct qstr last;
int type;
unsigned int lookup_flags = 0;
+ bool foldtree;
retry:
name = filename_parentat(dfd, getname(pathname), lookup_flags,
- &path, &last, &type);
+ &path, &last, &type, &foldtree);
if (IS_ERR(name))
return PTR_ERR(name);
@@ -3926,6 +3945,13 @@ static long do_rmdir(int dfd, const char __user *pathname)
if (error)
goto exit1;
+ /* LOOKUP_CASEFOLD needs to be explicitly cleared in case it is
+ * doing retry. */
+ if (foldtree)
+ lookup_flags |= LOOKUP_CASEFOLD;
+ else
+ lookup_flags &= ~LOOKUP_CASEFOLD;
+
inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT);
dentry = __lookup_hash(&last, path.dentry, lookup_flags);
error = PTR_ERR(dentry);
@@ -4033,8 +4059,10 @@ long do_unlinkat(int dfd, struct filename *name)
struct inode *inode = NULL;
struct inode *delegated_inode = NULL;
unsigned int lookup_flags = 0;
+ bool foldtree = false;
retry:
- name = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
+ name = filename_parentat(dfd, name, lookup_flags, &path, &last, &type,
+ &foldtree);
if (IS_ERR(name))
return PTR_ERR(name);
@@ -4045,6 +4073,13 @@ long do_unlinkat(int dfd, struct filename *name)
error = mnt_want_write(path.mnt);
if (error)
goto exit1;
+
+ /* LOOKUP_CASEFOLD needs to be explicitly cleared in case it is
+ * doing retry. */
+ if (foldtree)
+ lookup_flags |= LOOKUP_CASEFOLD;
+ else
+ lookup_flags &= ~LOOKUP_CASEFOLD;
retry_deleg:
inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT);
dentry = __lookup_hash(&last, path.dentry, lookup_flags);
@@ -4514,6 +4549,7 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
struct filename *to;
unsigned int lookup_flags = 0, target_flags = LOOKUP_RENAME_TARGET;
bool should_retry = false;
+ bool foldtree = false;
int error;
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
@@ -4531,14 +4567,14 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
retry:
from = filename_parentat(olddfd, getname(oldname), lookup_flags,
- &old_path, &old_last, &old_type);
+ &old_path, &old_last, &old_type, &foldtree);
if (IS_ERR(from)) {
error = PTR_ERR(from);
goto exit;
}
to = filename_parentat(newdfd, getname(newname), lookup_flags,
- &new_path, &new_last, &new_type);
+ &new_path, &new_last, &new_type, &foldtree);
if (IS_ERR(to)) {
error = PTR_ERR(to);
goto exit1;
@@ -4561,6 +4597,17 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
if (error)
goto exit2;
+ /* Since rename(2) doesn't work across mountpoints, we are sure
+ * that foldtree for TO and FROM are the same.
+ *
+ * LOOKUP_CASEFOLD needs to be explicitly cleared in case it is
+ * doing retry. */
+ if (foldtree)
+ lookup_flags |= LOOKUP_CASEFOLD;
+ else
+ lookup_flags &= ~LOOKUP_CASEFOLD;
+
+
retry_deleg:
trap = lock_rename(new_path.dentry, old_path.dentry);
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 03/13] vfs: Add support for positive dentries CI lookups in the dentry cache
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 01/13] vfs: Add support for mounting with MS_CASEFOLD Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 02/13] vfs: Propagate LOOKUP_CASEFOLD after doing parent lookups Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 04/13] vfs: Allow bind,remount with MS_CASEFOLD Gabriel Krisman Bertazi
` (9 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
Negative dentries are still invalidated, triggering a lookup in the
disk.
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
fs/dcache.c | 43 +++++++++++++++++++++++++++++++++---------
fs/namei.c | 5 +++--
include/linux/dcache.h | 8 ++++++--
3 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 7c38f39958bc..4bd28d7caa53 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2049,6 +2049,16 @@ struct dentry *d_obtain_root(struct inode *inode)
}
EXPORT_SYMBOL(d_obtain_root);
+static inline bool d_same_name_ci(const struct dentry *dentry,
+ const struct dentry *parent,
+ const struct qstr *name)
+{
+ return parent->d_op->d_compare_ci(dentry,
+ dentry->d_name.len,
+ dentry->d_name.name,
+ name) == 0;
+}
+
/**
* d_add_ci - lookup or allocate new dentry with case-exact name
* @inode: the inode case-insensitive lookup has found
@@ -2122,6 +2132,7 @@ static inline bool d_same_name(const struct dentry *dentry,
* @parent: parent dentry
* @name: qstr of name we wish to find
* @seqp: returns d_seq value at the point where the dentry was found
+ * @ci_lookup: Whether d_lookup_rcu should do a CI lookup
* Returns: dentry, or NULL
*
* __d_lookup_rcu is the dcache lookup function for rcu-walk name
@@ -2148,7 +2159,7 @@ static inline bool d_same_name(const struct dentry *dentry,
*/
struct dentry *__d_lookup_rcu(const struct dentry *parent,
const struct qstr *name,
- unsigned *seqp)
+ unsigned *seqp, int ci_lookup)
{
u64 hashlen = name->hash_len;
const unsigned char *str = name->name;
@@ -2215,9 +2226,16 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
cpu_relax();
goto seqretry;
}
- if (parent->d_op->d_compare(dentry,
- tlen, tname, name) != 0)
- continue;
+
+ if (ci_lookup) {
+ if (parent->d_op->d_compare_ci(dentry, tlen,
+ tname, name) != 0)
+ continue;
+ } else {
+ if (parent->d_op->d_compare(dentry, tlen,
+ tname, name) != 0)
+ continue;
+ }
} else {
if (dentry->d_name.hash_len != hashlen)
continue;
@@ -2248,7 +2266,7 @@ struct dentry *d_lookup(const struct dentry *parent, const struct qstr *name)
do {
seq = read_seqbegin(&rename_lock);
- dentry = __d_lookup(parent, name);
+ dentry = __d_lookup(parent, name, 0);
if (dentry)
break;
} while (read_seqretry(&rename_lock, seq));
@@ -2260,6 +2278,7 @@ EXPORT_SYMBOL(d_lookup);
* __d_lookup - search for a dentry (racy)
* @parent: parent dentry
* @name: qstr of name we wish to find
+ * @ci_lookup: Whether d_lookup_rcu should do a CI lookup
* Returns: dentry, or NULL
*
* __d_lookup is like d_lookup, however it may (rarely) return a
@@ -2271,7 +2290,8 @@ EXPORT_SYMBOL(d_lookup);
*
* __d_lookup callers must be commented.
*/
-struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
+struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name,
+ int ci_lookup)
{
unsigned int hash = name->hash;
struct hlist_bl_head *b = d_hash(hash);
@@ -2312,8 +2332,13 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
if (d_unhashed(dentry))
goto next;
- if (!d_same_name(dentry, parent, name))
- goto next;
+ if (ci_lookup) {
+ if (!d_same_name_ci(dentry, parent, name))
+ goto next;
+ } else {
+ if (!d_same_name(dentry, parent, name))
+ goto next;
+ }
dentry->d_lockref.count++;
found = dentry;
@@ -2476,7 +2501,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
rcu_read_lock();
seq = smp_load_acquire(&parent->d_inode->i_dir_seq) & ~1;
r_seq = read_seqbegin(&rename_lock);
- dentry = __d_lookup_rcu(parent, name, &d_seq);
+ dentry = __d_lookup_rcu(parent, name, &d_seq, 0);
if (unlikely(dentry)) {
if (!lockref_get_not_dead(&dentry->d_lockref)) {
rcu_read_unlock();
diff --git a/fs/namei.c b/fs/namei.c
index 135a9a4e676b..1ebe5e775a9a 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1540,6 +1540,7 @@ static int lookup_fast(struct nameidata *nd,
struct dentry *dentry, *parent = nd->path.dentry;
int status = 1;
int err;
+ int ci_lookup = (nd->flags & LOOKUP_CASEFOLD);
/*
* Rename seqlock is not required here because in the off chance
@@ -1549,7 +1550,7 @@ static int lookup_fast(struct nameidata *nd,
if (nd->flags & LOOKUP_RCU) {
unsigned seq;
bool negative;
- dentry = __d_lookup_rcu(parent, &nd->last, &seq);
+ dentry = __d_lookup_rcu(parent, &nd->last, &seq, ci_lookup);
if (unlikely(!dentry)) {
if (unlazy_walk(nd))
return -ECHILD;
@@ -1595,7 +1596,7 @@ static int lookup_fast(struct nameidata *nd,
/* we'd been told to redo it in non-rcu mode */
status = d_revalidate(dentry, nd->flags);
} else {
- dentry = __d_lookup(parent, &nd->last);
+ dentry = __d_lookup(parent, &nd->last, ci_lookup);
if (unlikely(!dentry))
return 0;
status = d_revalidate(dentry, nd->flags);
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 82a99d366aec..a4ce5ea207ad 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -139,6 +139,8 @@ struct dentry_operations {
int (*d_hash)(const struct dentry *, struct qstr *);
int (*d_compare)(const struct dentry *,
unsigned int, const char *, const struct qstr *);
+ int (*d_compare_ci)(const struct dentry *,
+ unsigned int, const char *, const struct qstr *);
int (*d_delete)(const struct dentry *);
int (*d_init)(struct dentry *);
void (*d_release)(struct dentry *);
@@ -282,9 +284,11 @@ extern struct dentry *d_ancestor(struct dentry *, struct dentry *);
/* appendix may either be NULL or be used for transname suffixes */
extern struct dentry *d_lookup(const struct dentry *, const struct qstr *);
extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
-extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *);
+extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *,
+ int ci_lookup);
extern struct dentry *__d_lookup_rcu(const struct dentry *parent,
- const struct qstr *name, unsigned *seq);
+ const struct qstr *name, unsigned *seq,
+ int ci_lookup);
static inline unsigned d_count(const struct dentry *dentry)
{
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 04/13] vfs: Allow bind,remount with MS_CASEFOLD
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
` (2 preceding siblings ...)
2018-05-22 20:38 ` [PATCH NOMERGE 03/13] vfs: Add support for positive dentries CI lookups in the dentry cache Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 05/13] vfs: Handle case-exact lookup in d_add_ci Gabriel Krisman Bertazi
` (8 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
fs/namespace.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/fs/namespace.c b/fs/namespace.c
index 0053e29b73cc..127d3028c1e8 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2261,17 +2261,28 @@ static int do_loopback(struct path *path, const char *old_name,
static int change_mount_flags(struct vfsmount *mnt, int ms_flags)
{
int error = 0;
- int readonly_request = 0;
+ int readonly_request = 0, casefold_request = 0;
if (ms_flags & MS_RDONLY)
readonly_request = 1;
- if (readonly_request == __mnt_is_readonly(mnt))
- return 0;
+ if (ms_flags & MS_CASEFOLD)
+ casefold_request = 1;
+
+ if (readonly_request != __mnt_is_readonly(mnt)) {
+ if (readonly_request)
+ error = mnt_make_readonly(real_mount(mnt));
+ else
+ __mnt_unmake_readonly(real_mount(mnt));
+ if (error)
+ goto out;
+ }
- if (readonly_request)
- error = mnt_make_readonly(real_mount(mnt));
+ if (casefold_request)
+ mnt->mnt_flags |= MNT_CASEFOLD;
else
- __mnt_unmake_readonly(real_mount(mnt));
+ mnt->mnt_flags &= ~MNT_CASEFOLD;
+
+out:
return error;
}
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 05/13] vfs: Handle case-exact lookup in d_add_ci
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
` (3 preceding siblings ...)
2018-05-22 20:38 ` [PATCH NOMERGE 04/13] vfs: Allow bind,remount with MS_CASEFOLD Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 06/13] vfs: Add Support for hard negative dentries in the dcache Gabriel Krisman Bertazi
` (7 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
This prevents a soft hang if called d_add_ci is called from the FS
layer, when doing a CI search but the result dentry is the exact match.
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
fs/dcache.c | 33 ++++++++++++++++++---------------
1 file changed, 18 insertions(+), 15 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 4bd28d7caa53..30c5eff31e88 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -2049,6 +2049,20 @@ struct dentry *d_obtain_root(struct inode *inode)
}
EXPORT_SYMBOL(d_obtain_root);
+static inline bool d_same_name(const struct dentry *dentry,
+ const struct dentry *parent,
+ const struct qstr *name)
+{
+ if (likely(!(parent->d_flags & DCACHE_OP_COMPARE))) {
+ if (dentry->d_name.len != name->len)
+ return false;
+ return dentry_cmp(dentry, name->name, name->len) == 0;
+ }
+ return parent->d_op->d_compare(dentry,
+ dentry->d_name.len, dentry->d_name.name,
+ name) == 0;
+}
+
static inline bool d_same_name_ci(const struct dentry *dentry,
const struct dentry *parent,
const struct qstr *name)
@@ -2080,6 +2094,10 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
{
struct dentry *found, *res;
+ /* Trivial case: CI search is exact match. */
+ if (d_same_name(dentry, dentry->d_parent, name))
+ return d_splice_alias(inode, dentry);
+
/*
* First check if a dentry matching the name already exists,
* if not go ahead and create it now.
@@ -2112,21 +2130,6 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
}
EXPORT_SYMBOL(d_add_ci);
-
-static inline bool d_same_name(const struct dentry *dentry,
- const struct dentry *parent,
- const struct qstr *name)
-{
- if (likely(!(parent->d_flags & DCACHE_OP_COMPARE))) {
- if (dentry->d_name.len != name->len)
- return false;
- return dentry_cmp(dentry, name->name, name->len) == 0;
- }
- return parent->d_op->d_compare(dentry,
- dentry->d_name.len, dentry->d_name.name,
- name) == 0;
-}
-
/**
* __d_lookup_rcu - search for a dentry (racy, store-free)
* @parent: parent dentry
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 06/13] vfs: Add Support for hard negative dentries in the dcache
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
` (4 preceding siblings ...)
2018-05-22 20:38 ` [PATCH NOMERGE 05/13] vfs: Handle case-exact lookup in d_add_ci Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 07/13] vfs: Handle MNT_CASEFOLD in /proc/mounts Gabriel Krisman Bertazi
` (6 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
A hard negative dentry is created after an unsuccessful
case-insensitive(CI) lookup operation, to indicate that there is not any
file in that directory whose casefolded name matches the casefolded
searched name.
Hard negative dentries are the CI counterpart of the existing negative
dentries for the case-isensitive lookup case. For clarity, this patch
denotes the old negative dentry as "soft negative dentry" where
applicable. In places where it doesn't matter whether it is a hard or
soft dentry, the wrapper d_is_negative() can still be used.
Despite being the counterpart of soft negative dentries, a hard dentry
actually express a much stronger constraint, asserting that there is no
name in the filesystem that would match the string being searched, AFTER
a casefold() operation. A hard negative dentry allows the dcache to
return a -ENOENT immediately during a dcache lookup , eliminating the
need to go to the disk for every CI operation. The hard negative dentry
definition also encloses the soft dentry constraint, such that we can
also use a hard negative dentry to return ENOENT after a Case
sensitive(CS) lookup.
Special care must be taken to invalidate (or at least demote) Hard
dentries once a matching file is created in the disk. The file being
created might not have the exact name as the hard dentry (but it must
have an exact casefold match), but this still means the dentry must be
invalidated. This is handled by invalidating the dentry found in
lookup_open, only if it is a hard negative. Unless we are doing a
creation, there is no need to invalidate it elsewhere.
Soft dentries could be promoted to hard dentries after a LOOKUP_CASEFOLD
operation, but for simplifying the code, we don't do the promotion
explicitly, instead we invalidate the soft dentry and recreate it during
the following lookup as a hard dentry. Likewise, hard dentries could be
demoted when a inexact-case match is created. For this case, the
current code also invalidates the dentry and creates a new one.
Filesystems who want to expose CI operations must make sure their
revalidate() functions no longer reject any type of negative dentries,
they can only reject soft negatives. If they do reject negative
dentries, say in the transition phase, there is no problem, they will be
basically ignoring this feature and paying the cost to hit the disk
everytime.
A function called d_add_ci_negative_dentry is also added in this series,
as a helper for user filesystems, when they hit an inexisting file
during a LOOKUP_CASEFOLD operation. An example of usage comes later in
the series, with the patches that add LOOKUP_CASEFOLD support for the
EXT4 filesystem.
This patch reduces the time of doing an inexact-name lookup of 10k
inexistant but already dcached files, down to 0.007 seconds in my test
vm, which is pretty similar to issuing the same operation to a CS
filesystem without this patch series.
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
fs/dcache.c | 29 +++++++++++++++++++++--------
fs/namei.c | 7 +++++--
include/linux/dcache.h | 16 ++++++++++++++--
3 files changed, 40 insertions(+), 12 deletions(-)
diff --git a/fs/dcache.c b/fs/dcache.c
index 30c5eff31e88..a68af63c8a96 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1784,12 +1784,17 @@ void d_set_fallthru(struct dentry *dentry)
}
EXPORT_SYMBOL(d_set_fallthru);
-static unsigned d_flags_for_inode(struct inode *inode)
+static unsigned d_flags_for_inode(struct dentry *dentry, struct inode *inode)
{
unsigned add_flags = DCACHE_REGULAR_TYPE;
- if (!inode)
- return DCACHE_MISS_TYPE;
+ if (!inode) {
+ /* hard negative dentries get set beforehand. */
+ if (d_is_hard_negative(dentry))
+ return DCACHE_HARD_NEGATIVE_TYPE;
+ else
+ return DCACHE_MISS_TYPE;
+ }
if (S_ISDIR(inode->i_mode)) {
add_flags = DCACHE_DIRECTORY_TYPE;
@@ -1821,7 +1826,7 @@ static unsigned d_flags_for_inode(struct inode *inode)
static void __d_instantiate(struct dentry *dentry, struct inode *inode)
{
- unsigned add_flags = d_flags_for_inode(inode);
+ unsigned add_flags = d_flags_for_inode(dentry, inode);
WARN_ON(d_in_lookup(dentry));
spin_lock(&dentry->d_lock);
@@ -1948,7 +1953,7 @@ static struct dentry *__d_instantiate_anon(struct dentry *dentry,
}
/* attach a disconnected dentry */
- add_flags = d_flags_for_inode(inode);
+ add_flags = d_flags_for_inode(dentry, inode);
if (disconnected)
add_flags |= DCACHE_DISCONNECTED;
@@ -2130,6 +2135,14 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
}
EXPORT_SYMBOL(d_add_ci);
+struct dentry *d_add_ci_negative_dentry(struct dentry *dentry)
+{
+ /* Mark the dentry as hard negative. */
+ dentry->d_flags |= DCACHE_HARD_NEGATIVE_TYPE;
+
+ return d_splice_alias(NULL, dentry);
+}
+
/**
* __d_lookup_rcu - search for a dentry (racy, store-free)
* @parent: parent dentry
@@ -2230,7 +2243,7 @@ struct dentry *__d_lookup_rcu(const struct dentry *parent,
goto seqretry;
}
- if (ci_lookup) {
+ if (ci_lookup || d_is_hard_negative(dentry)) {
if (parent->d_op->d_compare_ci(dentry, tlen,
tname, name) != 0)
continue;
@@ -2335,7 +2348,7 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name,
if (d_unhashed(dentry))
goto next;
- if (ci_lookup) {
+ if (ci_lookup || d_is_hard_negative(dentry)) {
if (!d_same_name_ci(dentry, parent, name))
goto next;
} else {
@@ -2618,7 +2631,7 @@ static inline void __d_add(struct dentry *dentry, struct inode *inode)
__d_lookup_done(dentry);
}
if (inode) {
- unsigned add_flags = d_flags_for_inode(inode);
+ unsigned add_flags = d_flags_for_inode(dentry, inode);
hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
raw_write_seqcount_begin(&dentry->d_seq);
__d_set_inode_and_type(dentry, inode, add_flags);
diff --git a/fs/namei.c b/fs/namei.c
index 1ebe5e775a9a..69726d2f6f81 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -765,7 +765,7 @@ static inline int d_revalidate(struct dentry *dentry, unsigned int flags)
/* Completely ignore negative dentries
for LOOKUP_CASEFOLD. */
if (unlikely(flags & LOOKUP_CASEFOLD)) {
- if (d_is_negative(dentry))
+ if (d_is_soft_negative(dentry))
return 0;
}
@@ -3142,7 +3142,9 @@ static int lookup_open(struct nameidata *nd, struct path *path,
dentry = d_alloc_parallel(dir, &nd->last, &wq);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
- }
+ } else if (d_is_hard_negative(dentry))
+ goto invalidate;
+
if (d_in_lookup(dentry))
break;
@@ -3151,6 +3153,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
break;
if (error)
goto out_dput;
+invalidate:
d_invalidate(dentry);
dput(dentry);
dentry = NULL;
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index a4ce5ea207ad..f215bcc2f60b 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -206,13 +206,14 @@ struct dentry_operations {
#define DCACHE_LRU_LIST 0x00080000
#define DCACHE_ENTRY_TYPE 0x00700000
-#define DCACHE_MISS_TYPE 0x00000000 /* Negative dentry (maybe fallthru to nowhere) */
+#define DCACHE_MISS_TYPE 0x00000000 /* Soft negative dentry (maybe fallthru to nowhere) */
#define DCACHE_WHITEOUT_TYPE 0x00100000 /* Whiteout dentry (stop pathwalk) */
#define DCACHE_DIRECTORY_TYPE 0x00200000 /* Normal directory */
#define DCACHE_AUTODIR_TYPE 0x00300000 /* Lookupless directory (presumed automount) */
#define DCACHE_REGULAR_TYPE 0x00400000 /* Regular file type (or fallthru to such) */
#define DCACHE_SPECIAL_TYPE 0x00500000 /* Other file type (or fallthru to such) */
#define DCACHE_SYMLINK_TYPE 0x00600000 /* Symlink (or fallthru to such) */
+#define DCACHE_HARD_NEGATIVE_TYPE 0x00700000 /* Hard negative dentry */
#define DCACHE_MAY_FREE 0x00800000
#define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */
@@ -244,6 +245,7 @@ extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *,
wait_queue_head_t *);
extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *);
+extern struct dentry * d_add_ci_negative_dentry(struct dentry *);
extern struct dentry * d_exact_alias(struct dentry *, struct inode *);
extern struct dentry *d_find_any_alias(struct inode *inode);
extern struct dentry * d_obtain_alias(struct inode *);
@@ -444,12 +446,22 @@ static inline bool d_is_file(const struct dentry *dentry)
return d_is_reg(dentry) || d_is_special(dentry);
}
-static inline bool d_is_negative(const struct dentry *dentry)
+static inline bool d_is_soft_negative(const struct dentry *dentry)
{
// TODO: check d_is_whiteout(dentry) also.
return d_is_miss(dentry);
}
+static inline bool d_is_hard_negative(const struct dentry *dentry)
+{
+ return __d_entry_type(dentry) == DCACHE_HARD_NEGATIVE_TYPE;
+}
+
+static inline bool d_is_negative(const struct dentry *dentry)
+{
+ return d_is_soft_negative(dentry) || d_is_hard_negative(dentry);
+}
+extern const struct inode_operations ext4_dir_inode_operations;
static inline bool d_is_positive(const struct dentry *dentry)
{
return !d_is_negative(dentry);
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 07/13] vfs: Handle MNT_CASEFOLD in /proc/mounts
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
` (5 preceding siblings ...)
2018-05-22 20:38 ` [PATCH NOMERGE 06/13] vfs: Add Support for hard negative dentries in the dcache Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 08/13] fscrypt: Introduce charset-based matching functions Gabriel Krisman Bertazi
` (5 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
fs/proc_namespace.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c
index e16fb8f2049e..95d5b987c8b5 100644
--- a/fs/proc_namespace.c
+++ b/fs/proc_namespace.c
@@ -70,6 +70,7 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
{ MNT_NOATIME, ",noatime" },
{ MNT_NODIRATIME, ",nodiratime" },
{ MNT_RELATIME, ",relatime" },
+ { MNT_CASEFOLD, ",ignorecase" },
{ 0, NULL }
};
const struct proc_fs_info *fs_infop;
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 08/13] fscrypt: Introduce charset-based matching functions
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
` (6 preceding siblings ...)
2018-05-22 20:38 ` [PATCH NOMERGE 07/13] vfs: Handle MNT_CASEFOLD in /proc/mounts Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 09/13] ext4: Include encoding information on the superblock Gabriel Krisman Bertazi
` (4 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
Changes since RFC v1:
- Send length of both strings to comparison functions.
- Change length type to size_t.
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
include/linux/fscrypt.h | 1 +
include/linux/fscrypt_notsupp.h | 16 ++++++++++++++++
include/linux/fscrypt_supp.h | 27 +++++++++++++++++++++++++++
3 files changed, 44 insertions(+)
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 952ab97af325..96559f7bfc63 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -15,6 +15,7 @@
#define _LINUX_FSCRYPT_H
#include <linux/fs.h>
+#include <linux/nls.h>
#define FS_CRYPTO_BLOCK_SIZE 16
diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h
index 44b50c04bae9..f38824aa3250 100644
--- a/include/linux/fscrypt_notsupp.h
+++ b/include/linux/fscrypt_notsupp.h
@@ -159,6 +159,22 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len);
}
+static inline bool fscrypt_charset_match_name(struct nls_table *charset,
+ const struct fscrypt_name *fname,
+ const u8 *de_name,
+ u32 de_name_len, bool ignorecase)
+{
+ if (!ignorecase) {
+ return !nls_strncmp(charset, (char *) de_name, de_name_len,
+ fname->disk_name.name,
+ fname->disk_name.len);
+ }
+
+ return !nls_strncasecmp(charset, (char *) de_name,
+ (size_t) de_name_len, fname->disk_name.name,
+ (size_t) fname->disk_name.len);
+}
+
/* bio.c */
static inline void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx,
struct bio *bio)
diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h
index 477a7a6504d2..8c55678ce9ce 100644
--- a/include/linux/fscrypt_supp.h
+++ b/include/linux/fscrypt_supp.h
@@ -187,6 +187,33 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
return !memcmp(de_name, fname->disk_name.name, fname->disk_name.len);
}
+static inline bool fscrypt_charset_match_name(struct nls_table *charset,
+ const struct fscrypt_name *fname,
+ const u8 *de_name,
+ u32 de_name_len, bool ignorecase)
+{
+ if (unlikely(!fname->disk_name.name)) {
+ const struct fscrypt_digested_name *n =
+ (const void *)fname->crypto_buf.name;
+ if (WARN_ON_ONCE(fname->usr_fname->name[0] != '_'))
+ return false;
+ if (de_name_len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE)
+ return false;
+ return !memcmp(FSCRYPT_FNAME_DIGEST(de_name, de_name_len),
+ n->digest, FSCRYPT_FNAME_DIGEST_SIZE);
+ }
+
+ if (!ignorecase) {
+ return !nls_strncmp(charset, (char *) de_name, de_name_len,
+ fname->disk_name.name,
+ fname->disk_name.len);
+ }
+
+ return !nls_strncasecmp(charset, (char *) de_name, de_name_len,
+ fname->disk_name.name,
+ fname->disk_name.len);
+}
+
/* bio.c */
extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
extern void fscrypt_pullback_bio_page(struct page **, bool);
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 09/13] ext4: Include encoding information on the superblock
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
` (7 preceding siblings ...)
2018-05-22 20:38 ` [PATCH NOMERGE 08/13] fscrypt: Introduce charset-based matching functions Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 10/13] ext4: Plumb LOOK_CASEFOLD up to ext4 comparison functions Gabriel Krisman Bertazi
` (3 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
fs/ext4/ext4.h | 1 +
fs/ext4/super.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 3241475a1733..22f49d7d3efc 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1366,6 +1366,7 @@ struct ext4_sb_info {
struct kobject s_kobj;
struct completion s_kobj_unregister;
struct super_block *s_sb;
+ struct nls_table *encoding;
/* Journaling */
struct journal_s *s_journal;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 39bf464c35f1..bbf0a5c4104b 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -42,6 +42,7 @@
#include <linux/cleancache.h>
#include <linux/uaccess.h>
#include <linux/iversion.h>
+#include <linux/nls.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
@@ -1352,6 +1353,7 @@ enum {
Opt_dioread_nolock, Opt_dioread_lock,
Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache,
+ Opt_encoding,
};
static const match_table_t tokens = {
@@ -1434,6 +1436,7 @@ static const match_table_t tokens = {
{Opt_noinit_itable, "noinit_itable"},
{Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
{Opt_test_dummy_encryption, "test_dummy_encryption"},
+ {Opt_encoding, "encoding=%s"},
{Opt_nombcache, "nombcache"},
{Opt_nombcache, "no_mbcache"}, /* for backward compatibility */
{Opt_removed, "check=none"}, /* mount option from ext2/3 */
@@ -1644,9 +1647,24 @@ static const struct mount_opts {
{Opt_max_dir_size_kb, 0, MOPT_GTE0},
{Opt_test_dummy_encryption, 0, MOPT_GTE0},
{Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},
+ {Opt_encoding, 0, MOPT_EXT4_ONLY | MOPT_STRING},
{Opt_err, 0, 0}
};
+static void split_charset_version(char *encoding_arg, char **charset,
+ char **version)
+{
+ char *separator;
+ *version = NULL;
+ *charset = encoding_arg;
+
+ separator = strchr(encoding_arg, '-');
+ if (separator && *separator && *(separator+1) != '\0') {
+ *separator = '\0';
+ *version = separator + 1;
+ }
+}
+
static int handle_mount_opt(struct super_block *sb, char *opt, int token,
substring_t *args, unsigned long *journal_devnum,
unsigned int *journal_ioprio, int is_remount)
@@ -1879,6 +1897,21 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
sbi->s_mount_opt |= m->mount_opt;
} else if (token == Opt_data_err_ignore) {
sbi->s_mount_opt &= ~m->mount_opt;
+ } else if (token == Opt_encoding) {
+ char *encoding_arg = match_strdup(&args[0]);
+ char *charset = NULL;
+ char *version = NULL;
+
+ split_charset_version(encoding_arg, &charset, &version);
+
+ sbi->encoding = load_nls_version(charset, version);
+ if (IS_ERR(sbi->encoding)) {
+ ext4_msg(sb, KERN_ERR, "Encoding %s-%s not supported",
+ charset,version);
+ kfree(encoding_arg);
+ return -1;
+ }
+ kfree(encoding_arg);
} else {
if (!args->from)
arg = 1;
@@ -1965,6 +1998,12 @@ static int parse_options(char *options, struct super_block *sb,
return 0;
}
}
+
+ if (!sbi->encoding) {
+ ext4_msg(sb, KERN_WARNING, "Encoding not explicitly specified "
+ "or identified on the superblock. ASCII is assumed.");
+ }
+
return 1;
}
@@ -3595,6 +3634,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
&journal_ioprio, 0))
goto failed_mount;
+ if (!sbi->encoding) {
+ sbi->encoding = load_nls("ascii");
+ if (!sbi->encoding)
+ goto failed_mount;
+ }
+
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
printk_once(KERN_WARNING "EXT4-fs: Warning: mounting "
"with data=journal disables delayed "
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 10/13] ext4: Plumb LOOK_CASEFOLD up to ext4 comparison functions
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
` (8 preceding siblings ...)
2018-05-22 20:38 ` [PATCH NOMERGE 09/13] ext4: Include encoding information on the superblock Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 11/13] ext4: Support charset name matching Gabriel Krisman Bertazi
` (2 subsequent siblings)
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
We also ignore the flags when creating a file, this means we allow files
to be created who only differ by case folding.
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
fs/ext4/ext4.h | 6 ++++--
fs/ext4/inline.c | 7 ++++---
fs/ext4/namei.c | 50 +++++++++++++++++++++++++++---------------------
3 files changed, 36 insertions(+), 27 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 22f49d7d3efc..ebda06e4cb24 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2505,7 +2505,8 @@ extern int ext4_search_dir(struct buffer_head *bh,
struct inode *dir,
struct ext4_filename *fname,
unsigned int offset,
- struct ext4_dir_entry_2 **res_dir);
+ struct ext4_dir_entry_2 **res_dir,
+ unsigned int flags);
extern int ext4_generic_delete_entry(handle_t *handle,
struct inode *dir,
struct ext4_dir_entry_2 *de_del,
@@ -2991,7 +2992,8 @@ extern int htree_inlinedir_to_tree(struct file *dir_file,
extern struct buffer_head *ext4_find_inline_entry(struct inode *dir,
struct ext4_filename *fname,
struct ext4_dir_entry_2 **res_dir,
- int *has_inline_data);
+ int *has_inline_data,
+ unsigned int flags);
extern int ext4_delete_inline_entry(handle_t *handle,
struct inode *dir,
struct ext4_dir_entry_2 *de_del,
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
index 70cf4c7b268a..273d28a9c0b7 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -1612,7 +1612,8 @@ int ext4_try_create_inline_dir(handle_t *handle, struct inode *parent,
struct buffer_head *ext4_find_inline_entry(struct inode *dir,
struct ext4_filename *fname,
struct ext4_dir_entry_2 **res_dir,
- int *has_inline_data)
+ int *has_inline_data,
+ unsigned int flags)
{
int ret;
struct ext4_iloc iloc;
@@ -1632,7 +1633,7 @@ struct buffer_head *ext4_find_inline_entry(struct inode *dir,
EXT4_INLINE_DOTDOT_SIZE;
inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE;
ret = ext4_search_dir(iloc.bh, inline_start, inline_size,
- dir, fname, 0, res_dir);
+ dir, fname, 0, res_dir, flags);
if (ret == 1)
goto out_find;
if (ret < 0)
@@ -1645,7 +1646,7 @@ struct buffer_head *ext4_find_inline_entry(struct inode *dir,
inline_size = ext4_get_inline_size(dir) - EXT4_MIN_INLINE_DATA_SIZE;
ret = ext4_search_dir(iloc.bh, inline_start, inline_size,
- dir, fname, 0, res_dir);
+ dir, fname, 0, res_dir, flags);
if (ret == 1)
goto out_find;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index b1f21e3a0763..3373017e9315 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -35,6 +35,7 @@
#include <linux/buffer_head.h>
#include <linux/bio.h>
#include <linux/iversion.h>
+#include <linux/namei.h>
#include "ext4.h"
#include "ext4_jbd2.h"
@@ -273,7 +274,8 @@ static int ext4_htree_next_block(struct inode *dir, __u32 hash,
__u32 *start_hash);
static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
struct ext4_filename *fname,
- struct ext4_dir_entry_2 **res_dir);
+ struct ext4_dir_entry_2 **res_dir,
+ unsigned int flags);
static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname,
struct inode *dir, struct inode *inode);
@@ -1172,10 +1174,11 @@ static inline int search_dirblock(struct buffer_head *bh,
struct inode *dir,
struct ext4_filename *fname,
unsigned int offset,
- struct ext4_dir_entry_2 **res_dir)
+ struct ext4_dir_entry_2 **res_dir,
+ unsigned int flags)
{
return ext4_search_dir(bh, bh->b_data, dir->i_sb->s_blocksize, dir,
- fname, offset, res_dir);
+ fname, offset, res_dir, flags);
}
/*
@@ -1257,7 +1260,8 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
* Return: %true if the directory entry matches, otherwise %false.
*/
static inline bool ext4_match(const struct ext4_filename *fname,
- const struct ext4_dir_entry_2 *de)
+ const struct ext4_dir_entry_2 *de,
+ bool casefold)
{
struct fscrypt_name f;
@@ -1277,7 +1281,8 @@ static inline bool ext4_match(const struct ext4_filename *fname,
*/
int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
struct inode *dir, struct ext4_filename *fname,
- unsigned int offset, struct ext4_dir_entry_2 **res_dir)
+ unsigned int offset, struct ext4_dir_entry_2 **res_dir,
+ unsigned int flags)
{
struct ext4_dir_entry_2 * de;
char * dlimit;
@@ -1289,7 +1294,7 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
/* this code is executed quadratically often */
/* do minimal checking `by hand' */
if ((char *) de + de->name_len <= dlimit &&
- ext4_match(fname, de)) {
+ ext4_match(fname, de, flags & LOOKUP_CASEFOLD)) {
/* found a match - just to be sure, do
* a full check */
if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data,
@@ -1339,7 +1344,7 @@ static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block,
static struct buffer_head * ext4_find_entry (struct inode *dir,
const struct qstr *d_name,
struct ext4_dir_entry_2 **res_dir,
- int *inlined)
+ int *inlined, unsigned int flags)
{
struct super_block *sb;
struct buffer_head *bh_use[NAMEI_RA_SIZE];
@@ -1369,7 +1374,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
if (ext4_has_inline_data(dir)) {
int has_inline_data = 1;
ret = ext4_find_inline_entry(dir, &fname, res_dir,
- &has_inline_data);
+ &has_inline_data, flags);
if (has_inline_data) {
if (inlined)
*inlined = 1;
@@ -1388,7 +1393,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
goto restart;
}
if (is_dx(dir)) {
- ret = ext4_dx_find_entry(dir, &fname, res_dir);
+ ret = ext4_dx_find_entry(dir, &fname, res_dir, flags);
/*
* On success, or if the error was file not found,
* return. Otherwise, fall back to doing a search the
@@ -1452,7 +1457,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
}
set_buffer_verified(bh);
i = search_dirblock(bh, dir, &fname,
- block << EXT4_BLOCK_SIZE_BITS(sb), res_dir);
+ block << EXT4_BLOCK_SIZE_BITS(sb), res_dir, flags);
if (i == 1) {
EXT4_I(dir)->i_dir_start_lookup = block;
ret = bh;
@@ -1488,7 +1493,8 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
struct ext4_filename *fname,
- struct ext4_dir_entry_2 **res_dir)
+ struct ext4_dir_entry_2 **res_dir,
+ unsigned int flags)
{
struct super_block * sb = dir->i_sb;
struct dx_frame frames[EXT4_HTREE_LEVEL], *frame;
@@ -1510,7 +1516,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir,
retval = search_dirblock(bh, dir, fname,
block << EXT4_BLOCK_SIZE_BITS(sb),
- res_dir);
+ res_dir, flags);
if (retval == 1)
goto success;
brelse(bh);
@@ -1553,7 +1559,7 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
if (dentry->d_name.len > EXT4_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG);
- bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
+ bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL, flags);
if (IS_ERR(bh))
return (struct dentry *) bh;
inode = NULL;
@@ -1597,7 +1603,7 @@ struct dentry *ext4_get_parent(struct dentry *child)
struct ext4_dir_entry_2 * de;
struct buffer_head *bh;
- bh = ext4_find_entry(d_inode(child), &dotdot, &de, NULL);
+ bh = ext4_find_entry(d_inode(child), &dotdot, &de, NULL, 0);
if (IS_ERR(bh))
return (struct dentry *) bh;
if (!bh)
@@ -1796,7 +1802,7 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
if (ext4_check_dir_entry(dir, NULL, de, bh,
buf, buf_size, offset))
return -EFSCORRUPTED;
- if (ext4_match(fname, de))
+ if (ext4_match(fname, de, false))
return -EEXIST;
nlen = EXT4_DIR_REC_LEN(de->name_len);
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
@@ -2925,7 +2931,7 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
return retval;
retval = -ENOENT;
- bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
+ bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL, 0);
if (IS_ERR(bh))
return PTR_ERR(bh);
if (!bh)
@@ -3002,7 +3008,7 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
return retval;
retval = -ENOENT;
- bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
+ bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL, 0);
if (IS_ERR(bh))
return PTR_ERR(bh);
if (!bh)
@@ -3364,7 +3370,7 @@ static int ext4_find_delete_entry(handle_t *handle, struct inode *dir,
struct buffer_head *bh;
struct ext4_dir_entry_2 *de;
- bh = ext4_find_entry(dir, d_name, &de, NULL);
+ bh = ext4_find_entry(dir, d_name, &de, NULL, 0);
if (IS_ERR(bh))
return PTR_ERR(bh);
if (bh) {
@@ -3499,7 +3505,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
return retval;
}
- old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL);
+ old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL, 0);
if (IS_ERR(old.bh))
return PTR_ERR(old.bh);
/*
@@ -3513,7 +3519,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
goto end_rename;
new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
- &new.de, &new.inlined);
+ &new.de, &new.inlined, 0);
if (IS_ERR(new.bh)) {
retval = PTR_ERR(new.bh);
new.bh = NULL;
@@ -3693,7 +3699,7 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
return retval;
old.bh = ext4_find_entry(old.dir, &old.dentry->d_name,
- &old.de, &old.inlined);
+ &old.de, &old.inlined, 0);
if (IS_ERR(old.bh))
return PTR_ERR(old.bh);
/*
@@ -3707,7 +3713,7 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
goto end_rename;
new.bh = ext4_find_entry(new.dir, &new.dentry->d_name,
- &new.de, &new.inlined);
+ &new.de, &new.inlined, 0);
if (IS_ERR(new.bh)) {
retval = PTR_ERR(new.bh);
new.bh = NULL;
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 11/13] ext4: Support charset name matching
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
` (9 preceding siblings ...)
2018-05-22 20:38 ` [PATCH NOMERGE 10/13] ext4: Plumb LOOK_CASEFOLD up to ext4 comparison functions Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 12/13] ext4: Implement ext4 dcache hooks for custom charsets Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 13/13] ext4: Notify VFS of support for casefolded mountpoints Gabriel Krisman Bertazi
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
Implement generic caseless lookup based on the mount flags using the
charset library.
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
fs/ext4/namei.c | 47 +++++++++++++++++++++++++++++++++++++++--------
1 file changed, 39 insertions(+), 8 deletions(-)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 3373017e9315..ad7330b82740 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1259,7 +1259,8 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block)
*
* Return: %true if the directory entry matches, otherwise %false.
*/
-static inline bool ext4_match(const struct ext4_filename *fname,
+static inline bool ext4_match(struct nls_table *charset,
+ const struct ext4_filename *fname,
const struct ext4_dir_entry_2 *de,
bool casefold)
{
@@ -1273,7 +1274,8 @@ static inline bool ext4_match(const struct ext4_filename *fname,
#ifdef CONFIG_EXT4_FS_ENCRYPTION
f.crypto_buf = fname->crypto_buf;
#endif
- return fscrypt_match_name(&f, de->name, de->name_len);
+ return fscrypt_charset_match_name(charset, &f, de->name,
+ de->name_len, casefold);
}
/*
@@ -1287,6 +1289,7 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
struct ext4_dir_entry_2 * de;
char * dlimit;
int de_len;
+ struct super_block *sb = dir->i_sb;
de = (struct ext4_dir_entry_2 *)search_buf;
dlimit = search_buf + buf_size;
@@ -1294,7 +1297,9 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
/* this code is executed quadratically often */
/* do minimal checking `by hand' */
if ((char *) de + de->name_len <= dlimit &&
- ext4_match(fname, de, flags & LOOKUP_CASEFOLD)) {
+ ext4_match(EXT4_SB(sb)->encoding, fname, de,
+ flags & LOOKUP_CASEFOLD)) {
+
/* found a match - just to be sure, do
* a full check */
if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data,
@@ -1395,11 +1400,13 @@ static struct buffer_head * ext4_find_entry (struct inode *dir,
if (is_dx(dir)) {
ret = ext4_dx_find_entry(dir, &fname, res_dir, flags);
/*
- * On success, or if the error was file not found,
- * return. Otherwise, fall back to doing a search the
- * old fashioned way.
+ * On success, or if the file cannot be found, return.
+ * If an error occurred, or if the file was not found
+ * but we can do case-insensitive lookups, fall back to
+ * the linear search.
*/
- if (!IS_ERR(ret) || PTR_ERR(ret) != ERR_BAD_DX_DIR)
+ if ((!IS_ERR(ret) && (ret || !(flags & LOOKUP_CASEFOLD))) ||
+ (IS_ERR(ret) && PTR_ERR(ret) != ERR_BAD_DX_DIR))
goto cleanup_and_exit;
dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, "
"falling back\n"));
@@ -1592,6 +1599,29 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
return ERR_PTR(-EPERM);
}
}
+
+ if (flags & LOOKUP_CASEFOLD) {
+ struct dentry *new;
+ struct qstr ciname;
+ char *name;
+
+ if (!de)
+ return d_add_ci_negative_dentry(dentry);
+
+ name = kmalloc((sizeof(char) * de->name_len) + 1,
+ GFP_NOFS);
+ if (!name)
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(name, de->name, de->name_len);
+ name[de->name_len] = '\0';
+ ciname.len = de->name_len;
+ ciname.name = name;
+ new = d_add_ci(dentry, inode, &ciname);
+ kfree(name);
+ return new;
+ }
+
return d_splice_alias(inode, dentry);
}
@@ -1795,6 +1825,7 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
int nlen, rlen;
unsigned int offset = 0;
char *top;
+ struct super_block *sb = dir->i_sb;
de = (struct ext4_dir_entry_2 *)buf;
top = buf + buf_size - reclen;
@@ -1802,7 +1833,7 @@ int ext4_find_dest_de(struct inode *dir, struct inode *inode,
if (ext4_check_dir_entry(dir, NULL, de, bh,
buf, buf_size, offset))
return -EFSCORRUPTED;
- if (ext4_match(fname, de, false))
+ if (ext4_match(EXT4_SB(sb)->encoding, fname, de, false))
return -EEXIST;
nlen = EXT4_DIR_REC_LEN(de->name_len);
rlen = ext4_rec_len_from_disk(de->rec_len, buf_size);
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 12/13] ext4: Implement ext4 dcache hooks for custom charsets
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
` (10 preceding siblings ...)
2018-05-22 20:38 ` [PATCH NOMERGE 11/13] ext4: Support charset name matching Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
2018-05-22 20:38 ` [PATCH NOMERGE 13/13] ext4: Notify VFS of support for casefolded mountpoints Gabriel Krisman Bertazi
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
Changes from RFC v1:
- Handle errors from charset_normalize/casefold (Olaf Weber)
- Send length of both strings to comparison functions.
- Cast length type to size_t
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
fs/ext4/dir.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
fs/ext4/ext4.h | 2 ++
fs/ext4/super.c | 2 ++
3 files changed, 52 insertions(+)
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index da87cf757f7d..02911f2681ab 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -26,6 +26,7 @@
#include <linux/buffer_head.h>
#include <linux/slab.h>
#include <linux/iversion.h>
+#include <linux/nls.h>
#include "ext4.h"
#include "xattr.h"
@@ -662,3 +663,50 @@ const struct file_operations ext4_dir_operations = {
.open = ext4_dir_open,
.release = ext4_release_dir,
};
+
+static int ext4_d_compare(const struct dentry *dentry, unsigned int len,
+ const char *str, const struct qstr *name)
+{
+ struct nls_table *charset = EXT4_SB(dentry->d_sb)->encoding;
+ size_t nlen = strlen(name->name);
+
+ return nls_strncmp(charset, str, len, name->name, nlen);
+}
+
+static int ext4_d_compare_ci(const struct dentry *dentry, unsigned int len,
+ const char *str, const struct qstr *name)
+{
+ struct nls_table *charset = EXT4_SB(dentry->d_sb)->encoding;
+ size_t nlen = strlen(name->name);
+
+ return nls_strncasecmp(charset, str, len, name->name, nlen);
+}
+
+static int ext4_d_ci_hash(const struct dentry *dentry, struct qstr *q)
+{
+ unsigned long hash;
+ int i, len;
+ unsigned char *folded = NULL;
+ const struct nls_table *charset = EXT4_SB(dentry->d_sb)->encoding;
+
+ len = nls_casefold(charset, q->name, q->len, &folded);
+
+ if (len < 0) {
+ kfree(folded);
+ return -EINVAL;
+ }
+
+ hash = init_name_hash(dentry);
+ for (i = 0; i < len; i++)
+ hash = partial_name_hash(folded[i], hash);
+ q->hash = end_name_hash(hash);
+
+ kfree(folded);
+ return 0;
+}
+
+const struct dentry_operations ext4_dentry_ops = {
+ .d_hash = ext4_d_ci_hash,
+ .d_compare = ext4_d_compare,
+ .d_compare_ci = ext4_d_compare_ci,
+};
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index ebda06e4cb24..eb193d66565a 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2939,6 +2939,8 @@ static inline void ext4_unlock_group(struct super_block *sb,
/* dir.c */
extern const struct file_operations ext4_dir_operations;
+extern const struct dentry_operations ext4_dentry_ops;
+extern const struct dentry_operations ext4_ci_dentry_ops;
/* file.c */
extern const struct inode_operations ext4_file_inode_operations;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index bbf0a5c4104b..e73976986dcb 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -4241,6 +4241,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
iput(root);
goto failed_mount4;
}
+
+ sb->s_d_op = &ext4_dentry_ops;
sb->s_root = d_make_root(root);
if (!sb->s_root) {
ext4_msg(sb, KERN_ERR, "get root dentry failed");
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH NOMERGE 13/13] ext4: Notify VFS of support for casefolded mountpoints
2018-05-22 20:38 [PATCH NOMERGE 00/13] Case insensitiveness as a mountpoint Gabriel Krisman Bertazi
` (11 preceding siblings ...)
2018-05-22 20:38 ` [PATCH NOMERGE 12/13] ext4: Implement ext4 dcache hooks for custom charsets Gabriel Krisman Bertazi
@ 2018-05-22 20:38 ` Gabriel Krisman Bertazi
12 siblings, 0 replies; 14+ messages in thread
From: Gabriel Krisman Bertazi @ 2018-05-22 20:38 UTC (permalink / raw)
To: viro; +Cc: linux-fsdevel, Gabriel Krisman Bertazi
This effectively enables case-insensitive lookups for ext4.
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
fs/ext4/super.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index e73976986dcb..dda63227c48e 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -5827,7 +5827,7 @@ static struct file_system_type ext4_fs_type = {
.name = "ext4",
.mount = ext4_mount,
.kill_sb = kill_block_super,
- .fs_flags = FS_REQUIRES_DEV,
+ .fs_flags = FS_REQUIRES_DEV | FS_HAS_CASEFOLD,
};
MODULE_ALIAS_FS("ext4");
--
2.17.0
^ permalink raw reply related [flat|nested] 14+ messages in thread