v9fs.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [PATCH V2 0/4] 9p: convert to the new mount API
@ 2025-07-30 19:18 Eric Sandeen
  2025-07-30 19:18 ` [PATCH V2 1/4] fs/fs_parse: add back fsparam_u32hex Eric Sandeen
                   ` (4 more replies)
  0 siblings, 5 replies; 13+ messages in thread
From: Eric Sandeen @ 2025-07-30 19:18 UTC (permalink / raw)
  To: v9fs
  Cc: linux-fsdevel, linux-kernel, ericvh, lucho, asmadeus, linux_oss,
	dhowells, sandeen

This is an updated attempt to convert 9p to the new mount API. 9p is
one of the last conversions needed, possibly because it is one of the
trickier ones!

I was able to test this to some degree, but I am not sure how to test
all transports; there may well be bugs here. It would be great to get
some feedback on whether this approach seems reasonable, and of course
any further review or testing would be most welcome.

V2: Address "make W=1" warnings from kernel test robot, comments from
dhowells, and some kernel-doc comments for changed arguments.

Thanks,
-Eric



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH V2 1/4] fs/fs_parse: add back fsparam_u32hex
  2025-07-30 19:18 [PATCH V2 0/4] 9p: convert to the new mount API Eric Sandeen
@ 2025-07-30 19:18 ` Eric Sandeen
  2025-07-30 19:18 ` [PATCH V2 2/4] net/9p: move structures and macros to header files Eric Sandeen
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: Eric Sandeen @ 2025-07-30 19:18 UTC (permalink / raw)
  To: v9fs
  Cc: linux-fsdevel, linux-kernel, ericvh, lucho, asmadeus, linux_oss,
	dhowells, sandeen

296b67059 removed fsparam_u32hex because there were no callers
(yet) and it didn't build due to using the nonexistent symbol
fs_param_is_u32_hex.

fs/9p will need this parser, so add it back with the appropriate
fix (use fs_param_is_u32).

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 include/linux/fs_parser.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/fs_parser.h b/include/linux/fs_parser.h
index 5a0e897cae80..5e8a3b546033 100644
--- a/include/linux/fs_parser.h
+++ b/include/linux/fs_parser.h
@@ -120,6 +120,8 @@ static inline bool fs_validate_description(const char *name,
 #define fsparam_u32(NAME, OPT)	__fsparam(fs_param_is_u32, NAME, OPT, 0, NULL)
 #define fsparam_u32oct(NAME, OPT) \
 			__fsparam(fs_param_is_u32, NAME, OPT, 0, (void *)8)
+#define fsparam_u32hex(NAME, OPT) \
+			__fsparam(fs_param_is_u32, NAME, OPT, 0, (void *)16)
 #define fsparam_s32(NAME, OPT)	__fsparam(fs_param_is_s32, NAME, OPT, 0, NULL)
 #define fsparam_u64(NAME, OPT)	__fsparam(fs_param_is_u64, NAME, OPT, 0, NULL)
 #define fsparam_enum(NAME, OPT, array)	__fsparam(fs_param_is_enum, NAME, OPT, 0, array)
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH V2 2/4] net/9p: move structures and macros to header files
  2025-07-30 19:18 [PATCH V2 0/4] 9p: convert to the new mount API Eric Sandeen
  2025-07-30 19:18 ` [PATCH V2 1/4] fs/fs_parse: add back fsparam_u32hex Eric Sandeen
@ 2025-07-30 19:18 ` Eric Sandeen
  2025-07-30 19:18 ` [PATCH V2 3/4] 9p: create a v9fs_context structure to hold parsed options Eric Sandeen
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 13+ messages in thread
From: Eric Sandeen @ 2025-07-30 19:18 UTC (permalink / raw)
  To: v9fs
  Cc: linux-fsdevel, linux-kernel, ericvh, lucho, asmadeus, linux_oss,
	dhowells, sandeen

With the new mount API all option parsing will need to happen
in fs/v9fs.c, so move necessary data structures and macros to
header files to facilitate this. Rename some to reflect
the transport they are used for (rdma, fd, etc), for clarity.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 include/net/9p/client.h    |  6 ++++++
 include/net/9p/transport.h | 39 ++++++++++++++++++++++++++++++++++++++
 net/9p/client.c            |  6 ------
 net/9p/trans_fd.c          | 20 ++-----------------
 net/9p/trans_rdma.c        | 25 ++----------------------
 5 files changed, 49 insertions(+), 47 deletions(-)

diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 4f785098c67a..2d46f8017bd5 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -16,6 +16,12 @@
 /* Number of requests per row */
 #define P9_ROW_MAXTAG 255
 
+/* DEFAULT MSIZE = 32 pages worth of payload + P9_HDRSZ +
+ * room for write (16 extra) or read (11 extra) operands.
+ */
+
+#define DEFAULT_MSIZE ((128 * 1024) + P9_IOHDRSZ)
+
 /** enum p9_proto_versions - 9P protocol versions
  * @p9_proto_legacy: 9P Legacy mode, pre-9P2000.u
  * @p9_proto_2000u: 9P2000.u extension
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h
index 766ec07c9599..88702953b1ef 100644
--- a/include/net/9p/transport.h
+++ b/include/net/9p/transport.h
@@ -14,6 +14,45 @@
 #define P9_DEF_MIN_RESVPORT	(665U)
 #define P9_DEF_MAX_RESVPORT	(1023U)
 
+#define P9_FD_PORT 564
+
+#define P9_RDMA_PORT		5640
+#define P9_RDMA_SQ_DEPTH	32
+#define P9_RDMA_RQ_DEPTH	32
+#define P9_RDMA_TIMEOUT		30000		/* 30 seconds */
+
+/**
+ * struct p9_fd_opts - per-transport options for fd transport
+ * @rfd: file descriptor for reading (trans=fd)
+ * @wfd: file descriptor for writing (trans=fd)
+ * @port: port to connect to (trans=tcp)
+ * @privport: port is privileged
+ */
+
+struct p9_fd_opts {
+	int rfd;
+	int wfd;
+	u16 port;
+	bool privport;
+};
+
+/**
+ * struct p9_rdma_opts - Collection of mount options for rdma transport
+ * @port: port of connection
+ * @privport: Whether a privileged port may be used
+ * @sq_depth: The requested depth of the SQ. This really doesn't need
+ * to be any deeper than the number of threads used in the client
+ * @rq_depth: The depth of the RQ. Should be greater than or equal to SQ depth
+ * @timeout: Time to wait in msecs for CM events
+ */
+struct p9_rdma_opts {
+	short port;
+	bool privport;
+	int sq_depth;
+	int rq_depth;
+	long timeout;
+};
+
 /**
  * struct p9_trans_module - transport module interface
  * @list: used to maintain a list of currently available transports
diff --git a/net/9p/client.c b/net/9p/client.c
index 5c1ca57ccd28..5e3230b1bfab 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -29,12 +29,6 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/9p.h>
 
-/* DEFAULT MSIZE = 32 pages worth of payload + P9_HDRSZ +
- * room for write (16 extra) or read (11 extra) operands.
- */
-
-#define DEFAULT_MSIZE ((128 * 1024) + P9_IOHDRSZ)
-
 /* Client Option Parsing (code inspired by NFS code)
  *  - a little lazy - parse all client options
  */
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 339ec4e54778..9ef4f2e0db3c 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -31,28 +31,12 @@
 
 #include <linux/syscalls.h> /* killme */
 
-#define P9_PORT 564
 #define MAX_SOCK_BUF (1024*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)
- * @wfd: file descriptor for writing (trans=fd)
- * @port: port to connect to (trans=tcp)
- * @privport: port is privileged
- */
-
-struct p9_fd_opts {
-	int rfd;
-	int wfd;
-	u16 port;
-	bool privport;
-};
-
 /*
   * Option Parsing (code inspired by NFS code)
   *  - a little lazy - parse all fd-transport options
@@ -749,7 +733,7 @@ static int p9_fd_cancelled(struct p9_client *client, struct p9_req_t *req)
 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)
+		if (clnt->trans_opts.tcp.port != P9_FD_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)
@@ -775,7 +759,7 @@ static int parse_opts(char *params, struct p9_fd_opts *opts)
 	int option;
 	char *options, *tmp_options;
 
-	opts->port = P9_PORT;
+	opts->port = P9_FD_PORT;
 	opts->rfd = ~0;
 	opts->wfd = ~0;
 	opts->privport = false;
diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
index b84748baf9cb..46ee37061faf 100644
--- a/net/9p/trans_rdma.c
+++ b/net/9p/trans_rdma.c
@@ -32,14 +32,10 @@
 #include <rdma/ib_verbs.h>
 #include <rdma/rdma_cm.h>
 
-#define P9_PORT			5640
-#define P9_RDMA_SQ_DEPTH	32
-#define P9_RDMA_RQ_DEPTH	32
 #define P9_RDMA_SEND_SGE	4
 #define P9_RDMA_RECV_SGE	4
 #define P9_RDMA_IRD		0
 #define P9_RDMA_ORD		0
-#define P9_RDMA_TIMEOUT		30000		/* 30 seconds */
 #define P9_RDMA_MAXSIZE		(1024*1024)	/* 1MB */
 
 /**
@@ -110,23 +106,6 @@ struct p9_rdma_context {
 	};
 };
 
-/**
- * struct p9_rdma_opts - Collection of mount options
- * @port: port of connection
- * @privport: Whether a privileged port may be used
- * @sq_depth: The requested depth of the SQ. This really doesn't need
- * to be any deeper than the number of threads used in the client
- * @rq_depth: The depth of the RQ. Should be greater than or equal to SQ depth
- * @timeout: Time to wait in msecs for CM events
- */
-struct p9_rdma_opts {
-	short port;
-	bool privport;
-	int sq_depth;
-	int rq_depth;
-	long timeout;
-};
-
 /*
  * Option Parsing (code inspired by NFS code)
  */
@@ -151,7 +130,7 @@ 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)
+	if (rdma->port != P9_RDMA_PORT)
 		seq_printf(m, ",port=%u", rdma->port);
 	if (rdma->sq_depth != P9_RDMA_SQ_DEPTH)
 		seq_printf(m, ",sq=%u", rdma->sq_depth);
@@ -178,7 +157,7 @@ static int parse_opts(char *params, struct p9_rdma_opts *opts)
 	int option;
 	char *options, *tmp_options;
 
-	opts->port = P9_PORT;
+	opts->port = P9_RDMA_PORT;
 	opts->sq_depth = P9_RDMA_SQ_DEPTH;
 	opts->rq_depth = P9_RDMA_RQ_DEPTH;
 	opts->timeout = P9_RDMA_TIMEOUT;
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH V2 3/4] 9p: create a v9fs_context structure to hold parsed options
  2025-07-30 19:18 [PATCH V2 0/4] 9p: convert to the new mount API Eric Sandeen
  2025-07-30 19:18 ` [PATCH V2 1/4] fs/fs_parse: add back fsparam_u32hex Eric Sandeen
  2025-07-30 19:18 ` [PATCH V2 2/4] net/9p: move structures and macros to header files Eric Sandeen
@ 2025-07-30 19:18 ` Eric Sandeen
  2025-07-30 19:18 ` [PATCH V2 4/4] 9p: convert to the new mount API Eric Sandeen
  2025-07-30 22:21 ` [PATCH V2 0/4] " asmadeus
  4 siblings, 0 replies; 13+ messages in thread
