aboutsummaryrefslogtreecommitdiffstats
diff options
-rw-r--r--queue-6.15/fs-add-s_anon_inode.patch142
-rw-r--r--queue-6.15/series1
2 files changed, 143 insertions, 0 deletions
diff --git a/queue-6.15/fs-add-s_anon_inode.patch b/queue-6.15/fs-add-s_anon_inode.patch
new file mode 100644
index 0000000000..2124ff345a
--- /dev/null
+++ b/queue-6.15/fs-add-s_anon_inode.patch
@@ -0,0 +1,142 @@
+From 19bbfe7b5fcc04d8711e8e1352acc77c1a5c3955 Mon Sep 17 00:00:00 2001
+From: Christian Brauner <brauner@kernel.org>
+Date: Mon, 21 Apr 2025 10:27:40 +0200
+Subject: fs: add S_ANON_INODE
+
+From: Christian Brauner <brauner@kernel.org>
+
+commit 19bbfe7b5fcc04d8711e8e1352acc77c1a5c3955 upstream.
+
+This makes it easy to detect proper anonymous inodes and to ensure that
+we can detect them in codepaths such as readahead().
+
+Readahead on anonymous inodes didn't work because they didn't have a
+proper mode. Now that they have we need to retain EINVAL being returned
+otherwise LTP will fail.
+
+We also need to ensure that ioctls aren't simply fired like they are for
+regular files so things like inotify inodes continue to correctly call
+their own ioctl handlers as in [1].
+
+Reported-by: Xilin Wu <sophon@radxa.com>
+Link: https://lore.kernel.org/3A9139D5CD543962+89831381-31b9-4392-87ec-a84a5b3507d8@radxa.com [1]
+Link: https://lore.kernel.org/7a1a7076-ff6b-4cb0-94e7-7218a0a44028@sirena.org.uk
+Signed-off-by: Christian Brauner <brauner@kernel.org>
+Cc: "Barry K. Nathan" <barryn@pobox.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ioctl.c | 7 ++++---
+ fs/libfs.c | 2 +-
+ fs/pidfs.c | 2 +-
+ include/linux/fs.h | 2 ++
+ mm/readahead.c | 20 ++++++++++++++++----
+ 5 files changed, 24 insertions(+), 9 deletions(-)
+
+--- a/fs/ioctl.c
++++ b/fs/ioctl.c
+@@ -821,7 +821,8 @@ static int do_vfs_ioctl(struct file *fil
+ return ioctl_fioasync(fd, filp, argp);
+
+ case FIOQSIZE:
+- if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) ||
++ if (S_ISDIR(inode->i_mode) ||
++ (S_ISREG(inode->i_mode) && !IS_ANON_FILE(inode)) ||
+ S_ISLNK(inode->i_mode)) {
+ loff_t res = inode_get_bytes(inode);
+ return copy_to_user(argp, &res, sizeof(res)) ?
+@@ -856,7 +857,7 @@ static int do_vfs_ioctl(struct file *fil
+ return ioctl_file_dedupe_range(filp, argp);
+
+ case FIONREAD:
+- if (!S_ISREG(inode->i_mode))
++ if (!S_ISREG(inode->i_mode) || IS_ANON_FILE(inode))
+ return vfs_ioctl(filp, cmd, arg);
+
+ return put_user(i_size_read(inode) - filp->f_pos,
+@@ -881,7 +882,7 @@ static int do_vfs_ioctl(struct file *fil
+ return ioctl_get_fs_sysfs_path(filp, argp);
+
+ default:
+- if (S_ISREG(inode->i_mode))
++ if (S_ISREG(inode->i_mode) && !IS_ANON_FILE(inode))
+ return file_ioctl(filp, cmd, argp);
+ break;
+ }
+--- a/fs/libfs.c
++++ b/fs/libfs.c
+@@ -1656,7 +1656,7 @@ struct inode *alloc_anon_inode(struct su
+ inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
+ inode->i_uid = current_fsuid();
+ inode->i_gid = current_fsgid();
+- inode->i_flags |= S_PRIVATE;
++ inode->i_flags |= S_PRIVATE | S_ANON_INODE;
+ simple_inode_init_ts(inode);
+ return inode;
+ }
+--- a/fs/pidfs.c
++++ b/fs/pidfs.c
+@@ -826,7 +826,7 @@ static int pidfs_init_inode(struct inode
+ const struct pid *pid = data;
+
+ inode->i_private = data;
+- inode->i_flags |= S_PRIVATE;
++ inode->i_flags |= S_PRIVATE | S_ANON_INODE;
+ inode->i_mode |= S_IRWXU;
+ inode->i_op = &pidfs_inode_operations;
+ inode->i_fop = &pidfs_file_operations;
+--- a/include/linux/fs.h
++++ b/include/linux/fs.h
+@@ -2344,6 +2344,7 @@ struct super_operations {
+ #define S_CASEFOLD (1 << 15) /* Casefolded file */
+ #define S_VERITY (1 << 16) /* Verity file (using fs/verity/) */
+ #define S_KERNEL_FILE (1 << 17) /* File is in use by the kernel (eg. fs/cachefiles) */
++#define S_ANON_INODE (1 << 19) /* Inode is an anonymous inode */
+
+ /*
+ * Note that nosuid etc flags are inode-specific: setting some file-system
+@@ -2400,6 +2401,7 @@ static inline bool sb_rdonly(const struc
+
+ #define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \
+ (inode)->i_rdev == WHITEOUT_DEV)
++#define IS_ANON_FILE(inode) ((inode)->i_flags & S_ANON_INODE)
+
+ static inline bool HAS_UNMAPPED_ID(struct mnt_idmap *idmap,
+ struct inode *inode)
+--- a/mm/readahead.c
++++ b/mm/readahead.c
+@@ -690,9 +690,15 @@ EXPORT_SYMBOL_GPL(page_cache_async_ra);
+
+ ssize_t ksys_readahead(int fd, loff_t offset, size_t count)
+ {
++ struct file *file;
++ const struct inode *inode;
++
+ CLASS(fd, f)(fd);
++ if (fd_empty(f))
++ return -EBADF;
+
+- if (fd_empty(f) || !(fd_file(f)->f_mode & FMODE_READ))
++ file = fd_file(f);
++ if (!(file->f_mode & FMODE_READ))
+ return -EBADF;
+
+ /*
+@@ -700,9 +706,15 @@ ssize_t ksys_readahead(int fd, loff_t of
+ * that can execute readahead. If readahead is not possible
+ * on this file, then we must return -EINVAL.
+ */
+- if (!fd_file(f)->f_mapping || !fd_file(f)->f_mapping->a_ops ||
+- (!S_ISREG(file_inode(fd_file(f))->i_mode) &&
+- !S_ISBLK(file_inode(fd_file(f))->i_mode)))
++ if (!file->f_mapping)
++ return -EINVAL;
++ if (!file->f_mapping->a_ops)
++ return -EINVAL;
++
++ inode = file_inode(file);
++ if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
++ return -EINVAL;
++ if (IS_ANON_FILE(inode))
+ return -EINVAL;
+
+ return vfs_fadvise(fd_file(f), offset, count, POSIX_FADV_WILLNEED);
diff --git a/queue-6.15/series b/queue-6.15/series
index 6f39856164..1b2da1d690 100644
--- a/queue-6.15/series
+++ b/queue-6.15/series
@@ -33,6 +33,7 @@ wifi-mt76-mt7925-fix-host-interrupt-register-initialization.patch
anon_inode-use-a-proper-mode-internally.patch
anon_inode-explicitly-block-setattr.patch
anon_inode-raise-sb_i_nodev-and-sb_i_noexec.patch
+fs-add-s_anon_inode.patch
wifi-ath11k-fix-rx-completion-meta-data-corruption.patch
wifi-rtw88-usb-upload-the-firmware-in-bigger-chunks.patch
wifi-ath11k-fix-ring-buffer-corruption.patch