Some file systems like FUSE-based ones or overlayfs may record the backing
file in struct vm_area_struct vm_file, instead of the user file that the
user mmapped.
That causes perf to misreport the device major/minor numbers of the file
system of the file, and the generation of the file, and potentially other
inode details. There is an existing helper file_user_inode() for that
situation.
Use file_user_inode() instead of file_inode() to get the inode for MMAP2
events.
Example:
Setup:
# cd /root
# mkdir test ; cd test ; mkdir lower upper work merged
# cp `which cat` lower
# mount -t overlay overlay -olowerdir=lower,upperdir=upper,workdir=work merged
# perf record -e cycles:u -- /root/test/merged/cat /proc/self/maps
...
55b2c91d0000-55b2c926b000 r-xp 00018000 00:1a 3419 /root/test/merged/cat
...
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.004 MB perf.data (5 samples) ]
#
# stat /root/test/merged/cat
File: /root/test/merged/cat
Size: 1127792 Blocks: 2208 IO Block: 4096 regular file
Device: 0,26 Inode: 3419 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2025-09-08 12:23:59.453309624 +0000
Modify: 2025-09-08 12:23:59.454309624 +0000
Change: 2025-09-08 12:23:59.454309624 +0000
Birth: 2025-09-08 12:23:59.453309624 +0000
Before:
Device reported 00:02 differs from stat output and /proc/self/maps
# perf script --show-mmap-events | grep /root/test/merged/cat
cat 377 [-01] 243.078558: PERF_RECORD_MMAP2 377/377: [0x55b2c91d0000(0x9b000) @ 0x18000 00:02 3419 2068525940]: r-xp /root/test/merged/cat
After:
Device reported 00:1a is the same as stat output and /proc/self/maps
# perf script --show-mmap-events | grep /root/test/merged/cat
cat 362 [-01] 127.755167: PERF_RECORD_MMAP2 362/362: [0x55ba6e781000(0x9b000) @ 0x18000 00:1a 3419 0]: r-xp /root/test/merged/cat
With respect to stable kernels, overlayfs mmap function ovl_mmap() was
added in v4.19 but file_user_inode() was not added until v6.8 and never
back-ported to stable kernels. FMODE_BACKING that it depends on was added
in v6.5. This issue has gone largely unnoticed, so back-porting before
v6.8 is probably not worth it, so put 6.8 as the stable kernel prerequisite
version, although in practice the next long term kernel is 6.12.
Cc: stable@vger.kernel.org # 6.8
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
kernel/events/core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index e203b8d90fd2..9d281785b99e 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -9403,7 +9403,7 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
flags |= MAP_HUGETLB;
if (file) {
- struct inode *inode;
+ const struct inode *inode;
dev_t dev;
buf = kmalloc(PATH_MAX, GFP_KERNEL);
@@ -9421,7 +9421,7 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
name = "//toolong";
goto cpy_name;
}
- inode = file_inode(vma->vm_file);
+ inode = file_user_inode(vma->vm_file);
dev = inode->i_sb->s_dev;
ino = inode->i_ino;
gen = inode->i_generation;
--
2.48.1
On Tue, Sep 9, 2025 at 2:42 PM Adrian Hunter <adrian.hunter@intel.com> wrote: > > Some file systems like FUSE-based ones or overlayfs may record the backing > file in struct vm_area_struct vm_file, instead of the user file that the > user mmapped. > > That causes perf to misreport the device major/minor numbers of the file > system of the file, and the generation of the file, and potentially other > inode details. There is an existing helper file_user_inode() for that > situation. > > Use file_user_inode() instead of file_inode() to get the inode for MMAP2 > events. > > Example: > > Setup: > > # cd /root > # mkdir test ; cd test ; mkdir lower upper work merged > # cp `which cat` lower > # mount -t overlay overlay -olowerdir=lower,upperdir=upper,workdir=work merged > # perf record -e cycles:u -- /root/test/merged/cat /proc/self/maps > ... > 55b2c91d0000-55b2c926b000 r-xp 00018000 00:1a 3419 /root/test/merged/cat > ... > [ perf record: Woken up 1 times to write data ] > [ perf record: Captured and wrote 0.004 MB perf.data (5 samples) ] > # > # stat /root/test/merged/cat > File: /root/test/merged/cat > Size: 1127792 Blocks: 2208 IO Block: 4096 regular file > Device: 0,26 Inode: 3419 Links: 1 > Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root) > Access: 2025-09-08 12:23:59.453309624 +0000 > Modify: 2025-09-08 12:23:59.454309624 +0000 > Change: 2025-09-08 12:23:59.454309624 +0000 > Birth: 2025-09-08 12:23:59.453309624 +0000 > > Before: > > Device reported 00:02 differs from stat output and /proc/self/maps > > # perf script --show-mmap-events | grep /root/test/merged/cat > cat 377 [-01] 243.078558: PERF_RECORD_MMAP2 377/377: [0x55b2c91d0000(0x9b000) @ 0x18000 00:02 3419 2068525940]: r-xp /root/test/merged/cat > > After: > > Device reported 00:1a is the same as stat output and /proc/self/maps > > # perf script --show-mmap-events | grep /root/test/merged/cat > cat 362 [-01] 127.755167: PERF_RECORD_MMAP2 362/362: [0x55ba6e781000(0x9b000) @ 0x18000 00:1a 3419 0]: r-xp /root/test/merged/cat > > With respect to stable kernels, overlayfs mmap function ovl_mmap() was > added in v4.19 but file_user_inode() was not added until v6.8 and never > back-ported to stable kernels. FMODE_BACKING that it depends on was added > in v6.5. This issue has gone largely unnoticed, so back-porting before > v6.8 is probably not worth it, so put 6.8 as the stable kernel prerequisite > version, although in practice the next long term kernel is 6.12. > > Cc: stable@vger.kernel.org # 6.8 > Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Feel free to add Acked-by: Amir Goldstein <amir73il@gmail.com> > --- > kernel/events/core.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/kernel/events/core.c b/kernel/events/core.c > index e203b8d90fd2..9d281785b99e 100644 > --- a/kernel/events/core.c > +++ b/kernel/events/core.c > @@ -9403,7 +9403,7 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) > flags |= MAP_HUGETLB; > > if (file) { > - struct inode *inode; > + const struct inode *inode; > dev_t dev; > > buf = kmalloc(PATH_MAX, GFP_KERNEL); > @@ -9421,7 +9421,7 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) > name = "//toolong"; > goto cpy_name; > } > - inode = file_inode(vma->vm_file); > + inode = file_user_inode(vma->vm_file); > dev = inode->i_sb->s_dev; > ino = inode->i_ino; > gen = inode->i_generation; > -- > 2.48.1 >
© 2016 - 2025 Red Hat, Inc.