From: Eric Sandeen @ 2025-07-30 19:18 UTC (permalink / raw)
  To: v9fs
  Cc: linux-fsdevel, linux-kernel, ericvh, lucho, asmadeus, linux_oss,
	dhowells, sandeen

This patch creates a new v9fs_context structure which includes
v9fs_session_info as well as p9_client, p9_fd_opts, and p9_rdma_opts
to hold all parsed options. The new structure will be used in the next
commit to pass all parsed options to the appropriate transports.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/9p/cache.c              |  1 +
 fs/9p/v9fs.h               | 49 ---------------------
 include/net/9p/client.h    | 88 ++++++++++++++++++++++++++++++++++++++
 include/net/9p/transport.h | 32 --------------
 4 files changed, 89 insertions(+), 81 deletions(-)

diff --git a/fs/9p/cache.c b/fs/9p/cache.c
index 12c0ae29f185..1def4dec1dcc 100644
--- a/fs/9p/cache.c
+++ b/fs/9p/cache.c
@@ -12,6 +12,7 @@
 #include <linux/sched.h>
 #include <linux/fs.h>
 #include <net/9p/9p.h>
+#include <net/9p/client.h>
 
 #include "v9fs.h"
 #include "cache.h"
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index f28bc763847a..4b8834daec8d 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -81,55 +81,6 @@ enum p9_cache_bits {
 	CACHE_FSCACHE       = 0b10000000,
 };
 
-/**
- * struct v9fs_session_info - per-instance session information
- * @flags: session options of type &p9_session_flags
- * @nodev: set to 1 to disable device mapping
- * @debug: debug level
- * @afid: authentication handle
- * @cache: cache mode of type &p9_cache_bits
- * @cachetag: the tag of the cache associated with this session
- * @fscache: session cookie associated with FS-Cache
- * @uname: string user name to mount hierarchy as
- * @aname: mount specifier for remote hierarchy
- * @maxdata: maximum data to be sent/recvd per protocol message
- * @dfltuid: default numeric userid to mount hierarchy as
- * @dfltgid: default numeric groupid to mount hierarchy as
- * @uid: if %V9FS_ACCESS_SINGLE, the numeric uid which mounted the hierarchy
- * @clnt: reference to 9P network client instantiated for this session
- * @slist: reference to list of registered 9p sessions
- *
- * This structure holds state for each session instance established during
- * a sys_mount() .
- *
- * Bugs: there seems to be a lot of state which could be condensed and/or
- * removed.
- */
-
-struct v9fs_session_info {
-	/* options */
-	unsigned int flags;
-	unsigned char nodev;
-	unsigned short debug;
-	unsigned int afid;
-	unsigned int cache;
-#ifdef CONFIG_9P_FSCACHE
-	char *cachetag;
-	struct fscache_volume *fscache;
-#endif
-
-	char *uname;		/* user name to mount as */
-	char *aname;		/* name of remote hierarchy being mounted */
-	unsigned int maxdata;	/* max data for client interface */
-	kuid_t dfltuid;		/* default uid/muid for legacy support */
-	kgid_t dfltgid;		/* default gid for legacy support */
-	kuid_t uid;		/* if ACCESS_SINGLE, the uid that has access */
-	struct p9_client *clnt;	/* 9p client */
-	struct list_head slist; /* list of sessions registered with v9fs */
-	struct rw_semaphore rename_sem;
-	long session_lock_timeout; /* retry interval for blocking locks */
-};
-
 /* cache_validity flags */
 #define V9FS_INO_INVALID_ATTR 0x01
 
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 2d46f8017bd5..33b8d9a79fa7 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -132,6 +132,94 @@ struct p9_client {
 	char name[__NEW_UTS_LEN + 1];
 };
 
+/**
+ * struct p9_fd_opts - per-transport options for fd transport
+ * @rfd: file descriptor for reading (trans=fd)
+ * @wfd: file descriptor for writing (trans=fd)
+ * @port: port to connect to (trans=tcp)
+ * @privport: port is privileged
+ */
+
+struct p9_fd_opts {
+	int rfd;
+	int wfd;
+	u16 port;
+	bool privport;
+};
+
+/**
+ * struct p9_rdma_opts - Collection of mount options for rdma transport
+ * @port: port of connection
+ * @privport: Whether a privileged port may be used
+ * @sq_depth: The requested depth of the SQ. This really doesn't need
+ * to be any deeper than the number of threads used in the client
+ * @rq_depth: The depth of the RQ. Should be greater than or equal to SQ depth
+ * @timeout: Time to wait in msecs for CM events
+ */
+struct p9_rdma_opts {
+	short port;
+	bool privport;
+	int sq_depth;
+	int rq_depth;
+	long timeout;
+};
+
+/**
+ * struct v9fs_session_info - per-instance session information
+ * @flags: session options of type &p9_session_flags
+ * @nodev: set to 1 to disable device mapping
+ * @debug: debug level
+ * @afid: authentication handle
+ * @cache: cache mode of type &p9_cache_bits
+ * @cachetag: the tag of the cache associated with this session
+ * @fscache: session cookie associated with FS-Cache
+ * @uname: string user name to mount hierarchy as
+ * @aname: mount specifier for remote hierarchy
+ * @maxdata: maximum data to be sent/recvd per protocol message
+ * @dfltuid: default numeric userid to mount hierarchy as
+ * @dfltgid: default numeric groupid to mount hierarchy as
+ * @uid: if %V9FS_ACCESS_SINGLE, the numeric uid which mounted the hierarchy
+ * @clnt: reference to 9P network client instantiated for this session
+ * @slist: reference to list of registered 9p sessions
+ *
+ * This structure holds state for each session instance established during
+ * a sys_mount() .
+ *
+ * Bugs: there seems to be a lot of state which could be condensed and/or
+ * removed.
+ */
+struct v9fs_session_info {
+	/* options */
+	unsigned int flags;
+	unsigned char nodev;
+	unsigned short debug;
+	unsigned int afid;
+	unsigned int cache;
+#ifdef CONFIG_9P_FSCACHE
+	char *cachetag;
+	struct fscache_volume *fscache;
+#endif
+
+	char *uname;		/* user name to mount as */
+	char *aname;		/* name of remote hierarchy being mounted */
+	unsigned int maxdata;	/* max data for client interface */
+	kuid_t dfltuid;		/* default uid/muid for legacy support */
+	kgid_t dfltgid;		/* default gid for legacy support */
+	kuid_t uid;		/* if ACCESS_SINGLE, the uid that has access */
+	struct p9_client *clnt;	/* 9p client */
+	struct list_head slist; /* list of sessions registered with v9fs */
+	struct rw_semaphore rename_sem;
+	long session_lock_timeout; /* retry interval for blocking locks */
+};
+
+/* Used by mount API to store parsed mount options */
+struct v9fs_context {
+	struct p9_client	client_opts;
+	struct p9_fd_opts	fd_opts;
+	struct p9_rdma_opts	rdma_opts;
+	struct v9fs_session_info v9ses;
+};
+
 /**
  * struct p9_fid - file system entity handle
  * @clnt: back pointer to instantiating &p9_client
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h
index 88702953b1ef..ebbb4b50ee20 100644
--- a/include/net/9p/transport.h
+++ b/include/net/9p/transport.h
@@ -21,38 +21,6 @@
 #define P9_RDMA_RQ_DEPTH	32
 #define P9_RDMA_TIMEOUT		30000		/* 30 seconds */
 
-/**
- * struct p9_fd_opts - per-transport options for fd transport
- * @rfd: file descriptor for reading (trans=fd)
- * @wfd: file descriptor for writing (trans=fd)
- * @port: port to connect to (trans=tcp)
- * @privport: port is privileged
- */
-
-struct p9_fd_opts {
-	int rfd;
-	int wfd;
-	u16 port;
-	bool privport;
-};
-
-/**
- * struct p9_rdma_opts - Collection of mount options for rdma transport
- * @port: port of connection
- * @privport: Whether a privileged port may be used
- * @sq_depth: The requested depth of the SQ. This really doesn't need
- * to be any deeper than the number of threads used in the client
- * @rq_depth: The depth of the RQ. Should be greater than or equal to SQ depth
- * @timeout: Time to wait in msecs for CM events
- */
-struct p9_rdma_opts {
-	short port;
-	bool privport;
-	int sq_depth;
-	int rq_depth;
-	long timeout;
-};
-
 /**
  * struct p9_trans_module - transport module interface
  * @list: used to maintain a list of currently available transports
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH V2 4/4] 9p: convert to the new mount API
  2025-07-30 19:18 [PATCH V2 0/4] 9p: convert to the new mount API Eric Sandeen
                   ` (2 preceding siblings ...)
  2025-07-30 19:18 ` [PATCH V2 3/4] 9p: create a v9fs_context structure to hold parsed options Eric Sandeen
@ 2025-07-30 19:18 ` Eric Sandeen
  2025-07-30 22:21 ` [PATCH V2 0/4] " asmadeus
  4 siblings, 0 replies; 13+ messages in thread
From: Eric Sandeen @ 2025-07-30 19:18 UTC (permalink / raw)
  To: v9fs
  Cc: linux-fsdevel, linux-kernel, ericvh, lucho, asmadeus, linux_oss,
	dhowells, sandeen

Convert 9p to the new mount API. This patch consolidates all parsing
parsing into fs/9p/v9fs.c, which stores all results into a filesystem
context which can be passed to the various transports as needed.

Some of the parsing helper functions such as get_cache_mode() can be
eliminated in favor of using the new mount API's enum param type,
for simplicity.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
 fs/9p/v9fs.c               | 531 ++++++++++++++++++-------------------
 fs/9p/v9fs.h               |   7 +-
 fs/9p/vfs_super.c          | 128 ++++++---
 include/net/9p/client.h    |   2 +-
 include/net/9p/transport.h |   2 +-
 net/9p/client.c            | 148 +----------
 net/9p/mod.c               |   2 +-
 net/9p/trans_fd.c          | 109 +-------
 net/9p/trans_rdma.c        | 108 +-------
 net/9p/trans_usbg.c        |   4 +-
 net/9p/trans_virtio.c      |   8 +-
 net/9p/trans_xen.c         |   4 +-
 12 files changed, 408 insertions(+), 645 deletions(-)

diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 77e9c4387c1d..55ba26186351 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -13,7 +13,8 @@
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/cred.h>
-#include <linux/parser.h>
+#include <linux/fs_parser.h>
+#include <linux/fs_context.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 #include <net/9p/9p.h>
@@ -43,55 +44,80 @@ enum {
 	Opt_access, Opt_posixacl,
 	/* Lock timeout option */
 	Opt_locktimeout,
-	/* Error token */
-	Opt_err
+
+	/* Client options */
+	Opt_msize, Opt_trans, Opt_legacy, Opt_version,
+
+	/* fd transport options */
+	/* Options that take integer arguments */
+	Opt_rfdno, Opt_wfdno,
+	/* Options that take no arguments */
+
+	/* rdma transport options */
+	/* Options that take integer arguments */
+	Opt_rq_depth, Opt_sq_depth, Opt_timeout,
+
+	/* Options for both fd and rdma transports */
+	Opt_port, Opt_privport,
 };
 
