Implement the show_options superblock op for 9p as part of a bid to get rid of s_options and generic_show_options() to make it easier to implement a context-based mount where the mount options can be passed individually over a file descriptor. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> cc: Eric Van Hensbergen <ericvh@xxxxxxxxx> cc: Ron Minnich <rminnich@xxxxxxxxxx> cc: Latchesar Ionkov <lucho@xxxxxxxxxx> cc: v9fs-developer@xxxxxxxxxxxxxxxxxxxxx --- fs/9p/v9fs.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ fs/9p/v9fs.h | 3 ++ fs/9p/vfs_super.c | 6 +--- include/net/9p/client.h | 13 ++++++++++ include/net/9p/transport.h | 1 + net/9p/client.c | 25 +++++++++++++++++++ net/9p/trans_fd.c | 31 +++++++++++++++++++++-- net/9p/trans_rdma.c | 31 +++++++++++++++++++++-- 8 files changed, 159 insertions(+), 10 deletions(-) diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index c202930086ed..d69046650a36 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,56 @@ 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]); + if (v9ses->cachetag && v9ses->cache == CACHE_FSCACHE) + seq_printf(m, ",cachetag=%s", v9ses->cachetag); + + 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 +288,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/include/net/9p/client.h b/include/net/9p/client.h index b582339ccef5..7a8395f75800 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/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, }; /**