diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-15 21:00:42 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-15 21:00:42 +0200 |
commit | 78dcf73421a879d22319d3889119945b85954a68 (patch) | |
tree | 26e76f3e9fdc6b40133f2158de23cfe74af9feac | |
parent | Merge branch 'work.__copy_to_user' of git://git.kernel.org/pub/scm/linux/kern... (diff) | |
parent | isofs: Fix isofs_show_options() (diff) | |
download | linux-78dcf73421a879d22319d3889119945b85954a68.tar.xz linux-78dcf73421a879d22319d3889119945b85954a68.zip |
Merge branch 'work.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull ->s_options removal from Al Viro:
"Preparations for fsmount/fsopen stuff (coming next cycle). Everything
gets moved to explicit ->show_options(), killing ->s_options off +
some cosmetic bits around fs/namespace.c and friends. Basically, the
stuff needed to work with fsmount series with minimum of conflicts
with other work.
It's not strictly required for this merge window, but it would reduce
the PITA during the coming cycle, so it would be nice to have those
bits and pieces out of the way"
* 'work.mount' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
isofs: Fix isofs_show_options()
VFS: Kill off s_options and helpers
orangefs: Implement show_options
9p: Implement show_options
isofs: Implement show_options
afs: Implement show_options
affs: Implement show_options
befs: Implement show_options
spufs: Implement show_options
bpf: Implement show_options
ramfs: Implement show_options
pstore: Implement show_options
omfs: Implement show_options
hugetlbfs: Implement show_options
VFS: Don't use save/replace_mount_options if not using generic_show_options
VFS: Provide empty name qstr
VFS: Make get_filesystem() return the affected filesystem
VFS: Clean up whitespace in fs/namespace.c and fs/super.c
Provide a function to create a NUL-terminated string from unterminated data
41 files changed, 531 insertions, 163 deletions
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 48c9faa73a76..73e7d91f03dc 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -1225,12 +1225,6 @@ The underlying reason for the above rules is to make sure, that a mount can be accurately replicated (e.g. umounting and mounting again) based on the information found in /proc/mounts. -A simple method of saving options at mount/remount time and showing -them is provided with the save_mount_options() and -generic_show_options() helper functions. Please note, that using -these may have drawbacks. For more info see header comments for these -functions in fs/namespace.c. - Resources ========= diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index d8af9bc0489f..9558d725a99b 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -605,6 +605,24 @@ static const match_table_t spufs_tokens = { { Opt_err, NULL }, }; +static int spufs_show_options(struct seq_file *m, struct dentry *root) +{ + struct spufs_sb_info *sbi = spufs_get_sb_info(root->d_sb); + struct inode *inode = root->d_inode; + + if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID)) + seq_printf(m, ",uid=%u", + from_kuid_munged(&init_user_ns, inode->i_uid)); + if (!gid_eq(inode->i_gid, GLOBAL_ROOT_GID)) + seq_printf(m, ",gid=%u", + from_kgid_munged(&init_user_ns, inode->i_gid)); + if ((inode->i_mode & S_IALLUGO) != 0775) + seq_printf(m, ",mode=%o", inode->i_mode); + if (sbi->debug) + seq_puts(m, ",debug"); + return 0; +} + static int spufs_parse_options(struct super_block *sb, char *options, struct inode *root) { @@ -724,11 +742,9 @@ spufs_fill_super(struct super_block *sb, void *data, int silent) .destroy_inode = spufs_destroy_inode, .statfs = simple_statfs, .evict_inode = spufs_evict_inode, - .show_options = generic_show_options, + .show_options = spufs_show_options, }; - save_mount_options(sb, data); - info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index c202930086ed..8fb89ddc6cc7 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -33,6 +33,7 @@ #include <linux/parser.h> #include <linux/idr.h> #include <linux/slab.h> +#include <linux/seq_file.h> #include <net/9p/9p.h> #include <net/9p/client.h> #include <net/9p/transport.h> @@ -82,6 +83,13 @@ static const match_table_t tokens = { {Opt_err, NULL} }; +static const char *const v9fs_cache_modes[nr__p9_cache_modes] = { + [CACHE_NONE] = "none", + [CACHE_MMAP] = "mmap", + [CACHE_LOOSE] = "loose", + [CACHE_FSCACHE] = "fscache", +}; + /* Interpret mount options for cache mode */ static int get_cache_mode(char *s) { @@ -104,6 +112,58 @@ static int get_cache_mode(char *s) return version; } +/* + * Display the mount options in /proc/mounts. + */ +int v9fs_show_options(struct seq_file *m, struct dentry *root) +{ + struct v9fs_session_info *v9ses = root->d_sb->s_fs_info; + + if (v9ses->debug) + seq_printf(m, ",debug=%x", v9ses->debug); + if (!uid_eq(v9ses->dfltuid, V9FS_DEFUID)) + seq_printf(m, ",dfltuid=%u", + from_kuid_munged(&init_user_ns, v9ses->dfltuid)); + if (!gid_eq(v9ses->dfltgid, V9FS_DEFGID)) + seq_printf(m, ",dfltgid=%u", + from_kgid_munged(&init_user_ns, v9ses->dfltgid)); + if (v9ses->afid != ~0) + seq_printf(m, ",afid=%u", v9ses->afid); + if (strcmp(v9ses->uname, V9FS_DEFUSER) != 0) + seq_printf(m, ",uname=%s", v9ses->uname); + if (strcmp(v9ses->aname, V9FS_DEFANAME) != 0) + seq_printf(m, ",aname=%s", v9ses->aname); + if (v9ses->nodev) + seq_puts(m, ",nodevmap"); + if (v9ses->cache) + seq_printf(m, ",%s", v9fs_cache_modes[v9ses->cache]); +#ifdef CONFIG_9P_FSCACHE + if (v9ses->cachetag && v9ses->cache == CACHE_FSCACHE) + seq_printf(m, ",cachetag=%s", v9ses->cachetag); +#endif + + switch (v9ses->flags & V9FS_ACCESS_MASK) { + case V9FS_ACCESS_USER: + seq_puts(m, ",access=user"); + break; + case V9FS_ACCESS_ANY: + seq_puts(m, ",access=any"); + break; + case V9FS_ACCESS_CLIENT: + seq_puts(m, ",access=client"); + break; + case V9FS_ACCESS_SINGLE: + seq_printf(m, ",access=%u", + from_kuid_munged(&init_user_ns, v9ses->uid)); + break; + } + + if (v9ses->flags & V9FS_POSIX_ACL) + seq_puts(m, ",posixacl"); + + return p9_show_client_options(m, v9ses->clnt); +} + /** * v9fs_parse_options - parse mount options into session structure * @v9ses: existing v9fs session information @@ -230,6 +290,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) break; case Opt_cachetag: #ifdef CONFIG_9P_FSCACHE + kfree(v9ses->cachetag); v9ses->cachetag = match_strdup(&args[0]); #endif break; diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 76eaf49abd3a..982e017acadb 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h @@ -67,6 +67,7 @@ enum p9_cache_modes { CACHE_MMAP, CACHE_LOOSE, CACHE_FSCACHE, + nr__p9_cache_modes }; /** @@ -137,6 +138,8 @@ static inline struct v9fs_inode *V9FS_I(const struct inode *inode) return container_of(inode, struct v9fs_inode, vfs_inode); } +extern int v9fs_show_options(struct seq_file *m, struct dentry *root); + struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *, char *); extern void v9fs_session_close(struct v9fs_session_info *v9ses); diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index a0965fb587a5..8b75463cb211 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -33,7 +33,6 @@ #include <linux/string.h> #include <linux/inet.h> #include <linux/pagemap.h> -#include <linux/seq_file.h> #include <linux/mount.h> #include <linux/idr.h> #include <linux/sched.h> @@ -104,7 +103,6 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses, sb->s_flags |= MS_POSIXACL; #endif - save_mount_options(sb, data); return 0; } @@ -349,7 +347,7 @@ static const struct super_operations v9fs_super_ops = { .destroy_inode = v9fs_destroy_inode, .statfs = simple_statfs, .evict_inode = v9fs_evict_inode, - .show_options = generic_show_options, + .show_options = v9fs_show_options, .umount_begin = v9fs_umount_begin, .write_inode = v9fs_write_inode, }; @@ -360,7 +358,7 @@ static const struct super_operations v9fs_super_ops_dotl = { .statfs = v9fs_statfs, .drop_inode = v9fs_drop_inode, .evict_inode = v9fs_evict_inode, - .show_options = generic_show_options, + .show_options = v9fs_show_options, .umount_begin = v9fs_umount_begin, .write_inode = v9fs_write_inode_dotl, }; diff --git a/fs/affs/super.c b/fs/affs/super.c index c2c27a8f128e..7bf47a41cb4f 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -20,9 +20,11 @@ #include <linux/slab.h> #include <linux/writeback.h> #include <linux/blkdev.h> +#include <linux/seq_file.h> #include "affs.h" static int affs_statfs(struct dentry *dentry, struct kstatfs *buf); +static int affs_show_options(struct seq_file *m, struct dentry *root); static int affs_remount (struct super_block *sb, int *flags, char *data); static void @@ -159,7 +161,7 @@ static const struct super_operations affs_sops = { .sync_fs = affs_sync_fs, .statfs = affs_statfs, .remount_fs = affs_remount, - .show_options = generic_show_options, + .show_options = affs_show_options, }; enum { @@ -293,6 +295,40 @@ parse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved, return 1; } +static int affs_show_options(struct seq_file *m, struct dentry *root) +{ + struct super_block *sb = root->d_sb; + struct affs_sb_info *sbi = AFFS_SB(sb); + + if (sb->s_blocksize) + seq_printf(m, ",bs=%lu", sb->s_blocksize); + if (affs_test_opt(sbi->s_flags, SF_SETMODE)) + seq_printf(m, ",mode=%o", sbi->s_mode); + if (affs_test_opt(sbi->s_flags, SF_MUFS)) + seq_puts(m, ",mufs"); + if (affs_test_opt(sbi->s_flags, SF_NO_TRUNCATE)) + seq_puts(m, ",nofilenametruncate"); + if (affs_test_opt(sbi->s_flags, SF_PREFIX)) + seq_printf(m, ",prefix=%s", sbi->s_prefix); + if (affs_test_opt(sbi->s_flags, SF_IMMUTABLE)) + seq_puts(m, ",protect"); + if (sbi->s_reserved != 2) + seq_printf(m, ",reserved=%u", sbi->s_reserved); + if (sbi->s_root_block != (sbi->s_reserved + sbi->s_partition_size - 1) / 2) + seq_printf(m, ",root=%u", sbi->s_root_block); + if (affs_test_opt(sbi->s_flags, SF_SETGID)) + seq_printf(m, ",setgid=%u", + from_kgid_munged(&init_user_ns, sbi->s_gid)); + if (affs_test_opt(sbi->s_flags, SF_SETUID)) + seq_printf(m, ",setuid=%u", + from_kuid_munged(&init_user_ns, sbi->s_uid)); + if (affs_test_opt(sbi->s_flags, SF_VERBOSE)) + seq_puts(m, ",verbose"); + if (sbi->s_volume[0]) + seq_printf(m, ",volume=%s", sbi->s_volume); + return 0; +} + /* This function definitely needs to be split up. Some fine day I'll * hopefully have the guts to do so. Until then: sorry for the mess. */ @@ -316,8 +352,6 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) u8 sig[4]; int ret; - save_mount_options(sb, data); - pr_debug("read_super(%s)\n", data ? (const char *)data : "no options"); sb->s_magic = AFFS_SUPER_MAGIC; @@ -548,8 +582,6 @@ affs_remount(struct super_block *sb, int *flags, char *data) } flush_delayed_work(&sbi->sb_work); - if (new_opts) - replace_mount_options(sb, new_opts); sbi->s_flags = mount_flags; sbi->s_mode = mode; diff --git a/fs/afs/super.c b/fs/afs/super.c index 67680c2d96cf..689173c0a682 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -37,6 +37,8 @@ static void afs_kill_super(struct super_block *sb); static struct inode *afs_alloc_inode(struct super_block *sb); static void afs_destroy_inode(struct inode *inode); static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); +static int afs_show_devname(struct seq_file *m, struct dentry *root); +static int afs_show_options(struct seq_file *m, struct dentry *root); struct file_system_type afs_fs_type = { .owner = THIS_MODULE, @@ -53,7 +55,8 @@ static const struct super_operations afs_super_ops = { .drop_inode = afs_drop_inode, .destroy_inode = afs_destroy_inode, .evict_inode = afs_evict_inode, - .show_options = generic_show_options, + .show_devname = afs_show_devname, + .show_options = afs_show_options, }; static struct kmem_cache *afs_inode_cachep; @@ -136,6 +139,45 @@ void __exit afs_fs_exit(void) } /* + * Display the mount device name in /proc/mounts. + */ +static int afs_show_devname(struct seq_file *m, struct dentry *root) +{ + struct afs_super_info *as = root->d_sb->s_fs_info; + struct afs_volume *volume = as->volume; + struct afs_cell *cell = volume->cell; + const char *suf = ""; + char pref = '%'; + + switch (volume->type) { + case AFSVL_RWVOL: + break; + case AFSVL_ROVOL: + pref = '#'; + if (volume->type_force) + suf = ".readonly"; + break; + case AFSVL_BACKVOL: + pref = '#'; + suf = ".backup"; + break; + } + + seq_printf(m, "%c%s:%s%s", pref, cell->name, volume->vlocation->vldb.name, suf); + return 0; +} + +/* + * Display the mount options in /proc/mounts. + */ +static int afs_show_options(struct seq_file *m, struct dentry *root) +{ + if (test_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(d_inode(root))->flags)) + seq_puts(m, "autocell"); + return 0; +} + +/* * parse the mount options * - this function has been shamelessly adapted from the ext3 fs which * shamelessly adapted it from the msdos fs @@ -427,7 +469,6 @@ static struct dentry *afs_mount(struct file_system_type *fs_type, deactivate_locked_super(sb); goto error; } - save_mount_options(sb, new_opts); sb->s_flags |= MS_ACTIVE; } else { _debug("reuse"); diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 63e7c4760bfb..4a4a5a366158 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -20,6 +20,7 @@ #include <linux/sched.h> #include <linux/cred.h> #include <linux/exportfs.h> +#include <linux/seq_file.h> #include "befs.h" #include "btree.h" @@ -53,6 +54,7 @@ static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, static void befs_put_super(struct super_block *); static int befs_remount(struct super_block *, int *, char *); static int befs_statfs(struct dentry *, struct kstatfs *); +static int befs_show_options(struct seq_file *, struct dentry *); static int parse_options(char *, struct befs_mount_options *); static struct dentry *befs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type); @@ -66,7 +68,7 @@ static const struct super_operations befs_sops = { .put_super = befs_put_super, /* uninit super */ .statfs = befs_statfs, /* statfs */ .remount_fs = befs_remount, - .show_options = generic_show_options, + .show_options = befs_show_options, }; /* slab cache for befs_inode_info objects */ @@ -771,6 +773,24 @@ parse_options(char *options, struct befs_mount_options *opts) return 1; } +static int befs_show_options(struct seq_file *m, struct dentry *root) +{ + struct befs_sb_info *befs_sb = BEFS_SB(root->d_sb); + struct befs_mount_options *opts = &befs_sb->mount_opts; + + if (!uid_eq(opts->uid, GLOBAL_ROOT_UID)) + seq_printf(m, ",uid=%u", + from_kuid_munged(&init_user_ns, opts->uid)); + if (!gid_eq(opts->gid, GLOBAL_ROOT_GID)) + seq_printf(m, ",gid=%u", + from_kgid_munged(&init_user_ns, opts->gid)); + if (opts->iocharset) + seq_printf(m, ",charset=%s", opts->iocharset); + if (opts->debug) + seq_puts(m, ",debug"); + return 0; +} + /* This function has the responsibiltiy of getting the * filesystem ready for unmounting. * Basically, we free everything that we allocated in @@ -804,8 +824,6 @@ befs_fill_super(struct super_block *sb, void *data, int silent) const off_t x86_sb_off = 512; int blocksize; - save_mount_options(sb, data); - sb->s_fs_info = kzalloc(sizeof(*befs_sb), GFP_KERNEL); if (sb->s_fs_info == NULL) goto unacquire_none; diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 74e47794e63f..12540b6104b5 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1154,7 +1154,6 @@ static int btrfs_fill_super(struct super_block *sb, goto fail_close; } - save_mount_options(sb, data); cleancache_init_fs(sb); sb->s_flags |= MS_ACTIVE; return 0; diff --git a/fs/dcache.c b/fs/dcache.c index 6c30be668487..f90141387f01 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -90,6 +90,11 @@ EXPORT_SYMBOL(rename_lock); static struct kmem_cache *dentry_cache __read_mostly; +const struct qstr empty_name = QSTR_INIT("", 0); +EXPORT_SYMBOL(empty_name); +const struct qstr slash_name = QSTR_INIT("/", 1); +EXPORT_SYMBOL(slash_name); + /* * This is the single most critical data structure when it comes * to the dcache: the hashtable for lookups. Somebody should try @@ -1606,8 +1611,7 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) */ dentry->d_iname[DNAME_INLINE_LEN-1] = 0; if (unlikely(!name)) { - static const struct qstr anon = QSTR_INIT("/", 1); - name = &anon; + name = &slash_name; dname = dentry->d_iname; } else if (name->len > DNAME_INLINE_LEN-1) { size_t size = offsetof(struct external_name, name[1]); diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index a0e4e2f7e0be..c59f015f386e 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c @@ -203,8 +203,6 @@ static int debug_fill_super(struct super_block *sb, void *data, int silent) struct debugfs_fs_info *fsi; int err; - save_mount_options(sb, data); - fsi = kzalloc(sizeof(struct debugfs_fs_info), GFP_KERNEL); sb->s_fs_info = fsi; if (!fsi) { diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index d7a7c53803c1..5b68e4294faa 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -29,7 +29,6 @@ static const struct super_operations efivarfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, .evict_inode = efivarfs_evict_inode, - .show_options = generic_show_options, }; static struct super_block *efivarfs_sb; diff --git a/fs/filesystems.c b/fs/filesystems.c index 8b99955e3504..a920ad2629ac 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -33,9 +33,10 @@ static struct file_system_type *file_systems; static DEFINE_RWLOCK(file_systems_lock); /* WARNING: This can be used only if we _already_ own a reference */ -void get_filesystem(struct file_system_type *fs) +struct file_system_type *get_filesystem(struct file_system_type *fs) { __module_get(fs->owner); + return fs; } void put_filesystem(struct file_system_type *fs) diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c index db427658ccd9..5ee2e2f8576c 100644 --- a/fs/gfs2/dir.c +++ b/fs/gfs2/dir.c @@ -872,7 +872,6 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, struct buffer_head *bh; struct gfs2_leaf *leaf; struct gfs2_dirent *dent; - struct qstr name = { .name = "" }; struct timespec tv = current_time(inode); error = gfs2_alloc_blocks(ip, &bn, &n, 0, NULL); @@ -896,7 +895,7 @@ static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, leaf->lf_sec = cpu_to_be64(tv.tv_sec); memset(leaf->lf_reserved2, 0, sizeof(leaf->lf_reserved2)); dent = (struct gfs2_dirent *)(leaf+1); - gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent); + gfs2_qstr2dirent(&empty_name, bh->b_size - sizeof(struct gfs2_leaf), dent); *pbh = bh; return leaf; } diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 52388611635e..28d2753be094 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -46,13 +46,13 @@ static const struct inode_operations hugetlbfs_dir_inode_operations; static const struct inode_operations hugetlbfs_inode_operations; struct hugetlbfs_config { - kuid_t uid; - kgid_t gid; - umode_t mode; - long max_hpages; - long nr_inodes; - struct hstate *hstate; - long min_hpages; + struct hstate *hstate; + long max_hpages; + long nr_inodes; + long min_hpages; + kuid_t uid; + kgid_t gid; + umode_t mode; }; struct hugetlbfs_inode_info { @@ -861,6 +861,46 @@ static int hugetlbfs_error_remove_page(struct address_space *mapping, return 0; } +/* + * Display the mount options in /proc/mounts. + */ +static int hugetlbfs_show_options(struct seq_file *m, struct dentry *root) +{ + struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(root->d_sb); + struct hugepage_subpool *spool = sbinfo->spool; + unsigned long hpage_size = huge_page_size(sbinfo->hstate); + unsigned hpage_shift = huge_page_shift(sbinfo->hstate); + char mod; + + if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID)) + seq_printf(m, ",uid=%u", + from_kuid_munged(&init_user_ns, sbinfo->uid)); + if (!gid_eq(sbinfo->gid, GLOBAL_ROOT_GID)) + seq_printf(m, ",gid=%u", + from_kgid_munged(&init_user_ns, sbinfo->gid)); + if (sbinfo->mode != 0755) + seq_printf(m, ",mode=%o", sbinfo->mode); + if (sbinfo->max_inodes != -1) + seq_printf(m, ",nr_inodes=%lu", sbinfo->max_inodes); + + hpage_size /= 1024; + mod = 'K'; + if (hpage_size >= 1024) { + hpage_size /= 1024; + mod = 'M'; + } + seq_printf(m, ",pagesize=%lu%c", hpage_size, mod); + if (spool) { + if (spool->max_hpages != -1) + seq_printf(m, ",size=%llu", + (unsigned long long)spool->max_hpages << hpage_shift); + if (spool->min_hpages != -1) + seq_printf(m, ",min_size=%llu", + (unsigned long long)spool->min_hpages << hpage_shift); + } + return 0; +} + static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb); @@ -1019,19 +1059,19 @@ static const struct super_operations hugetlbfs_ops = { .evict_inode = hugetlbfs_evict_inode, .statfs = hugetlbfs_statfs, .put_super = hugetlbfs_put_super, - .show_options = generic_show_options, + .show_options = hugetlbfs_show_options, }; -enum { NO_SIZE, SIZE_STD, SIZE_PERCENT }; +enum hugetlbfs_size_type { NO_SIZE, SIZE_STD, SIZE_PERCENT }; /* * Convert size option passed from command line to number of huge pages * in the pool specified by hstate. Size option could be in bytes * (val_type == SIZE_STD) or percentage of the pool (val_type == SIZE_PERCENT). */ -static long long +static long hugetlbfs_size_to_hpages(struct hstate *h, unsigned long long size_opt, - int val_type) + enum hugetlbfs_size_type val_type) { if (val_type == NO_SIZE) return -1; @@ -1053,7 +1093,7 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) substring_t args[MAX_OPT_ARGS]; int option; unsigned long long max_size_opt = 0, min_size_opt = 0; - int max_val_type = NO_SIZE, min_val_type = NO_SIZE; + enum hugetlbfs_size_type max_val_type = NO_SIZE, min_val_type = NO_SIZE; if (!options) return 0; @@ -1167,8 +1207,6 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) struct hugetlbfs_config config; struct hugetlbfs_sb_info *sbinfo; - save_mount_options(sb, data); - config.max_hpages = -1; /* No limit on size by default */ config.nr_inodes = -1; /* No limit on number of inodes by default */ config.uid = current_fsuid(); @@ -1189,6 +1227,10 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) sbinfo->max_inodes = config.nr_inodes; sbinfo->free_inodes = config.nr_inodes; sbinfo->spool = NULL; + sbinfo->uid = config.uid; + sbinfo->gid = config.gid; + sbinfo->mode = config.mode; + /* * Allocate and initialize subpool if maximum or minimum size is * specified. Any needed reservations (for minimim size) are taken diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 020ba0936146..8cf898a59730 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -23,6 +23,7 @@ #include <linux/parser.h> #include <linux/mpage.h> #include <linux/user_namespace.h> +#include <linux/seq_file.h> #include "isofs.h" #include "zisofs.h" @@ -57,6 +58,7 @@ static void isofs_put_super(struct super_block *sb) static int isofs_read_inode(struct inode *, int relocated); static int isofs_statfs (struct dentry *, struct kstatfs *); +static int isofs_show_options(struct seq_file *, struct dentry *); static struct kmem_cache *isofs_inode_cachep; @@ -123,7 +125,7 @@ static const struct super_operations isofs_sops = { .put_super = isofs_put_super, .statfs = isofs_statfs, .remount_fs = isofs_remount, - .show_options = generic_show_options, + .show_options = isofs_show_options, }; @@ -473,6 +475,48 @@ static int parse_options(char *options, struct iso9660_options *popt) } /* + * Display the mount options in /proc/mounts. + */ +static int isofs_show_options(struct seq_file *m, struct dentry *root) +{ + struct isofs_sb_info *sbi = ISOFS_SB(root->d_sb); + + if (!sbi->s_rock) seq_puts(m, ",norock"); + else if (!sbi->s_joliet_level) seq_puts(m, ",nojoliet"); + if (sbi->s_cruft) seq_puts(m, ",cruft"); + if (sbi->s_hide) seq_puts(m, ",hide"); + if (sbi->s_nocompress) seq_puts(m, ",nocompress"); + if (sbi->s_overriderockperm) seq_puts(m, ",overriderockperm"); + if (sbi->s_showassoc) seq_puts(m, ",showassoc"); + if (sbi->s_utf8) seq_puts(m, ",utf8"); + + if (sbi->s_check) seq_printf(m, ",check=%c", sbi->s_check); + if (sbi->s_mapping) seq_printf(m, ",map=%c", sbi->s_mapping); + if (sbi->s_session != 255) seq_printf(m, ",session=%u", sbi->s_session - 1); + if (sbi->s_sbsector != -1) seq_printf(m, ",sbsector=%u", sbi->s_sbsector); + + if (root->d_sb->s_blocksize != 1024) + seq_printf(m, ",blocksize=%lu", root->d_sb->s_blocksize); + + if (sbi->s_uid_set) + seq_printf(m, ",uid=%u", + from_kuid_munged(&init_user_ns, sbi->s_uid)); + if (sbi->s_gid_set) + seq_printf(m, ",gid=%u", + from_kgid_munged(&init_user_ns, sbi->s_gid)); + + if (sbi->s_dmode != ISOFS_INVALID_MODE) + seq_printf(m, ",dmode=%o", sbi->s_dmode); + if (sbi->s_fmode != ISOFS_INVALID_MODE) + seq_printf(m, ",fmode=%o", sbi->s_fmode); + + if (sbi->s_nls_iocharset && + strcmp(sbi->s_nls_iocharset->charset, CONFIG_NLS_DEFAULT) != 0) + seq_printf(m, ",iocharset=%s", sbi->s_nls_iocharset->charset); + return 0; +} + +/* * look if the driver can tell the multi session redirection value * * don't change this if you don't know what you do, please! @@ -583,8 +627,6 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) int table, error = -EINVAL; unsigned int vol_desc_start; - save_mount_options(s, data); - sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) return -ENOMEM; @@ -605,6 +647,8 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) opt.blocksize = sb_min_blocksize(s, opt.blocksize); sbi->s_high_sierra = 0; /* default is iso9660 */ + sbi->s_session = opt.session; + sbi->s_sbsector = opt.sbsector; vol_desc_start = (opt.sbsector != -1) ? opt.sbsector : isofs_get_last_session(s,opt.session); @@ -911,6 +955,7 @@ root_found: table += 2; if (opt.check == 'r') table++; + sbi->s_check = opt.check; if (table) s->s_d_op = &isofs_dentry_ops[table - 1]; diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index 0ac4c1f73fbd..133a456b0425 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h @@ -36,8 +36,11 @@ struct isofs_sb_info { unsigned long s_max_size; int s_rock_offset; /* offset of SUSP fields within SU area */ + s32 s_sbsector; unsigned char s_joliet_level; unsigned char s_mapping; + unsigned char s_check; + unsigned char s_session; unsigned int s_high_sierra:1; unsigned int s_rock:2; unsigned int s_utf8:1; diff --git a/fs/namei.c b/fs/namei.c index e0b46eb0e212..88fd38d1e3e7 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3400,7 +3400,6 @@ out: struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode, int open_flag) { - static const struct qstr name = QSTR_INIT("/", 1); struct dentry *child = NULL; struct inode *dir = dentry->d_inode; struct inode *inode; @@ -3414,7 +3413,7 @@ struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode, int open_flag) if (!dir->i_op->tmpfile) goto out_err; error = -ENOMEM; - child = d_alloc(dentry, &name); + child = d_alloc(dentry, &slash_name); if (unlikely(!child)) goto out_err; error = dir->i_op->tmpfile(dir, child, mode); diff --git a/fs/namespace.c b/fs/namespace.c index 81f934b5d571..f8893dc6a989 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1238,65 +1238,6 @@ struct vfsmount *mnt_clone_internal(const struct path *path) return &p->mnt; } -static inline void mangle(struct seq_file *m, const char *s) -{ - seq_escape(m, s, " \t\n\\"); -} - -/* - * Simple .show_options callback for filesystems which don't want to - * implement more complex mount option showing. - * - * See also save_mount_options(). - */ -int generic_show_options(struct seq_file *m, struct dentry *root) -{ - const char *options; - - rcu_read_lock(); - options = rcu_dereference(root->d_sb->s_options); - - if (options != NULL && options[0]) { - seq_putc(m, ','); - mangle(m, options); - } - rcu_read_unlock(); - - return 0; -} -EXPORT_SYMBOL(generic_show_options); - -/* - * If filesystem uses generic_show_options(), this function should be - * called from the fill_super() callback. - * - * The .remount_fs callback usually needs to be handled in a special - * way, to make sure, that previous options are not overwritten if the - * remount fails. - * - * Also note, that if the filesystem's .remount_fs function doesn't - * reset all options to their default value, but changes only newly - * given options, then the displayed options will not reflect reality - * any more. - */ -void save_mount_options(struct super_block *sb, char *options) -{ - BUG_ON(sb->s_options); - rcu_assign_pointer(sb->s_options, kstrdup(options, GFP_KERNEL)); -} -EXPORT_SYMBOL(save_mount_options); - -void replace_mount_options(struct super_block *sb, char *options) -{ - char *old = sb->s_options; - rcu_assign_pointer(sb->s_options, options); - if (old) { - synchronize_rcu(); - kfree(old); - } -} -EXPORT_SYMBOL(replace_mount_options); - #ifdef CONFIG_PROC_FS /* iterator; we want it to have access to namespace_sem, thus here... */ static void *m_start(struct seq_file *m, loff_t *pos) @@ -1657,7 +1598,7 @@ out_unlock: namespace_unlock(); } -/* +/* * Is the caller allowed to modify his namespace? */ static inline bool may_mount(void) @@ -2211,7 +2152,7 @@ static int do_loopback(struct path *path, const char *old_name, err = -EINVAL; if (mnt_ns_loop(old_path.dentry)) - goto out; + goto out; mp = lock_mount(path); err = PTR_ERR(mp); diff --git a/fs/nsfs.c b/fs/nsfs.c index f3db56e83dd2..08127a2b8559 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -53,7 +53,6 @@ static void nsfs_evict(struct inode *inode) static void *__ns_get_path(struct path *path, struct ns_common *ns) { struct vfsmount *mnt = nsfs_mnt; - struct qstr qname = { .name = "", }; struct dentry *dentry; struct inode *inode; unsigned long d; @@ -85,7 +84,7 @@ slow: inode->i_fop = &ns_file_operations; inode->i_private = ns; - dentry = d_alloc_pseudo(mnt->mnt_sb, &qname); + dentry = d_alloc_pseudo(mnt->mnt_sb, &empty_name); if (!dentry) { iput(inode); return ERR_PTR(-ENOMEM); diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index 8c9034ee7383..ee14af9e26f2 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -13,6 +13,7 @@ #include <linux/buffer_head.h> #include <linux/vmalloc.h> #include <linux/writeback.h> +#include <linux/seq_file.h> #include <linux/crc-itu-t.h> #include "omfs.h" @@ -290,12 +291,40 @@ static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf) return 0; } +/* + * Display the mount options in /proc/mounts. + */ +static int omfs_show_options(struct seq_file *m, struct dentry *root) +{ + struct omfs_sb_info *sbi = OMFS_SB(root->d_sb); + umode_t cur_umask = current_umask(); + + if (!uid_eq(sbi->s_uid, current_uid())) + seq_printf(m, ",uid=%u", + from_kuid_munged(&init_user_ns, sbi->s_uid)); + if (!gid_eq(sbi->s_gid, current_gid())) + seq_printf(m, ",gid=%u", + from_kgid_munged(&init_user_ns, sbi->s_gid)); + + if (sbi->s_dmask == sbi->s_fmask) { + if (sbi->s_fmask != cur_umask) + seq_printf(m, ",umask=%o", sbi->s_fmask); + } else { + if (sbi->s_dmask != cur_umask) + seq_printf(m, ",dmask=%o", sbi->s_dmask); + if (sbi->s_fmask != cur_umask) + seq_printf(m, ",fmask=%o", sbi->s_fmask); + } + + return 0; +} + static const struct super_operations omfs_sops = { .write_inode = omfs_write_inode, .evict_inode = omfs_evict_inode, .put_super = omfs_put_super, .statfs = omfs_statfs, - .show_options = generic_show_options, + .show_options = omfs_show_options, }; /* @@ -434,8 +463,6 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) struct inode *root; int ret = -EINVAL; - save_mount_options(sb, (char *) data); - sbi = kzalloc(sizeof(struct omfs_sb_info), GFP_KERNEL); if (!sbi) return -ENOMEM; diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c index 5c7c273e17ec..5a1bed6c8c6a 100644 --- a/fs/orangefs/super.c +++ b/fs/orangefs/super.c @@ -35,6 +35,19 @@ static const match_table_t tokens = { uint64_t orangefs_features; +static int orangefs_show_options(struct seq_file *m, struct dentry *root) +{ + struct orangefs_sb_info_s *orangefs_sb = ORANGEFS_SB(root->d_sb); + + if (root->d_sb->s_flags & MS_POSIXACL) + seq_puts(m, ",acl"); + if (orangefs_sb->flags & ORANGEFS_OPT_INTR) + seq_puts(m, ",intr"); + if (orangefs_sb->flags & ORANGEFS_OPT_LOCAL_LOCK) + seq_puts(m, ",local_lock"); + return 0; +} + static int parse_mount_options(struct super_block *sb, char *options, int silent) { @@ -305,7 +318,7 @@ static const struct super_operations orangefs_s_ops = { .drop_inode = generic_delete_inode, .statfs = orangefs_statfs, .remount_fs = orangefs_remount_fs, - .show_options = generic_show_options, + .show_options = orangefs_show_options, }; static struct dentry *orangefs_fh_to_dentry(struct super_block *sb, diff --git a/fs/pipe.c b/fs/pipe.c index 73b84baf58f8..97e5be897753 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -739,13 +739,12 @@ int create_pipe_files(struct file **res, int flags) struct inode *inode = get_pipe_inode(); struct file *f; struct path path; - static struct qstr name = { .name = "" }; if (!inode) return -ENFILE; err = -ENOMEM; - path.dentry = d_alloc_pseudo(pipe_mnt->mnt_sb, &name); + path.dentry = d_alloc_pseudo(pipe_mnt->mnt_sb, &empty_name); if (!path.dentry) goto err_inode; path.mnt = mntget(pipe_mnt); diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 4d02c3b65061..fefd22611cf6 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -283,6 +283,16 @@ static void parse_options(char *options) } } +/* + * Display the mount options in /proc/mounts. + */ +static int pstore_show_options(struct seq_file *m, struct dentry *root) +{ + if (kmsg_bytes != PSTORE_DEFAULT_KMSG_BYTES) + seq_printf(m, ",kmsg_bytes=%lu", kmsg_bytes); + return 0; +} + static int pstore_remount(struct super_block *sb, int *flags, char *data) { sync_filesystem(sb); @@ -296,7 +306,7 @@ static const struct super_operations pstore_ops = { .drop_inode = generic_delete_inode, .evict_inode = pstore_evict_inode, .remount_fs = pstore_remount, - .show_options = generic_show_options, + .show_options = pstore_show_options, }; static struct super_block *pstore_sb; @@ -448,8 +458,6 @@ static int pstore_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; - save_mount_options(sb, data); - pstore_sb = sb; sb->s_maxbytes = MAX_LFS_FILESIZE; diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h index 58051265626f..7f4e48c8d188 100644 --- a/fs/pstore/internal.h +++ b/fs/pstore/internal.h @@ -5,6 +5,9 @@ #include <linux/time.h> #include <linux/pstore.h> +#define PSTORE_DEFAULT_KMSG_BYTES 10240 +extern unsigned long kmsg_bytes; + #ifdef CONFIG_PSTORE_FTRACE extern void pstore_register_ftrace(void); extern void pstore_unregister_ftrace(void); diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 1b6e0ff6bff5..2b21d180157c 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -99,7 +99,7 @@ static char *big_oops_buf; static size_t big_oops_buf_sz; /* How much of the console log to snapshot */ -static unsigned long kmsg_bytes = 10240; +unsigned long kmsg_bytes = PSTORE_DEFAULT_KMSG_BYTES; void pstore_set_kmsg_bytes(int bytes) { diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 26e45863e499..11201b2d06b9 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -38,6 +38,14 @@ #include <linux/uaccess.h> #include "internal.h" +struct ramfs_mount_opts { + umode_t mode; +}; + +struct ramfs_fs_info { + struct ramfs_mount_opts mount_opts; +}; + #define RAMFS_DEFAULT_MODE 0755 static const struct super_operations ramfs_ops; @@ -149,14 +157,22 @@ static const struct inode_operations ramfs_dir_inode_operations = { .rename = simple_rename, }; +/* + * Display the mount options in /proc/mounts. + */ +static int ramfs_show_options(struct seq_file *m, struct dentry *root) +{ + struct ramfs_fs_info *fsi = root->d_sb->s_fs_info; + + if (fsi->mount_opts.mode != RAMFS_DEFAULT_MODE) + seq_printf(m, ",mode=%o", fsi->mount_opts.mode); + return 0; +} + static const struct super_operations ramfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, - .show_options = generic_show_options, -}; - -struct ramfs_mount_opts { - umode_t mode; + .show_options = ramfs_show_options, }; enum { @@ -169,10 +185,6 @@ static const match_table_t tokens = { {Opt_err, NULL} }; -struct ramfs_fs_info { - struct ramfs_mount_opts mount_opts; -}; - static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts) { substring_t args[MAX_OPT_ARGS]; @@ -211,8 +223,6 @@ int ramfs_fill_super(struct super_block *sb, void *data, int silent) struct inode *inode; int err; - save_mount_options(sb, data); - fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL); sb->s_fs_info = fsi; if (!fsi) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 685f1e056998..306e4e9d172d 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1599,8 +1599,6 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) } out_ok_unlocked: - if (new_opts) - replace_mount_options(s, new_opts); return 0; out_err_unlock: @@ -1916,8 +1914,6 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) char *qf_names[REISERFS_MAXQUOTAS] = {}; unsigned int qfmt = 0; - save_mount_options(s, data); - sbi = kzalloc(sizeof(struct reiserfs_sb_info), GFP_KERNEL); if (!sbi) return -ENOMEM; diff --git a/fs/super.c b/fs/super.c index adb0c0de428c..6bc3352adcf3 100644 --- a/fs/super.c +++ b/fs/super.c @@ -168,7 +168,6 @@ static void destroy_super(struct super_block *s) WARN_ON(!list_empty(&s->s_mounts)); put_user_ns(s->s_user_ns); kfree(s->s_subtype); - kfree(s->s_options); call_rcu(&s->rcu, destroy_super_rcu); } @@ -508,7 +507,7 @@ retry: return ERR_PTR(-ENOMEM); goto retry; } - + err = set(s, data); if (err) { spin_unlock(&sb_lock); @@ -771,7 +770,7 @@ restart: spin_unlock(&sb_lock); return NULL; } - + struct super_block *user_get_super(dev_t dev) { struct super_block *sb; diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index 328e89c2cf83..bea8ad876bf9 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -270,8 +270,6 @@ static int trace_fill_super(struct super_block *sb, void *data, int silent) struct tracefs_fs_info *fsi; int err; - save_mount_options(sb, data); - fsi = kzalloc(sizeof(struct tracefs_fs_info), GFP_KERNEL); sb->s_fs_info = fsi; if (!fsi) { diff --git a/include/linux/dcache.h b/include/linux/dcache.h index c706eaac692e..3f3ff4ccdc3f 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -55,6 +55,11 @@ struct qstr { #define QSTR_INIT(n,l) { { { .len = l } }, .name = n } +extern const char empty_string[]; +extern const struct qstr empty_name; +extern const char slash_string[]; +extern const struct qstr slash_name; + struct dentry_stat_t { long nr_dentry; long nr_unused; diff --git a/include/linux/fs.h b/include/linux/fs.h index 976aaa1af82a..7b5d6816542b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1364,11 +1364,6 @@ struct super_block { */ char *s_subtype; - /* - * Saved mount options for lazy filesystems using - * generic_show_options() - */ - char __rcu *s_options; const struct dentry_operations *s_d_op; /* default d_op for dentries */ /* @@ -3046,7 +3041,7 @@ extern int generic_block_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len, get_block_t *get_block); -extern void get_filesystem(struct file_system_type *fs); +extern struct file_system_type *get_filesystem(struct file_system_type *fs); extern void put_filesystem(struct file_system_type *fs); extern struct file_system_type *get_fs_type(const char *name); extern struct super_block *get_super(struct block_device *); @@ -3123,10 +3118,6 @@ extern void setattr_copy(struct inode *inode, const struct iattr *attr); extern int file_update_time(struct file *file); -extern int generic_show_options(struct seq_file *m, struct dentry *root); -extern void save_mount_options(struct super_block *sb, char *options); -extern void replace_mount_options(struct super_block *sb, char *options); - static inline bool io_is_direct(struct file *filp) { return (filp->f_flags & O_DIRECT) || IS_DAX(filp->f_mapping->host); diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 8d9fe131a240..0ed8e41aaf11 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -268,6 +268,9 @@ struct hugetlbfs_sb_info { spinlock_t stat_lock; struct hstate *hstate; struct hugepage_subpool *spool; + kuid_t uid; + kgid_t gid; + umode_t mode; }; static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb) diff --git a/include/linux/string.h b/include/linux/string.h index 049866760e8b..a467e617eeb0 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -137,6 +137,7 @@ extern char *kstrdup(const char *s, gfp_t gfp) __malloc; extern const char *kstrdup_const(const char *s, gfp_t gfp); extern char *kstrndup(const char *s, size_t len, gfp_t gfp); extern void *kmemdup(const void *src, size_t len, gfp_t gfp); +extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp); extern char **argv_split(gfp_t gfp, const char *str, int *argcp); extern void argv_free(char **argv); diff --git a/include/net/9p/client.h b/include/net/9p/client.h index b582339ccef5..7af9d769b97d 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h @@ -157,6 +157,18 @@ struct p9_client { enum p9_trans_status status; void *trans; + union { + struct { + int rfd; + int wfd; + } fd; + struct { + u16 port; + bool privport; + + } tcp; + } trans_opts; + struct p9_idpool *fidpool; struct list_head fidlist; @@ -213,6 +225,7 @@ struct p9_dirent { struct iov_iter; +int p9_show_client_options(struct seq_file *m, struct p9_client *clnt); int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb); int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, const char *name); diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h index 5122b5e40f78..1625fb842ac4 100644 --- a/include/net/9p/transport.h +++ b/include/net/9p/transport.h @@ -62,6 +62,7 @@ struct p9_trans_module { int (*cancelled)(struct p9_client *, struct p9_req_t *req); int (*zc_request)(struct p9_client *, struct p9_req_t *, struct iov_iter *, struct iov_iter *, int , int, int); + int (*show_options)(struct seq_file *, struct p9_client *); }; void v9fs_register_trans(struct p9_trans_module *m); diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 9bbd33497d3d..e833ed914358 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -377,10 +377,22 @@ static void bpf_evict_inode(struct inode *inode) bpf_any_put(inode->i_private, type); } +/* + * Display the mount options in /proc/mounts. + */ +static int bpf_show_options(struct seq_file *m, struct dentry *root) +{ + umode_t mode = d_inode(root)->i_mode & S_IALLUGO & ~S_ISVTX; + + if (mode != S_IRWXUGO) + seq_printf(m, ",mode=%o", mode); + return 0; +} + static const struct super_operations bpf_super_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, - .show_options = generic_show_options, + .show_options = bpf_show_options, .evict_inode = bpf_evict_inode, }; @@ -434,8 +446,6 @@ static int bpf_fill_super(struct super_block *sb, void *data, int silent) struct inode *inode; int ret; - save_mount_options(sb, data); - ret = bpf_parse_options(data, &opts); if (ret) return ret; diff --git a/mm/util.c b/mm/util.c index ee250e2cde34..7b07ec852e01 100644 --- a/mm/util.c +++ b/mm/util.c @@ -83,6 +83,8 @@ EXPORT_SYMBOL(kstrdup_const); * @s: the string to duplicate * @max: read at most @max chars from @s * @gfp: the GFP mask used in the kmalloc() call when allocating memory + * + * Note: Use kmemdup_nul() instead if the size is known exactly. */ char *kstrndup(const char *s, size_t max, gfp_t gfp) { @@ -121,6 +123,28 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp) EXPORT_SYMBOL(kmemdup); /** + * kmemdup_nul - Create a NUL-terminated string from unterminated data + * @s: The data to stringify + * @len: The size of the data + * @gfp: the GFP mask used in the kmalloc() call when allocating memory + */ +char *kmemdup_nul(const char *s, size_t len, gfp_t gfp) +{ + char *buf; + + if (!s) + return NULL; + + buf = kmalloc_track_caller(len + 1, gfp); + if (buf) { + memcpy(buf, s, len); + buf[len] = '\0'; + } + return buf; +} +EXPORT_SYMBOL(kmemdup_nul); + +/** * memdup_user - duplicate memory region from user space * * @src: source address in user space diff --git a/net/9p/client.c b/net/9p/client.c index 1218fb3b52da..4674235b0d9b 100644 --- a/net/9p/client.c +++ b/net/9p/client.c @@ -37,6 +37,7 @@ #include <linux/uio.h> #include <net/9p/9p.h> #include <linux/parser.h> +#include <linux/seq_file.h> #include <net/9p/client.h> #include <net/9p/transport.h> #include "protocol.h" @@ -77,6 +78,30 @@ inline int p9_is_proto_dotu(struct p9_client *clnt) } EXPORT_SYMBOL(p9_is_proto_dotu); +int p9_show_client_options(struct seq_file *m, struct p9_client *clnt) +{ + if (clnt->msize != 8192) + seq_printf(m, ",msize=%u", clnt->msize); + seq_printf(m, "trans=%s", clnt->trans_mod->name); + + switch (clnt->proto_version) { + case p9_proto_legacy: + seq_puts(m, ",noextend"); + break; + case p9_proto_2000u: + seq_puts(m, ",version=9p2000.u"); + break; + case p9_proto_2000L: + /* Default */ + break; + } + + if (clnt->trans_mod->show_options) + return clnt->trans_mod->show_options(m, clnt); + return 0; +} +EXPORT_SYMBOL(p9_show_client_options); + /* * Some error codes are taken directly from the server replies, * make sure they are valid. diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index dca3cdd1a014..ddfa86648f95 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c @@ -41,6 +41,7 @@ #include <linux/file.h> #include <linux/parser.h> #include <linux/slab.h> +#include <linux/seq_file.h> #include <net/9p/9p.h> #include <net/9p/client.h> #include <net/9p/transport.h> @@ -51,6 +52,9 @@ #define MAX_SOCK_BUF (64*1024) #define MAXPOLLWADDR 2 +static struct p9_trans_module p9_tcp_trans; +static struct p9_trans_module p9_fd_trans; + /** * struct p9_fd_opts - per-transport options * @rfd: file descriptor for reading (trans=fd) @@ -63,7 +67,7 @@ struct p9_fd_opts { int rfd; int wfd; u16 port; - int privport; + bool privport; }; /* @@ -720,6 +724,20 @@ static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req) return 0; } +static int p9_fd_show_options(struct seq_file *m, struct p9_client *clnt) +{ + if (clnt->trans_mod == &p9_tcp_trans) { + if (clnt->trans_opts.tcp.port != P9_PORT) + seq_printf(m, "port=%u", clnt->trans_opts.tcp.port); + } else if (clnt->trans_mod == &p9_fd_trans) { + if (clnt->trans_opts.fd.rfd != ~0) + seq_printf(m, "rfd=%u", clnt->trans_opts.fd.rfd); + if (clnt->trans_opts.fd.wfd != ~0) + seq_printf(m, "wfd=%u", clnt->trans_opts.fd.wfd); + } + return 0; +} + /** * parse_opts - parse mount options into p9_fd_opts structure * @params: options string passed from mount @@ -738,7 +756,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts) opts->port = P9_PORT; opts->rfd = ~0; opts->wfd = ~0; - opts->privport = 0; + opts->privport = false; if (!params) return 0; @@ -776,7 +794,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts) opts->wfd = option; break; case Opt_privport: - opts->privport = 1; + opts->privport = true; break; default: continue; @@ -942,6 +960,8 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args) csocket = NULL; + client->trans_opts.tcp.port = opts.port; + client->trans_opts.tcp.privport = opts.privport; sin_server.sin_family = AF_INET; sin_server.sin_addr.s_addr = in_aton(addr); sin_server.sin_port = htons(opts.port); @@ -1020,6 +1040,8 @@ p9_fd_create(struct p9_client *client, const char *addr, char *args) struct p9_fd_opts opts; parse_opts(args, &opts); + client->trans_opts.fd.rfd = opts.rfd; + client->trans_opts.fd.wfd = opts.wfd; if (opts.rfd == ~0 || opts.wfd == ~0) { pr_err("Insufficient options for proto=fd\n"); @@ -1044,6 +1066,7 @@ static struct p9_trans_module p9_tcp_trans = { .request = p9_fd_request, .cancel = p9_fd_cancel, .cancelled = p9_fd_cancelled, + .show_options = p9_fd_show_options, .owner = THIS_MODULE, }; @@ -1056,6 +1079,7 @@ static struct p9_trans_module p9_unix_trans = { .request = p9_fd_request, .cancel = p9_fd_cancel, .cancelled = p9_fd_cancelled, + .show_options = p9_fd_show_options, .owner = THIS_MODULE, }; @@ -1068,6 +1092,7 @@ static struct p9_trans_module p9_fd_trans = { .request = p9_fd_request, .cancel = p9_fd_cancel, .cancelled = p9_fd_cancelled, + .show_options = p9_fd_show_options, .owner = THIS_MODULE, }; diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index 553ed4ecb6a0..6d8e3031978f 100644 --- a/net/9p/trans_rdma.c +++ b/net/9p/trans_rdma.c @@ -43,6 +43,7 @@ #include <linux/parser.h> #include <linux/semaphore.h> #include <linux/slab.h> +#include <linux/seq_file.h> #include <net/9p/9p.h> #include <net/9p/client.h> #include <net/9p/transport.h> @@ -70,6 +71,8 @@ * @dm_mr: DMA Memory Region pointer * @lkey: The local access only memory region key * @timeout: Number of uSecs to wait for connection management events + * @privport: Whether a privileged port may be used + * @port: The port to use * @sq_depth: The depth of the Send Queue * @sq_sem: Semaphore for the SQ * @rq_depth: The depth of the Receive Queue. @@ -95,6 +98,8 @@ struct p9_trans_rdma { struct ib_qp *qp; struct ib_cq *cq; long timeout; + bool privport; + u16 port; int sq_depth; struct semaphore sq_sem; int rq_depth; @@ -133,10 +138,10 @@ struct p9_rdma_context { */ struct p9_rdma_opts { short port; + bool privport; int sq_depth; int rq_depth; long timeout; - int privport; }; /* @@ -159,6 +164,23 @@ static match_table_t tokens = { {Opt_err, NULL}, }; +static int p9_rdma_show_options(struct seq_file *m, struct p9_client *clnt) +{ + struct p9_trans_rdma *rdma = clnt->trans; + + if (rdma->port != P9_PORT) + seq_printf(m, ",port=%u", rdma->port); + if (rdma->sq_depth != P9_RDMA_SQ_DEPTH) + seq_printf(m, ",sq=%u", rdma->sq_depth); + if (rdma->rq_depth != P9_RDMA_RQ_DEPTH) + seq_printf(m, ",rq=%u", rdma->rq_depth); + if (rdma->timeout != P9_RDMA_TIMEOUT) + seq_printf(m, ",timeout=%lu", rdma->timeout); + if (rdma->privport) + seq_puts(m, ",privport"); + return 0; +} + /** * parse_opts - parse mount options into rdma options structure * @params: options string passed from mount @@ -177,7 +199,7 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts) opts->sq_depth = P9_RDMA_SQ_DEPTH; opts->rq_depth = P9_RDMA_RQ_DEPTH; opts->timeout = P9_RDMA_TIMEOUT; - opts->privport = 0; + opts->privport = false; if (!params) return 0; @@ -218,7 +240,7 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts) opts->timeout = option; break; case Opt_privport: - opts->privport = 1; + opts->privport = true; break; default: continue; @@ -560,6 +582,8 @@ static struct p9_trans_rdma *alloc_rdma(struct p9_rdma_opts *opts) if (!rdma) return NULL; + rdma->port = opts->port; + rdma->privport = opts->privport; rdma->sq_depth = opts->sq_depth; rdma->rq_depth = opts->rq_depth; rdma->timeout = opts->timeout; @@ -733,6 +757,7 @@ static struct p9_trans_module p9_rdma_trans = { .request = rdma_request, .cancel = rdma_cancel, .cancelled = rdma_cancelled, + .show_options = p9_rdma_show_options, }; /** |