-static const match_table_t tokens = {
-	{Opt_debug, "debug=%x"},
-	{Opt_dfltuid, "dfltuid=%u"},
-	{Opt_dfltgid, "dfltgid=%u"},
-	{Opt_afid, "afid=%u"},
-	{Opt_uname, "uname=%s"},
-	{Opt_remotename, "aname=%s"},
-	{Opt_nodevmap, "nodevmap"},
-	{Opt_noxattr, "noxattr"},
-	{Opt_directio, "directio"},
-	{Opt_ignoreqv, "ignoreqv"},
-	{Opt_cache, "cache=%s"},
-	{Opt_cachetag, "cachetag=%s"},
-	{Opt_access, "access=%s"},
-	{Opt_posixacl, "posixacl"},
-	{Opt_locktimeout, "locktimeout=%u"},
-	{Opt_err, NULL}
+static const struct constant_table p9_versions[] = {
+	{ "9p2000",	p9_proto_legacy },
+	{ "9p2000.u",	p9_proto_2000u },
+	{ "9p2000.L",	p9_proto_2000L },
+	{}
 };
 
-/* Interpret mount options for cache mode */
-static int get_cache_mode(char *s)
-{
-	int version = -EINVAL;
-
-	if (!strcmp(s, "loose")) {
-		version = CACHE_SC_LOOSE;
-		p9_debug(P9_DEBUG_9P, "Cache mode: loose\n");
-	} else if (!strcmp(s, "fscache")) {
-		version = CACHE_SC_FSCACHE;
-		p9_debug(P9_DEBUG_9P, "Cache mode: fscache\n");
-	} else if (!strcmp(s, "mmap")) {
-		version = CACHE_SC_MMAP;
-		p9_debug(P9_DEBUG_9P, "Cache mode: mmap\n");
-	} else if (!strcmp(s, "readahead")) {
-		version = CACHE_SC_READAHEAD;
-		p9_debug(P9_DEBUG_9P, "Cache mode: readahead\n");
-	} else if (!strcmp(s, "none")) {
-		version = CACHE_SC_NONE;
-		p9_debug(P9_DEBUG_9P, "Cache mode: none\n");
-	} else if (kstrtoint(s, 0, &version) != 0) {
-		version = -EINVAL;
-		pr_info("Unknown Cache mode or invalid value %s\n", s);
-	}
-	return version;
-}
+static const struct constant_table p9_cache_mode[] = {
+	{ "loose",	CACHE_SC_LOOSE },
+	{ "fscache",	CACHE_SC_FSCACHE },
+	{ "mmap",	CACHE_SC_MMAP },
+	{ "readahead",	CACHE_SC_READAHEAD },
+	{ "none",	CACHE_SC_NONE },
+	{}
+};
+
+/*
+ * This structure contains all parameters used for the core code,
+ * the client, and all the transports.
+ */
+const struct fs_parameter_spec v9fs_param_spec[] = {
+	fsparam_u32hex	("debug",	Opt_debug),
+	fsparam_uid	("dfltuid",	Opt_dfltuid),
+	fsparam_gid	("dfltgid",	Opt_dfltgid),
+	fsparam_u32	("afid",	Opt_afid),
+	fsparam_string	("uname",	Opt_uname),
+	fsparam_string	("aname",	Opt_remotename),
+	fsparam_flag	("nodevmap",	Opt_nodevmap),
+	fsparam_flag	("noxattr",	Opt_noxattr),
+	fsparam_flag	("directio",	Opt_directio),
+	fsparam_flag	("ignoreqv",	Opt_ignoreqv),
+	fsparam_enum	("cache",	Opt_cache, p9_cache_mode),
+	fsparam_string	("cachetag",	Opt_cachetag),
+	fsparam_string	("access",	Opt_access),
+	fsparam_flag	("posixacl",	Opt_posixacl),
+	fsparam_u32	("locktimeout",	Opt_locktimeout),
+
+	/* client options */
+	fsparam_u32	("msize",	Opt_msize),
+	fsparam_flag	("noextend",	Opt_legacy),
+	fsparam_string	("trans",	Opt_trans),
+	fsparam_enum	("version",	Opt_version, p9_versions),
+
+	/* fd transport options */
+	fsparam_u32	("rfdno",	Opt_rfdno),
+	fsparam_u32	("wfdno",	Opt_wfdno),
+
+	/* rdma transport options */
+	fsparam_u32	("sq",		Opt_sq_depth),
+	fsparam_u32	("rq",		Opt_rq_depth),
+	fsparam_u32	("timeout",	Opt_timeout),
+
+	/* fd and rdma transprt options */
+	fsparam_u32	("port",	Opt_port),
+	fsparam_flag	("privport",	Opt_privport),
+	{}
+};
 
 /*
  * Display the mount options in /proc/mounts.
@@ -153,267 +179,232 @@ int v9fs_show_options(struct seq_file *m, struct dentry *root)
 }
 
 /**
- * v9fs_parse_options - parse mount options into session structure
- * @v9ses: existing v9fs session information
- * @opts: The mount option string
+ * v9fs_parse_param - parse a mount option into the filesystem context
+ * @fc: the filesystem context
+ * @param: the parameter to parse
  *
  * Return 0 upon success, -ERRNO upon failure.
  */
-
-static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
+int v9fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
 {
-	char *options, *tmp_options;
-	substring_t args[MAX_OPT_ARGS];
-	char *p;
-	int option = 0;
+	struct v9fs_context *ctx = fc->fs_private;
+	struct fs_parse_result result;
 	char *s;
-	int ret = 0;
-
-	/* setup defaults */
-	v9ses->afid = ~0;
-	v9ses->debug = 0;
-	v9ses->cache = CACHE_NONE;
-#ifdef CONFIG_9P_FSCACHE
-	v9ses->cachetag = NULL;
-#endif
-	v9ses->session_lock_timeout = P9_LOCK_TIMEOUT;
-
-	if (!opts)
-		return 0;
-
-	tmp_options = kstrdup(opts, GFP_KERNEL);
-	if (!tmp_options) {
-		ret = -ENOMEM;
-		goto fail_option_alloc;
-	}
-	options = tmp_options;
-
-	while ((p = strsep(&options, ",")) != NULL) {
-		int token, r;
-
-		if (!*p)
-			continue;
-
-		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_debug:
-			r = match_int(&args[0], &option);
-			if (r < 0) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "integer field, but no integer?\n");
-				ret = r;
-			} else {
-				v9ses->debug = option;
+	int r;
+	int opt;
+	struct p9_client        *clnt = &ctx->client_opts;
+	struct p9_fd_opts       *fd_opts = &ctx->fd_opts;
+	struct p9_rdma_opts     *rdma_opts = &ctx->rdma_opts;
+	struct v9fs_session_info *v9ses_opts = &ctx->v9ses;
+
+	opt = fs_parse(fc, v9fs_param_spec, param, &result);
+	if (opt < 0)
+		return opt;
+
+	switch (opt) {
+	case Opt_debug:
+		v9ses_opts->debug = result.uint_32;
 #ifdef CONFIG_NET_9P_DEBUG
-				p9_debug_level = option;
+		p9_debug_level = result.uint_32;
 #endif
-			}
-			break;
-
-		case Opt_dfltuid:
-			r = match_int(&args[0], &option);
-			if (r < 0) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "integer field, but no integer?\n");
-				ret = r;
-				continue;
-			}
-			v9ses->dfltuid = make_kuid(current_user_ns(), option);
-			if (!uid_valid(v9ses->dfltuid)) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "uid field, but not a uid?\n");
-				ret = -EINVAL;
-			}
-			break;
-		case Opt_dfltgid:
-			r = match_int(&args[0], &option);
-			if (r < 0) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "integer field, but no integer?\n");
-				ret = r;
-				continue;
-			}
-			v9ses->dfltgid = make_kgid(current_user_ns(), option);
-			if (!gid_valid(v9ses->dfltgid)) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "gid field, but not a gid?\n");
-				ret = -EINVAL;
-			}
-			break;
-		case Opt_afid:
-			r = match_int(&args[0], &option);
-			if (r < 0) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "integer field, but no integer?\n");
-				ret = r;
-			} else {
-				v9ses->afid = option;
-			}
-			break;
-		case Opt_uname:
-			kfree(v9ses->uname);
-			v9ses->uname = match_strdup(&args[0]);
-			if (!v9ses->uname) {
-				ret = -ENOMEM;
-				goto free_and_return;
-			}
-			break;
-		case Opt_remotename:
-			kfree(v9ses->aname);
-			v9ses->aname = match_strdup(&args[0]);
-			if (!v9ses->aname) {
-				ret = -ENOMEM;
-				goto free_and_return;
-			}
-			break;
-		case Opt_nodevmap:
-			v9ses->nodev = 1;
-			break;
-		case Opt_noxattr:
-			v9ses->flags |= V9FS_NO_XATTR;
-			break;
-		case Opt_directio:
-			v9ses->flags |= V9FS_DIRECT_IO;
-			break;
-		case Opt_ignoreqv:
-			v9ses->flags |= V9FS_IGNORE_QV;
-			break;
-		case Opt_cachetag:
+		break;
+
+	case Opt_dfltuid:
+		v9ses_opts->dfltuid = result.uid;
+		break;
+	case Opt_dfltgid:
+		v9ses_opts->dfltgid = result.gid;
+		break;
+	case Opt_afid:
+		v9ses_opts->afid = result.uint_32;
+		break;
+	case Opt_uname:
+		kfree(v9ses_opts->uname);
+		v9ses_opts->uname = param->string;
+		param->string = NULL;
+		break;
+	case Opt_remotename:
+		kfree(v9ses_opts->aname);
+		v9ses_opts->aname = param->string;
+		param->string = NULL;
+		break;
+	case Opt_nodevmap:
+		v9ses_opts->nodev = 1;
+		break;
+	case Opt_noxattr:
+		v9ses_opts->flags |= V9FS_NO_XATTR;
+		break;
+	case Opt_directio:
+		v9ses_opts->flags |= V9FS_DIRECT_IO;
+		break;
+	case Opt_ignoreqv:
+		v9ses_opts->flags |= V9FS_IGNORE_QV;
+		break;
+	case Opt_cachetag:
 #ifdef CONFIG_9P_FSCACHE
-			kfree(v9ses->cachetag);
-			v9ses->cachetag = match_strdup(&args[0]);
-			if (!v9ses->cachetag) {
-				ret = -ENOMEM;
-				goto free_and_return;
-			}
+		kfree(v9ses_opts->cachetag);
+		v9ses_opts->cachetag = param->string;
+		param->string = NULL;
 #endif
