Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'vfs-6.18-rc1.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull vfs mount updates from Christian Brauner:
"This contains some work around mount api handling:

- Output the warning message for mnt_too_revealing() triggered during
fsmount() to the fscontext log. This makes it possible for the
mount tool to output appropriate warnings on the command line.

For example, with the newest fsopen()-based mount(8) from
util-linux, the error messages now look like:

# mount -t proc proc /tmp
mount: /tmp: fsmount() failed: VFS: Mount too revealing.
dmesg(1) may have more information after failed mount system call.

- Do not consume fscontext log entries when returning -EMSGSIZE

Userspace generally expects APIs that return -EMSGSIZE to allow for
them to adjust their buffer size and retry the operation.

However, the fscontext log would previously clear the message even
in the -EMSGSIZE case.

Given that it is very cheap for us to check whether the buffer is
too small before we remove the message from the ring buffer, let's
just do that instead.

- Drop an unused argument from do_remount()"

* tag 'vfs-6.18-rc1.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
vfs: fs/namespace.c: remove ms_flags argument from do_remount
selftests/filesystems: add basic fscontext log tests
fscontext: do not consume log entries when returning -EMSGSIZE
vfs: output mount_too_revealing() errors to fscontext
docs/vfs: Remove mentions to the old mount API helpers
fscontext: add custom-prefix log helpers
fs: Remove mount_bdev
fs: Remove mount_nodev

