* [PATCH] erofs: ensure valid f_path for page cache sharing
@ 2026-07-23 5:03 Gao Xiang
0 siblings, 0 replies; only message in thread
From: Gao Xiang @ 2026-07-23 5:03 UTC (permalink / raw)
To: linux-erofs; +Cc: LKML, Gao Xiang
Previously, backing files for page cache sharing were set up with
f_path left as NULL (only f_inode was valid). It worked, but a recent
mincore fix relies on f_path.mnt and crashes (found by "erofs/028" on
7.2-rc4):
BUG: kernel NULL pointer dereference, address: 0000000000000018
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 0 P4D 0
Oops: Oops: 0000 [#1] SMP PTI
CPU: 3 UID: 0 PID: 675528 Comm: fincore Not tainted 7.2.0-rc4-00002-g[]-dirty #1 PREEMPT(lazy)
Hardware name: Red Hat KVM, BIOS 1.16.0-4.al8 04/01/2014
RIP: 0010:__do_sys_mincore+0xc0/0x2c0
...
Specify valid paths using valid disconnected dentries together with
erofs_ishare_mnt instead of leaving f_path empty, so they are more
like real backing files in a pseudo filesystem and standard
backing_file_open() can be used directly.
Fixes: e187bc02f8fa ("mm: do file ownership checks with the proper mount idmap")
Signed-off-by: Gao Xiang <xiang@kernel.org>
---
fs/erofs/Kconfig | 1 +
fs/erofs/internal.h | 4 +--
fs/erofs/ishare.c | 60 ++++++++++++++++++++++-----------------------
3 files changed, 33 insertions(+), 32 deletions(-)
diff --git a/fs/erofs/Kconfig b/fs/erofs/Kconfig
index 4789b1077d8c..1feb28cfe557 100644
--- a/fs/erofs/Kconfig
+++ b/fs/erofs/Kconfig
@@ -189,6 +189,7 @@ config EROFS_FS_PCPU_KTHREAD_HIPRI
config EROFS_FS_PAGE_CACHE_SHARE
bool "EROFS page cache share support (experimental)"
depends on EROFS_FS && EROFS_FS_XATTR
+ select FS_STACK
help
This enables page cache sharing among inodes with identical
content fingerprints on the same machine.
diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
index 580f8d9f14e7..57bd21859c65 100644
--- a/fs/erofs/internal.h
+++ b/fs/erofs/internal.h
@@ -288,8 +288,8 @@ struct erofs_inode {
struct erofs_inode_fingerprint fingerprint;
spinlock_t ishare_lock;
};
- /* for each real inode */
- struct inode *sharedinode;
+ /* for each real filesystem inode */
+ struct dentry *sharedentry;
};
#endif
/* the corresponding vfs inode */
diff --git a/fs/erofs/ishare.c b/fs/erofs/ishare.c
index a1a20a5ba548..51b81aaf9ac3 100644
--- a/fs/erofs/ishare.c
+++ b/fs/erofs/ishare.c
@@ -2,14 +2,13 @@
/*
* Copyright (C) 2024, Alibaba Cloud
*/
+#include <linux/backing-file.h>
#include <linux/xxhash.h>
#include <linux/mount.h>
#include <linux/security.h>
#include "internal.h"
#include "xattr.h"
-#include "../internal.h"
-
static struct vfsmount *erofs_ishare_mnt;
static int erofs_ishare_iget5_eq(struct inode *inode, void *data)
@@ -33,10 +32,12 @@ static int erofs_ishare_iget5_set(struct inode *inode, void *data)
bool erofs_ishare_fill_inode(struct inode *inode)
{
+ static const struct file_operations empty_fops = {};
struct erofs_sb_info *sbi = EROFS_SB(inode->i_sb);
const struct address_space_operations *aops;
struct erofs_inode *vi = EROFS_I(inode);
struct erofs_inode_fingerprint fp;
+ struct dentry *sd;
struct inode *si;
aops = erofs_get_aops(inode);
@@ -49,7 +50,9 @@ bool erofs_ishare_fill_inode(struct inode *inode)
xxh32(fp.opaque, fp.size, 0),
erofs_ishare_iget5_eq, erofs_ishare_iget5_set, &fp);
if (si && (inode_state_read_once(si) & I_NEW)) {
+ si->i_fop = &empty_fops;
si->i_mapping->a_ops = aops;
+ si->i_mode = 0444 | S_IFREG;
si->i_size = inode->i_size;
unlock_new_inode(si);
} else {
@@ -65,7 +68,12 @@ bool erofs_ishare_fill_inode(struct inode *inode)
return false;
}
}
- vi->sharedinode = si;
+ sd = d_obtain_alias(si); /* disconnected denties for sharedinodes */
+ if (IS_ERR(sd)) {
+ iput(si);
+ return false;
+ }
+ vi->sharedentry = sd;
INIT_LIST_HEAD(&vi->ishare_list);
spin_lock(&EROFS_I(si)->ishare_lock);
list_add(&vi->ishare_list, &EROFS_I(si)->ishare_list);
@@ -75,48 +83,40 @@ bool erofs_ishare_fill_inode(struct inode *inode)
void erofs_ishare_free_inode(struct inode *inode)
{
- struct erofs_inode *vi = EROFS_I(inode);
- struct inode *sharedinode = vi->sharedinode;
+ struct erofs_inode *vi = EROFS_I(inode), *svi;
- if (!sharedinode)
+ if (!vi->sharedentry)
return;
- spin_lock(&EROFS_I(sharedinode)->ishare_lock);
+ svi = EROFS_I(d_inode(vi->sharedentry));
+ spin_lock(&svi->ishare_lock);
list_del(&vi->ishare_list);
- spin_unlock(&EROFS_I(sharedinode)->ishare_lock);
- iput(sharedinode);
- vi->sharedinode = NULL;
+ spin_unlock(&svi->ishare_lock);
+ dput(vi->sharedentry);
+ vi->sharedentry = NULL;
}
static int erofs_ishare_file_open(struct inode *inode, struct file *file)
{
- struct inode *sharedinode = EROFS_I(inode)->sharedinode;
- struct file *realfile;
+ struct path sharedpath = {
+ .mnt = erofs_ishare_mnt,
+ .dentry = EROFS_I(inode)->sharedentry,
+ };
+ struct file *rf;
if (file->f_flags & O_DIRECT)
return -EINVAL;
- realfile = alloc_empty_backing_file(O_RDONLY|O_NOATIME, current_cred(),
- file);
- if (IS_ERR(realfile))
- return PTR_ERR(realfile);
- ihold(sharedinode);
- realfile->f_op = &erofs_file_fops;
- realfile->f_inode = sharedinode;
- realfile->f_mapping = sharedinode->i_mapping;
- path_get(&file->f_path);
- backing_file_set_user_path(realfile, &file->f_path);
-
- file_ra_state_init(&realfile->f_ra, file->f_mapping);
- realfile->private_data = EROFS_I(inode);
- file->private_data = realfile;
+
+ rf = backing_file_open(file, file->f_flags | O_NOATIME | FMODE_NONOTIFY,
+ &sharedpath, current_cred());
+ if (IS_ERR(rf))
+ return PTR_ERR(rf);
+ file->private_data = rf;
return 0;
}
static int erofs_ishare_file_release(struct inode *inode, struct file *file)
{
- struct file *realfile = file->private_data;
-
- iput(realfile->f_inode);
- fput(realfile);
+ fput(file->private_data);
file->private_data = NULL;
return 0;
}
--
2.47.3
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-07-23 5:03 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-23 5:03 [PATCH] erofs: ensure valid f_path for page cache sharing Gao Xiang
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.