-			break;
-		case Opt_cache:
-			s = match_strdup(&args[0]);
-			if (!s) {
-				ret = -ENOMEM;
-				p9_debug(P9_DEBUG_ERROR,
-					 "problem allocating copy of cache arg\n");
-				goto free_and_return;
-			}
-			r = get_cache_mode(s);
-			if (r < 0)
-				ret = r;
-			else
-				v9ses->cache = r;
-
-			kfree(s);
-			break;
-
-		case Opt_access:
-			s = match_strdup(&args[0]);
-			if (!s) {
-				ret = -ENOMEM;
-				p9_debug(P9_DEBUG_ERROR,
-					 "problem allocating copy of access arg\n");
-				goto free_and_return;
+		break;
+	case Opt_cache:
+		v9ses_opts->cache = result.uint_32;
+		p9_debug(P9_DEBUG_9P, "Cache mode: %s\n", param->string);
+		break;
+	case Opt_access:
+		s = param->string;
+		v9ses_opts->flags &= ~V9FS_ACCESS_MASK;
+		if (strcmp(s, "user") == 0) {
+			v9ses_opts->flags |= V9FS_ACCESS_USER;
+		} else if (strcmp(s, "any") == 0) {
+			v9ses_opts->flags |= V9FS_ACCESS_ANY;
+		} else if (strcmp(s, "client") == 0) {
+			v9ses_opts->flags |= V9FS_ACCESS_CLIENT;
+		} else {
+			uid_t uid;
+
+			v9ses_opts->flags |= V9FS_ACCESS_SINGLE;
+			r = kstrtouint(s, 10, &uid);
+			if (r) {
+				pr_info("Unknown access argument %s: %d\n",
+					param->string, r);
+				return r;
 			}
-
-			v9ses->flags &= ~V9FS_ACCESS_MASK;
-			if (strcmp(s, "user") == 0)
-				v9ses->flags |= V9FS_ACCESS_USER;
-			else if (strcmp(s, "any") == 0)
-				v9ses->flags |= V9FS_ACCESS_ANY;
-			else if (strcmp(s, "client") == 0) {
-				v9ses->flags |= V9FS_ACCESS_CLIENT;
-			} else {
-				uid_t uid;
-
-				v9ses->flags |= V9FS_ACCESS_SINGLE;
-				r = kstrtouint(s, 10, &uid);
-				if (r) {
-					ret = r;
-					pr_info("Unknown access argument %s: %d\n",
-						s, r);
-					kfree(s);
-					continue;
-				}
-				v9ses->uid = make_kuid(current_user_ns(), uid);
-				if (!uid_valid(v9ses->uid)) {
-					ret = -EINVAL;
-					pr_info("Unknown uid %s\n", s);
-				}
+			v9ses_opts->uid = make_kuid(current_user_ns(), uid);
+			if (!uid_valid(v9ses_opts->uid)) {
+				pr_info("Unknown uid %s\n", s);
+				return -EINVAL;
 			}
+		}
+		break;
 
-			kfree(s);
-			break;
-
-		case Opt_posixacl:
+	case Opt_posixacl:
 #ifdef CONFIG_9P_FS_POSIX_ACL
-			v9ses->flags |= V9FS_POSIX_ACL;
+		v9ses_opts->flags |= V9FS_POSIX_ACL;
 #else
-			p9_debug(P9_DEBUG_ERROR,
-				 "Not defined CONFIG_9P_FS_POSIX_ACL. Ignoring posixacl option\n");
+		p9_debug(P9_DEBUG_ERROR,
+			 "Not defined CONFIG_9P_FS_POSIX_ACL. Ignoring posixacl option\n");
 #endif
-			break;
-
-		case Opt_locktimeout:
-			r = match_int(&args[0], &option);
-			if (r < 0) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "integer field, but no integer?\n");
-				ret = r;
-				continue;
-			}
-			if (option < 1) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "locktimeout must be a greater than zero integer.\n");
-				ret = -EINVAL;
-				continue;
-			}
-			v9ses->session_lock_timeout = (long)option * HZ;
-			break;
+		break;
 
-		default:
-			continue;
+	case Opt_locktimeout:
+		if (result.uint_32 < 1) {
+			p9_debug(P9_DEBUG_ERROR,
+				 "locktimeout must be a greater than zero integer.\n");
+			return -EINVAL;
+		}
+		v9ses_opts->session_lock_timeout = (long)result.uint_32 * HZ;
+		break;
+
+	/* Options for client */
+	case Opt_msize:
+		if (result.uint_32 < 4096) {
+			p9_debug(P9_DEBUG_ERROR, "msize should be at least 4k\n");
+			return -EINVAL;
+		}
+		clnt->msize = result.uint_32;
+		break;
+	case Opt_trans:
+		v9fs_put_trans(clnt->trans_mod);
+		clnt->trans_mod = v9fs_get_trans_by_name(param->string);
+		if (!clnt->trans_mod) {
+			pr_info("Could not find request transport: %s\n",
+				param->string);
+			return -EINVAL;
 		}
+		break;
+	case Opt_legacy:
+		clnt->proto_version = p9_proto_legacy;
+		break;
+	case Opt_version:
+		clnt->proto_version = result.uint_32;
+		p9_debug(P9_DEBUG_9P, "Protocol version: %s\n", param->string);
+		break;
+	/* Options for fd transport */
+	case Opt_rfdno:
+		fd_opts->rfd = result.uint_32;
+		break;
+	case Opt_wfdno:
+		fd_opts->wfd = result.uint_32;
+		break;
+	/* Options for rdma transport */
+	case Opt_sq_depth:
+		rdma_opts->sq_depth = result.uint_32;
+		break;
+	case Opt_rq_depth:
+		rdma_opts->rq_depth = result.uint_32;
+		break;
+	case Opt_timeout:
+		rdma_opts->timeout = result.uint_32;
+		break;
+	/* Options for both fd and rdma transports */
+	case Opt_port:
+		fd_opts->port = result.uint_32;
+		rdma_opts->port = result.uint_32;
+		break;
+	case Opt_privport:
+		fd_opts->privport = true;
+		rdma_opts->port = true;
+		break;
 	}
 
-free_and_return:
-	kfree(tmp_options);
-fail_option_alloc:
-	return ret;
+	return 0;
+}
+
+static void v9fs_apply_options(struct v9fs_session_info *v9ses,
+		  struct fs_context *fc)
+{
+	struct v9fs_context	*ctx = fc->fs_private;
+
+	v9ses->debug = ctx->v9ses.debug;
+	v9ses->dfltuid = ctx->v9ses.dfltuid;
+	v9ses->dfltgid = ctx->v9ses.dfltgid;
+	v9ses->afid = ctx->v9ses.afid;
+	v9ses->uname = ctx->v9ses.uname;
+	ctx->v9ses.uname = NULL;
+	v9ses->aname = ctx->v9ses.aname;
+	ctx->v9ses.aname = NULL;
+	v9ses->nodev = ctx->v9ses.nodev;
+	/*
+	 * Note that we must |= flags here as session_init already
+	 * set basic flags. This adds in flags from parsed options.
+	 */
+	v9ses->flags |= ctx->v9ses.flags;
+#ifdef CONFIG_9P_FSCACHE
+	v9ses->cachetag = ctx->v9ses.cachetag;
+	ctx->v9ses.cachetag = NULL;
+#endif
+	v9ses->cache = ctx->v9ses.cache;
+	v9ses->uid = ctx->v9ses.uid;
+	v9ses->session_lock_timeout = ctx->v9ses.session_lock_timeout;
 }
 
 /**
  * v9fs_session_init - initialize session
  * @v9ses: session information structure
- * @dev_name: device being mounted
- * @data: options
+ * @fc: the filesystem mount context
  *
  */
 
 struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
-		  const char *dev_name, char *data)
+		  struct fs_context *fc)
 {
 	struct p9_fid *fid;
 	int rc = -ENOMEM;
 
-	v9ses->uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL);
-	if (!v9ses->uname)
-		goto err_names;
-
-	v9ses->aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL);
-	if (!v9ses->aname)
-		goto err_names;
 	init_rwsem(&v9ses->rename_sem);
 
-	v9ses->uid = INVALID_UID;
-	v9ses->dfltuid = V9FS_DEFUID;
-	v9ses->dfltgid = V9FS_DEFGID;
-
-	v9ses->clnt = p9_client_create(dev_name, data);
+	v9ses->clnt = p9_client_create(fc);
 	if (IS_ERR(v9ses->clnt)) {
 		rc = PTR_ERR(v9ses->clnt);
 		p9_debug(P9_DEBUG_ERROR, "problem initializing 9p client\n");
 		goto err_names;
 	}
 
+	/*
+	 * Initialize flags on the real v9ses. v9fs_apply_options below
+	 * will |= the additional flags from parsed options.
+	 */
 	v9ses->flags = V9FS_ACCESS_USER;
 
 	if (p9_is_proto_dotl(v9ses->clnt)) {
@@ -423,9 +414,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
 		v9ses->flags |= V9FS_PROTO_2000U;
 	}
 
-	rc = v9fs_parse_options(v9ses, data);
-	if (rc < 0)
-		goto err_clnt;
+	v9fs_apply_options(v9ses, fc);
 
 	v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
 
@@ -472,7 +461,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
 #ifdef CONFIG_9P_FSCACHE
 	/* register the session for caching */
 	if (v9ses->cache & CACHE_FSCACHE) {
-		rc = v9fs_cache_session_get_cookie(v9ses, dev_name);
+		rc = v9fs_cache_session_get_cookie(v9ses, fc->source);
 		if (rc < 0)
 			goto err_clnt;
 	}
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 4b8834daec8d..fb6d06128da5 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -10,6 +10,9 @@
 
 #include <linux/backing-dev.h>
 #include <linux/netfs.h>
+#include <linux/fs_parser.h>
+#include <net/9p/client.h>
+#include <net/9p/transport.h>
 
 /**
  * enum p9_session_flags - option flags for each 9P session
@@ -114,11 +117,13 @@ static inline struct fscache_volume *v9fs_session_cache(struct v9fs_session_info
 #endif
 }
 
+extern const struct fs_parameter_spec v9fs_param_spec[];
 
+extern int v9fs_parse_param(struct fs_context *fc, struct fs_parameter *param);
 extern int v9fs_show_options(struct seq_file *m, struct dentry *root);
 
 struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
-				 const char *dev_name, char *data);
+				 struct fs_context *fc);
 extern void v9fs_session_close(struct v9fs_session_info *v9ses);
 extern void v9fs_session_cancel(struct v9fs_session_info *v9ses);
 extern void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses);
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 489db161abc9..92a189651c07 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -19,6 +19,7 @@
 #include <linux/statfs.h>
 #include <linux/magic.h>
 #include <linux/fscache.h>
+#include <linux/fs_context.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 
@@ -33,29 +34,23 @@ static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
 /**
  * v9fs_set_super - set the superblock
  * @s: super block
- * @data: file system specific data
+ * @fc: the filesystem context
  *
  */
 
-static int v9fs_set_super(struct super_block *s, void *data)
+static int v9fs_set_super(struct super_block *s, struct fs_context *fc)
 {
-	s->s_fs_info = data;
-	return set_anon_super(s, data);
-}
+	struct v9fs_session_info *v9ses = fc->s_fs_info;
 
-/**
- * v9fs_fill_super - populate superblock with info
- * @sb: superblock
- * @v9ses: session information
- * @flags: flags propagated from v9fs_mount()
- *
- */
+	s->s_fs_info = v9ses;
+	return set_anon_super(s, NULL);
+}
 
-static int
-v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
-		int flags)
+static int v9fs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
 	int ret;
+	struct v9fs_context	*ctx = fc->fs_private;
+	struct v9fs_session_info *v9ses = &ctx->v9ses;
 
 	sb->s_maxbytes = MAX_LFS_FILESIZE;
 	sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
