* [PATCH v4 0/9] ovl: Enable support for casefold filesystems
@ 2025-08-13 22:36 André Almeida
2025-08-13 22:36 ` [PATCH v4 1/9] ovl: Support mounting case-insensitive enabled filesystems André Almeida
` (8 more replies)
0 siblings, 9 replies; 21+ messages in thread
From: André Almeida @ 2025-08-13 22:36 UTC (permalink / raw)
To: Miklos Szeredi, Amir Goldstein, Theodore Tso,
Gabriel Krisman Bertazi
Cc: linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev, André Almeida
Hi all,
We would like to support the usage of casefold filesystems with
overlayfs to be used with container tools. This use case requires a
simple setup, where every layer will have the same encoding setting
(i.e. Unicode version and flags), using one upper and one lower layer.
* Implementation
When merge layers, ovl uses a red-black tree to check if a given dentry
name from a lower layers already exists in the upper layer. For merging
case-insensitive names, we need to store then in tree casefolded.
However, when displaying to the user the dentry name, we need to respect
the name chosen when the file was created (e.g. Picture.PNG, instead of
picture.png). To achieve this, I create a new field for cache entries
that stores the casefolded names and a function ovl_strcmp() that uses
this name for searching the rb_tree. For composing the layer, ovl uses
the original name, keeping it consistency with whatever name the user
created.
The rest of the patches are mostly for checking if casefold is being
consistently used across the layers and dropping the mount restrictions
that prevented case-insensitive filesystems to be mounted.
Thanks for the feedback!
---
Changes in v4:
- Split patch "ovl: Support case-insensitive lookup" and move patch that
creates ofs->casefold to the begging of the series
- Merge patch "Store casefold name..." and "Create ovl_casefold()..."
- Make encoding restrictions apply just when casefold is enabled
- Rework set_d_op() with new helper
- Set encoding and encoding flags inside of ovl_get_layers()
- Rework how inode flags are set and checked
v3: https://lore.kernel.org/r/20250808-tonyk-overlayfs-v3-0-30f9be426ba8@igalia.com
Changes in v3:
- Rebased on top of vfs-6.18.misc branch
- Added more guards for casefolding things inside of IS_ENABLED(UNICODE)
- Refactor the strncmp() patch to do a single kmalloc() per rb_tree operation
- Instead of casefolding the cache entry name everytime per strncmp(),
casefold it once and reuse it for every strncmp().
- Created ovl_dentry_ci_operations to not override dentry ops set by
ovl_dentry_operations
- Instead of setting encoding just when there's a upper layer, set it
for any first layer (ofs->fs[0].sb), regardless of it being upper or
not.
- Rewrote the patch that set inode flags
- Check if every dentry is consistent with the root dentry regarding
casefold
v2: https://lore.kernel.org/r/20250805-tonyk-overlayfs-v2-0-0e54281da318@igalia.com
Changes in v2:
- Almost a full rewritten from the v1.
v1: https://lore.kernel.org/lkml/20250409-tonyk-overlayfs-v1-0-3991616fe9a3@igalia.com/
---
André Almeida (9):
ovl: Support mounting case-insensitive enabled filesystems
fs: Create new helper sb_encoding()
ovl: Create ovl_casefold() to support casefolded strncmp()
fs: Create sb_same_encoding() helper
ovl: Ensure that all layers have the same encoding
ovl: Set case-insensitive dentry operations for ovl sb
ovl: Add S_CASEFOLD as part of the inode flag to be copied
ovl: Check for casefold consistency when creating new dentries
ovl: Allow case-insensitive lookup
fs/overlayfs/copy_up.c | 2 +-
fs/overlayfs/dir.c | 5 +++
fs/overlayfs/inode.c | 1 +
fs/overlayfs/namei.c | 17 +++++----
fs/overlayfs/overlayfs.h | 8 ++--
fs/overlayfs/ovl_entry.h | 1 +
fs/overlayfs/params.c | 15 ++++++--
fs/overlayfs/params.h | 1 +
fs/overlayfs/readdir.c | 99 ++++++++++++++++++++++++++++++++++++++++++------
fs/overlayfs/super.c | 51 +++++++++++++++++++++++++
fs/overlayfs/util.c | 8 ++--
include/linux/fs.h | 27 ++++++++++++-
12 files changed, 202 insertions(+), 33 deletions(-)
---
base-commit: 7aef10fd5ca1726315dc387448924b9e3e417e8e
change-id: 20250409-tonyk-overlayfs-591f5e4d407a
Best regards,
--
André Almeida <andrealmeid@igalia.com>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH v4 1/9] ovl: Support mounting case-insensitive enabled filesystems
2025-08-13 22:36 [PATCH v4 0/9] ovl: Enable support for casefold filesystems André Almeida
@ 2025-08-13 22:36 ` André Almeida
2025-08-14 8:35 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 2/9] fs: Create new helper sb_encoding() André Almeida
` (7 subsequent siblings)
8 siblings, 1 reply; 21+ messages in thread
From: André Almeida @ 2025-08-13 22:36 UTC (permalink / raw)
To: Miklos Szeredi, Amir Goldstein, Theodore Tso,
Gabriel Krisman Bertazi
Cc: linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev, André Almeida
Enable mounting filesystems with case-insensitive dentries in order to
support such filesystems in overlayfs.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
Changes from v3:
- Move this patch to be ealier in the series
- Split this patch with the ovl_lookup_single() restriction patch
---
fs/overlayfs/ovl_entry.h | 1 +
fs/overlayfs/params.c | 15 ++++++++++++---
fs/overlayfs/params.h | 1 +
fs/overlayfs/util.c | 8 ++++----
4 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
index 4c1bae935ced274f93a0d23fe10d34455e226ec4..1d4828dbcf7ac4ba9657221e601bbf79d970d225 100644
--- a/fs/overlayfs/ovl_entry.h
+++ b/fs/overlayfs/ovl_entry.h
@@ -91,6 +91,7 @@ struct ovl_fs {
struct mutex whiteout_lock;
/* r/o snapshot of upperdir sb's only taken on volatile mounts */
errseq_t errseq;
+ bool casefold;
};
/* Number of lower layers, not including data-only layers */
diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c
index f4e7fff909ac49e2f8c58a76273426c1158a7472..17d2354ba88d92e1d9653e8cb1382d860a7329c5 100644
--- a/fs/overlayfs/params.c
+++ b/fs/overlayfs/params.c
@@ -277,16 +277,25 @@ static int ovl_mount_dir_check(struct fs_context *fc, const struct path *path,
enum ovl_opt layer, const char *name, bool upper)
{
struct ovl_fs_context *ctx = fc->fs_private;
+ struct ovl_fs *ofs = fc->s_fs_info;
+ bool is_casefolded = ovl_dentry_casefolded(path->dentry);
if (!d_is_dir(path->dentry))
return invalfc(fc, "%s is not a directory", name);
/*
* Allow filesystems that are case-folding capable but deny composing
- * ovl stack from case-folded directories.
+ * ovl stack from inconsistent case-folded directories.
*/
- if (ovl_dentry_casefolded(path->dentry))
- return invalfc(fc, "case-insensitive directory on %s not supported", name);
+ if (!ctx->casefold_set) {
+ ofs->casefold = is_casefolded;
+ ctx->casefold_set = true;
+ }
+
+ if (ofs->casefold != is_casefolded) {
+ return invalfc(fc, "case-%ssensitive directory on %s is inconsistent",
+ is_casefolded ? "in" : "", name);
+ }
if (ovl_dentry_weird(path->dentry))
return invalfc(fc, "filesystem on %s not supported", name);
diff --git a/fs/overlayfs/params.h b/fs/overlayfs/params.h
index c96d939820211ddc63e265670a2aff60d95eec49..ffd53cdd84827cce827e8852f2de545f966ce60d 100644
--- a/fs/overlayfs/params.h
+++ b/fs/overlayfs/params.h
@@ -33,6 +33,7 @@ struct ovl_fs_context {
struct ovl_opt_set set;
struct ovl_fs_context_layer *lower;
char *lowerdir_all; /* user provided lowerdir string */
+ bool casefold_set;
};
int ovl_init_fs_context(struct fs_context *fc);
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index a33115e7384c129c543746326642813add63f060..7a6ee058568283453350153c1720c35e11ad4d1b 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -210,11 +210,11 @@ bool ovl_dentry_weird(struct dentry *dentry)
return true;
/*
- * Allow filesystems that are case-folding capable but deny composing
- * ovl stack from case-folded directories.
+ * Exceptionally for casefold dentries, we accept that they have their
+ * own hash and compare operations
*/
- if (sb_has_encoding(dentry->d_sb))
- return IS_CASEFOLDED(d_inode(dentry));
+ if (ovl_dentry_casefolded(dentry))
+ return false;
return dentry->d_flags & (DCACHE_OP_HASH | DCACHE_OP_COMPARE);
}
--
2.50.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 2/9] fs: Create new helper sb_encoding()
2025-08-13 22:36 [PATCH v4 0/9] ovl: Enable support for casefold filesystems André Almeida
2025-08-13 22:36 ` [PATCH v4 1/9] ovl: Support mounting case-insensitive enabled filesystems André Almeida
@ 2025-08-13 22:36 ` André Almeida
2025-08-14 12:18 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 3/9] ovl: Create ovl_casefold() to support casefolded strncmp() André Almeida
` (6 subsequent siblings)
8 siblings, 1 reply; 21+ messages in thread
From: André Almeida @ 2025-08-13 22:36 UTC (permalink / raw)
To: Miklos Szeredi, Amir Goldstein, Theodore Tso,
Gabriel Krisman Bertazi
Cc: linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev, André Almeida
Filesystems that need to deal with the super block encoding need to use
a if IS_ENABLED(CONFIG_UNICODE) around it because this struct member is
not declared otherwise. In order to move this if/endif guards outside of
the filesytem code and make it simpler, create a new function that
returns the s_encoding member of struct super_block if Unicode is
enabled, and return NULL otherwise.
Suggested-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
Changes from v3:
- New patch
---
include/linux/fs.h | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 796319914b0a063642c2bd0c0140697a0eb651f6..20102d81e18a59d5daaed06855d1f168979b4fa7 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3739,15 +3739,20 @@ static inline bool generic_ci_validate_strict_name(struct inode *dir, struct qst
}
#endif
-static inline bool sb_has_encoding(const struct super_block *sb)
+static inline struct unicode_map *sb_encoding(const struct super_block *sb)
{
#if IS_ENABLED(CONFIG_UNICODE)
- return !!sb->s_encoding;
+ return sb->s_encoding;
#else
- return false;
+ return NULL;
#endif
}
+static inline bool sb_has_encoding(const struct super_block *sb)
+{
+ return !!sb_encoding(sb);
+}
+
int may_setattr(struct mnt_idmap *idmap, struct inode *inode,
unsigned int ia_valid);
int setattr_prepare(struct mnt_idmap *, struct dentry *, struct iattr *);
--
2.50.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 3/9] ovl: Create ovl_casefold() to support casefolded strncmp()
2025-08-13 22:36 [PATCH v4 0/9] ovl: Enable support for casefold filesystems André Almeida
2025-08-13 22:36 ` [PATCH v4 1/9] ovl: Support mounting case-insensitive enabled filesystems André Almeida
2025-08-13 22:36 ` [PATCH v4 2/9] fs: Create new helper sb_encoding() André Almeida
@ 2025-08-13 22:36 ` André Almeida
2025-08-14 12:53 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 4/9] fs: Create sb_same_encoding() helper André Almeida
` (5 subsequent siblings)
8 siblings, 1 reply; 21+ messages in thread
From: André Almeida @ 2025-08-13 22:36 UTC (permalink / raw)
To: Miklos Szeredi, Amir Goldstein, Theodore Tso,
Gabriel Krisman Bertazi
Cc: linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev, André Almeida
To add overlayfs support casefold filesystems, create a new function
ovl_casefold(), to be able to do case-insensitive strncmp().
ovl_casefold() allocates a new buffer and stores the casefolded version
of the string on it. If the allocation or the casefold operation fails,
fallback to use the original string.
The case-insentive name is then used in the rb-tree search/insertion
operation. If the name is found in the rb-tree, the name can be
discarded and the buffer is freed. If the name isn't found, it's then
stored at struct ovl_cache_entry to be used later.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
Changes from v3:
- Improve commit message text
- s/OVL_NAME_LEN/NAME_MAX
- drop #ifdef in favor of if(IS_ENABLED)
- use new helper sb_encoding
- merged patch "Store casefold name..." and "Create ovl_casefold()..."
- Guard all the casefolding inside of IS_ENABLED(UNICODE)
Changes from v2:
- Refactor the patch to do a single kmalloc() per rb_tree operation
- Instead of casefolding the cache entry name everytime per strncmp(),
casefold it once and reuse it for every strncmp().
---
fs/overlayfs/readdir.c | 99 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 87 insertions(+), 12 deletions(-)
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index b65cdfce31ce27172d28d879559f1008b9c87320..3d92c0b407fe355053ca80ef999d3520eb7d2462 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -27,6 +27,8 @@ struct ovl_cache_entry {
bool is_upper;
bool is_whiteout;
bool check_xwhiteout;
+ const char *cf_name;
+ int cf_len;
char name[];
};
@@ -45,6 +47,7 @@ struct ovl_readdir_data {
struct list_head *list;
struct list_head middle;
struct ovl_cache_entry *first_maybe_whiteout;
+ struct unicode_map *map;
int count;
int err;
bool is_upper;
@@ -66,6 +69,27 @@ static struct ovl_cache_entry *ovl_cache_entry_from_node(struct rb_node *n)
return rb_entry(n, struct ovl_cache_entry, node);
}
+static int ovl_casefold(struct unicode_map *map, const char *str, int len, char **dst)
+{
+ const struct qstr qstr = { .name = str, .len = len };
+ int cf_len;
+
+ if (!IS_ENABLED(CONFIG_UNICODE) || !map || is_dot_dotdot(str, len))
+ return 0;
+
+ *dst = kmalloc(NAME_MAX, GFP_KERNEL);
+
+ if (dst) {
+ cf_len = utf8_casefold(map, &qstr, *dst, NAME_MAX);
+
+ if (cf_len > 0)
+ return cf_len;
+ }
+
+ kfree(*dst);
+ return 0;
+}
+
static bool ovl_cache_entry_find_link(const char *name, int len,
struct rb_node ***link,
struct rb_node **parent)
@@ -79,7 +103,7 @@ static bool ovl_cache_entry_find_link(const char *name, int len,
*parent = *newp;
tmp = ovl_cache_entry_from_node(*newp);
- cmp = strncmp(name, tmp->name, len);
+ cmp = strncmp(name, tmp->cf_name, tmp->cf_len);
if (cmp > 0)
newp = &tmp->node.rb_right;
else if (cmp < 0 || len < tmp->len)
@@ -101,7 +125,7 @@ static struct ovl_cache_entry *ovl_cache_entry_find(struct rb_root *root,
while (node) {
struct ovl_cache_entry *p = ovl_cache_entry_from_node(node);
- cmp = strncmp(name, p->name, len);
+ cmp = strncmp(name, p->cf_name, p->cf_len);
if (cmp > 0)
node = p->node.rb_right;
else if (cmp < 0 || len < p->len)
@@ -145,13 +169,16 @@ static bool ovl_calc_d_ino(struct ovl_readdir_data *rdd,
static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd,
const char *name, int len,
+ const char *cf_name, int cf_len,
u64 ino, unsigned int d_type)
{
struct ovl_cache_entry *p;
p = kmalloc(struct_size(p, name, len + 1), GFP_KERNEL);
- if (!p)
+ if (!p) {
+ kfree(cf_name);
return NULL;
+ }
memcpy(p->name, name, len);
p->name[len] = '\0';
@@ -167,6 +194,14 @@ static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd,
/* Defer check for overlay.whiteout to ovl_iterate() */
p->check_xwhiteout = rdd->in_xwhiteouts_dir && d_type == DT_REG;
+ if (cf_name && cf_name != name) {
+ p->cf_name = cf_name;
+ p->cf_len = cf_len;
+ } else {
+ p->cf_name = p->name;
+ p->cf_len = len;
+ }
+
if (d_type == DT_CHR) {
p->next_maybe_whiteout = rdd->first_maybe_whiteout;
rdd->first_maybe_whiteout = p;
@@ -175,17 +210,24 @@ static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd,
}
static bool ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
- const char *name, int len, u64 ino,
+ const char *name, int len,
+ const char *cf_name, int cf_len,
+ u64 ino,
unsigned int d_type)
{
struct rb_node **newp = &rdd->root->rb_node;
struct rb_node *parent = NULL;
struct ovl_cache_entry *p;
- if (ovl_cache_entry_find_link(name, len, &newp, &parent))
+ if (ovl_cache_entry_find_link(cf_name, cf_len, &newp, &parent)) {
+ if (cf_name != name) {
+ kfree(cf_name);
+ cf_name = NULL;
+ }
return true;
+ }
- p = ovl_cache_entry_new(rdd, name, len, ino, d_type);
+ p = ovl_cache_entry_new(rdd, name, len, cf_name, cf_len, ino, d_type);
if (p == NULL) {
rdd->err = -ENOMEM;
return false;
@@ -200,15 +242,21 @@ static bool ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
static bool ovl_fill_lowest(struct ovl_readdir_data *rdd,
const char *name, int namelen,
+ const char *cf_name, int cf_len,
loff_t offset, u64 ino, unsigned int d_type)
{
struct ovl_cache_entry *p;
- p = ovl_cache_entry_find(rdd->root, name, namelen);
+ p = ovl_cache_entry_find(rdd->root, cf_name, cf_len);
if (p) {
list_move_tail(&p->l_node, &rdd->middle);
+ if (cf_name != name) {
+ kfree(cf_name);
+ cf_name = NULL;
+ }
} else {
- p = ovl_cache_entry_new(rdd, name, namelen, ino, d_type);
+ p = ovl_cache_entry_new(rdd, name, namelen, cf_name, cf_len,
+ ino, d_type);
if (p == NULL)
rdd->err = -ENOMEM;
else
@@ -223,8 +271,11 @@ void ovl_cache_free(struct list_head *list)
struct ovl_cache_entry *p;
struct ovl_cache_entry *n;
- list_for_each_entry_safe(p, n, list, l_node)
+ list_for_each_entry_safe(p, n, list, l_node) {
+ if (p->cf_name != p->name)
+ kfree(p->cf_name);
kfree(p);
+ }
INIT_LIST_HEAD(list);
}
@@ -260,12 +311,28 @@ static bool ovl_fill_merge(struct dir_context *ctx, const char *name,
{
struct ovl_readdir_data *rdd =
container_of(ctx, struct ovl_readdir_data, ctx);
+ struct ovl_fs *ofs = OVL_FS(rdd->dentry->d_sb);
+ const char *aux = NULL;
+ char *cf_name = NULL;
+ int cf_len = 0;
+
+ if (ofs->casefold)
+ cf_len = ovl_casefold(rdd->map, name, namelen, &cf_name);
+
+ if (cf_len <= 0) {
+ aux = name;
+ cf_len = namelen;
+ } else {
+ aux = cf_name;
+ }
rdd->count++;
if (!rdd->is_lowest)
- return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type);
+ return ovl_cache_entry_add_rb(rdd, name, namelen, aux, cf_len,
+ ino, d_type);
else
- return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
+ return ovl_fill_lowest(rdd, name, namelen, aux, cf_len,
+ offset, ino, d_type);
}
static int ovl_check_whiteouts(const struct path *path, struct ovl_readdir_data *rdd)
@@ -357,12 +424,18 @@ static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list,
.list = list,
.root = root,
.is_lowest = false,
+ .map = NULL,
};
int idx, next;
const struct ovl_layer *layer;
+ struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
for (idx = 0; idx != -1; idx = next) {
next = ovl_path_next(idx, dentry, &realpath, &layer);
+
+ if (ofs->casefold)
+ rdd.map = sb_encoding(realpath.dentry->d_sb);
+
rdd.is_upper = ovl_dentry_upper(dentry) == realpath.dentry;
rdd.in_xwhiteouts_dir = layer->has_xwhiteouts &&
ovl_dentry_has_xwhiteouts(dentry);
@@ -555,7 +628,7 @@ static bool ovl_fill_plain(struct dir_context *ctx, const char *name,
container_of(ctx, struct ovl_readdir_data, ctx);
rdd->count++;
- p = ovl_cache_entry_new(rdd, name, namelen, ino, d_type);
+ p = ovl_cache_entry_new(rdd, name, namelen, NULL, 0, ino, d_type);
if (p == NULL) {
rdd->err = -ENOMEM;
return false;
@@ -1023,6 +1096,8 @@ int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
del_entry:
list_del(&p->l_node);
+ if (p->cf_name != p->name)
+ kfree(p->cf_name);
kfree(p);
}
--
2.50.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 4/9] fs: Create sb_same_encoding() helper
2025-08-13 22:36 [PATCH v4 0/9] ovl: Enable support for casefold filesystems André Almeida
` (2 preceding siblings ...)
2025-08-13 22:36 ` [PATCH v4 3/9] ovl: Create ovl_casefold() to support casefolded strncmp() André Almeida
@ 2025-08-13 22:36 ` André Almeida
2025-08-14 12:19 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 5/9] ovl: Ensure that all layers have the same encoding André Almeida
` (4 subsequent siblings)
8 siblings, 1 reply; 21+ messages in thread
From: André Almeida @ 2025-08-13 22:36 UTC (permalink / raw)
To: Miklos Szeredi, Amir Goldstein, Theodore Tso,
Gabriel Krisman Bertazi
Cc: linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev, André Almeida
For cases where a file lookup can look in different filesystems (like in
overlayfs), both super blocks must have the same encoding and the same
flags. To help with that, create a sb_same_encoding() function.
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
Changes from v3:
- Improve wording
Changes from v2:
- Simplify the code. Instead of `if (cond) return true`, just do `return
cond`;
---
include/linux/fs.h | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 20102d81e18a59d5daaed06855d1f168979b4fa7..64d24e89bc5593915158b40f0442e6d8ef3d968d 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -3753,6 +3753,24 @@ static inline bool sb_has_encoding(const struct super_block *sb)
return !!sb_encoding(sb);
}
+/*
+ * Compare if two super blocks have the same encoding and flags
+ */
+static inline bool sb_same_encoding(const struct super_block *sb1,
+ const struct super_block *sb2)
+{
+#if IS_ENABLED(CONFIG_UNICODE)
+ if (sb1->s_encoding == sb2->s_encoding)
+ return true;
+
+ return (sb1->s_encoding && sb2->s_encoding &&
+ (sb1->s_encoding->version == sb2->s_encoding->version) &&
+ (sb1->s_encoding_flags == sb2->s_encoding_flags));
+#else
+ return true;
+#endif
+}
+
int may_setattr(struct mnt_idmap *idmap, struct inode *inode,
unsigned int ia_valid);
int setattr_prepare(struct mnt_idmap *, struct dentry *, struct iattr *);
--
2.50.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 5/9] ovl: Ensure that all layers have the same encoding
2025-08-13 22:36 [PATCH v4 0/9] ovl: Enable support for casefold filesystems André Almeida
` (3 preceding siblings ...)
2025-08-13 22:36 ` [PATCH v4 4/9] fs: Create sb_same_encoding() helper André Almeida
@ 2025-08-13 22:36 ` André Almeida
2025-08-14 12:56 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 6/9] ovl: Set case-insensitive dentry operations for ovl sb André Almeida
` (3 subsequent siblings)
8 siblings, 1 reply; 21+ messages in thread
From: André Almeida @ 2025-08-13 22:36 UTC (permalink / raw)
To: Miklos Szeredi, Amir Goldstein, Theodore Tso,
Gabriel Krisman Bertazi
Cc: linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev, André Almeida
When merging layers from different filesystems with casefold enabled,
all layers should use the same encoding version and have the same flags
to avoid any kind of incompatibility issues.
Also, set the encoding and the encoding flags for the ovl super block as
the same as used by the first valid layer.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
Changes from v3:
- Check this restriction just when casefold is enabled
- Create new helper ovl_set_encoding() and change the logic a bit
---
fs/overlayfs/super.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index df85a76597e910d00323018f1d2cd720c5db921d..b1dbd3c79961094d00c7f99cc622e515d544d22f 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -991,6 +991,18 @@ static int ovl_get_data_fsid(struct ovl_fs *ofs)
return ofs->numfs;
}
+/*
+ * Set the ovl sb encoding as the same one used by the first layer
+ */
+static void ovl_set_encoding(struct super_block *sb, struct super_block *fs_sb)
+{
+#if IS_ENABLED(CONFIG_UNICODE)
+ if (sb_has_encoding(fs_sb)) {
+ sb->s_encoding = fs_sb->s_encoding;
+ sb->s_encoding_flags = fs_sb->s_encoding_flags;
+ }
+#endif
+}
static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
struct ovl_fs_context *ctx, struct ovl_layer *layers)
@@ -1024,6 +1036,9 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
if (ovl_upper_mnt(ofs)) {
ofs->fs[0].sb = ovl_upper_mnt(ofs)->mnt_sb;
ofs->fs[0].is_lower = false;
+
+ if (ofs->casefold)
+ ovl_set_encoding(sb, ofs->fs[0].sb);
}
nr_merged_lower = ctx->nr - ctx->nr_data;
@@ -1083,6 +1098,16 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
l->name = NULL;
ofs->numlayer++;
ofs->fs[fsid].is_lower = true;
+
+ if (ofs->casefold) {
+ if (!ovl_upper_mnt(ofs) && !sb_has_encoding(sb))
+ ovl_set_encoding(sb, ofs->fs[fsid].sb);
+
+ if (!sb_has_encoding(sb) || !sb_same_encoding(sb, mnt->mnt_sb)) {
+ pr_err("all layers must have the same encoding\n");
+ return -EINVAL;
+ }
+ }
}
/*
--
2.50.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 6/9] ovl: Set case-insensitive dentry operations for ovl sb
2025-08-13 22:36 [PATCH v4 0/9] ovl: Enable support for casefold filesystems André Almeida
` (4 preceding siblings ...)
2025-08-13 22:36 ` [PATCH v4 5/9] ovl: Ensure that all layers have the same encoding André Almeida
@ 2025-08-13 22:36 ` André Almeida
2025-08-14 12:57 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 7/9] ovl: Add S_CASEFOLD as part of the inode flag to be copied André Almeida
` (2 subsequent siblings)
8 siblings, 1 reply; 21+ messages in thread
From: André Almeida @ 2025-08-13 22:36 UTC (permalink / raw)
To: Miklos Szeredi, Amir Goldstein, Theodore Tso,
Gabriel Krisman Bertazi
Cc: linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev, André Almeida
For filesystems with encoding (i.e. with case-insensitive support), set
the dentry operations for the super block as ovl_dentry_ci_operations.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
Changes from v3:
- new helper ovl_set_d_op()
- encoding flags are now set in a step earlier
Changes from v2:
- Create ovl_dentry_ci_operations to not override dentry ops set by
ovl_dentry_operations
- Create a new function for this
- Instead of setting encoding just when there's a upper layer, set it
for any first layer (ofs->fs[0].sb), regardless of it being upper or
not.
---
fs/overlayfs/super.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index b1dbd3c79961094d00c7f99cc622e515d544d22f..a99c77802efa1a6d96c43019728d3517fccdc16a 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -161,6 +161,16 @@ static const struct dentry_operations ovl_dentry_operations = {
.d_weak_revalidate = ovl_dentry_weak_revalidate,
};
+#if IS_ENABLED(CONFIG_UNICODE)
+static const struct dentry_operations ovl_dentry_ci_operations = {
+ .d_real = ovl_d_real,
+ .d_revalidate = ovl_dentry_revalidate,
+ .d_weak_revalidate = ovl_dentry_weak_revalidate,
+ .d_hash = generic_ci_d_hash,
+ .d_compare = generic_ci_d_compare,
+};
+#endif
+
static struct kmem_cache *ovl_inode_cachep;
static struct inode *ovl_alloc_inode(struct super_block *sb)
@@ -1332,6 +1342,19 @@ static struct dentry *ovl_get_root(struct super_block *sb,
return root;
}
+static void ovl_set_d_op(struct super_block *sb)
+{
+ struct ovl_fs *ofs = sb->s_fs_info;
+
+#if IS_ENABLED(CONFIG_UNICODE)
+ if (ofs->casefold) {
+ set_default_d_op(sb, &ovl_dentry_ci_operations);
+ return;
+ }
+#endif
+ set_default_d_op(sb, &ovl_dentry_operations);
+}
+
int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct ovl_fs *ofs = sb->s_fs_info;
@@ -1443,6 +1466,8 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
if (IS_ERR(oe))
goto out_err;
+ ovl_set_d_op(sb);
+
/* If the upper fs is nonexistent, we mark overlayfs r/o too */
if (!ovl_upper_mnt(ofs))
sb->s_flags |= SB_RDONLY;
--
2.50.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 7/9] ovl: Add S_CASEFOLD as part of the inode flag to be copied
2025-08-13 22:36 [PATCH v4 0/9] ovl: Enable support for casefold filesystems André Almeida
` (5 preceding siblings ...)
2025-08-13 22:36 ` [PATCH v4 6/9] ovl: Set case-insensitive dentry operations for ovl sb André Almeida
@ 2025-08-13 22:36 ` André Almeida
2025-08-14 13:00 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 8/9] ovl: Check for casefold consistency when creating new dentries André Almeida
2025-08-13 22:36 ` [PATCH v4 9/9] ovl: Allow case-insensitive lookup André Almeida
8 siblings, 1 reply; 21+ messages in thread
From: André Almeida @ 2025-08-13 22:36 UTC (permalink / raw)
To: Miklos Szeredi, Amir Goldstein, Theodore Tso,
Gabriel Krisman Bertazi
Cc: linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev, André Almeida
To keep ovl's inodes consistent with their real inodes, create a new
mask for inode file attributes that needs to be copied. Add the
S_CASEFOLD flag as part of the flags that need to be copied along with
the other file attributes.
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
Changes from v3:
- Create new flag OVL_FATTR_I_FLAGS_MASK for the file attributes and add
S_CASEFOLD in the OVL_COPY_I_FLAGS_MASK.
- Add WARN()s to check for inode consistency
- Add check for copied up directories
Changes from v2:
- Instead of manually setting the flag if the realpath dentry is
casefolded, just add this flag as part of the flags that need to be
copied.
---
fs/overlayfs/copy_up.c | 2 +-
fs/overlayfs/inode.c | 1 +
fs/overlayfs/overlayfs.h | 8 +++++---
fs/overlayfs/super.c | 1 +
4 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 27396fe63f6d5b36143750443304a1f0856e2f56..66bd43a99d2e8548eecf21699a9a6b97e9454d79 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -670,7 +670,7 @@ static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp)
if (err)
return err;
- if (inode->i_flags & OVL_COPY_I_FLAGS_MASK &&
+ if (inode->i_flags & OVL_FATTR_I_FLAGS_MASK &&
(S_ISREG(c->stat.mode) || S_ISDIR(c->stat.mode))) {
/*
* Copy the fileattr inode flags that are the source of already
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index ecb9f2019395ecd01a124ad029375b1a1d13ebb5..aaa4cf579561299c50046f5ded03d93f056c370c 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -1277,6 +1277,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
}
ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev);
ovl_inode_init(inode, oip, ino, fsid);
+ WARN_ON_ONCE(!!IS_CASEFOLDED(inode) != ofs->casefold);
if (upperdentry && ovl_is_impuredir(sb, upperdentry))
ovl_set_flag(OVL_IMPURE, inode);
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index bb0d7ded8e763a4a7a6fc506d966ed2f3bdb4f06..50d550dd1b9d7841723880da85359e735bfc9277 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -821,10 +821,12 @@ struct inode *ovl_get_inode(struct super_block *sb,
struct ovl_inode_params *oip);
void ovl_copyattr(struct inode *to);
+/* vfs fileattr flags read from overlay.protattr xattr to ovl inode */
+#define OVL_PROT_I_FLAGS_MASK (S_APPEND | S_IMMUTABLE)
+/* vfs fileattr flags copied from real to ovl inode */
+#define OVL_FATTR_I_FLAGS_MASK (OVL_PROT_I_FLAGS_MASK | S_SYNC | S_NOATIME)
/* vfs inode flags copied from real to ovl inode */
-#define OVL_COPY_I_FLAGS_MASK (S_SYNC | S_NOATIME | S_APPEND | S_IMMUTABLE)
-/* vfs inode flags read from overlay.protattr xattr to ovl inode */
-#define OVL_PROT_I_FLAGS_MASK (S_APPEND | S_IMMUTABLE)
+#define OVL_COPY_I_FLAGS_MASK (OVL_FATTR_I_FLAGS_MASK | S_CASEFOLD)
/*
* fileattr flags copied from lower to upper inode on copy up.
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index a99c77802efa1a6d96c43019728d3517fccdc16a..7937aa4daa9c29e8b9219f7fcc2abe7fb55b2e5c 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -1335,6 +1335,7 @@ static struct dentry *ovl_get_root(struct super_block *sb,
ovl_dentry_set_flag(OVL_E_CONNECTED, root);
ovl_set_upperdata(d_inode(root));
ovl_inode_init(d_inode(root), &oip, ino, fsid);
+ WARN_ON(!!IS_CASEFOLDED(d_inode(root)) != ofs->casefold);
ovl_dentry_init_flags(root, upperdentry, oe, DCACHE_OP_WEAK_REVALIDATE);
/* root keeps a reference of upperdentry */
dget(upperdentry);
--
2.50.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 8/9] ovl: Check for casefold consistency when creating new dentries
2025-08-13 22:36 [PATCH v4 0/9] ovl: Enable support for casefold filesystems André Almeida
` (6 preceding siblings ...)
2025-08-13 22:36 ` [PATCH v4 7/9] ovl: Add S_CASEFOLD as part of the inode flag to be copied André Almeida
@ 2025-08-13 22:36 ` André Almeida
2025-08-14 13:06 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 9/9] ovl: Allow case-insensitive lookup André Almeida
8 siblings, 1 reply; 21+ messages in thread
From: André Almeida @ 2025-08-13 22:36 UTC (permalink / raw)
To: Miklos Szeredi, Amir Goldstein, Theodore Tso,
Gabriel Krisman Bertazi
Cc: linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev, André Almeida
In a overlayfs with casefold enabled, all new dentries should have
casefold enabled as well. Check this at ovl_create_real()
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
Changes from v3:
- New patch
---
fs/overlayfs/dir.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 70b8687dc45e8e33079c865ae302ac58464224a6..be8c5d02302de7a3ee63220a69f99a808fde3128 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -187,6 +187,11 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs, struct dentry *parent,
/* mkdir is special... */
newdentry = ovl_do_mkdir(ofs, dir, newdentry, attr->mode);
err = PTR_ERR_OR_ZERO(newdentry);
+ /* expect to inherit casefolding from workdir/upperdir */
+ if (!err && ofs->casefold != ovl_dentry_casefolded(newdentry)) {
+ dput(newdentry);
+ err = -EINVAL;
+ }
break;
case S_IFCHR:
--
2.50.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH v4 9/9] ovl: Allow case-insensitive lookup
2025-08-13 22:36 [PATCH v4 0/9] ovl: Enable support for casefold filesystems André Almeida
` (7 preceding siblings ...)
2025-08-13 22:36 ` [PATCH v4 8/9] ovl: Check for casefold consistency when creating new dentries André Almeida
@ 2025-08-13 22:36 ` André Almeida
2025-08-14 8:44 ` Amir Goldstein
8 siblings, 1 reply; 21+ messages in thread
From: André Almeida @ 2025-08-13 22:36 UTC (permalink / raw)
To: Miklos Szeredi, Amir Goldstein, Theodore Tso,
Gabriel Krisman Bertazi
Cc: linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev, André Almeida
Drop the restriction for casefold dentries lookup to enable support for
case-insensitive filesystems in overlayfs.
Support case-insensitive filesystems with the condition that they should
be uniformly enabled across the stack and the layers (i.e. if the root
mount dir has casefold enabled, so should all the dirs bellow for every
layer).
Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
Changes from v3:
- New patch, splited from the patch that creates ofs->casefold
---
fs/overlayfs/namei.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index 76d6248b625e7c58e09685e421aef616aadea40a..e93bcc5727bcafdc18a499b47a7609fd41ecaec8 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -239,13 +239,14 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
char val;
/*
- * We allow filesystems that are case-folding capable but deny composing
- * ovl stack from case-folded directories. If someone has enabled case
- * folding on a directory on underlying layer, the warranty of the ovl
- * stack is voided.
+ * We allow filesystems that are case-folding capable as long as the
+ * layers are consistently enabled in the stack, enabled for every dir
+ * or disabled in all dirs. If someone has modified case folding on a
+ * directory on underlying layer, the warranty of the ovl stack is
+ * voided.
*/
- if (ovl_dentry_casefolded(base)) {
- warn = "case folded parent";
+ if (ofs->casefold != ovl_dentry_casefolded(base)) {
+ warn = "parent wrong casefold";
err = -ESTALE;
goto out_warn;
}
@@ -259,8 +260,8 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
goto out_err;
}
- if (ovl_dentry_casefolded(this)) {
- warn = "case folded child";
+ if (ofs->casefold != ovl_dentry_casefolded(this)) {
+ warn = "child wrong casefold";
err = -EREMOTE;
goto out_warn;
}
--
2.50.1
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v4 1/9] ovl: Support mounting case-insensitive enabled filesystems
2025-08-13 22:36 ` [PATCH v4 1/9] ovl: Support mounting case-insensitive enabled filesystems André Almeida
@ 2025-08-14 8:35 ` Amir Goldstein
0 siblings, 0 replies; 21+ messages in thread
From: Amir Goldstein @ 2025-08-14 8:35 UTC (permalink / raw)
To: André Almeida
Cc: Miklos Szeredi, Theodore Tso, Gabriel Krisman Bertazi,
linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev
Hi Andre,
As a methodology in patch series, although they are often merged together
we want to abide by the concept of bisectability of the series, so it is not
good practice to "Support mounting case-insensitive enabled filesystems"
before this support is fully implemented.
Suggest to change the title of this patch to:
"ovl: Prepare for mounting case-insensitive enabled filesystems"
which implements the logic of enforcing "uniform casefolded layers"
but do not change ovl_dentry_weird() yet - do that in patch 9, so that
both lookup and mount of casefolded dirs are allowed together.
commit message need to be changed of course.
On Thu, Aug 14, 2025 at 12:37 AM André Almeida <andrealmeid@igalia.com> wrote:
>
> Enable mounting filesystems with case-insensitive dentries in order to
> support such filesystems in overlayfs.
>
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
> ---
> Changes from v3:
> - Move this patch to be ealier in the series
> - Split this patch with the ovl_lookup_single() restriction patch
> ---
> fs/overlayfs/ovl_entry.h | 1 +
> fs/overlayfs/params.c | 15 ++++++++++++---
> fs/overlayfs/params.h | 1 +
> fs/overlayfs/util.c | 8 ++++----
> 4 files changed, 18 insertions(+), 7 deletions(-)
>
> diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
> index 4c1bae935ced274f93a0d23fe10d34455e226ec4..1d4828dbcf7ac4ba9657221e601bbf79d970d225 100644
> --- a/fs/overlayfs/ovl_entry.h
> +++ b/fs/overlayfs/ovl_entry.h
> @@ -91,6 +91,7 @@ struct ovl_fs {
> struct mutex whiteout_lock;
> /* r/o snapshot of upperdir sb's only taken on volatile mounts */
> errseq_t errseq;
> + bool casefold;
> };
>
> /* Number of lower layers, not including data-only layers */
> diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c
> index f4e7fff909ac49e2f8c58a76273426c1158a7472..17d2354ba88d92e1d9653e8cb1382d860a7329c5 100644
> --- a/fs/overlayfs/params.c
> +++ b/fs/overlayfs/params.c
> @@ -277,16 +277,25 @@ static int ovl_mount_dir_check(struct fs_context *fc, const struct path *path,
> enum ovl_opt layer, const char *name, bool upper)
> {
> struct ovl_fs_context *ctx = fc->fs_private;
> + struct ovl_fs *ofs = fc->s_fs_info;
> + bool is_casefolded = ovl_dentry_casefolded(path->dentry);
>
> if (!d_is_dir(path->dentry))
> return invalfc(fc, "%s is not a directory", name);
>
> /*
> * Allow filesystems that are case-folding capable but deny composing
> - * ovl stack from case-folded directories.
> + * ovl stack from inconsistent case-folded directories.
> */
> - if (ovl_dentry_casefolded(path->dentry))
> - return invalfc(fc, "case-insensitive directory on %s not supported", name);
> + if (!ctx->casefold_set) {
> + ofs->casefold = is_casefolded;
> + ctx->casefold_set = true;
> + }
> +
> + if (ofs->casefold != is_casefolded) {
> + return invalfc(fc, "case-%ssensitive directory on %s is inconsistent",
> + is_casefolded ? "in" : "", name);
> + }
>
> if (ovl_dentry_weird(path->dentry))
> return invalfc(fc, "filesystem on %s not supported", name);
> diff --git a/fs/overlayfs/params.h b/fs/overlayfs/params.h
> index c96d939820211ddc63e265670a2aff60d95eec49..ffd53cdd84827cce827e8852f2de545f966ce60d 100644
> --- a/fs/overlayfs/params.h
> +++ b/fs/overlayfs/params.h
> @@ -33,6 +33,7 @@ struct ovl_fs_context {
> struct ovl_opt_set set;
> struct ovl_fs_context_layer *lower;
> char *lowerdir_all; /* user provided lowerdir string */
> + bool casefold_set;
> };
>
> int ovl_init_fs_context(struct fs_context *fc);
> diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
> index a33115e7384c129c543746326642813add63f060..7a6ee058568283453350153c1720c35e11ad4d1b 100644
> --- a/fs/overlayfs/util.c
> +++ b/fs/overlayfs/util.c
> @@ -210,11 +210,11 @@ bool ovl_dentry_weird(struct dentry *dentry)
> return true;
>
> /*
> - * Allow filesystems that are case-folding capable but deny composing
> - * ovl stack from case-folded directories.
> + * Exceptionally for casefold dentries, we accept that they have their
> + * own hash and compare operations
> */
> - if (sb_has_encoding(dentry->d_sb))
> - return IS_CASEFOLDED(d_inode(dentry));
> + if (ovl_dentry_casefolded(dentry))
> + return false;
>
> return dentry->d_flags & (DCACHE_OP_HASH | DCACHE_OP_COMPARE);
> }
Move relaxing of ovl_dentry_weird() to patch 9 please.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 9/9] ovl: Allow case-insensitive lookup
2025-08-13 22:36 ` [PATCH v4 9/9] ovl: Allow case-insensitive lookup André Almeida
@ 2025-08-14 8:44 ` Amir Goldstein
0 siblings, 0 replies; 21+ messages in thread
From: Amir Goldstein @ 2025-08-14 8:44 UTC (permalink / raw)
To: André Almeida
Cc: Miklos Szeredi, Theodore Tso, Gabriel Krisman Bertazi,
linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev
This last commit title should be like the title you gave patch 1:
ovl: Support mounting case-insensitive enabled layers
Because this is the commit that de-facto enabled the feature,
which is why I also asked to move the ovl_dentry_weird() change to this commit.
On Thu, Aug 14, 2025 at 12:37 AM André Almeida <andrealmeid@igalia.com> wrote:
>
> Drop the restriction for casefold dentries lookup to enable support for
> case-insensitive filesystems in overlayfs.
>
> Support case-insensitive filesystems
This is a problematic terminology
Please use the word "layers" instead of "filesystems" because casefolding is
not enabled at the filesystem level. Could also say "subtrees"
Same for the rest of the commit messages, e.g.
"ovl: Prepare for mounting case-insensitive enabled layers"
Thanks,
Amir.
> with the condition that they should
> be uniformly enabled across the stack and the layers (i.e. if the root
> mount dir has casefold enabled, so should all the dirs bellow for every
> layer).
>
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
> ---
> Changes from v3:
> - New patch, splited from the patch that creates ofs->casefold
> ---
> fs/overlayfs/namei.c | 17 +++++++++--------
> 1 file changed, 9 insertions(+), 8 deletions(-)
>
> diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
> index 76d6248b625e7c58e09685e421aef616aadea40a..e93bcc5727bcafdc18a499b47a7609fd41ecaec8 100644
> --- a/fs/overlayfs/namei.c
> +++ b/fs/overlayfs/namei.c
> @@ -239,13 +239,14 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
> char val;
>
> /*
> - * We allow filesystems that are case-folding capable but deny composing
> - * ovl stack from case-folded directories. If someone has enabled case
> - * folding on a directory on underlying layer, the warranty of the ovl
> - * stack is voided.
> + * We allow filesystems that are case-folding capable as long as the
> + * layers are consistently enabled in the stack, enabled for every dir
> + * or disabled in all dirs. If someone has modified case folding on a
> + * directory on underlying layer, the warranty of the ovl stack is
> + * voided.
> */
> - if (ovl_dentry_casefolded(base)) {
> - warn = "case folded parent";
> + if (ofs->casefold != ovl_dentry_casefolded(base)) {
> + warn = "parent wrong casefold";
> err = -ESTALE;
> goto out_warn;
> }
> @@ -259,8 +260,8 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
> goto out_err;
> }
>
> - if (ovl_dentry_casefolded(this)) {
> - warn = "case folded child";
> + if (ofs->casefold != ovl_dentry_casefolded(this)) {
> + warn = "child wrong casefold";
> err = -EREMOTE;
> goto out_warn;
> }
>
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 2/9] fs: Create new helper sb_encoding()
2025-08-13 22:36 ` [PATCH v4 2/9] fs: Create new helper sb_encoding() André Almeida
@ 2025-08-14 12:18 ` Amir Goldstein
0 siblings, 0 replies; 21+ messages in thread
From: Amir Goldstein @ 2025-08-14 12:18 UTC (permalink / raw)
To: André Almeida
Cc: Miklos Szeredi, Theodore Tso, Gabriel Krisman Bertazi,
linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev
On Thu, Aug 14, 2025 at 12:37 AM André Almeida <andrealmeid@igalia.com> wrote:
>
> Filesystems that need to deal with the super block encoding need to use
> a if IS_ENABLED(CONFIG_UNICODE) around it because this struct member is
> not declared otherwise. In order to move this if/endif guards outside of
> the filesytem code and make it simpler, create a new function that
> returns the s_encoding member of struct super_block if Unicode is
> enabled, and return NULL otherwise.
>
> Suggested-by: Amir Goldstein <amir73il@gmail.com>
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Andre,
I know I suggested starting the series with ofs->casefold patch,
but I meant the ovl patches series.
The two vfs helper patches should come before the ovl patches,
because Christian might prefer to carry them separately via vfs tree.
Thanks,
Amir.
> ---
> Changes from v3:
> - New patch
> ---
> include/linux/fs.h | 11 ++++++++---
> 1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 796319914b0a063642c2bd0c0140697a0eb651f6..20102d81e18a59d5daaed06855d1f168979b4fa7 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -3739,15 +3739,20 @@ static inline bool generic_ci_validate_strict_name(struct inode *dir, struct qst
> }
> #endif
>
> -static inline bool sb_has_encoding(const struct super_block *sb)
> +static inline struct unicode_map *sb_encoding(const struct super_block *sb)
> {
> #if IS_ENABLED(CONFIG_UNICODE)
> - return !!sb->s_encoding;
> + return sb->s_encoding;
> #else
> - return false;
> + return NULL;
> #endif
> }
>
> +static inline bool sb_has_encoding(const struct super_block *sb)
> +{
> + return !!sb_encoding(sb);
> +}
> +
> int may_setattr(struct mnt_idmap *idmap, struct inode *inode,
> unsigned int ia_valid);
> int setattr_prepare(struct mnt_idmap *, struct dentry *, struct iattr *);
>
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 4/9] fs: Create sb_same_encoding() helper
2025-08-13 22:36 ` [PATCH v4 4/9] fs: Create sb_same_encoding() helper André Almeida
@ 2025-08-14 12:19 ` Amir Goldstein
0 siblings, 0 replies; 21+ messages in thread
From: Amir Goldstein @ 2025-08-14 12:19 UTC (permalink / raw)
To: André Almeida
Cc: Miklos Szeredi, Theodore Tso, Gabriel Krisman Bertazi,
linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev
On Thu, Aug 14, 2025 at 12:37 AM André Almeida <andrealmeid@igalia.com> wrote:
>
> For cases where a file lookup can look in different filesystems (like in
> overlayfs), both super blocks must have the same encoding and the same
> flags. To help with that, create a sb_same_encoding() function.
>
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
please reorder vfs patches before ovl patches
> Changes from v3:
> - Improve wording
>
> Changes from v2:
> - Simplify the code. Instead of `if (cond) return true`, just do `return
> cond`;
> ---
> include/linux/fs.h | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
>
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 20102d81e18a59d5daaed06855d1f168979b4fa7..64d24e89bc5593915158b40f0442e6d8ef3d968d 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -3753,6 +3753,24 @@ static inline bool sb_has_encoding(const struct super_block *sb)
> return !!sb_encoding(sb);
> }
>
> +/*
> + * Compare if two super blocks have the same encoding and flags
> + */
> +static inline bool sb_same_encoding(const struct super_block *sb1,
> + const struct super_block *sb2)
> +{
> +#if IS_ENABLED(CONFIG_UNICODE)
> + if (sb1->s_encoding == sb2->s_encoding)
> + return true;
> +
> + return (sb1->s_encoding && sb2->s_encoding &&
> + (sb1->s_encoding->version == sb2->s_encoding->version) &&
> + (sb1->s_encoding_flags == sb2->s_encoding_flags));
> +#else
> + return true;
> +#endif
> +}
> +
> int may_setattr(struct mnt_idmap *idmap, struct inode *inode,
> unsigned int ia_valid);
> int setattr_prepare(struct mnt_idmap *, struct dentry *, struct iattr *);
>
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 3/9] ovl: Create ovl_casefold() to support casefolded strncmp()
2025-08-13 22:36 ` [PATCH v4 3/9] ovl: Create ovl_casefold() to support casefolded strncmp() André Almeida
@ 2025-08-14 12:53 ` Amir Goldstein
2025-08-14 13:02 ` André Almeida
0 siblings, 1 reply; 21+ messages in thread
From: Amir Goldstein @ 2025-08-14 12:53 UTC (permalink / raw)
To: André Almeida
Cc: Miklos Szeredi, Theodore Tso, Gabriel Krisman Bertazi,
linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev
On Thu, Aug 14, 2025 at 12:37 AM André Almeida <andrealmeid@igalia.com> wrote:
>
> To add overlayfs support casefold filesystems, create a new function
> ovl_casefold(), to be able to do case-insensitive strncmp().
>
> ovl_casefold() allocates a new buffer and stores the casefolded version
> of the string on it. If the allocation or the casefold operation fails,
> fallback to use the original string.
>
> The case-insentive name is then used in the rb-tree search/insertion
> operation. If the name is found in the rb-tree, the name can be
> discarded and the buffer is freed. If the name isn't found, it's then
> stored at struct ovl_cache_entry to be used later.
>
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
> ---
> Changes from v3:
> - Improve commit message text
> - s/OVL_NAME_LEN/NAME_MAX
> - drop #ifdef in favor of if(IS_ENABLED)
> - use new helper sb_encoding
> - merged patch "Store casefold name..." and "Create ovl_casefold()..."
> - Guard all the casefolding inside of IS_ENABLED(UNICODE)
>
> Changes from v2:
> - Refactor the patch to do a single kmalloc() per rb_tree operation
> - Instead of casefolding the cache entry name everytime per strncmp(),
> casefold it once and reuse it for every strncmp().
> ---
> fs/overlayfs/readdir.c | 99 ++++++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 87 insertions(+), 12 deletions(-)
>
> diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
> index b65cdfce31ce27172d28d879559f1008b9c87320..3d92c0b407fe355053ca80ef999d3520eb7d2462 100644
> --- a/fs/overlayfs/readdir.c
> +++ b/fs/overlayfs/readdir.c
> @@ -27,6 +27,8 @@ struct ovl_cache_entry {
> bool is_upper;
> bool is_whiteout;
> bool check_xwhiteout;
> + const char *cf_name;
> + int cf_len;
> char name[];
> };
>
> @@ -45,6 +47,7 @@ struct ovl_readdir_data {
> struct list_head *list;
> struct list_head middle;
> struct ovl_cache_entry *first_maybe_whiteout;
> + struct unicode_map *map;
> int count;
> int err;
> bool is_upper;
> @@ -66,6 +69,27 @@ static struct ovl_cache_entry *ovl_cache_entry_from_node(struct rb_node *n)
> return rb_entry(n, struct ovl_cache_entry, node);
> }
>
> +static int ovl_casefold(struct unicode_map *map, const char *str, int len, char **dst)
> +{
> + const struct qstr qstr = { .name = str, .len = len };
> + int cf_len;
> +
> + if (!IS_ENABLED(CONFIG_UNICODE) || !map || is_dot_dotdot(str, len))
> + return 0;
> +
> + *dst = kmalloc(NAME_MAX, GFP_KERNEL);
> +
> + if (dst) {
> + cf_len = utf8_casefold(map, &qstr, *dst, NAME_MAX);
> +
> + if (cf_len > 0)
> + return cf_len;
> + }
> +
> + kfree(*dst);
> + return 0;
> +}
> +
> static bool ovl_cache_entry_find_link(const char *name, int len,
> struct rb_node ***link,
> struct rb_node **parent)
> @@ -79,7 +103,7 @@ static bool ovl_cache_entry_find_link(const char *name, int len,
>
> *parent = *newp;
> tmp = ovl_cache_entry_from_node(*newp);
> - cmp = strncmp(name, tmp->name, len);
> + cmp = strncmp(name, tmp->cf_name, tmp->cf_len);
> if (cmp > 0)
> newp = &tmp->node.rb_right;
> else if (cmp < 0 || len < tmp->len)
> @@ -101,7 +125,7 @@ static struct ovl_cache_entry *ovl_cache_entry_find(struct rb_root *root,
> while (node) {
> struct ovl_cache_entry *p = ovl_cache_entry_from_node(node);
>
> - cmp = strncmp(name, p->name, len);
> + cmp = strncmp(name, p->cf_name, p->cf_len);
> if (cmp > 0)
> node = p->node.rb_right;
> else if (cmp < 0 || len < p->len)
> @@ -145,13 +169,16 @@ static bool ovl_calc_d_ino(struct ovl_readdir_data *rdd,
>
> static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd,
> const char *name, int len,
> + const char *cf_name, int cf_len,
> u64 ino, unsigned int d_type)
> {
> struct ovl_cache_entry *p;
>
> p = kmalloc(struct_size(p, name, len + 1), GFP_KERNEL);
> - if (!p)
> + if (!p) {
> + kfree(cf_name);
> return NULL;
> + }
>
> memcpy(p->name, name, len);
> p->name[len] = '\0';
> @@ -167,6 +194,14 @@ static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd,
> /* Defer check for overlay.whiteout to ovl_iterate() */
> p->check_xwhiteout = rdd->in_xwhiteouts_dir && d_type == DT_REG;
>
> + if (cf_name && cf_name != name) {
> + p->cf_name = cf_name;
> + p->cf_len = cf_len;
> + } else {
> + p->cf_name = p->name;
> + p->cf_len = len;
> + }
> +
> if (d_type == DT_CHR) {
> p->next_maybe_whiteout = rdd->first_maybe_whiteout;
> rdd->first_maybe_whiteout = p;
> @@ -175,17 +210,24 @@ static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd,
> }
>
> static bool ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
> - const char *name, int len, u64 ino,
> + const char *name, int len,
> + const char *cf_name, int cf_len,
> + u64 ino,
> unsigned int d_type)
> {
> struct rb_node **newp = &rdd->root->rb_node;
> struct rb_node *parent = NULL;
> struct ovl_cache_entry *p;
>
> - if (ovl_cache_entry_find_link(name, len, &newp, &parent))
> + if (ovl_cache_entry_find_link(cf_name, cf_len, &newp, &parent)) {
> + if (cf_name != name) {
> + kfree(cf_name);
> + cf_name = NULL;
> + }
No use of setting cf_name to NULL here.
Please include comment to explain this free (as you did in commit message)
> return true;
> + }
>
> - p = ovl_cache_entry_new(rdd, name, len, ino, d_type);
> + p = ovl_cache_entry_new(rdd, name, len, cf_name, cf_len, ino, d_type);
> if (p == NULL) {
> rdd->err = -ENOMEM;
> return false;
> @@ -200,15 +242,21 @@ static bool ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
>
> static bool ovl_fill_lowest(struct ovl_readdir_data *rdd,
> const char *name, int namelen,
> + const char *cf_name, int cf_len,
> loff_t offset, u64 ino, unsigned int d_type)
> {
> struct ovl_cache_entry *p;
>
> - p = ovl_cache_entry_find(rdd->root, name, namelen);
> + p = ovl_cache_entry_find(rdd->root, cf_name, cf_len);
> if (p) {
> list_move_tail(&p->l_node, &rdd->middle);
> + if (cf_name != name) {
> + kfree(cf_name);
> + cf_name = NULL;
No use of setting cf_name to NULL here.
Please include comment to explain this free (as you did in commit message)
> + }
> } else {
> - p = ovl_cache_entry_new(rdd, name, namelen, ino, d_type);
> + p = ovl_cache_entry_new(rdd, name, namelen, cf_name, cf_len,
> + ino, d_type);
> if (p == NULL)
> rdd->err = -ENOMEM;
> else
> @@ -223,8 +271,11 @@ void ovl_cache_free(struct list_head *list)
> struct ovl_cache_entry *p;
> struct ovl_cache_entry *n;
>
> - list_for_each_entry_safe(p, n, list, l_node)
> + list_for_each_entry_safe(p, n, list, l_node) {
> + if (p->cf_name != p->name)
> + kfree(p->cf_name);
> kfree(p);
> + }
>
> INIT_LIST_HEAD(list);
> }
> @@ -260,12 +311,28 @@ static bool ovl_fill_merge(struct dir_context *ctx, const char *name,
> {
> struct ovl_readdir_data *rdd =
> container_of(ctx, struct ovl_readdir_data, ctx);
> + struct ovl_fs *ofs = OVL_FS(rdd->dentry->d_sb);
> + const char *aux = NULL;
It looks strange to me that you need aux
and it looks strange to pair <aux, cf_len>
neither here or there...
> + char *cf_name = NULL;
> + int cf_len = 0;
> +
> + if (ofs->casefold)
> + cf_len = ovl_casefold(rdd->map, name, namelen, &cf_name);
> +
> + if (cf_len <= 0) {
> + aux = name;
why not:
cf_name = name;
> + cf_len = namelen;
> + } else {
> + aux = cf_name;
> + }
and no aux and no else needed at all?
If you don't like a var named cf_name to point at a non-casefolded
name buffer, then use other var names which are consistent such as
<c_name, c_len> (c for "canonical" or "compare" name).
>
> rdd->count++;
> if (!rdd->is_lowest)
> - return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type);
> + return ovl_cache_entry_add_rb(rdd, name, namelen, aux, cf_len,
> + ino, d_type);
> else
> - return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
> + return ovl_fill_lowest(rdd, name, namelen, aux, cf_len,
> + offset, ino, d_type);
> }
>
What do you think about moving all the consume/free buffer logic out to caller:
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index b65cdfce31ce..e77530c63207 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -174,7 +174,8 @@ static struct ovl_cache_entry
*ovl_cache_entry_new(struct ovl_readdir_data *rdd,
return p;
}
-static bool ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
+/* Return 0 for found, >0 for added, <0 for error */
+static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
const char *name, int len, u64 ino,
unsigned int d_type)
{
@@ -183,22 +184,23 @@ static bool ovl_cache_entry_add_rb(struct
ovl_readdir_data *rdd,
struct ovl_cache_entry *p;
if (ovl_cache_entry_find_link(name, len, &newp, &parent))
- return true;
+ return 0;
p = ovl_cache_entry_new(rdd, name, len, ino, d_type);
if (p == NULL) {
rdd->err = -ENOMEM;
- return false;
+ return -ENOMEM;
}
list_add_tail(&p->l_node, rdd->list);
rb_link_node(&p->node, parent, newp);
rb_insert_color(&p->node, rdd->root);
- return true;
+ return 1;
}
-static bool ovl_fill_lowest(struct ovl_readdir_data *rdd,
+/* Return 0 for found, >0 for added, <0 for error */
+static int ovl_fill_lowest(struct ovl_readdir_data *rdd,
const char *name, int namelen,
loff_t offset, u64 ino, unsigned int d_type)
{
@@ -207,6 +209,7 @@ static bool ovl_fill_lowest(struct ovl_readdir_data *rdd,
p = ovl_cache_entry_find(rdd->root, name, namelen);
if (p) {
list_move_tail(&p->l_node, &rdd->middle);
+ return 0;
} else {
p = ovl_cache_entry_new(rdd, name, namelen, ino, d_type);
if (p == NULL)
@@ -215,7 +218,7 @@ static bool ovl_fill_lowest(struct ovl_readdir_data *rdd,
list_add_tail(&p->l_node, &rdd->middle);
}
- return rdd->err == 0;
+ return rdd->err ?: 1;
}
@@ -260,12 +263,31 @@ static bool ovl_fill_merge(struct dir_context
*ctx, const char *name,
{
struct ovl_readdir_data *rdd =
container_of(ctx, struct ovl_readdir_data, ctx);
+ struct ovl_fs *ofs = OVL_FS(rdd->dentry->d_sb);
+ char *c_name = NULL;
+ int c_len = 0;
+ int ret;
+
+ if (ofs->casefold)
+ c_len = ovl_casefold(rdd->map, name, namelen, &c_name);
+
+ if (c_len <= 0) {
+ c_name = name;
+ c_len = namelen;
+ }
rdd->count++;
- if (!rdd->is_lowest)
- return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type);
- else
- return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
+ if (!rdd->is_lowest) {
+ ret = ovl_cache_entry_add_rb(rdd, name, namelen, c_name, c_len,
+ ino, d_type);
+ } else {
+ ret = ovl_fill_lowest(rdd, name, namelen, c_name, c_len, offset,
+ ino, d_type);
+ }
+ // ret > 1 means c_name is consumed
+ if (ret <= 0 && c_len > 0)
+ kfree(c_name);
+ return ret >= 0;
}
Thanks,
Amir.
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH v4 5/9] ovl: Ensure that all layers have the same encoding
2025-08-13 22:36 ` [PATCH v4 5/9] ovl: Ensure that all layers have the same encoding André Almeida
@ 2025-08-14 12:56 ` Amir Goldstein
0 siblings, 0 replies; 21+ messages in thread
From: Amir Goldstein @ 2025-08-14 12:56 UTC (permalink / raw)
To: André Almeida
Cc: Miklos Szeredi, Theodore Tso, Gabriel Krisman Bertazi,
linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev
On Thu, Aug 14, 2025 at 12:37 AM André Almeida <andrealmeid@igalia.com> wrote:
>
> When merging layers from different filesystems with casefold enabled,
> all layers should use the same encoding version and have the same flags
> to avoid any kind of incompatibility issues.
>
> Also, set the encoding and the encoding flags for the ovl super block as
> the same as used by the first valid layer.
>
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> ---
> Changes from v3:
> - Check this restriction just when casefold is enabled
> - Create new helper ovl_set_encoding() and change the logic a bit
> ---
> fs/overlayfs/super.c | 25 +++++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
>
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index df85a76597e910d00323018f1d2cd720c5db921d..b1dbd3c79961094d00c7f99cc622e515d544d22f 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -991,6 +991,18 @@ static int ovl_get_data_fsid(struct ovl_fs *ofs)
> return ofs->numfs;
> }
>
> +/*
> + * Set the ovl sb encoding as the same one used by the first layer
> + */
> +static void ovl_set_encoding(struct super_block *sb, struct super_block *fs_sb)
> +{
> +#if IS_ENABLED(CONFIG_UNICODE)
> + if (sb_has_encoding(fs_sb)) {
> + sb->s_encoding = fs_sb->s_encoding;
> + sb->s_encoding_flags = fs_sb->s_encoding_flags;
> + }
> +#endif
> +}
>
> static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
> struct ovl_fs_context *ctx, struct ovl_layer *layers)
> @@ -1024,6 +1036,9 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
> if (ovl_upper_mnt(ofs)) {
> ofs->fs[0].sb = ovl_upper_mnt(ofs)->mnt_sb;
> ofs->fs[0].is_lower = false;
> +
> + if (ofs->casefold)
> + ovl_set_encoding(sb, ofs->fs[0].sb);
> }
>
> nr_merged_lower = ctx->nr - ctx->nr_data;
> @@ -1083,6 +1098,16 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
> l->name = NULL;
> ofs->numlayer++;
> ofs->fs[fsid].is_lower = true;
> +
> + if (ofs->casefold) {
> + if (!ovl_upper_mnt(ofs) && !sb_has_encoding(sb))
> + ovl_set_encoding(sb, ofs->fs[fsid].sb);
> +
> + if (!sb_has_encoding(sb) || !sb_same_encoding(sb, mnt->mnt_sb)) {
> + pr_err("all layers must have the same encoding\n");
> + return -EINVAL;
> + }
> + }
> }
>
> /*
>
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 6/9] ovl: Set case-insensitive dentry operations for ovl sb
2025-08-13 22:36 ` [PATCH v4 6/9] ovl: Set case-insensitive dentry operations for ovl sb André Almeida
@ 2025-08-14 12:57 ` Amir Goldstein
0 siblings, 0 replies; 21+ messages in thread
From: Amir Goldstein @ 2025-08-14 12:57 UTC (permalink / raw)
To: André Almeida
Cc: Miklos Szeredi, Theodore Tso, Gabriel Krisman Bertazi,
linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev
On Thu, Aug 14, 2025 at 12:37 AM André Almeida <andrealmeid@igalia.com> wrote:
>
> For filesystems with encoding (i.e. with case-insensitive support), set
> the dentry operations for the super block as ovl_dentry_ci_operations.
>
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> ---
> Changes from v3:
> - new helper ovl_set_d_op()
> - encoding flags are now set in a step earlier
>
> Changes from v2:
> - Create ovl_dentry_ci_operations to not override dentry ops set by
> ovl_dentry_operations
> - Create a new function for this
> - Instead of setting encoding just when there's a upper layer, set it
> for any first layer (ofs->fs[0].sb), regardless of it being upper or
> not.
> ---
> fs/overlayfs/super.c | 25 +++++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
>
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index b1dbd3c79961094d00c7f99cc622e515d544d22f..a99c77802efa1a6d96c43019728d3517fccdc16a 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -161,6 +161,16 @@ static const struct dentry_operations ovl_dentry_operations = {
> .d_weak_revalidate = ovl_dentry_weak_revalidate,
> };
>
> +#if IS_ENABLED(CONFIG_UNICODE)
> +static const struct dentry_operations ovl_dentry_ci_operations = {
> + .d_real = ovl_d_real,
> + .d_revalidate = ovl_dentry_revalidate,
> + .d_weak_revalidate = ovl_dentry_weak_revalidate,
> + .d_hash = generic_ci_d_hash,
> + .d_compare = generic_ci_d_compare,
> +};
> +#endif
> +
> static struct kmem_cache *ovl_inode_cachep;
>
> static struct inode *ovl_alloc_inode(struct super_block *sb)
> @@ -1332,6 +1342,19 @@ static struct dentry *ovl_get_root(struct super_block *sb,
> return root;
> }
>
> +static void ovl_set_d_op(struct super_block *sb)
> +{
> + struct ovl_fs *ofs = sb->s_fs_info;
> +
> +#if IS_ENABLED(CONFIG_UNICODE)
> + if (ofs->casefold) {
> + set_default_d_op(sb, &ovl_dentry_ci_operations);
> + return;
> + }
> +#endif
> + set_default_d_op(sb, &ovl_dentry_operations);
> +}
> +
> int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
> {
> struct ovl_fs *ofs = sb->s_fs_info;
> @@ -1443,6 +1466,8 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
> if (IS_ERR(oe))
> goto out_err;
>
> + ovl_set_d_op(sb);
> +
> /* If the upper fs is nonexistent, we mark overlayfs r/o too */
> if (!ovl_upper_mnt(ofs))
> sb->s_flags |= SB_RDONLY;
>
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 7/9] ovl: Add S_CASEFOLD as part of the inode flag to be copied
2025-08-13 22:36 ` [PATCH v4 7/9] ovl: Add S_CASEFOLD as part of the inode flag to be copied André Almeida
@ 2025-08-14 13:00 ` Amir Goldstein
0 siblings, 0 replies; 21+ messages in thread
From: Amir Goldstein @ 2025-08-14 13:00 UTC (permalink / raw)
To: André Almeida
Cc: Miklos Szeredi, Theodore Tso, Gabriel Krisman Bertazi,
linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev
On Thu, Aug 14, 2025 at 12:37 AM André Almeida <andrealmeid@igalia.com> wrote:
>
> To keep ovl's inodes consistent with their real inodes, create a new
> mask for inode file attributes that needs to be copied. Add the
> S_CASEFOLD flag as part of the flags that need to be copied along with
> the other file attributes.
>
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
> ---
> Changes from v3:
> - Create new flag OVL_FATTR_I_FLAGS_MASK for the file attributes and add
> S_CASEFOLD in the OVL_COPY_I_FLAGS_MASK.
> - Add WARN()s to check for inode consistency
> - Add check for copied up directories
>
> Changes from v2:
> - Instead of manually setting the flag if the realpath dentry is
> casefolded, just add this flag as part of the flags that need to be
> copied.
> ---
> fs/overlayfs/copy_up.c | 2 +-
> fs/overlayfs/inode.c | 1 +
> fs/overlayfs/overlayfs.h | 8 +++++---
> fs/overlayfs/super.c | 1 +
> 4 files changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
> index 27396fe63f6d5b36143750443304a1f0856e2f56..66bd43a99d2e8548eecf21699a9a6b97e9454d79 100644
> --- a/fs/overlayfs/copy_up.c
> +++ b/fs/overlayfs/copy_up.c
> @@ -670,7 +670,7 @@ static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp)
> if (err)
> return err;
>
> - if (inode->i_flags & OVL_COPY_I_FLAGS_MASK &&
> + if (inode->i_flags & OVL_FATTR_I_FLAGS_MASK &&
> (S_ISREG(c->stat.mode) || S_ISDIR(c->stat.mode))) {
> /*
> * Copy the fileattr inode flags that are the source of already
> diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
> index ecb9f2019395ecd01a124ad029375b1a1d13ebb5..aaa4cf579561299c50046f5ded03d93f056c370c 100644
> --- a/fs/overlayfs/inode.c
> +++ b/fs/overlayfs/inode.c
> @@ -1277,6 +1277,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
> }
> ovl_fill_inode(inode, realinode->i_mode, realinode->i_rdev);
> ovl_inode_init(inode, oip, ino, fsid);
> + WARN_ON_ONCE(!!IS_CASEFOLDED(inode) != ofs->casefold);
>
> if (upperdentry && ovl_is_impuredir(sb, upperdentry))
> ovl_set_flag(OVL_IMPURE, inode);
> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
> index bb0d7ded8e763a4a7a6fc506d966ed2f3bdb4f06..50d550dd1b9d7841723880da85359e735bfc9277 100644
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -821,10 +821,12 @@ struct inode *ovl_get_inode(struct super_block *sb,
> struct ovl_inode_params *oip);
> void ovl_copyattr(struct inode *to);
>
> +/* vfs fileattr flags read from overlay.protattr xattr to ovl inode */
> +#define OVL_PROT_I_FLAGS_MASK (S_APPEND | S_IMMUTABLE)
> +/* vfs fileattr flags copied from real to ovl inode */
> +#define OVL_FATTR_I_FLAGS_MASK (OVL_PROT_I_FLAGS_MASK | S_SYNC | S_NOATIME)
> /* vfs inode flags copied from real to ovl inode */
> -#define OVL_COPY_I_FLAGS_MASK (S_SYNC | S_NOATIME | S_APPEND | S_IMMUTABLE)
> -/* vfs inode flags read from overlay.protattr xattr to ovl inode */
> -#define OVL_PROT_I_FLAGS_MASK (S_APPEND | S_IMMUTABLE)
> +#define OVL_COPY_I_FLAGS_MASK (OVL_FATTR_I_FLAGS_MASK | S_CASEFOLD)
>
> /*
> * fileattr flags copied from lower to upper inode on copy up.
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index a99c77802efa1a6d96c43019728d3517fccdc16a..7937aa4daa9c29e8b9219f7fcc2abe7fb55b2e5c 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -1335,6 +1335,7 @@ static struct dentry *ovl_get_root(struct super_block *sb,
> ovl_dentry_set_flag(OVL_E_CONNECTED, root);
> ovl_set_upperdata(d_inode(root));
> ovl_inode_init(d_inode(root), &oip, ino, fsid);
> + WARN_ON(!!IS_CASEFOLDED(d_inode(root)) != ofs->casefold);
> ovl_dentry_init_flags(root, upperdentry, oe, DCACHE_OP_WEAK_REVALIDATE);
> /* root keeps a reference of upperdentry */
> dget(upperdentry);
>
> --
> 2.50.1
>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 3/9] ovl: Create ovl_casefold() to support casefolded strncmp()
2025-08-14 12:53 ` Amir Goldstein
@ 2025-08-14 13:02 ` André Almeida
2025-08-14 13:20 ` Amir Goldstein
0 siblings, 1 reply; 21+ messages in thread
From: André Almeida @ 2025-08-14 13:02 UTC (permalink / raw)
To: Amir Goldstein
Cc: Miklos Szeredi, Theodore Tso, Gabriel Krisman Bertazi,
linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev
Hi Amir,
Em 14/08/2025 09:53, Amir Goldstein escreveu:
> On Thu, Aug 14, 2025 at 12:37 AM André Almeida <andrealmeid@igalia.com> wrote:
>>
>> To add overlayfs support casefold filesystems, create a new function
>> ovl_casefold(), to be able to do case-insensitive strncmp().
>>
>> ovl_casefold() allocates a new buffer and stores the casefolded version
>> of the string on it. If the allocation or the casefold operation fails,
>> fallback to use the original string.
>>
>> The case-insentive name is then used in the rb-tree search/insertion
>> operation. If the name is found in the rb-tree, the name can be
>> discarded and the buffer is freed. If the name isn't found, it's then
>> stored at struct ovl_cache_entry to be used later.
>>
>> Signed-off-by: André Almeida <andrealmeid@igalia.com>
>> ---
[...]
>> + }
>>
>> INIT_LIST_HEAD(list);
>> }
>> @@ -260,12 +311,28 @@ static bool ovl_fill_merge(struct dir_context *ctx, const char *name,
>> {
>> struct ovl_readdir_data *rdd =
>> container_of(ctx, struct ovl_readdir_data, ctx);
>> + struct ovl_fs *ofs = OVL_FS(rdd->dentry->d_sb);
>> + const char *aux = NULL;
>
> It looks strange to me that you need aux
> and it looks strange to pair <aux, cf_len>
> neither here or there...
>
The reason behind this `aux` var is because I need a `const char`
pointer to point to the `name` argument, and `cf_name` can't be const
because it goes through ovl_casefold(). I tried a couple approaches here
to get rid of the compiler warning regarding const, and the only way I
managed to was using a third variable like that.
>> + char *cf_name = NULL;
>> + int cf_len = 0;
>> +
>> + if (ofs->casefold)
>> + cf_len = ovl_casefold(rdd->map, name, namelen, &cf_name);
>> +
>> + if (cf_len <= 0) {
>> + aux = name;
>
> why not:
> cf_name = name;
>
>> + cf_len = namelen;
>> + } else {
>> + aux = cf_name;
>> + }
>
> and no aux and no else needed at all?
>
> If you don't like a var named cf_name to point at a non-casefolded
> name buffer, then use other var names which are consistent such as
> <c_name, c_len> (c for "canonical" or "compare" name).
>
>>
>> rdd->count++;
>> if (!rdd->is_lowest)
>> - return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type);
>> + return ovl_cache_entry_add_rb(rdd, name, namelen, aux, cf_len,
>> + ino, d_type);
>> else
>> - return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
>> + return ovl_fill_lowest(rdd, name, namelen, aux, cf_len,
>> + offset, ino, d_type);
>> }
>>
>
> What do you think about moving all the consume/free buffer logic out to caller:
>
That looks way cleaner to me, thanks! I will apply this approach for v5.
> diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
> index b65cdfce31ce..e77530c63207 100644
> --- a/fs/overlayfs/readdir.c
> +++ b/fs/overlayfs/readdir.c
> @@ -174,7 +174,8 @@ static struct ovl_cache_entry
> *ovl_cache_entry_new(struct ovl_readdir_data *rdd,
> return p;
> }
>
> -static bool ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
> +/* Return 0 for found, >0 for added, <0 for error */
> +static int ovl_cache_entry_add_rb(struct ovl_readdir_data *rdd,
> const char *name, int len, u64 ino,
> unsigned int d_type)
> {
> @@ -183,22 +184,23 @@ static bool ovl_cache_entry_add_rb(struct
> ovl_readdir_data *rdd,
> struct ovl_cache_entry *p;
>
> if (ovl_cache_entry_find_link(name, len, &newp, &parent))
> - return true;
> + return 0;
>
> p = ovl_cache_entry_new(rdd, name, len, ino, d_type);
> if (p == NULL) {
> rdd->err = -ENOMEM;
> - return false;
> + return -ENOMEM;
> }
>
> list_add_tail(&p->l_node, rdd->list);
> rb_link_node(&p->node, parent, newp);
> rb_insert_color(&p->node, rdd->root);
>
> - return true;
> + return 1;
> }
>
> -static bool ovl_fill_lowest(struct ovl_readdir_data *rdd,
> +/* Return 0 for found, >0 for added, <0 for error */
> +static int ovl_fill_lowest(struct ovl_readdir_data *rdd,
> const char *name, int namelen,
> loff_t offset, u64 ino, unsigned int d_type)
> {
> @@ -207,6 +209,7 @@ static bool ovl_fill_lowest(struct ovl_readdir_data *rdd,
> p = ovl_cache_entry_find(rdd->root, name, namelen);
> if (p) {
> list_move_tail(&p->l_node, &rdd->middle);
> + return 0;
> } else {
> p = ovl_cache_entry_new(rdd, name, namelen, ino, d_type);
> if (p == NULL)
> @@ -215,7 +218,7 @@ static bool ovl_fill_lowest(struct ovl_readdir_data *rdd,
> list_add_tail(&p->l_node, &rdd->middle);
> }
>
> - return rdd->err == 0;
> + return rdd->err ?: 1;
> }
>
> @@ -260,12 +263,31 @@ static bool ovl_fill_merge(struct dir_context
> *ctx, const char *name,
> {
> struct ovl_readdir_data *rdd =
> container_of(ctx, struct ovl_readdir_data, ctx);
> + struct ovl_fs *ofs = OVL_FS(rdd->dentry->d_sb);
> + char *c_name = NULL;
> + int c_len = 0;
> + int ret;
> +
> + if (ofs->casefold)
> + c_len = ovl_casefold(rdd->map, name, namelen, &c_name);
> +
> + if (c_len <= 0) {
> + c_name = name;
> + c_len = namelen;
> + }
>
> rdd->count++;
> - if (!rdd->is_lowest)
> - return ovl_cache_entry_add_rb(rdd, name, namelen, ino, d_type);
> - else
> - return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
> + if (!rdd->is_lowest) {
> + ret = ovl_cache_entry_add_rb(rdd, name, namelen, c_name, c_len,
> + ino, d_type);
> + } else {
> + ret = ovl_fill_lowest(rdd, name, namelen, c_name, c_len, offset,
> + ino, d_type);
> + }
> + // ret > 1 means c_name is consumed
> + if (ret <= 0 && c_len > 0)
> + kfree(c_name);
> + return ret >= 0;
> }
>
> Thanks,
> Amir.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 8/9] ovl: Check for casefold consistency when creating new dentries
2025-08-13 22:36 ` [PATCH v4 8/9] ovl: Check for casefold consistency when creating new dentries André Almeida
@ 2025-08-14 13:06 ` Amir Goldstein
0 siblings, 0 replies; 21+ messages in thread
From: Amir Goldstein @ 2025-08-14 13:06 UTC (permalink / raw)
To: André Almeida
Cc: Miklos Szeredi, Theodore Tso, Gabriel Krisman Bertazi,
linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev
On Thu, Aug 14, 2025 at 12:37 AM André Almeida <andrealmeid@igalia.com> wrote:
>
> In a overlayfs with casefold enabled, all new dentries should have
> casefold enabled as well. Check this at ovl_create_real()
>
> Signed-off-by: André Almeida <andrealmeid@igalia.com>
> ---
> Changes from v3:
> - New patch
> ---
> fs/overlayfs/dir.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> index 70b8687dc45e8e33079c865ae302ac58464224a6..be8c5d02302de7a3ee63220a69f99a808fde3128 100644
> --- a/fs/overlayfs/dir.c
> +++ b/fs/overlayfs/dir.c
> @@ -187,6 +187,11 @@ struct dentry *ovl_create_real(struct ovl_fs *ofs, struct dentry *parent,
> /* mkdir is special... */
> newdentry = ovl_do_mkdir(ofs, dir, newdentry, attr->mode);
> err = PTR_ERR_OR_ZERO(newdentry);
> + /* expect to inherit casefolding from workdir/upperdir */
> + if (!err && ofs->casefold != ovl_dentry_casefolded(newdentry)) {
> + dput(newdentry);
> + err = -EINVAL;
> + }
If we do encounter a filesystem that does not inherit casefolding
(which is perfectly legal) the reason for this error is going to be very
hard for users to track down.
I think this calls for pr_warn_ratelimited() like we did for the lookup
warnings with inconsistent casefloding.
Thanks,
Amir.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH v4 3/9] ovl: Create ovl_casefold() to support casefolded strncmp()
2025-08-14 13:02 ` André Almeida
@ 2025-08-14 13:20 ` Amir Goldstein
0 siblings, 0 replies; 21+ messages in thread
From: Amir Goldstein @ 2025-08-14 13:20 UTC (permalink / raw)
To: André Almeida
Cc: Miklos Szeredi, Theodore Tso, Gabriel Krisman Bertazi,
linux-unionfs, linux-kernel, linux-fsdevel, Alexander Viro,
Christian Brauner, Jan Kara, kernel-dev
On Thu, Aug 14, 2025 at 3:02 PM André Almeida <andrealmeid@igalia.com> wrote:
>
> Hi Amir,
>
> Em 14/08/2025 09:53, Amir Goldstein escreveu:
> > On Thu, Aug 14, 2025 at 12:37 AM André Almeida <andrealmeid@igalia.com> wrote:
> >>
> >> To add overlayfs support casefold filesystems, create a new function
> >> ovl_casefold(), to be able to do case-insensitive strncmp().
> >>
> >> ovl_casefold() allocates a new buffer and stores the casefolded version
> >> of the string on it. If the allocation or the casefold operation fails,
> >> fallback to use the original string.
> >>
> >> The case-insentive name is then used in the rb-tree search/insertion
> >> operation. If the name is found in the rb-tree, the name can be
> >> discarded and the buffer is freed. If the name isn't found, it's then
> >> stored at struct ovl_cache_entry to be used later.
> >>
> >> Signed-off-by: André Almeida <andrealmeid@igalia.com>
> >> ---
>
> [...]
>
> >> + }
> >>
> >> INIT_LIST_HEAD(list);
> >> }
> >> @@ -260,12 +311,28 @@ static bool ovl_fill_merge(struct dir_context *ctx, const char *name,
> >> {
> >> struct ovl_readdir_data *rdd =
> >> container_of(ctx, struct ovl_readdir_data, ctx);
> >> + struct ovl_fs *ofs = OVL_FS(rdd->dentry->d_sb);
> >> + const char *aux = NULL;
> >
> > It looks strange to me that you need aux
> > and it looks strange to pair <aux, cf_len>
> > neither here or there...
> >
>
> The reason behind this `aux` var is because I need a `const char`
> pointer to point to the `name` argument, and `cf_name` can't be const
> because it goes through ovl_casefold(). I tried a couple approaches here
> to get rid of the compiler warning regarding const, and the only way I
> managed to was using a third variable like that.
>
I see. In that case, I'd just use these cleaner var names:
@@ -260,12 +311,28 @@ static bool ovl_fill_merge(struct dir_context
*ctx, const char *name,
{
struct ovl_readdir_data *rdd =
container_of(ctx, struct ovl_readdir_data, ctx);
+ struct ovl_fs *ofs = OVL_FS(rdd->dentry->d_sb);
+ char *cf_name = NULL;
+ const char *c_name;
+ int c_len = 0;
+
+ if (ofs->casefold)
+ c_len = ovl_casefold(rdd->map, name, namelen, &cf_name);
+
+ if (c_len <= 0) {
+ c_name = name;
+ c_len = namelen;
+ } else {
+ c_name = cf_name;
+ }
Thanks,
Amir.
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2025-08-14 13:20 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-13 22:36 [PATCH v4 0/9] ovl: Enable support for casefold filesystems André Almeida
2025-08-13 22:36 ` [PATCH v4 1/9] ovl: Support mounting case-insensitive enabled filesystems André Almeida
2025-08-14 8:35 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 2/9] fs: Create new helper sb_encoding() André Almeida
2025-08-14 12:18 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 3/9] ovl: Create ovl_casefold() to support casefolded strncmp() André Almeida
2025-08-14 12:53 ` Amir Goldstein
2025-08-14 13:02 ` André Almeida
2025-08-14 13:20 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 4/9] fs: Create sb_same_encoding() helper André Almeida
2025-08-14 12:19 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 5/9] ovl: Ensure that all layers have the same encoding André Almeida
2025-08-14 12:56 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 6/9] ovl: Set case-insensitive dentry operations for ovl sb André Almeida
2025-08-14 12:57 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 7/9] ovl: Add S_CASEFOLD as part of the inode flag to be copied André Almeida
2025-08-14 13:00 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 8/9] ovl: Check for casefold consistency when creating new dentries André Almeida
2025-08-14 13:06 ` Amir Goldstein
2025-08-13 22:36 ` [PATCH v4 9/9] ovl: Allow case-insensitive lookup André Almeida
2025-08-14 8:44 ` Amir Goldstein
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).