+192 -135
+2 -25
Documentation/filesystems/vfs.rst
··· 209 209 super_operations" which describes the next level of the filesystem 210 210 implementation. 211 211 212 - Usually, a filesystem uses one of the generic mount() implementations 213 - and provides a fill_super() callback instead. The generic variants are: 214 - 215 - ``mount_bdev`` 216 - mount a filesystem residing on a block device 217 - 218 - ``mount_nodev`` 219 - mount a filesystem that is not backed by a device 220 - 221 - ``mount_single`` 222 - mount a filesystem which shares the instance between all mounts 223 - 224 - A fill_super() callback implementation has the following arguments: 225 - 226 - ``struct super_block *sb`` 227 - the superblock structure. The callback must initialize this 228 - properly. 229 - 230 - ``void *data`` 231 - arbitrary mount options, usually comes as an ASCII string (see 232 - "Mount Options" section) 233 - 234 - ``int silent`` 235 - whether or not to be silent on error 236 - 212 + For more information on mounting (and the new mount API), see 213 + Documentation/filesystems/mount_api.rst. 237 214 238 215 The Superblock Object 239 216 =====================
+38 -32
fs/fsopen.c
··· 18 18 #include "internal.h" 19 19 #include "mount.h" 20 20 21 + static inline const char *fetch_message_locked(struct fc_log *log, size_t len, 22 + bool *need_free) 23 + { 24 + const char *p; 25 + int index; 26 + 27 + if (unlikely(log->head == log->tail)) 28 + return ERR_PTR(-ENODATA); 29 + 30 + index = log->tail & (ARRAY_SIZE(log->buffer) - 1); 31 + p = log->buffer[index]; 32 + if (unlikely(strlen(p) > len)) 33 + return ERR_PTR(-EMSGSIZE); 34 + 35 + log->buffer[index] = NULL; 36 + *need_free = log->need_free & (1 << index); 37 + log->need_free &= ~(1 << index); 38 + log->tail++; 39 + 40 + return p; 41 + } 42 + 21 43 /* 22 44 * Allow the user to read back any error, warning or informational messages. 45 + * Only one message is returned for each read(2) call. 23 46 */ 24 47 static ssize_t fscontext_read(struct file *file, 25 48 char __user *_buf, size_t len, loff_t *pos) 26 49 { 27 50 struct fs_context *fc = file->private_data; 28 - struct fc_log *log = fc->log.log; 29 - unsigned int logsize = ARRAY_SIZE(log->buffer); 30 - ssize_t ret; 31 - char *p; 51 + ssize_t err; 52 + const char *p __free(kfree) = NULL, *message; 32 53 bool need_free; 33 - int index, n; 54 + int n; 34 55 35 - ret = mutex_lock_interruptible(&fc->uapi_mutex); 36 - if (ret < 0) 37 - return ret; 38 - 39 - if (log->head == log->tail) { 40 - mutex_unlock(&fc->uapi_mutex); 41 - return -ENODATA; 42 - } 43 - 44 - index = log->tail & (logsize - 1); 45 - p = log->buffer[index]; 46 - need_free = log->need_free & (1 << index); 47 - log->buffer[index] = NULL; 48 - log->need_free &= ~(1 << index); 49 - log->tail++; 56 + err = mutex_lock_interruptible(&fc->uapi_mutex); 57 + if (err < 0) 58 + return err; 59 + message = fetch_message_locked(fc->log.log, len, &need_free); 50 60 mutex_unlock(&fc->uapi_mutex); 61 + if (IS_ERR(message)) 62 + return PTR_ERR(message); 51 63 52 - ret = -EMSGSIZE; 53 - n = strlen(p); 54 - if (n > len) 55 - goto err_free; 56 - ret = -EFAULT; 57 - if (copy_to_user(_buf, p, n) != 0) 58 - goto err_free; 59 - ret = n; 60 - 61 - err_free: 62 64 if (need_free) 63 - kfree(p); 64 - return ret; 65 + p = message; 66 + 67 + n = strlen(message); 68 + if (copy_to_user(_buf, message, n)) 69 + return -EFAULT; 70 + return n; 65 71 } 66 72 67 73 static int fscontext_release(struct inode *inode, struct file *file)
+6 -4
fs/namespace.c
··· 3298 3298 * If you've mounted a non-root directory somewhere and want to do remount 3299 3299 * on it - tough luck. 3300 3300 */ 3301 - static int do_remount(struct path *path, int ms_flags, int sb_flags, 3301 + static int do_remount(struct path *path, int sb_flags, 3302 3302 int mnt_flags, void *data) 3303 3303 { 3304 3304 int err; ··· 3736 3736 int error; 3737 3737 3738 3738 error = security_sb_kern_mount(sb); 3739 - if (!error && mount_too_revealing(sb, &mnt_flags)) 3739 + if (!error && mount_too_revealing(sb, &mnt_flags)) { 3740 + errorfcp(fc, "VFS", "Mount too revealing"); 3740 3741 error = -EPERM; 3742 + } 3741 3743 3742 3744 if (unlikely(error)) { 3743 3745 fc_drop_locked(fc); ··· 4123 4121 if ((flags & (MS_REMOUNT | MS_BIND)) == (MS_REMOUNT | MS_BIND)) 4124 4122 return do_reconfigure_mnt(path, mnt_flags); 4125 4123 if (flags & MS_REMOUNT) 4126 - return do_remount(path, flags, sb_flags, mnt_flags, data_page); 4124 + return do_remount(path, sb_flags, mnt_flags, data_page); 4127 4125 if (flags & MS_BIND) 4128 4126 return do_loopback(path, dev_name, flags & MS_REC); 4129 4127 if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) ··· 4455 4453 4456 4454 ret = -EPERM; 4457 4455 if (mount_too_revealing(fc->root->d_sb, &mnt_flags)) { 4458 - pr_warn("VFS: Mount too revealing\n"); 4456 + errorfcp(fc, "VFS", "Mount too revealing"); 4459 4457 goto err_unlock; 4460 4458 } 4461 4459
-63
fs/super.c
··· 1716 1716 } 1717 1717 EXPORT_SYMBOL(get_tree_bdev); 1718 1718 1719 - static int test_bdev_super(struct super_block *s, void *data) 1720 - { 1721 - return !(s->s_iflags & SB_I_RETIRED) && s->s_dev == *(dev_t *)data; 1722 - } 1723 - 1724 - struct dentry *mount_bdev(struct file_system_type *fs_type, 1725 - int flags, const char *dev_name, void *data, 1726 - int (*fill_super)(struct super_block *, void *, int)) 1727 - { 1728 - struct super_block *s; 1729 - int error; 1730 - dev_t dev; 1731 - 1732 - error = lookup_bdev(dev_name, &dev); 1733 - if (error) 1734 - return ERR_PTR(error); 1735 - 1736 - flags |= SB_NOSEC; 1737 - s = sget(fs_type, test_bdev_super, set_bdev_super, flags, &dev); 1738 - if (IS_ERR(s)) 1739 - return ERR_CAST(s); 1740 - 1741 - if (s->s_root) { 1742 - if ((flags ^ s->s_flags) & SB_RDONLY) { 1743 - deactivate_locked_super(s); 1744 - return ERR_PTR(-EBUSY); 1745 - } 1746 - } else { 1747 - error = setup_bdev_super(s, flags, NULL); 1748 - if (!error) 1749 - error = fill_super(s, data, flags & SB_SILENT ? 1 : 0); 1750 - if (error) { 1751 - deactivate_locked_super(s); 1752 - return ERR_PTR(error); 1753 - } 1754 - 1755 - s->s_flags |= SB_ACTIVE; 1756 - } 1757 - 1758 - return dget(s->s_root); 1759 - } 1760 - EXPORT_SYMBOL(mount_bdev); 1761 - 1762 1719 void kill_block_super(struct super_block *sb) 1763 1720 { 1764 1721 struct block_device *bdev = sb->s_bdev; ··· 1729 1772 1730 1773 EXPORT_SYMBOL(kill_block_super); 1731 1774 #endif 1732 - 1733 - struct dentry *mount_nodev(struct file_system_type *fs_type, 1734 - int flags, void *data, 1735 - int (*fill_super)(struct super_block *, void *, int)) 1736 - { 1737 - int error; 1738 - struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL); 1739 - 1740 - if (IS_ERR(s)) 1741 - return ERR_CAST(s); 1742 - 1743 - error = fill_super(s, data, flags & SB_SILENT ? 1 : 0); 1744 - if (error) { 1745 - deactivate_locked_super(s); 1746 - return ERR_PTR(error); 1747 - } 1748 - s->s_flags |= SB_ACTIVE; 1749 - return dget(s->s_root); 1750 - } 1751 - EXPORT_SYMBOL(mount_nodev); 1752 1775 1753 1776 /** 1754 1777 * vfs_get_tree - Get the mountable root
-6
include/linux/fs.h
··· 2713 2713 return inode->i_opflags & IOP_MGTIME; 2714 2714 } 2715 2715 2716 - extern struct dentry *mount_bdev(struct file_system_type *fs_type, 2717 - int flags, const char *dev_name, void *data, 2718 - int (*fill_super)(struct super_block *, void *, int)); 2719 - extern struct dentry *mount_nodev(struct file_system_type *fs_type, 2720 - int flags, void *data, 2721 - int (*fill_super)(struct super_block *, void *, int)); 2722 2716 extern struct dentry *mount_subtree(struct vfsmount *mnt, const char *path); 2723 2717 void retire_super(struct super_block *sb); 2724 2718 void generic_shutdown_super(struct super_block *sb);
+14 -4
include/linux/fs_context.h
··· 186 186 extern __attribute__((format(printf, 4, 5))) 187 187 void logfc(struct fc_log *log, const char *prefix, char level, const char *fmt, ...); 188 188 189 - #define __logfc(fc, l, fmt, ...) logfc((fc)->log.log, NULL, \ 190 - l, fmt, ## __VA_ARGS__) 191 - #define __plog(p, l, fmt, ...) logfc((p)->log, (p)->prefix, \ 192 - l, fmt, ## __VA_ARGS__) 189 + #define __logfc(fc, l, fmt, ...) \ 190 + logfc((fc)->log.log, NULL, (l), (fmt), ## __VA_ARGS__) 191 + #define __plogp(p, prefix, l, fmt, ...) \ 192 + logfc((p)->log, (prefix), (l), (fmt), ## __VA_ARGS__) 193 + #define __plog(p, l, fmt, ...) __plogp(p, (p)->prefix, l, fmt, ## __VA_ARGS__) 194 + 193 195 /** 194 196 * infof - Store supplementary informational message 195 197 * @fc: The context in which to log the informational message ··· 203 201 #define infof(fc, fmt, ...) __logfc(fc, 'i', fmt, ## __VA_ARGS__) 204 202 #define info_plog(p, fmt, ...) __plog(p, 'i', fmt, ## __VA_ARGS__) 205 203 #define infofc(fc, fmt, ...) __plog((&(fc)->log), 'i', fmt, ## __VA_ARGS__) 204 + #define infofcp(fc, prefix, fmt, ...) \ 205 + __plogp((&(fc)->log), prefix, 'i', fmt, ## __VA_ARGS__) 206 206 207 207 /** 208 208 * warnf - Store supplementary warning message ··· 217 213 #define warnf(fc, fmt, ...) __logfc(fc, 'w', fmt, ## __VA_ARGS__) 218 214 #define warn_plog(p, fmt, ...) __plog(p, 'w', fmt, ## __VA_ARGS__) 219 215 #define warnfc(fc, fmt, ...) __plog((&(fc)->log), 'w', fmt, ## __VA_ARGS__) 216 + #define warnfcp(fc, prefix, fmt, ...) \ 217 + __plogp((&(fc)->log), prefix, 'w', fmt, ## __VA_ARGS__) 220 218 221 219 /** 222 220 * errorf - Store supplementary error message ··· 231 225 #define errorf(fc, fmt, ...) __logfc(fc, 'e', fmt, ## __VA_ARGS__) 232 226 #define error_plog(p, fmt, ...) __plog(p, 'e', fmt, ## __VA_ARGS__) 233 227 #define errorfc(fc, fmt, ...) __plog((&(fc)->log), 'e', fmt, ## __VA_ARGS__) 228 + #define errorfcp(fc, prefix, fmt, ...) \ 229 + __plogp((&(fc)->log), prefix, 'e', fmt, ## __VA_ARGS__) 234 230 235 231 /** 236 232 * invalf - Store supplementary invalid argument error message ··· 245 237 #define invalf(fc, fmt, ...) (errorf(fc, fmt, ## __VA_ARGS__), -EINVAL) 246 238 #define inval_plog(p, fmt, ...) (error_plog(p, fmt, ## __VA_ARGS__), -EINVAL) 247 239 #define invalfc(fc, fmt, ...) (errorfc(fc, fmt, ## __VA_ARGS__), -EINVAL) 240 + #define invalfcp(fc, prefix, fmt, ...) \ 241 + (errorfcp(fc, prefix, fmt, ## __VA_ARGS__), -EINVAL) 248 242 249 243 #endif /* _LINUX_FS_CONTEXT_H */
+1
tools/testing/selftests/filesystems/.gitignore
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 dnotify_test 3 3 devpts_pts 4 + fclog 4 5 file_stressor 5 6 anon_inode_test 6 7 kernfs_test
+1 -1
tools/testing/selftests/filesystems/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 3 CFLAGS += $(KHDR_INCLUDES) 4 - TEST_GEN_PROGS := devpts_pts file_stressor anon_inode_test kernfs_test 4 + TEST_GEN_PROGS := devpts_pts file_stressor anon_inode_test kernfs_test fclog 5 5 TEST_GEN_PROGS_EXTENDED := dnotify_test 6 6 7 7 include ../lib.mk
+130
tools/testing/selftests/filesystems/fclog.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * Author: Aleksa Sarai <cyphar@cyphar.com> 4 + * Copyright (C) 2025 SUSE LLC. 5 + */ 6 + 7 + #include <assert.h> 8 + #include <errno.h> 9 + #include <sched.h> 10 + #include <stdio.h> 11 + #include <stdlib.h> 12 + #include <string.h> 13 + #include <unistd.h> 14 + #include <sys/mount.h> 15 + 16 + #include "../kselftest_harness.h" 17 + 18 + #define ASSERT_ERRNO(expected, _t, seen) \ 19 + __EXPECT(expected, #expected, \ 20 + ({__typeof__(seen) _tmp_seen = (seen); \ 21 + _tmp_seen >= 0 ? _tmp_seen : -errno; }), #seen, _t, 1) 22 + 23 + #define ASSERT_ERRNO_EQ(expected, seen) \ 24 + ASSERT_ERRNO(expected, ==, seen) 25 + 26 + #define ASSERT_SUCCESS(seen) \ 27 + ASSERT_ERRNO(0, <=, seen) 28 + 29 + FIXTURE(ns) 30 + { 31 + int host_mntns; 32 + }; 33 + 34 + FIXTURE_SETUP(ns) 35 + { 36 + /* Stash the old mntns. */ 37 + self->host_mntns = open("/proc/self/ns/mnt", O_RDONLY|O_CLOEXEC); 38 + ASSERT_SUCCESS(self->host_mntns); 39 + 40 + /* Create a new mount namespace and make it private. */ 41 + ASSERT_SUCCESS(unshare(CLONE_NEWNS)); 42 + ASSERT_SUCCESS(mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL)); 43 + } 44 + 45 + FIXTURE_TEARDOWN(ns) 46 + { 47 + ASSERT_SUCCESS(setns(self->host_mntns, CLONE_NEWNS)); 48 + ASSERT_SUCCESS(close(self->host_mntns)); 49 + } 50 + 51 + TEST_F(ns, fscontext_log_enodata) 52 + { 53 + int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC); 54 + ASSERT_SUCCESS(fsfd); 55 + 56 + /* A brand new fscontext has no log entries. */ 57 + char buf[128] = {}; 58 + for (int i = 0; i < 16; i++) 59 + ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf))); 60 + 61 + ASSERT_SUCCESS(close(fsfd)); 62 + } 63 + 64 + TEST_F(ns, fscontext_log_errorfc) 65 + { 66 + int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC); 67 + ASSERT_SUCCESS(fsfd); 68 + 69 + ASSERT_ERRNO_EQ(-EINVAL, fsconfig(fsfd, FSCONFIG_SET_STRING, "invalid-arg", "123", 0)); 70 + 71 + char buf[128] = {}; 72 + ASSERT_SUCCESS(read(fsfd, buf, sizeof(buf))); 73 + EXPECT_STREQ("e tmpfs: Unknown parameter 'invalid-arg'\n", buf); 74 + 75 + /* The message has been consumed. */ 76 + ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf))); 77 + ASSERT_SUCCESS(close(fsfd)); 78 + } 79 + 80 + TEST_F(ns, fscontext_log_errorfc_after_fsmount) 81 + { 82 + int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC); 83 + ASSERT_SUCCESS(fsfd); 84 + 85 + ASSERT_ERRNO_EQ(-EINVAL, fsconfig(fsfd, FSCONFIG_SET_STRING, "invalid-arg", "123", 0)); 86 + 87 + ASSERT_SUCCESS(fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0)); 88 + int mfd = fsmount(fsfd, FSMOUNT_CLOEXEC, MOUNT_ATTR_NOEXEC | MOUNT_ATTR_NOSUID); 89 + ASSERT_SUCCESS(mfd); 90 + ASSERT_SUCCESS(move_mount(mfd, "", AT_FDCWD, "/tmp", MOVE_MOUNT_F_EMPTY_PATH)); 91 + 92 + /* 93 + * The fscontext log should still contain data even after 94 + * FSCONFIG_CMD_CREATE and fsmount(). 95 + */ 96 + char buf[128] = {}; 97 + ASSERT_SUCCESS(read(fsfd, buf, sizeof(buf))); 98 + EXPECT_STREQ("e tmpfs: Unknown parameter 'invalid-arg'\n", buf); 99 + 100 + /* The message has been consumed. */ 101 + ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf))); 102 + ASSERT_SUCCESS(close(fsfd)); 103 + } 104 + 105 + TEST_F(ns, fscontext_log_emsgsize) 106 + { 107 + int fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC); 108 + ASSERT_SUCCESS(fsfd); 109 + 110 + ASSERT_ERRNO_EQ(-EINVAL, fsconfig(fsfd, FSCONFIG_SET_STRING, "invalid-arg", "123", 0)); 111 + 112 + char buf[128] = {}; 113 + /* 114 + * Attempting to read a message with too small a buffer should not 115 + * result in the message getting consumed. 116 + */ 117 + ASSERT_ERRNO_EQ(-EMSGSIZE, read(fsfd, buf, 0)); 118 + ASSERT_ERRNO_EQ(-EMSGSIZE, read(fsfd, buf, 1)); 119 + for (int i = 0; i < 16; i++) 120 + ASSERT_ERRNO_EQ(-EMSGSIZE, read(fsfd, buf, 16)); 121 + 122 + ASSERT_SUCCESS(read(fsfd, buf, sizeof(buf))); 123 + EXPECT_STREQ("e tmpfs: Unknown parameter 'invalid-arg'\n", buf); 124 + 125 + /* The message has been consumed. */ 126 + ASSERT_ERRNO_EQ(-ENODATA, read(fsfd, buf, sizeof(buf))); 127 + ASSERT_SUCCESS(close(fsfd)); 128 + } 129 + 130 + TEST_HARNESS_MAIN