@@ -95,16 +90,12 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
 }
 
 /**
- * v9fs_mount - mount a superblock
- * @fs_type: file system type
- * @flags: mount flags
- * @dev_name: device name that was mounted
- * @data: mount options
+ * v9fs_get_tree - create the mountable root and superblock
+ * @fc: the filesystem context
  *
  */
 
-static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
-		       const char *dev_name, void *data)
+static int v9fs_get_tree(struct fs_context *fc)
 {
 	struct super_block *sb = NULL;
 	struct inode *inode = NULL;
@@ -117,20 +108,21 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
 
 	v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
 	if (!v9ses)
-		return ERR_PTR(-ENOMEM);
+		return -ENOMEM;
 
-	fid = v9fs_session_init(v9ses, dev_name, data);
+	fid = v9fs_session_init(v9ses, fc);
 	if (IS_ERR(fid)) {
 		retval = PTR_ERR(fid);
 		goto free_session;
 	}
 
-	sb = sget(fs_type, NULL, v9fs_set_super, flags, v9ses);
+	fc->s_fs_info = v9ses;
+	sb = sget_fc(fc, NULL, v9fs_set_super);
 	if (IS_ERR(sb)) {
 		retval = PTR_ERR(sb);
 		goto clunk_fid;
 	}
-	retval = v9fs_fill_super(sb, v9ses, flags);
+	retval = v9fs_fill_super(sb, fc);
 	if (retval)
 		goto release_sb;
 
@@ -157,14 +149,15 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
 	v9fs_fid_add(root, &fid);
 
 	p9_debug(P9_DEBUG_VFS, " simple set mount, return 0\n");
-	return dget(sb->s_root);
+	fc->root = dget(sb->s_root);
+	return 0;
 
 clunk_fid:
 	p9_fid_put(fid);
 	v9fs_session_close(v9ses);
 free_session:
 	kfree(v9ses);
-	return ERR_PTR(retval);
+	return retval;
 
 release_sb:
 	/*
@@ -175,7 +168,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
 	 */
 	p9_fid_put(fid);
 	deactivate_locked_super(sb);
-	return ERR_PTR(retval);
+	return retval;
 }
 
 /**
@@ -301,11 +294,86 @@ static const struct super_operations v9fs_super_ops_dotl = {
 	.write_inode = v9fs_write_inode_dotl,
 };
 
+static void v9fs_free_fc(struct fs_context *fc)
+{
+	struct v9fs_context *ctx = fc->fs_private;
+
+	if (!ctx)
+		return;
+
+	/* These should be NULL by now but guard against leaks */
+	kfree(ctx->v9ses.uname);
+	kfree(ctx->v9ses.aname);
+#ifdef CONFIG_9P_FSCACHE
+	kfree(ctx->v9ses.cachetag);
+#endif
+	if (ctx->client_opts.trans_mod)
+		v9fs_put_trans(ctx->client_opts.trans_mod);
+	kfree(ctx);
+}
+
+static const struct fs_context_operations v9fs_context_ops = {
+	.parse_param	= v9fs_parse_param,
+	.get_tree	= v9fs_get_tree,
+	.free		= v9fs_free_fc,
+};
+
+static int v9fs_init_fs_context(struct fs_context *fc)
+{
+	struct v9fs_context	*ctx;
+
+	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	/* initialize core options */
+	ctx->v9ses.afid = ~0;
+	ctx->v9ses.cache = CACHE_NONE;
+	ctx->v9ses.session_lock_timeout = P9_LOCK_TIMEOUT;
+	ctx->v9ses.uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL);
+	if (!ctx->v9ses.uname)
+		goto error;
+
+	ctx->v9ses.aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL);
+	if (!ctx->v9ses.aname)
+		goto error;
+
+	ctx->v9ses.uid = INVALID_UID;
+	ctx->v9ses.dfltuid = V9FS_DEFUID;
+	ctx->v9ses.dfltgid = V9FS_DEFGID;
+
+	/* initialize client options */
+	ctx->client_opts.proto_version = p9_proto_2000L;
+	ctx->client_opts.msize = DEFAULT_MSIZE;
+
+	/* initialize fd transport options */
+	ctx->fd_opts.port = P9_FD_PORT;
+	ctx->fd_opts.rfd = ~0;
+	ctx->fd_opts.wfd = ~0;
+	ctx->fd_opts.privport = false;
+
+	/* initialize rdma transport options */
+	ctx->rdma_opts.port = P9_RDMA_PORT;
+	ctx->rdma_opts.sq_depth = P9_RDMA_SQ_DEPTH;
+	ctx->rdma_opts.rq_depth = P9_RDMA_RQ_DEPTH;
+	ctx->rdma_opts.timeout = P9_RDMA_TIMEOUT;
+	ctx->rdma_opts.privport = false;
+
+	fc->ops = &v9fs_context_ops;
+	fc->fs_private = ctx;
+
+	return 0;
+error:
+	fc->need_free = 1;
+	return -ENOMEM;
+}
+
 struct file_system_type v9fs_fs_type = {
 	.name = "9p",
-	.mount = v9fs_mount,
 	.kill_sb = v9fs_kill_super,
 	.owner = THIS_MODULE,
 	.fs_flags = FS_RENAME_DOES_D_MOVE,
+	.init_fs_context = v9fs_init_fs_context,
+	.parameters = v9fs_param_spec,
 };
 MODULE_ALIAS_FS("9p");
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 33b8d9a79fa7..a95b8b6ea583 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -277,7 +277,7 @@ int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid,
 		     const char *name);
 int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name,
 		       struct p9_fid *newdirfid, const char *new_name);
-struct p9_client *p9_client_create(const char *dev_name, char *options);
+struct p9_client *p9_client_create(struct fs_context *fc);
 void p9_client_destroy(struct p9_client *clnt);
 void p9_client_disconnect(struct p9_client *clnt);
 void p9_client_begin_disconnect(struct p9_client *clnt);
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h
index ebbb4b50ee20..e53f312191b6 100644
--- a/include/net/9p/transport.h
+++ b/include/net/9p/transport.h
@@ -53,7 +53,7 @@ struct p9_trans_module {
 	int def;		/* this transport should be default */
 	struct module *owner;
 	int (*create)(struct p9_client *client,
-		      const char *devname, char *args);
+		      struct fs_context *fc);
 	void (*close)(struct p9_client *client);
 	int (*request)(struct p9_client *client, struct p9_req_t *req);
 	int (*cancel)(struct p9_client *client, struct p9_req_t *req);
diff --git a/net/9p/client.c b/net/9p/client.c
index 5e3230b1bfab..22b88596e2fe 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -20,8 +20,8 @@
 #include <linux/uio.h>
 #include <linux/netfs.h>
 #include <net/9p/9p.h>
-#include <linux/parser.h>
 #include <linux/seq_file.h>
+#include <linux/fs_context.h>
 #include <net/9p/client.h>
 #include <net/9p/transport.h>
 #include "protocol.h"
@@ -33,22 +33,6 @@
  *  - a little lazy - parse all client options
  */
 
-enum {
-	Opt_msize,
-	Opt_trans,
-	Opt_legacy,
-	Opt_version,
-	Opt_err,
-};
-
-static const match_table_t tokens = {
-	{Opt_msize, "msize=%u"},
-	{Opt_legacy, "noextend"},
-	{Opt_trans, "trans=%s"},
-	{Opt_version, "version=%s"},
-	{Opt_err, NULL},
-};
-
 inline int p9_is_proto_dotl(struct p9_client *clnt)
 {
 	return clnt->proto_version == p9_proto_2000L;
@@ -97,124 +81,16 @@ static int safe_errno(int err)
 	return err;
 }
 
-/* Interpret mount option for protocol version */
-static int get_protocol_version(char *s)
+static int apply_client_options(struct p9_client *clnt, struct fs_context *fc)
 {
-	int version = -EINVAL;
-
-	if (!strcmp(s, "9p2000")) {
-		version = p9_proto_legacy;
-		p9_debug(P9_DEBUG_9P, "Protocol version: Legacy\n");
-	} else if (!strcmp(s, "9p2000.u")) {
-		version = p9_proto_2000u;
-		p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.u\n");
-	} else if (!strcmp(s, "9p2000.L")) {
-		version = p9_proto_2000L;
-		p9_debug(P9_DEBUG_9P, "Protocol version: 9P2000.L\n");
-	} else {
-		pr_info("Unknown protocol version %s\n", s);
-	}
+	struct v9fs_context *ctx = fc->fs_private;
 
-	return version;
-}
-
-/**
- * parse_opts - parse mount options into client structure
- * @opts: options string passed from mount
- * @clnt: existing v9fs client information
- *
- * Return 0 upon success, -ERRNO upon failure
- */
-
-static int parse_opts(char *opts, struct p9_client *clnt)
-{
-	char *options, *tmp_options;
-	char *p;
-	substring_t args[MAX_OPT_ARGS];
-	int option;
-	char *s;
-	int ret = 0;
-
-	clnt->proto_version = p9_proto_2000L;
-	clnt->msize = DEFAULT_MSIZE;
-
-	if (!opts)
-		return 0;
+	clnt->msize = ctx->client_opts.msize;
+	clnt->trans_mod = ctx->client_opts.trans_mod;
+	ctx->client_opts.trans_mod = NULL;
+	clnt->proto_version = ctx->client_opts.proto_version;
 
-	tmp_options = kstrdup(opts, GFP_KERNEL);
-	if (!tmp_options)
-		return -ENOMEM;
-	options = tmp_options;
-
-	while ((p = strsep(&options, ",")) != NULL) {
-		int token, r;
-
-		if (!*p)
-			continue;
-		token = match_token(p, tokens, args);
-		switch (token) {
-		case Opt_msize:
-			r = match_int(&args[0], &option);
-			if (r < 0) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "integer field, but no integer?\n");
-				ret = r;
-				continue;
-			}
-			if (option < 4096) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "msize should be at least 4k\n");
-				ret = -EINVAL;
-				continue;
-			}
-			clnt->msize = option;
-			break;
-		case Opt_trans:
-			s = match_strdup(&args[0]);
-			if (!s) {
-				ret = -ENOMEM;
-				p9_debug(P9_DEBUG_ERROR,
-					 "problem allocating copy of trans arg\n");
-				goto free_and_return;
-			}
-
-			v9fs_put_trans(clnt->trans_mod);
-			clnt->trans_mod = v9fs_get_trans_by_name(s);
-			if (!clnt->trans_mod) {
-				pr_info("Could not find request transport: %s\n",
-					s);
-				ret = -EINVAL;
-			}
-			kfree(s);
-			break;
-		case Opt_legacy:
-			clnt->proto_version = p9_proto_legacy;
-			break;
-		case Opt_version:
-			s = match_strdup(&args[0]);
-			if (!s) {
-				ret = -ENOMEM;
-				p9_debug(P9_DEBUG_ERROR,
-					 "problem allocating copy of version arg\n");
-				goto free_and_return;
-			}
-			r = get_protocol_version(s);
-			if (r < 0)
-				ret = r;
-			else
-				clnt->proto_version = r;
-			kfree(s);
-			break;
-		default:
-			continue;
-		}
-	}
-
-free_and_return:
-	if (ret)
-		v9fs_put_trans(clnt->trans_mod);
-	kfree(tmp_options);
-	return ret;
+	return 0;
 }
 
 static int p9_fcall_init(struct p9_client *c, struct p9_fcall *fc,
@@ -968,7 +844,7 @@ static int p9_client_version(struct p9_client *c)
 	return err;
 }
 
