diff options
41 files changed, 531 insertions, 163 deletions
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 48c9faa..73e7d91 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 d8af9bc0..9558d72 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 c202930..8fb89dd 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 76eaf49..982e017 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 a0965fb..8b75463 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 c2c27a8..7bf47a4 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 67680c2..689173c 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 63e7c47..4a4a5a3 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 74e4779..12540b6 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 6c30be6..f901413 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 a0e4e2f..c59f015 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 d7a7c53..5b68e42 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 8b99955..a920ad2 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 db42765..5ee2e2f 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 5238861..28d2753 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 020ba09..8cf898a 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 0ac4c1f..133a456 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; @@ -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 81f934b..f8893dc 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); @@ -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 8c9034e..ee14af9 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 5c7c273..5a1bed6 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, @@ -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 4d02c3b..fefd226 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 5805126..7f4e48c 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 1b6e0ff..2b21d18 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 26e4586..11201b2 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 685f1e0..306e4e9 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; @@ -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 328e89c..bea8ad8 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 c706eaa..3f3ff4c 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 976aaa1..7b5d681 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 8d9fe13..0ed8e41 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 0498667..a467e61 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 b582339..7af9d76 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 5122b5e..1625fb8 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 9bbd334..e833ed9 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; @@ -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 1218fb3..4674235 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 dca3cdd..ddfa866 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 553ed4e..6d8e303 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, }; /** |