[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260107034551.439-1-luochunsheng@ustc.edu>
Date: Wed, 7 Jan 2026 11:45:51 +0800
From: Chunsheng Luo <luochunsheng@...c.edu>
To: miklos@...redi.hu,
amir73il@...il.com
Cc: bschubert@....com,
linux-unionfs@...r.kernel.org,
linux-kernel@...r.kernel.org,
Chunsheng Luo <luochunsheng@...c.edu>
Subject: [PATCH] overlayfs: mask d_type high bits before whiteout check
Commit c31f91c6af96 ("fuse: don't allow signals to interrupt getdents
copying") introduced the use of high bits in d_type as flags. However,
overlayfs was not adapted to handle this change.
In ovl_cache_entry_new(), the code checks if d_type == DT_CHR to
determine if an entry might be a whiteout. When fuse is used as the
lower layer and sets high bits in d_type, this comparison fails,
causing whiteout files to not be recognized properly and resulting in
incorrect overlayfs behavior.
Fix this by masking out the high bits with S_DT_MASK before checking.
Fixes: c31f91c6af96 ("fuse: don't allow signals to interrupt getdents copying")
Link: https://github.com/containerd/stargz-snapshotter/issues/2214
Signed-off-by: Chunsheng Luo <luochunsheng@...c.edu>
---
fs/overlayfs/readdir.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 160960bb0ad0..a2ac47458bf9 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -246,6 +246,9 @@ static int ovl_fill_lowest(struct ovl_readdir_data *rdd,
{
struct ovl_cache_entry *p;
+ /* Mask out high bits that may be used (e.g., fuse) */
+ d_type &= S_DT_MASK;
+
p = ovl_cache_entry_find(rdd->root, c_name, c_len);
if (p) {
list_move_tail(&p->l_node, &rdd->middle);
@@ -316,6 +319,9 @@ static bool ovl_fill_merge(struct dir_context *ctx, const char *name,
char *cf_name = NULL;
int c_len = 0, ret;
+ /* Mask out high bits that may be used (e.g., fuse) */
+ d_type &= S_DT_MASK;
+
if (ofs->casefold)
c_len = ovl_casefold(rdd, name, namelen, &cf_name);
@@ -632,6 +638,9 @@ static bool ovl_fill_plain(struct dir_context *ctx, const char *name,
struct ovl_readdir_data *rdd =
container_of(ctx, struct ovl_readdir_data, ctx);
+ /* Mask out high bits that may be used (e.g., fuse) */
+ d_type &= S_DT_MASK;
+
rdd->count++;
p = ovl_cache_entry_new(rdd, name, namelen, NULL, 0, ino, d_type);
if (p == NULL) {
@@ -755,6 +764,9 @@ static bool ovl_fill_real(struct dir_context *ctx, const char *name,
struct dir_context *orig_ctx = rdt->orig_ctx;
bool res;
+ /* Mask out high bits that may be used (e.g., fuse) */
+ d_type &= S_DT_MASK;
+
if (rdt->parent_ino && strcmp(name, "..") == 0) {
ino = rdt->parent_ino;
} else if (rdt->cache) {
@@ -1144,6 +1156,9 @@ static bool ovl_check_d_type(struct dir_context *ctx, const char *name,
struct ovl_readdir_data *rdd =
container_of(ctx, struct ovl_readdir_data, ctx);
+ /* Mask out high bits that may be used (e.g., fuse) */
+ d_type &= S_DT_MASK;
+
/* Even if d_type is not supported, DT_DIR is returned for . and .. */
if (!strncmp(name, ".", namelen) || !strncmp(name, "..", namelen))
return true;
--
2.43.0
Powered by blists - more mailing lists