-struct p9_client *p9_client_create(const char *dev_name, char *options)
+struct p9_client *p9_client_create(struct fs_context *fc)
 {
 	int err;
 	static atomic_t seqno = ATOMIC_INIT(0);
@@ -991,8 +867,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
 	idr_init(&clnt->fids);
 	idr_init(&clnt->reqs);
 
-	err = parse_opts(options, clnt);
-	if (err < 0)
+	err = apply_client_options(clnt, fc);
+	if (err)
 		goto free_client;
 
 	if (!clnt->trans_mod)
@@ -1008,7 +884,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
 	p9_debug(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
 		 clnt, clnt->trans_mod, clnt->msize, clnt->proto_version);
 
-	err = clnt->trans_mod->create(clnt, dev_name, options);
+	err = clnt->trans_mod->create(clnt, fc);
 	if (err)
 		goto put_trans;
 
diff --git a/net/9p/mod.c b/net/9p/mod.c
index 55576c1866fa..85160b52da55 100644
--- a/net/9p/mod.c
+++ b/net/9p/mod.c
@@ -16,7 +16,6 @@
 #include <linux/moduleparam.h>
 #include <net/9p/9p.h>
 #include <linux/fs.h>
-#include <linux/parser.h>
 #include <net/9p/client.h>
 #include <net/9p/transport.h>
 #include <linux/list.h>
@@ -171,6 +170,7 @@ void v9fs_put_trans(struct p9_trans_module *m)
 	if (m)
 		module_put(m->owner);
 }
+EXPORT_SYMBOL(v9fs_put_trans);
 
 /**
  * init_p9 - Initialize module
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index 9ef4f2e0db3c..cb4398d79b0a 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -22,7 +22,7 @@
 #include <linux/uaccess.h>
 #include <linux/inet.h>
 #include <linux/file.h>
-#include <linux/parser.h>
+#include <linux/fs_context.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 #include <net/9p/9p.h>
@@ -37,26 +37,6 @@
 static struct p9_trans_module p9_tcp_trans;
 static struct p9_trans_module p9_fd_trans;
 
-/*
-  * Option Parsing (code inspired by NFS code)
-  *  - a little lazy - parse all fd-transport options
-  */
-
-enum {
-	/* Options that take integer arguments */
-	Opt_port, Opt_rfdno, Opt_wfdno, Opt_err,
-	/* Options that take no arguments */
-	Opt_privport,
-};
-
-static const match_table_t tokens = {
-	{Opt_port, "port=%u"},
-	{Opt_rfdno, "rfdno=%u"},
-	{Opt_wfdno, "wfdno=%u"},
-	{Opt_privport, "privport"},
-	{Opt_err, NULL},
-};
-
 enum {
 	Rworksched = 1,		/* read work scheduled or running */
 	Rpending = 2,		/* can read */
@@ -744,73 +724,6 @@ static int p9_fd_show_options(struct seq_file *m, struct p9_client *clnt)
 	return 0;
 }
 
-/**
- * parse_opts - parse mount options into p9_fd_opts structure
- * @params: options string passed from mount
- * @opts: fd transport-specific structure to parse options into
- *
- * Returns 0 upon success, -ERRNO upon failure
- */
-
-static int parse_opts(char *params, struct p9_fd_opts *opts)
-{
-	char *p;
-	substring_t args[MAX_OPT_ARGS];
-	int option;
-	char *options, *tmp_options;
-
-	opts->port = P9_FD_PORT;
-	opts->rfd = ~0;
-	opts->wfd = ~0;
-	opts->privport = false;
-
-	if (!params)
-		return 0;
-
-	tmp_options = kstrdup(params, GFP_KERNEL);
-	if (!tmp_options) {
-		p9_debug(P9_DEBUG_ERROR,
-			 "failed to allocate copy of option string\n");
-		return -ENOMEM;
-	}
-	options = tmp_options;
-
-	while ((p = strsep(&options, ",")) != NULL) {
-		int token;
-		int r;
-		if (!*p)
-			continue;
-		token = match_token(p, tokens, args);
-		if ((token != Opt_err) && (token != Opt_privport)) {
-			r = match_int(&args[0], &option);
-			if (r < 0) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "integer field, but no integer?\n");
-				continue;
-			}
-		}
-		switch (token) {
-		case Opt_port:
-			opts->port = option;
-			break;
-		case Opt_rfdno:
-			opts->rfd = option;
-			break;
-		case Opt_wfdno:
-			opts->wfd = option;
-			break;
-		case Opt_privport:
-			opts->privport = true;
-			break;
-		default:
-			continue;
-		}
-	}
-
-	kfree(tmp_options);
-	return 0;
-}
-
 static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
 {
 	struct p9_trans_fd *ts = kzalloc(sizeof(struct p9_trans_fd),
@@ -965,17 +878,18 @@ static int p9_bind_privport(struct socket *sock)
 }
 
 static int
-p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
+p9_fd_create_tcp(struct p9_client *client, struct fs_context *fc)
 {
+	const char *addr = fc->source;
+	struct v9fs_context *ctx = fc->fs_private;
 	int err;
 	char port_str[6];
 	struct socket *csocket;
 	struct sockaddr_storage stor = { 0 };
 	struct p9_fd_opts opts;
 
-	err = parse_opts(args, &opts);
-	if (err < 0)
-		return err;
+	/* opts are already parsed in context */
+	opts = ctx->fd_opts;
 
 	if (!addr)
 		return -EINVAL;
@@ -1022,8 +936,9 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
 }
 
 static int
-p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
+p9_fd_create_unix(struct p9_client *client, struct fs_context *fc)
 {
+	const char *addr = fc->source;
 	int err;
 	struct socket *csocket;
 	struct sockaddr_un sun_server;
@@ -1062,14 +977,12 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
 }
 
 static int
-p9_fd_create(struct p9_client *client, const char *addr, char *args)
+p9_fd_create(struct p9_client *client, struct fs_context *fc)
 {
+	struct v9fs_context *ctx = fc->fs_private;
+	struct p9_fd_opts opts = ctx->fd_opts;
 	int err;
-	struct p9_fd_opts opts;
 
-	err = parse_opts(args, &opts);
-	if (err < 0)
-		return err;
 	client->trans_opts.fd.rfd = opts.rfd;
 	client->trans_opts.fd.wfd = opts.wfd;
 
diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
index 46ee37061faf..fa3365990fdf 100644
--- a/net/9p/trans_rdma.c
+++ b/net/9p/trans_rdma.c
@@ -22,7 +22,7 @@
 #include <linux/uaccess.h>
 #include <linux/inet.h>
 #include <linux/file.h>
-#include <linux/parser.h>
+#include <linux/fs_context.h>
 #include <linux/semaphore.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
@@ -106,26 +106,6 @@ struct p9_rdma_context {
 	};
 };
 
-/*
- * Option Parsing (code inspired by NFS code)
- */
-enum {
-	/* Options that take integer arguments */
-	Opt_port, Opt_rq_depth, Opt_sq_depth, Opt_timeout,
-	/* Options that take no argument */
-	Opt_privport,
-	Opt_err,
-};
-
-static match_table_t tokens = {
-	{Opt_port, "port=%u"},
-	{Opt_sq_depth, "sq=%u"},
-	{Opt_rq_depth, "rq=%u"},
-	{Opt_timeout, "timeout=%u"},
-	{Opt_privport, "privport"},
-	{Opt_err, NULL},
-};
-
 static int p9_rdma_show_options(struct seq_file *m, struct p9_client *clnt)
 {
 	struct p9_trans_rdma *rdma = clnt->trans;
@@ -143,77 +123,6 @@ static int p9_rdma_show_options(struct seq_file *m, struct p9_client *clnt)
 	return 0;
 }
 
-/**
- * parse_opts - parse mount options into rdma options structure
- * @params: options string passed from mount
- * @opts: rdma transport-specific structure to parse options into
- *
- * Returns 0 upon success, -ERRNO upon failure
- */
-static int parse_opts(char *params, struct p9_rdma_opts *opts)
-{
-	char *p;
-	substring_t args[MAX_OPT_ARGS];
-	int option;
-	char *options, *tmp_options;
-
-	opts->port = P9_RDMA_PORT;
-	opts->sq_depth = P9_RDMA_SQ_DEPTH;
-	opts->rq_depth = P9_RDMA_RQ_DEPTH;
-	opts->timeout = P9_RDMA_TIMEOUT;
-	opts->privport = false;
-
-	if (!params)
-		return 0;
-
-	tmp_options = kstrdup(params, GFP_KERNEL);
-	if (!tmp_options) {
-		p9_debug(P9_DEBUG_ERROR,
-			 "failed to allocate copy of option string\n");
-		return -ENOMEM;
-	}
-	options = tmp_options;
-
-	while ((p = strsep(&options, ",")) != NULL) {
-		int token;
-		int r;
-		if (!*p)
-			continue;
-		token = match_token(p, tokens, args);
-		if ((token != Opt_err) && (token != Opt_privport)) {
-			r = match_int(&args[0], &option);
-			if (r < 0) {
-				p9_debug(P9_DEBUG_ERROR,
-					 "integer field, but no integer?\n");
-				continue;
-			}
-		}
-		switch (token) {
-		case Opt_port:
-			opts->port = option;
-			break;
-		case Opt_sq_depth:
-			opts->sq_depth = option;
-			break;
-		case Opt_rq_depth:
-			opts->rq_depth = option;
-			break;
-		case Opt_timeout:
-			opts->timeout = option;
-			break;
-		case Opt_privport:
-			opts->privport = true;
-			break;
-		default:
-			continue;
-		}
-	}
-	/* RQ must be at least as large as the SQ */
-	opts->rq_depth = max(opts->rq_depth, opts->sq_depth);
-	kfree(tmp_options);
-	return 0;
-}
-
 static int
 p9_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
 {
@@ -607,14 +516,15 @@ static int p9_rdma_bind_privport(struct p9_trans_rdma *rdma)
 /**
  * rdma_create_trans - Transport method for creating a transport instance
  * @client: client instance
- * @addr: IP address string
- * @args: Mount options string
+ * @fc: The filesystem context
  */
 static int
-rdma_create_trans(struct p9_client *client, const char *addr, char *args)
+rdma_create_trans(struct p9_client *client, struct fs_context *fc)
 {
+	const char *addr = fc->source;
+	struct v9fs_context *ctx = fc->fs_private;
+	struct p9_rdma_opts opts = ctx->rdma_opts;
 	int err;
-	struct p9_rdma_opts opts;
 	struct p9_trans_rdma *rdma;
 	struct rdma_conn_param conn_param;
 	struct ib_qp_init_attr qp_attr;
@@ -622,10 +532,8 @@ rdma_create_trans(struct p9_client *client, const char *addr, char *args)
 	if (addr == NULL)
 		return -EINVAL;
 
-	/* Parse the transport specific mount options */
-	err = parse_opts(args, &opts);
-	if (err < 0)
-		return err;
+	/* options are already parsed, in the fs context */
+	opts = ctx->rdma_opts;
 
 	/* Create and initialize the RDMA transport structure */
 	rdma = alloc_rdma(&opts);
diff --git a/net/9p/trans_usbg.c b/net/9p/trans_usbg.c
index 6b694f117aef..61197dae52cb 100644
--- a/net/9p/trans_usbg.c
+++ b/net/9p/trans_usbg.c
@@ -27,6 +27,7 @@
 #include <linux/cleanup.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/fs_context.h>
 #include <linux/usb/composite.h>
 #include <linux/usb/func_utils.h>
 
@@ -366,8 +367,9 @@ enable_usb9pfs(struct usb_composite_dev *cdev, struct f_usb9pfs *usb9pfs)
 	return ret;
 }
 
-static int p9_usbg_create(struct p9_client *client, const char *devname, char *args)
+static int p9_usbg_create(struct p9_client *client, struct fs_context *fc)
 {
+	const char *devname = fc->source;
 	struct f_usb9pfs_dev *dev;
 	struct f_usb9pfs *usb9pfs;
 	int ret = -ENOENT;
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 0b8086f58ad5..580d74ca92b0 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -26,7 +26,7 @@
 #include <linux/highmem.h>
 #include <linux/slab.h>
 #include <net/9p/9p.h>
-#include <linux/parser.h>
+#include <linux/fs_context.h>
 #include <net/9p/client.h>
 #include <net/9p/transport.h>
 #include <linux/scatterlist.h>
@@ -679,8 +679,7 @@ static int p9_virtio_probe(struct virtio_device *vdev)
 /**
  * p9_virtio_create - allocate a new virtio channel
  * @client: client instance invoking this transport
- * @devname: string identifying the channel to connect to (unused)
- * @args: args passed from sys_mount() for per-transport options (unused)
+ * @fc: the filesystem context
  *
  * This sets up a transport channel for 9p communication.  Right now
  * we only match the first available channel, but eventually we could look up
@@ -691,8 +690,9 @@ static int p9_virtio_probe(struct virtio_device *vdev)
  */
 
 static int
-p9_virtio_create(struct p9_client *client, const char *devname, char *args)
+p9_virtio_create(struct p9_client *client, struct fs_context *fc)
 {
+	const char *devname = fc->source;
 	struct virtio_chan *chan;
 	int ret = -ENOENT;
 	int found = 0;
diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c
index b9ff69c7522a..091a99eb51f4 100644
--- a/net/9p/trans_xen.c
+++ b/net/9p/trans_xen.c
@@ -15,6 +15,7 @@
 
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/fs_context.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 #include <net/9p/transport.h>
@@ -66,8 +67,9 @@ static int p9_xen_cancel(struct p9_client *client, struct p9_req_t *req)
 	return 1;
 }
 
-static int p9_xen_create(struct p9_client *client, const char *addr, char *args)
+static int p9_xen_create(struct p9_client *client, struct fs_context *fc)
 {
+	const char *addr = fc->source;
 	struct xen_9pfs_front_priv *priv;
 
 	if (addr == NULL)
-- 
2.50.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH V2 0/4] 9p: convert to the new mount API
  2025-07-30 19:18 [PATCH V2 0/4] 9p: convert to the new mount API Eric Sandeen
                   ` (3 preceding siblings ...)
  2025-07-30 19:18 ` [PATCH V2 4/4] 9p: convert to the new mount API Eric Sandeen
@ 2025-07-30 22:21 ` asmadeus
  2025-07-31  1:38   ` Eric Sandeen
  2025-08-14 16:55   ` Eric Sandeen
  4 siblings, 2 replies; 13+ messages in thread
From: asmadeus @ 2025-07-30 22:21 UTC (permalink / raw)
  To: Eric Sandeen
  Cc: v9fs, linux-fsdevel, linux-kernel, ericvh, lucho, linux_oss,
	dhowells

Hi Eric,

Eric Sandeen wrote on Wed, Jul 30, 2025 at 02:18:51PM -0500:
> This is an updated attempt to convert 9p to the new mount API. 9p is
> one of the last conversions needed, possibly because it is one of the
> trickier ones!

Thanks for this work!

I think the main contention point here is that we're moving some opaque
logic that was in each transport into the common code, so e.g. an out of
tree transport can no longer have its own options (not that I'm aware of
such a transport existing anyway, so we probably don't have to worry
about this)

OTOH this is also a blessing because 9p used to silently ignore unknown
options, and will now properly refuse them (although it'd still silently
ignore e.g. rdma options being set for a virtio mount -- I guess there's
little harm in that as long as typos are caught?)

So I think I'm fine with the approach.

> I was able to test this to some degree, but I am not sure how to test
> all transports; there may well be bugs here. It would be great to get
> some feedback on whether this approach seems reasonable, and of course
> any further review or testing would be most welcome.

I still want to de-dust my test setup with rdma over siw for lack of
supported hardware, so I'll try to give it a try, but don't necessarily
wait for me as I don't know when that'll be..

-- 
Dominique Martinet | Asmadeus

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V2 0/4] 9p: convert to the new mount API
  2025-07-30 22:21 ` [PATCH V2 0/4] " asmadeus
@ 2025-07-31  1:38   ` Eric Sandeen
  2025-07-31 12:24     ` asmadeus
  2025-08-14 16:55   ` Eric Sandeen
  1 sibling, 1 reply; 13+ messages in thread
From: Eric Sandeen @ 2025-07-31  1:38 UTC (permalink / raw)
  To: asmadeus
  Cc: v9fs, linux-fsdevel, linux-kernel, ericvh, lucho, linux_oss,
	dhowells

On 7/30/25 5:21 PM, asmadeus@codewreck.org wrote:
> Hi Eric,
> 
> Eric Sandeen wrote on Wed, Jul 30, 2025 at 02:18:51PM -0500:
>> This is an updated attempt to convert 9p to the new mount API. 9p is
>> one of the last conversions needed, possibly because it is one of the
>> trickier ones!
> 
> Thanks for this work!
> 
> I think the main contention point here is that we're moving some opaque
> logic that was in each transport into the common code, so e.g. an out of
> tree transport can no longer have its own options (not that I'm aware of
> such a transport existing anyway, so we probably don't have to worry
> about this)

I had not thought about out of tree transports. And I was a little unsure
about moving everything into fs/9p/* but I'm not sure I saw any other way
to do it in the new framework. @dhowells?

> OTOH this is also a blessing because 9p used to silently ignore unknown
> options, and will now properly refuse them (although it'd still silently
> ignore e.g. rdma options being set for a virtio mount -- I guess there's
> little harm in that as long as typos are caught?)

Well, that might be considered a regression. Such conversions have burned
us before, so if you want, it might be possible to keep the old more
permissive behavior ... I'd have to look, not sure.

> So I think I'm fine with the approach.
> 
>> I was able to test this to some degree, but I am not sure how to test
>> all transports; there may well be bugs here. It would be great to get
>> some feedback on whether this approach seems reasonable, and of course
>> any further review or testing would be most welcome.
> 
> I still want to de-dust my test setup with rdma over siw for lack of
> supported hardware, so I'll try to give it a try, but don't necessarily
> wait for me as I don't know when that'll be..

Cool, thanks.

-Eric


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V2 0/4] 9p: convert to the new mount API
  2025-07-31  1:38   ` Eric Sandeen
@ 2025-07-31 12:24     ` asmadeus
  0 siblings, 0 replies; 13+ messages in thread
From: asmadeus @ 2025-07-31 12:24 UTC (permalink / raw)
  To: Eric Sandeen
  Cc: v9fs, linux-fsdevel, linux-kernel, ericvh, lucho, linux_oss,
	dhowells

Eric Sandeen wrote on Wed, Jul 30, 2025 at 08:38:17PM -0500:
> > I think the main contention point here is that we're moving some opaque
> > logic that was in each transport into the common code, so e.g. an out of
> > tree transport can no longer have its own options (not that I'm aware of
> > such a transport existing anyway, so we probably don't have to worry
> > about this)
> 
> I had not thought about out of tree transports. And I was a little unsure
> about moving everything into fs/9p/* but I'm not sure I saw any other way
> to do it in the new framework. @dhowells?

I've had a quick look as well and I don't see either -- parameters are
parsed one at a time so we can't do the two passes needed to first get
the transport out of the arguments and then instantiate a transport and
parse again.
I really think it's fine in practice, just something to remember.

> > OTOH this is also a blessing because 9p used to silently ignore unknown
> > options, and will now properly refuse them (although it'd still silently
> > ignore e.g. rdma options being set for a virtio mount -- I guess there's
> > little harm in that as long as typos are caught?)
> 
> Well, that might be considered a regression. Such conversions have burned
> us before, so if you want, it might be possible to keep the old more
> permissive behavior ... I'd have to look, not sure.

From my understanding we just need to make v9fs_parse_param return 0
instead of 'opt' if fs_parse() < 0, but I think it's fine to error on
unknown options (more in line with other filesystems at least)
We can reconsider this and make it a non-error when or if someone
complains about it.

-- 
Dominique Martinet | Asmadeus

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V2 0/4] 9p: convert to the new mount API
  2025-07-30 22:21 ` [PATCH V2 0/4] " asmadeus
  2025-07-31  1:38   ` Eric Sandeen
@ 2025-08-14 16:55   ` Eric Sandeen
  2025-08-15  1:49     ` Dominique Martinet
  1 sibling, 1 reply; 13+ messages in thread
From: Eric Sandeen @ 2025-08-14 16:55 UTC (permalink / raw)
  To: asmadeus, Eric Sandeen
  Cc: v9fs, linux-fsdevel, linux-kernel, ericvh, lucho, linux_oss,
	dhowells, Christian Brauner

On 7/30/25 5:21 PM, asmadeus@codewreck.org wrote:
> Hi Eric,
> 
> Eric Sandeen wrote on Wed, Jul 30, 2025 at 02:18:51PM -0500:
>> This is an updated attempt to convert 9p to the new mount API. 9p is
>> one of the last conversions needed, possibly because it is one of the
>> trickier ones!
> 
> Thanks for this work!
> 
> I think the main contention point here is that we're moving some opaque
> logic that was in each transport into the common code, so e.g. an out of
> tree transport can no longer have its own options (not that I'm aware of
> such a transport existing anyway, so we probably don't have to worry
> about this)
> 
> OTOH this is also a blessing because 9p used to silently ignore unknown
> options, and will now properly refuse them (although it'd still silently
> ignore e.g. rdma options being set for a virtio mount -- I guess there's
> little harm in that as long as typos are caught?)
> 
> So I think I'm fine with the approach.
> 
>> I was able to test this to some degree, but I am not sure how to test
>> all transports; there may well be bugs here. It would be great to get
>> some feedback on whether this approach seems reasonable, and of course
>> any further review or testing would be most welcome.
> 
> I still want to de-dust my test setup with rdma over siw for lack of
> supported hardware, so I'll try to give it a try, but don't necessarily
> wait for me as I don't know when that'll be..
> 

Any news on testing? :)

As for "waiting for you," I assume that's more for your maintainer peers
than for me? I'm not sure if this would go through Christian (cc'd) or
through you?

Thanks,
-Eric

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V2 0/4] 9p: convert to the new mount API
  2025-08-14 16:55   ` Eric Sandeen
@ 2025-08-15  1:49     ` Dominique Martinet
  2025-08-15  2:45       ` Eric Sandeen
  2025-08-15 13:55       ` Christian Brauner
  0 siblings, 2 replies; 13+ messages in thread
From: Dominique Martinet @ 2025-08-15  1:49 UTC (permalink / raw)
  To: Eric Sandeen
  Cc: Eric Sandeen, v9fs, linux-fsdevel, linux-kernel, ericvh, lucho,
	linux_oss, dhowells, Christian Brauner

Eric Sandeen wrote on Thu, Aug 14, 2025 at 11:55:20AM -0500:
> >> I was able to test this to some degree, but I am not sure how to test
> >> all transports; there may well be bugs here. It would be great to get
> >> some feedback on whether this approach seems reasonable, and of course
> >> any further review or testing would be most welcome.
> > 
> > I still want to de-dust my test setup with rdma over siw for lack of
> > supported hardware, so I'll try to give it a try, but don't necessarily
> > wait for me as I don't know when that'll be..
> 
> Any news on testing? :)

Thanks for the prompting, that's the kind of things I never get around
to if not reminded...

I got this to run with a fedora-based host (unlike debian siw is
built-in):

- host side
```
$ sudo modprobe siw
$ sudo rdma link add siw0 type siw netdev br0
(sanity check)
$ ibv_devices
    device          	  node GUID
    ------          	----------------
    siw0            	020000fffe000001
( https://github.com/chaos/diod build)
$ ./configure --enable-rdma --disable-auth && make -j
(diod run, it runs rdma by default; not squashing as root fails with
  rdma because of the ib_safe_file_access check:
  [611503.258375] uverbs_write: process 1490213 (diod) changed security contexts after opening file descriptor, this is not allowed.
)
$ sudo ./diod -f -e /tmp/linux-test/ --no-auth -U root -S 
```
- guest side (with -net user)
```
# modprobe siw
# rdma link add siw0 type siw netdev eth0
# mount -t 9p -o trans=rdma,aname=/tmp/linux-test <hostip> /mnt
```

I've tested both the new and old mount api (with util-linux mount and
busybox mount) and it all seems in order to me;
as discussed in the other part of the thread we're now failing on
unknown options but I think that's a feature and we can change that if
someone complains.

> As for "waiting for you," I assume that's more for your maintainer peers
> than for me? I'm not sure if this would go through Christian (cc'd) or
> through you?

Sorry, I wasn't paying attention and confused you with another Eric
(Van Hensbergen) who is a 9p maintainer, so I was thinking you'd take
the patches, but that wasn't correct.
And that's after seeing your name all the time in #xfs, I'm sorry..

Christian is "just" a reviewer (for now!), and none of the other
maintainers pick much up lately, so I'll give this a second look and
take the patches.
Linus just closed up 6.17-rc1 so I guess this will get in 6.18 in the
next cycle, unless there'd be a reason to hurry?

Thanks,
-- 
Dominique Martinet | Asmadeus

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V2 0/4] 9p: convert to the new mount API
  2025-08-15  1:49     ` Dominique Martinet
@ 2025-08-15  2:45       ` Eric Sandeen
  2025-08-15 13:55       ` Christian Brauner
  1 sibling, 0 replies; 13+ messages in thread
From: Eric Sandeen @ 2025-08-15  2:45 UTC (permalink / raw)
  To: Dominique Martinet, Eric Sandeen
  Cc: v9fs, linux-fsdevel, linux-kernel, ericvh, lucho, linux_oss,
	dhowells, Christian Brauner

On 8/14/25 8:49 PM, Dominique Martinet wrote:
> Eric Sandeen wrote on Thu, Aug 14, 2025 at 11:55:20AM -0500:

...

>> Any news on testing? :)
> 
> Thanks for the prompting, that's the kind of things I never get around
> to if not reminded...
> 
> I got this to run with a fedora-based host (unlike debian siw is
> built-in):
> 
> - host side
> ```
> $ sudo modprobe siw
> $ sudo rdma link add siw0 type siw netdev br0
> (sanity check)
> $ ibv_devices
>     device          	  node GUID
>     ------          	----------------
>     siw0            	020000fffe000001
> ( https://github.com/chaos/diod build)
> $ ./configure --enable-rdma --disable-auth && make -j
> (diod run, it runs rdma by default; not squashing as root fails with
>   rdma because of the ib_safe_file_access check:
>   [611503.258375] uverbs_write: process 1490213 (diod) changed security contexts after opening file descriptor, this is not allowed.
> )
> $ sudo ./diod -f -e /tmp/linux-test/ --no-auth -U root -S 
> ```
> - guest side (with -net user)
> ```
> # modprobe siw
> # rdma link add siw0 type siw netdev eth0
> # mount -t 9p -o trans=rdma,aname=/tmp/linux-test <hostip> /mnt
> ```
> 
> I've tested both the new and old mount api (with util-linux mount and
> busybox mount) and it all seems in order to me;
> as discussed in the other part of the thread we're now failing on
> unknown options but I think that's a feature and we can change that if
> someone complains.

Super, thanks.

>> As for "waiting for you," I assume that's more for your maintainer peers
>> than for me? I'm not sure if this would go through Christian (cc'd) or
>> through you?
> 
> Sorry, I wasn't paying attention and confused you with another Eric
> (Van Hensbergen) who is a 9p maintainer, so I was thinking you'd take
> the patches, but that wasn't correct.
> And that's after seeing your name all the time in #xfs, I'm sorry..

No worries! I don't mind being confused with awesome people ;)

> Christian is "just" a reviewer (for now!), and none of the other
> maintainers pick much up lately, so I'll give this a second look and
> take the patches.
> Linus just closed up 6.17-rc1 so I guess this will get in 6.18 in the
> next cycle, unless there'd be a reason to hurry?

No reason to hurry. This has been a long process, and a little longer will
not hurt.

Thanks!
-Eric (Sandeen)

> Thanks,


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V2 0/4] 9p: convert to the new mount API
  2025-08-15  1:49     ` Dominique Martinet
  2025-08-15  2:45       ` Eric Sandeen
@ 2025-08-15 13:55       ` Christian Brauner
  2025-08-15 20:53         ` Dominique Martinet
  1 sibling, 1 reply; 13+ messages in thread
From: Christian Brauner @ 2025-08-15 13:55 UTC (permalink / raw)
  To: Dominique Martinet
  Cc: Eric Sandeen, Eric Sandeen, v9fs, linux-fsdevel, linux-kernel,
	ericvh, lucho, linux_oss, dhowells

On Fri, Aug 15, 2025 at 10:49:48AM +0900, Dominique Martinet wrote:
> Eric Sandeen wrote on Thu, Aug 14, 2025 at 11:55:20AM -0500:
> > >> I was able to test this to some degree, but I am not sure how to test
> > >> all transports; there may well be bugs here. It would be great to get
> > >> some feedback on whether this approach seems reasonable, and of course
> > >> any further review or testing would be most welcome.
> > > 
> > > I still want to de-dust my test setup with rdma over siw for lack of
> > > supported hardware, so I'll try to give it a try, but don't necessarily
> > > wait for me as I don't know when that'll be..
> > 
> > Any news on testing? :)
> 
> Thanks for the prompting, that's the kind of things I never get around
> to if not reminded...
> 
> I got this to run with a fedora-based host (unlike debian siw is
> built-in):
> 
> - host side
> ```
> $ sudo modprobe siw
> $ sudo rdma link add siw0 type siw netdev br0
> (sanity check)
> $ ibv_devices
>     device          	  node GUID
>     ------          	----------------
>     siw0            	020000fffe000001
> ( https://github.com/chaos/diod build)
> $ ./configure --enable-rdma --disable-auth && make -j
> (diod run, it runs rdma by default; not squashing as root fails with
>   rdma because of the ib_safe_file_access check:
>   [611503.258375] uverbs_write: process 1490213 (diod) changed security contexts after opening file descriptor, this is not allowed.
> )
> $ sudo ./diod -f -e /tmp/linux-test/ --no-auth -U root -S 
> ```
> - guest side (with -net user)
> ```
> # modprobe siw
> # rdma link add siw0 type siw netdev eth0
> # mount -t 9p -o trans=rdma,aname=/tmp/linux-test <hostip> /mnt
> ```
> 
> I've tested both the new and old mount api (with util-linux mount and
> busybox mount) and it all seems in order to me;
> as discussed in the other part of the thread we're now failing on
> unknown options but I think that's a feature and we can change that if
> someone complains.
> 
> > As for "waiting for you," I assume that's more for your maintainer peers
> > than for me? I'm not sure if this would go through Christian (cc'd) or
> > through you?
> 
> Sorry, I wasn't paying attention and confused you with another Eric
> (Van Hensbergen) who is a 9p maintainer, so I was thinking you'd take
> the patches, but that wasn't correct.
> And that's after seeing your name all the time in #xfs, I'm sorry..
> 
> Christian is "just" a reviewer (for now!), and none of the other
> maintainers pick much up lately, so I'll give this a second look and
> take the patches.

Fyi, Eric (Sandeen) is talking about me, Christian Brauner, whereas you
seem to be thinking of Christian Schoenebeck...

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH V2 0/4] 9p: convert to the new mount API
  2025-08-15 13:55       ` Christian Brauner
@ 2025-08-15 20:53         ` Dominique Martinet
  0 siblings, 0 replies; 13+ messages in thread
From: Dominique Martinet @ 2025-08-15 20:53 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Eric Sandeen, Eric Sandeen, v9fs, linux-fsdevel, linux-kernel,
	ericvh, lucho, linux_oss, dhowells

Christian Brauner wrote on Fri, Aug 15, 2025 at 03:55:13PM +0200:
> Fyi, Eric (Sandeen) is talking about me, Christian Brauner, whereas you
> seem to be thinking of Christian Schoenebeck...

Ah, yes.. (He's also in cc, although is name doesn't show up in his
linux_oss@crudebyte mail)

Well, that makes more sense; I've picked up the patches now so I think
it's fine as it is but happy to drop the set if you have any reason to
want them, just let me know.
-- 
Dominique

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2025-08-15 20:53 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-30 19:18 [PATCH V2 0/4] 9p: convert to the new mount API Eric Sandeen
2025-07-30 19:18 ` [PATCH V2 1/4] fs/fs_parse: add back fsparam_u32hex Eric Sandeen
2025-07-30 19:18 ` [PATCH V2 2/4] net/9p: move structures and macros to header files Eric Sandeen
2025-07-30 19:18 ` [PATCH V2 3/4] 9p: create a v9fs_context structure to hold parsed options Eric Sandeen
2025-07-30 19:18 ` [PATCH V2 4/4] 9p: convert to the new mount API Eric Sandeen
2025-07-30 22:21 ` [PATCH V2 0/4] " asmadeus
2025-07-31  1:38   ` Eric Sandeen
2025-07-31 12:24     ` asmadeus
2025-08-14 16:55   ` Eric Sandeen
2025-08-15  1:49     ` Dominique Martinet
2025-08-15  2:45       ` Eric Sandeen
2025-08-15 13:55       ` Christian Brauner
2025-08-15 20:53         ` Dominique Martinet

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).