1
0
mirror of https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2026-01-11 17:10:13 +00:00

- fix a bug with O_APPEND in cached mode causing data to be written multiple times on server

- use kvmalloc for trans_fd to avoid problems with large msize and fragmented memory
 This should hopefully be used in more transports when time allows
 - convert to new mount API
 - minor cleanups
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE/IPbcYBuWt0zoYhOq06b7GqY5nAFAmk1dvwACgkQq06b7GqY
 5nCRWA//a4qCTs/8FRS7N0Mz5Jg84VZ2JPnVN6iydLKbFDkgUL8JXI723VmApb6D
 wR21yRm7VuWpnGVdfPF6BtjZV7cYXEEwukfLqkXtOwx/WaRREKpN0sOciXMd0htg
 ZgnhhrabCOiSAYJYb9/29sNwhvfweQi0BeAFdIEAPrVonFUYXRzFS0v4AiBCs5PY
 n8X6aoshViAG05MZycB2VYaCxT45I+8YNCXtSsT/uX+3BP1FuRYMRluAYCLu/TU8
 oKyFjkpIri01211OEORx6gs5CDeCv0LpELfk5EW2QF/mz4oW3/4bAchg22NgNV6x
 0OCbgTqwlSJVETCZfZso/TV8efMlk1rLxSA0xjQY9r1lA26BTubrNadnC2W2nhSv
 GpPbDu6s3Cj3WD7P2InGtXxzUIZDCm8kHfHjzbbzgwOS6jl8SaDSnc6J2HtKNESL
 T55hqzqzv4POFQKrgznaQcaDW7imftOA+9xv+k+j5DTDKS9LLxiKS7+dyyzYAyyX
 sCjOd/T7JMvXIp4TxwbROn2+VBVYVO3ZaaKdK8e+qVKvWooP3iorGXAg0O0wZYJV
 tLE5zioZiRngzhqAczDIpJAe5Qd/SIi6W+sAOpKLSvVVKGf/akr0wH0KxI5z7ox8
 uBStVXTOoh52qQr0L7nnBIUJ2VJLJUt9TCzwwvaLM5B1TyPgxh8=
 =7ST9
 -----END PGP SIGNATURE-----

Merge tag '9p-for-6.19-rc1' of https://github.com/martinetd/linux

Pull 9p updates from Dominique Martinet:

 - fix a bug with O_APPEND in cached mode causing data to be written
   multiple times on server

 - use kvmalloc for trans_fd to avoid problems with large msize and
   fragmented memory This should hopefully be used in more transports
   when time allows

 - convert to new mount API

 - minor cleanups

* tag '9p-for-6.19-rc1' of https://github.com/martinetd/linux:
  9p: fix new mount API cache option handling
  9p: fix cache/debug options printing in v9fs_show_options
  9p: convert to the new mount API
  9p: create a v9fs_context structure to hold parsed options
  net/9p: move structures and macros to header files
  fs/fs_parse: add back fsparam_u32hex
  fs/9p: delete unnnecessary condition
  fs/9p: Don't open remote file with APPEND mode when writeback cache is used
  net/9p: cleanup: change p9_trans_module->def to bool
  9p: Use kvmalloc for message buffers on supported transports
This commit is contained in:
Linus Torvalds 2025-12-07 08:29:09 -08:00
commit bbbf7f3284
17 changed files with 573 additions and 698 deletions

View File

@ -13,7 +13,8 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/cred.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/slab.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <net/9p/9p.h> #include <net/9p/9p.h>
@ -33,6 +34,10 @@ struct kmem_cache *v9fs_inode_cache;
*/ */
enum { enum {
/* Mount-point source, we need to handle this explicitly because
* the code below accepts unknown args and the vfs layer only handles
* source if we rejected it as EINVAL */
Opt_source,
/* Options that take integer arguments */ /* Options that take integer arguments */
Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid, Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid,
/* String options */ /* String options */
@ -43,27 +48,71 @@ enum {
Opt_access, Opt_posixacl, Opt_access, Opt_posixacl,
/* Lock timeout option */ /* Lock timeout option */
Opt_locktimeout, 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 = { static const struct constant_table p9_versions[] = {
{Opt_debug, "debug=%x"}, { "9p2000", p9_proto_legacy },
{Opt_dfltuid, "dfltuid=%u"}, { "9p2000.u", p9_proto_2000u },
{Opt_dfltgid, "dfltgid=%u"}, { "9p2000.L", p9_proto_2000L },
{Opt_afid, "afid=%u"}, {}
{Opt_uname, "uname=%s"}, };
{Opt_remotename, "aname=%s"},
{Opt_nodevmap, "nodevmap"}, /*
{Opt_noxattr, "noxattr"}, * This structure contains all parameters used for the core code,
{Opt_directio, "directio"}, * the client, and all the transports.
{Opt_ignoreqv, "ignoreqv"}, */
{Opt_cache, "cache=%s"}, const struct fs_parameter_spec v9fs_param_spec[] = {
{Opt_cachetag, "cachetag=%s"}, fsparam_string ("source", Opt_source),
{Opt_access, "access=%s"}, fsparam_u32hex ("debug", Opt_debug),
{Opt_posixacl, "posixacl"}, fsparam_uid ("dfltuid", Opt_dfltuid),
{Opt_locktimeout, "locktimeout=%u"}, fsparam_gid ("dfltgid", Opt_dfltgid),
{Opt_err, NULL} 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_string ("cache", Opt_cache),
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),
{}
}; };
/* Interpret mount options for cache mode */ /* Interpret mount options for cache mode */
@ -101,7 +150,7 @@ int v9fs_show_options(struct seq_file *m, struct dentry *root)
struct v9fs_session_info *v9ses = root->d_sb->s_fs_info; struct v9fs_session_info *v9ses = root->d_sb->s_fs_info;
if (v9ses->debug) if (v9ses->debug)
seq_printf(m, ",debug=%x", v9ses->debug); seq_printf(m, ",debug=%#x", v9ses->debug);
if (!uid_eq(v9ses->dfltuid, V9FS_DEFUID)) if (!uid_eq(v9ses->dfltuid, V9FS_DEFUID))
seq_printf(m, ",dfltuid=%u", seq_printf(m, ",dfltuid=%u",
from_kuid_munged(&init_user_ns, v9ses->dfltuid)); from_kuid_munged(&init_user_ns, v9ses->dfltuid));
@ -117,7 +166,7 @@ int v9fs_show_options(struct seq_file *m, struct dentry *root)
if (v9ses->nodev) if (v9ses->nodev)
seq_puts(m, ",nodevmap"); seq_puts(m, ",nodevmap");
if (v9ses->cache) if (v9ses->cache)
seq_printf(m, ",cache=%x", v9ses->cache); seq_printf(m, ",cache=%#x", v9ses->cache);
#ifdef CONFIG_9P_FSCACHE #ifdef CONFIG_9P_FSCACHE
if (v9ses->cachetag && (v9ses->cache & CACHE_FSCACHE)) if (v9ses->cachetag && (v9ses->cache & CACHE_FSCACHE))
seq_printf(m, ",cachetag=%s", v9ses->cachetag); seq_printf(m, ",cachetag=%s", v9ses->cachetag);
@ -153,199 +202,126 @@ int v9fs_show_options(struct seq_file *m, struct dentry *root)
} }
/** /**
* v9fs_parse_options - parse mount options into session structure * v9fs_parse_param - parse a mount option into the filesystem context
* @v9ses: existing v9fs session information * @fc: the filesystem context
* @opts: The mount option string * @param: the parameter to parse
* *
* Return 0 upon success, -ERRNO upon failure. * Return 0 upon success, -ERRNO upon failure.
*/ */
int v9fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
{ {
char *options, *tmp_options; struct v9fs_context *ctx = fc->fs_private;
substring_t args[MAX_OPT_ARGS]; struct fs_parse_result result;
char *p;
int option = 0;
char *s; char *s;
int ret = 0; int r;
int opt;
struct p9_client_opts *clnt = &ctx->client_opts;
struct p9_fd_opts *fd_opts = &ctx->fd_opts;
struct p9_rdma_opts *rdma_opts = &ctx->rdma_opts;
struct p9_session_opts *session_opts = &ctx->session_opts;
/* setup defaults */ opt = fs_parse(fc, v9fs_param_spec, param, &result);
v9ses->afid = ~0; if (opt < 0) {
v9ses->debug = 0; /*
v9ses->cache = CACHE_NONE; * We might like to report bad mount options here, but
#ifdef CONFIG_9P_FSCACHE * traditionally 9p has ignored unknown mount options
v9ses->cachetag = NULL; */
#endif if (opt == -ENOPARAM)
v9ses->session_lock_timeout = P9_LOCK_TIMEOUT;
if (!opts)
return 0; return 0;
tmp_options = kstrdup(opts, GFP_KERNEL); return opt;
if (!tmp_options) {
ret = -ENOMEM;
goto fail_option_alloc;
} }
options = tmp_options;
while ((p = strsep(&options, ",")) != NULL) { switch (opt) {
int token, r; case Opt_source:
if (fc->source) {
if (!*p) pr_info("p9: multiple sources not supported\n");
continue; return -EINVAL;
}
token = match_token(p, tokens, args); fc->source = param->string;
switch (token) { param->string = NULL;
break;
case Opt_debug: case Opt_debug:
r = match_int(&args[0], &option); session_opts->debug = result.uint_32;
if (r < 0) {
p9_debug(P9_DEBUG_ERROR,
"integer field, but no integer?\n");
ret = r;
} else {
v9ses->debug = option;
#ifdef CONFIG_NET_9P_DEBUG #ifdef CONFIG_NET_9P_DEBUG
p9_debug_level = option; p9_debug_level = result.uint_32;
#endif #endif
}
break; break;
case Opt_dfltuid: case Opt_dfltuid:
r = match_int(&args[0], &option); session_opts->dfltuid = result.uid;
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; break;
case Opt_dfltgid: case Opt_dfltgid:
r = match_int(&args[0], &option); session_opts->dfltgid = result.gid;
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; break;
case Opt_afid: case Opt_afid:
r = match_int(&args[0], &option); session_opts->afid = result.uint_32;
if (r < 0) {
p9_debug(P9_DEBUG_ERROR,
"integer field, but no integer?\n");
ret = r;
} else {
v9ses->afid = option;
}
break; break;
case Opt_uname: case Opt_uname:
kfree(v9ses->uname); kfree(session_opts->uname);
v9ses->uname = match_strdup(&args[0]); session_opts->uname = param->string;
if (!v9ses->uname) { param->string = NULL;
ret = -ENOMEM;
goto free_and_return;
}
break; break;
case Opt_remotename: case Opt_remotename:
kfree(v9ses->aname); kfree(session_opts->aname);
v9ses->aname = match_strdup(&args[0]); session_opts->aname = param->string;
if (!v9ses->aname) { param->string = NULL;
ret = -ENOMEM;
goto free_and_return;
}
break; break;
case Opt_nodevmap: case Opt_nodevmap:
v9ses->nodev = 1; session_opts->nodev = 1;
break; break;
case Opt_noxattr: case Opt_noxattr:
v9ses->flags |= V9FS_NO_XATTR; session_opts->flags |= V9FS_NO_XATTR;
break; break;
case Opt_directio: case Opt_directio:
v9ses->flags |= V9FS_DIRECT_IO; session_opts->flags |= V9FS_DIRECT_IO;
break; break;
case Opt_ignoreqv: case Opt_ignoreqv:
v9ses->flags |= V9FS_IGNORE_QV; session_opts->flags |= V9FS_IGNORE_QV;
break; break;
case Opt_cachetag: case Opt_cachetag:
#ifdef CONFIG_9P_FSCACHE #ifdef CONFIG_9P_FSCACHE
kfree(v9ses->cachetag); kfree(session_opts->cachetag);
v9ses->cachetag = match_strdup(&args[0]); session_opts->cachetag = param->string;
if (!v9ses->cachetag) { param->string = NULL;
ret = -ENOMEM;
goto free_and_return;
}
#endif #endif
break; break;
case Opt_cache: case Opt_cache:
s = match_strdup(&args[0]); r = get_cache_mode(param->string);
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) if (r < 0)
ret = r; return r;
else session_opts->cache = r;
v9ses->cache = r;
kfree(s);
break; break;
case Opt_access: case Opt_access:
s = match_strdup(&args[0]); s = param->string;
if (!s) { session_opts->flags &= ~V9FS_ACCESS_MASK;
ret = -ENOMEM; if (strcmp(s, "user") == 0) {
p9_debug(P9_DEBUG_ERROR, session_opts->flags |= V9FS_ACCESS_USER;
"problem allocating copy of access arg\n"); } else if (strcmp(s, "any") == 0) {
goto free_and_return; session_opts->flags |= V9FS_ACCESS_ANY;
} } else if (strcmp(s, "client") == 0) {
session_opts->flags |= V9FS_ACCESS_CLIENT;
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 { } else {
uid_t uid; uid_t uid;
v9ses->flags |= V9FS_ACCESS_SINGLE; session_opts->flags |= V9FS_ACCESS_SINGLE;
r = kstrtouint(s, 10, &uid); r = kstrtouint(s, 10, &uid);
if (r) { if (r) {
ret = r;
pr_info("Unknown access argument %s: %d\n", pr_info("Unknown access argument %s: %d\n",
s, r); param->string, r);
kfree(s); return r;
continue;
} }
v9ses->uid = make_kuid(current_user_ns(), uid); session_opts->uid = make_kuid(current_user_ns(), uid);
if (!uid_valid(v9ses->uid)) { if (!uid_valid(session_opts->uid)) {
ret = -EINVAL;
pr_info("Unknown uid %s\n", s); pr_info("Unknown uid %s\n", s);
return -EINVAL;
} }
} }
kfree(s);
break; break;
case Opt_posixacl: case Opt_posixacl:
#ifdef CONFIG_9P_FS_POSIX_ACL #ifdef CONFIG_9P_FS_POSIX_ACL
v9ses->flags |= V9FS_POSIX_ACL; session_opts->flags |= V9FS_POSIX_ACL;
#else #else
p9_debug(P9_DEBUG_ERROR, p9_debug(P9_DEBUG_ERROR,
"Not defined CONFIG_9P_FS_POSIX_ACL. Ignoring posixacl option\n"); "Not defined CONFIG_9P_FS_POSIX_ACL. Ignoring posixacl option\n");
@ -353,67 +329,127 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
break; break;
case Opt_locktimeout: case Opt_locktimeout:
r = match_int(&args[0], &option); if (result.uint_32 < 1) {
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, p9_debug(P9_DEBUG_ERROR,
"locktimeout must be a greater than zero integer.\n"); "locktimeout must be a greater than zero integer.\n");
ret = -EINVAL; return -EINVAL;
continue;
} }
v9ses->session_lock_timeout = (long)option * HZ; session_opts->session_lock_timeout = (long)result.uint_32 * HZ;
break; break;
default: /* Options for client */
continue; case Opt_msize:
if (result.uint_32 < 4096) {
p9_debug(P9_DEBUG_ERROR, "msize should be at least 4k\n");
return -EINVAL;
} }
if (result.uint_32 > INT_MAX) {
p9_debug(P9_DEBUG_ERROR, "msize too big\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: return 0;
kfree(tmp_options); }
fail_option_alloc:
return ret; static void v9fs_apply_options(struct v9fs_session_info *v9ses,
struct fs_context *fc)
{
struct v9fs_context *ctx = fc->fs_private;
v9ses->debug = ctx->session_opts.debug;
v9ses->dfltuid = ctx->session_opts.dfltuid;
v9ses->dfltgid = ctx->session_opts.dfltgid;
v9ses->afid = ctx->session_opts.afid;
v9ses->uname = ctx->session_opts.uname;
ctx->session_opts.uname = NULL;
v9ses->aname = ctx->session_opts.aname;
ctx->session_opts.aname = NULL;
v9ses->nodev = ctx->session_opts.nodev;
/*
* Note that we must |= flags here as session_init already
* set basic flags. This adds in flags from parsed options.
*/
v9ses->flags |= ctx->session_opts.flags;
#ifdef CONFIG_9P_FSCACHE
v9ses->cachetag = ctx->session_opts.cachetag;
ctx->session_opts.cachetag = NULL;
#endif
v9ses->cache = ctx->session_opts.cache;
v9ses->uid = ctx->session_opts.uid;
v9ses->session_lock_timeout = ctx->session_opts.session_lock_timeout;
} }
/** /**
* v9fs_session_init - initialize session * v9fs_session_init - initialize session
* @v9ses: session information structure * @v9ses: session information structure
* @dev_name: device being mounted * @fc: the filesystem mount context
* @data: options
* *
*/ */
struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, 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; struct p9_fid *fid;
int rc = -ENOMEM; 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); init_rwsem(&v9ses->rename_sem);
v9ses->uid = INVALID_UID; v9ses->clnt = p9_client_create(fc);
v9ses->dfltuid = V9FS_DEFUID;
v9ses->dfltgid = V9FS_DEFGID;
v9ses->clnt = p9_client_create(dev_name, data);
if (IS_ERR(v9ses->clnt)) { if (IS_ERR(v9ses->clnt)) {
rc = PTR_ERR(v9ses->clnt); rc = PTR_ERR(v9ses->clnt);
p9_debug(P9_DEBUG_ERROR, "problem initializing 9p client\n"); p9_debug(P9_DEBUG_ERROR, "problem initializing 9p client\n");
goto err_names; 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; v9ses->flags = V9FS_ACCESS_USER;
if (p9_is_proto_dotl(v9ses->clnt)) { if (p9_is_proto_dotl(v9ses->clnt)) {
@ -423,9 +459,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
v9ses->flags |= V9FS_PROTO_2000U; v9ses->flags |= V9FS_PROTO_2000U;
} }
rc = v9fs_parse_options(v9ses, data); v9fs_apply_options(v9ses, fc);
if (rc < 0)
goto err_clnt;
v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
@ -471,7 +505,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
#ifdef CONFIG_9P_FSCACHE #ifdef CONFIG_9P_FSCACHE
/* register the session for caching */ /* register the session for caching */
if (v9ses->cache & CACHE_FSCACHE) { 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) if (rc < 0)
goto err_clnt; goto err_clnt;
} }

View File

@ -10,6 +10,9 @@
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/netfs.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 * enum p9_session_flags - option flags for each 9P session
@ -163,11 +166,13 @@ static inline struct fscache_volume *v9fs_session_cache(struct v9fs_session_info
#endif #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); extern int v9fs_show_options(struct seq_file *m, struct dentry *root);
struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, 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_close(struct v9fs_session_info *v9ses);
extern void v9fs_session_cancel(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); extern void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses);

View File

@ -109,7 +109,6 @@ static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
p9_debug(P9_DEBUG_VFS, p9_debug(P9_DEBUG_VFS,
"refresh inode: dentry = %pd (%p), got error %pe\n", "refresh inode: dentry = %pd (%p), got error %pe\n",
dentry, dentry, ERR_PTR(retval)); dentry, dentry, ERR_PTR(retval));
if (retval < 0)
return retval; return retval;
} }
} }

View File

@ -43,14 +43,18 @@ int v9fs_file_open(struct inode *inode, struct file *file)
struct v9fs_session_info *v9ses; struct v9fs_session_info *v9ses;
struct p9_fid *fid; struct p9_fid *fid;
int omode; int omode;
int o_append;
p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file); p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
v9ses = v9fs_inode2v9ses(inode); v9ses = v9fs_inode2v9ses(inode);
if (v9fs_proto_dotl(v9ses)) if (v9fs_proto_dotl(v9ses)) {
omode = v9fs_open_to_dotl_flags(file->f_flags); omode = v9fs_open_to_dotl_flags(file->f_flags);
else o_append = P9_DOTL_APPEND;
} else {
omode = v9fs_uflags2omode(file->f_flags, omode = v9fs_uflags2omode(file->f_flags,
v9fs_proto_dotu(v9ses)); v9fs_proto_dotu(v9ses));
o_append = P9_OAPPEND;
}
fid = file->private_data; fid = file->private_data;
if (!fid) { if (!fid) {
fid = v9fs_fid_clone(file_dentry(file)); fid = v9fs_fid_clone(file_dentry(file));
@ -58,9 +62,10 @@ int v9fs_file_open(struct inode *inode, struct file *file)
return PTR_ERR(fid); return PTR_ERR(fid);
if ((v9ses->cache & CACHE_WRITEBACK) && (omode & P9_OWRITE)) { if ((v9ses->cache & CACHE_WRITEBACK) && (omode & P9_OWRITE)) {
int writeback_omode = (omode & ~P9_OWRITE) | P9_ORDWR; int writeback_omode = (omode & ~(P9_OWRITE | o_append)) | P9_ORDWR;
p9_debug(P9_DEBUG_CACHE, "write-only file with writeback enabled, try opening O_RDWR\n"); p9_debug(P9_DEBUG_CACHE, "write-only file with writeback enabled, try opening O_RDWR\n");
err = p9_client_open(fid, writeback_omode); err = p9_client_open(fid, writeback_omode);
if (err < 0) { if (err < 0) {
p9_debug(P9_DEBUG_CACHE, "could not open O_RDWR, disabling caches\n"); p9_debug(P9_DEBUG_CACHE, "could not open O_RDWR, disabling caches\n");

View File

@ -786,7 +786,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
p9_omode = v9fs_uflags2omode(flags, v9fs_proto_dotu(v9ses)); p9_omode = v9fs_uflags2omode(flags, v9fs_proto_dotu(v9ses));
if ((v9ses->cache & CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) { if ((v9ses->cache & CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) {
p9_omode = (p9_omode & ~P9_OWRITE) | P9_ORDWR; p9_omode = (p9_omode & ~(P9_OWRITE | P9_OAPPEND)) | P9_ORDWR;
p9_debug(P9_DEBUG_CACHE, p9_debug(P9_DEBUG_CACHE,
"write-only file with writeback enabled, creating w/ O_RDWR\n"); "write-only file with writeback enabled, creating w/ O_RDWR\n");
} }
@ -1393,4 +1393,3 @@ static const struct inode_operations v9fs_symlink_inode_operations = {
.getattr = v9fs_vfs_getattr, .getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr, .setattr = v9fs_vfs_setattr,
}; };

View File

@ -282,7 +282,7 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
} }
if ((v9ses->cache & CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) { if ((v9ses->cache & CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) {
p9_omode = (p9_omode & ~P9_OWRITE) | P9_ORDWR; p9_omode = (p9_omode & ~(P9_OWRITE | P9_DOTL_APPEND)) | P9_ORDWR;
p9_debug(P9_DEBUG_CACHE, p9_debug(P9_DEBUG_CACHE,
"write-only file with writeback enabled, creating w/ O_RDWR\n"); "write-only file with writeback enabled, creating w/ O_RDWR\n");
} }

View File

@ -19,6 +19,7 @@
#include <linux/statfs.h> #include <linux/statfs.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/fscache.h> #include <linux/fscache.h>
#include <linux/fs_context.h>
#include <net/9p/9p.h> #include <net/9p/9p.h>
#include <net/9p/client.h> #include <net/9p/client.h>
@ -30,32 +31,10 @@
static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl; static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
/** static int v9fs_fill_super(struct super_block *sb)
* v9fs_set_super - set the superblock
* @s: super block
* @data: file system specific data
*
*/
static int v9fs_set_super(struct super_block *s, void *data)
{
s->s_fs_info = data;
return set_anon_super(s, data);
}
/**
* v9fs_fill_super - populate superblock with info
* @sb: superblock
* @v9ses: session information
* @flags: flags propagated from v9fs_mount()
*
*/
static int
v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
int flags)
{ {
int ret; int ret;
struct v9fs_session_info *v9ses = v9ses = sb->s_fs_info;
sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_maxbytes = MAX_LFS_FILESIZE;
sb->s_blocksize_bits = fls(v9ses->maxdata - 1); sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
@ -95,16 +74,12 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
} }
/** /**
* v9fs_mount - mount a superblock * v9fs_get_tree - create the mountable root and superblock
* @fs_type: file system type * @fc: the filesystem context
* @flags: mount flags
* @dev_name: device name that was mounted
* @data: mount options
* *
*/ */
static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, static int v9fs_get_tree(struct fs_context *fc)
const char *dev_name, void *data)
{ {
struct super_block *sb = NULL; struct super_block *sb = NULL;
struct inode *inode = NULL; struct inode *inode = NULL;
@ -117,20 +92,21 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL); v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
if (!v9ses) 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)) { if (IS_ERR(fid)) {
retval = PTR_ERR(fid); retval = PTR_ERR(fid);
goto free_session; goto free_session;
} }
sb = sget(fs_type, NULL, v9fs_set_super, flags, v9ses); fc->s_fs_info = v9ses;
sb = sget_fc(fc, NULL, set_anon_super_fc);
if (IS_ERR(sb)) { if (IS_ERR(sb)) {
retval = PTR_ERR(sb); retval = PTR_ERR(sb);
goto clunk_fid; goto clunk_fid;
} }
retval = v9fs_fill_super(sb, v9ses, flags); retval = v9fs_fill_super(sb);
if (retval) if (retval)
goto release_sb; goto release_sb;
@ -159,14 +135,15 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags,
v9fs_fid_add(root, &fid); v9fs_fid_add(root, &fid);
p9_debug(P9_DEBUG_VFS, " simple set mount, return 0\n"); 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: clunk_fid:
p9_fid_put(fid); p9_fid_put(fid);
v9fs_session_close(v9ses); v9fs_session_close(v9ses);
free_session: free_session:
kfree(v9ses); kfree(v9ses);
return ERR_PTR(retval); return retval;
release_sb: release_sb:
/* /*
@ -177,7 +154,7 @@ release_sb:
*/ */
p9_fid_put(fid); p9_fid_put(fid);
deactivate_locked_super(sb); deactivate_locked_super(sb);
return ERR_PTR(retval); return retval;
} }
/** /**
@ -303,11 +280,86 @@ static const struct super_operations v9fs_super_ops_dotl = {
.write_inode = v9fs_write_inode_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->session_opts.uname);
kfree(ctx->session_opts.aname);
#ifdef CONFIG_9P_FSCACHE
kfree(ctx->session_opts.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->session_opts.afid = ~0;
ctx->session_opts.cache = CACHE_NONE;
ctx->session_opts.session_lock_timeout = P9_LOCK_TIMEOUT;
ctx->session_opts.uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL);
if (!ctx->session_opts.uname)
goto error;
ctx->session_opts.aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL);
if (!ctx->session_opts.aname)
goto error;
ctx->session_opts.uid = INVALID_UID;
ctx->session_opts.dfltuid = V9FS_DEFUID;
ctx->session_opts.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 = { struct file_system_type v9fs_fs_type = {
.name = "9p", .name = "9p",
.mount = v9fs_mount,
.kill_sb = v9fs_kill_super, .kill_sb = v9fs_kill_super,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.fs_flags = FS_RENAME_DOES_D_MOVE, .fs_flags = FS_RENAME_DOES_D_MOVE,
.init_fs_context = v9fs_init_fs_context,
.parameters = v9fs_param_spec,
}; };
MODULE_ALIAS_FS("9p"); MODULE_ALIAS_FS("9p");

View File

@ -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_u32(NAME, OPT) __fsparam(fs_param_is_u32, NAME, OPT, 0, NULL)
#define fsparam_u32oct(NAME, OPT) \ #define fsparam_u32oct(NAME, OPT) \
__fsparam(fs_param_is_u32, NAME, OPT, 0, (void *)8) __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_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_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) #define fsparam_enum(NAME, OPT, array) __fsparam(fs_param_is_enum, NAME, OPT, 0, array)

View File

@ -16,6 +16,12 @@
/* Number of requests per row */ /* Number of requests per row */
#define P9_ROW_MAXTAG 255 #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 /** enum p9_proto_versions - 9P protocol versions
* @p9_proto_legacy: 9P Legacy mode, pre-9P2000.u * @p9_proto_legacy: 9P Legacy mode, pre-9P2000.u
* @p9_proto_2000u: 9P2000.u extension * @p9_proto_2000u: 9P2000.u extension
@ -126,6 +132,96 @@ struct p9_client {
char name[__NEW_UTS_LEN + 1]; char name[__NEW_UTS_LEN + 1];
}; };
/**
* struct p9_fd_opts - holds client options during parsing
* @msize: maximum data size negotiated by protocol
* @prot-Oversion: 9P protocol version to use
* @trans_mod: module API instantiated with this client
*
* These parsed options get transferred into client in
* apply_client_options()
*/
struct p9_client_opts {
unsigned int msize;
unsigned char proto_version;
struct p9_trans_module *trans_mod;
};
/**
* 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_session_opts - holds parsed options for v9fs_session_info
* @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
* @uname: string user name to mount hierarchy as
* @aname: mount specifier for remote hierarchy
* @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
* @session_lock_timeout: retry interval for blocking locks
*
* This strucure holds options which are parsed and will be transferred
* to the v9fs_session_info structure when mounted, and therefore largely
* duplicates struct v9fs_session_info.
*/
struct p9_session_opts {
unsigned int flags;
unsigned char nodev;
unsigned short debug;
unsigned int afid;
unsigned int cache;
#ifdef CONFIG_9P_FSCACHE
char *cachetag;
#endif
char *uname;
char *aname;
kuid_t dfltuid;
kgid_t dfltgid;
kuid_t uid;
long session_lock_timeout;
};
/* Used by mount API to store parsed mount options */
struct v9fs_context {
struct p9_client_opts client_opts;
struct p9_fd_opts fd_opts;
struct p9_rdma_opts rdma_opts;
struct p9_session_opts session_opts;
};
/** /**
* struct p9_fid - file system entity handle * struct p9_fid - file system entity handle
* @clnt: back pointer to instantiating &p9_client * @clnt: back pointer to instantiating &p9_client
@ -183,7 +279,7 @@ int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid,
const char *name); const char *name);
int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name, int p9_client_renameat(struct p9_fid *olddirfid, const char *old_name,
struct p9_fid *newdirfid, const char *new_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_destroy(struct p9_client *clnt);
void p9_client_disconnect(struct p9_client *clnt); void p9_client_disconnect(struct p9_client *clnt);
void p9_client_begin_disconnect(struct p9_client *clnt); void p9_client_begin_disconnect(struct p9_client *clnt);

View File

@ -14,6 +14,13 @@
#define P9_DEF_MIN_RESVPORT (665U) #define P9_DEF_MIN_RESVPORT (665U)
#define P9_DEF_MAX_RESVPORT (1023U) #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_trans_module - transport module interface * struct p9_trans_module - transport module interface
* @list: used to maintain a list of currently available transports * @list: used to maintain a list of currently available transports
@ -24,6 +31,9 @@
* we're less flexible when choosing the response message * we're less flexible when choosing the response message
* size in this case * size in this case
* @def: set if this transport should be considered the default * @def: set if this transport should be considered the default
* @supports_vmalloc: set if this transport can work with vmalloc'd buffers
* (non-physically contiguous memory). Transports requiring
* DMA should leave this as false.
* @create: member function to create a new connection on this transport * @create: member function to create a new connection on this transport
* @close: member function to discard a connection on this transport * @close: member function to discard a connection on this transport
* @request: member function to issue a request to the transport * @request: member function to issue a request to the transport
@ -43,10 +53,11 @@ struct p9_trans_module {
char *name; /* name of transport */ char *name; /* name of transport */
int maxsize; /* max message size of transport */ int maxsize; /* max message size of transport */
bool pooled_rbuffers; bool pooled_rbuffers;
int def; /* this transport should be default */ bool def; /* this transport should be default */
bool supports_vmalloc; /* can work with vmalloc'd buffers */
struct module *owner; struct module *owner;
int (*create)(struct p9_client *client, int (*create)(struct p9_client *client,
const char *devname, char *args); struct fs_context *fc);
void (*close)(struct p9_client *client); void (*close)(struct p9_client *client);
int (*request)(struct p9_client *client, struct p9_req_t *req); int (*request)(struct p9_client *client, struct p9_req_t *req);
int (*cancel)(struct p9_client *client, struct p9_req_t *req); int (*cancel)(struct p9_client *client, struct p9_req_t *req);

View File

@ -20,8 +20,8 @@
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/netfs.h> #include <linux/netfs.h>
#include <net/9p/9p.h> #include <net/9p/9p.h>
#include <linux/parser.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/fs_context.h>
#include <net/9p/client.h> #include <net/9p/client.h>
#include <net/9p/transport.h> #include <net/9p/transport.h>
#include "protocol.h" #include "protocol.h"
@ -29,32 +29,10 @@
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/9p.h> #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) /* Client Option Parsing (code inspired by NFS code)
* - a little lazy - parse all client options * - 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) inline int p9_is_proto_dotl(struct p9_client *clnt)
{ {
return clnt->proto_version == p9_proto_2000L; return clnt->proto_version == p9_proto_2000L;
@ -103,124 +81,16 @@ static int safe_errno(int err)
return err; return err;
} }
/* Interpret mount option for protocol version */ static int apply_client_options(struct p9_client *clnt, struct fs_context *fc)
static int get_protocol_version(char *s)
{ {
int version = -EINVAL; struct v9fs_context *ctx = fc->fs_private;
if (!strcmp(s, "9p2000")) { clnt->msize = ctx->client_opts.msize;
version = p9_proto_legacy; clnt->trans_mod = ctx->client_opts.trans_mod;
p9_debug(P9_DEBUG_9P, "Protocol version: Legacy\n"); ctx->client_opts.trans_mod = NULL;
} else if (!strcmp(s, "9p2000.u")) { clnt->proto_version = ctx->client_opts.proto_version;
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);
}
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; return 0;
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;
} }
static int p9_fcall_init(struct p9_client *c, struct p9_fcall *fc, static int p9_fcall_init(struct p9_client *c, struct p9_fcall *fc,
@ -229,7 +99,14 @@ static int p9_fcall_init(struct p9_client *c, struct p9_fcall *fc,
if (likely(c->fcall_cache) && alloc_msize == c->msize) { if (likely(c->fcall_cache) && alloc_msize == c->msize) {
fc->sdata = kmem_cache_alloc(c->fcall_cache, GFP_NOFS); fc->sdata = kmem_cache_alloc(c->fcall_cache, GFP_NOFS);
fc->cache = c->fcall_cache; fc->cache = c->fcall_cache;
if (!fc->sdata && c->trans_mod->supports_vmalloc) {
fc->sdata = kvmalloc(alloc_msize, GFP_NOFS);
fc->cache = NULL;
}
} else { } else {
if (c->trans_mod->supports_vmalloc)
fc->sdata = kvmalloc(alloc_msize, GFP_NOFS);
else
fc->sdata = kmalloc(alloc_msize, GFP_NOFS); fc->sdata = kmalloc(alloc_msize, GFP_NOFS);
fc->cache = NULL; fc->cache = NULL;
} }
@ -252,7 +129,7 @@ void p9_fcall_fini(struct p9_fcall *fc)
if (fc->cache) if (fc->cache)
kmem_cache_free(fc->cache, fc->sdata); kmem_cache_free(fc->cache, fc->sdata);
else else
kfree(fc->sdata); kvfree(fc->sdata);
} }
EXPORT_SYMBOL(p9_fcall_fini); EXPORT_SYMBOL(p9_fcall_fini);
@ -974,7 +851,7 @@ error:
return err; 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; int err;
static atomic_t seqno = ATOMIC_INIT(0); static atomic_t seqno = ATOMIC_INIT(0);
@ -997,8 +874,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
idr_init(&clnt->fids); idr_init(&clnt->fids);
idr_init(&clnt->reqs); idr_init(&clnt->reqs);
err = parse_opts(options, clnt); err = apply_client_options(clnt, fc);
if (err < 0) if (err)
goto free_client; goto free_client;
if (!clnt->trans_mod) if (!clnt->trans_mod)
@ -1014,7 +891,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", p9_debug(P9_DEBUG_MUX, "clnt %p trans %p msize %d protocol %d\n",
clnt, clnt->trans_mod, clnt->msize, clnt->proto_version); 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) if (err)
goto put_trans; goto put_trans;

View File

@ -16,7 +16,6 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <net/9p/9p.h> #include <net/9p/9p.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/parser.h>
#include <net/9p/client.h> #include <net/9p/client.h>
#include <net/9p/transport.h> #include <net/9p/transport.h>
#include <linux/list.h> #include <linux/list.h>
@ -171,6 +170,7 @@ void v9fs_put_trans(struct p9_trans_module *m)
if (m) if (m)
module_put(m->owner); module_put(m->owner);
} }
EXPORT_SYMBOL(v9fs_put_trans);
/** /**
* init_p9 - Initialize module * init_p9 - Initialize module

View File

@ -22,7 +22,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/parser.h> #include <linux/fs_context.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <net/9p/9p.h> #include <net/9p/9p.h>
@ -31,48 +31,12 @@
#include <linux/syscalls.h> /* killme */ #include <linux/syscalls.h> /* killme */
#define P9_PORT 564
#define MAX_SOCK_BUF (1024*1024) #define MAX_SOCK_BUF (1024*1024)
#define MAXPOLLWADDR 2 #define MAXPOLLWADDR 2
static struct p9_trans_module p9_tcp_trans; static struct p9_trans_module p9_tcp_trans;
static struct p9_trans_module p9_fd_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
*/
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 { enum {
Rworksched = 1, /* read work scheduled or running */ Rworksched = 1, /* read work scheduled or running */
Rpending = 2, /* can read */ Rpending = 2, /* can read */
@ -742,7 +706,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) static int p9_fd_show_options(struct seq_file *m, struct p9_client *clnt)
{ {
if (clnt->trans_mod == &p9_tcp_trans) { 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); seq_printf(m, ",port=%u", clnt->trans_opts.tcp.port);
} else if (clnt->trans_mod == &p9_fd_trans) { } else if (clnt->trans_mod == &p9_fd_trans) {
if (clnt->trans_opts.fd.rfd != ~0) if (clnt->trans_opts.fd.rfd != ~0)
@ -753,73 +717,6 @@ static int p9_fd_show_options(struct seq_file *m, struct p9_client *clnt)
return 0; 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_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) static int p9_fd_open(struct p9_client *client, int rfd, int wfd)
{ {
struct p9_trans_fd *ts = kzalloc(sizeof(struct p9_trans_fd), struct p9_trans_fd *ts = kzalloc(sizeof(struct p9_trans_fd),
@ -974,17 +871,18 @@ static int p9_bind_privport(struct socket *sock)
} }
static int 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; int err;
char port_str[6]; char port_str[6];
struct socket *csocket; struct socket *csocket;
struct sockaddr_storage stor = { 0 }; struct sockaddr_storage stor = { 0 };
struct p9_fd_opts opts; struct p9_fd_opts opts;
err = parse_opts(args, &opts); /* opts are already parsed in context */
if (err < 0) opts = ctx->fd_opts;
return err;
if (!addr) if (!addr)
return -EINVAL; return -EINVAL;
@ -1031,8 +929,9 @@ p9_fd_create_tcp(struct p9_client *client, const char *addr, char *args)
} }
static int 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; int err;
struct socket *csocket; struct socket *csocket;
struct sockaddr_un sun_server; struct sockaddr_un sun_server;
@ -1071,14 +970,12 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
} }
static int 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; 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.rfd = opts.rfd;
client->trans_opts.fd.wfd = opts.wfd; client->trans_opts.fd.wfd = opts.wfd;
@ -1100,7 +997,8 @@ static struct p9_trans_module p9_tcp_trans = {
.name = "tcp", .name = "tcp",
.maxsize = MAX_SOCK_BUF, .maxsize = MAX_SOCK_BUF,
.pooled_rbuffers = false, .pooled_rbuffers = false,
.def = 0, .def = false,
.supports_vmalloc = true,
.create = p9_fd_create_tcp, .create = p9_fd_create_tcp,
.close = p9_fd_close, .close = p9_fd_close,
.request = p9_fd_request, .request = p9_fd_request,
@ -1114,7 +1012,8 @@ MODULE_ALIAS_9P("tcp");
static struct p9_trans_module p9_unix_trans = { static struct p9_trans_module p9_unix_trans = {
.name = "unix", .name = "unix",
.maxsize = MAX_SOCK_BUF, .maxsize = MAX_SOCK_BUF,
.def = 0, .def = false,
.supports_vmalloc = true,
.create = p9_fd_create_unix, .create = p9_fd_create_unix,
.close = p9_fd_close, .close = p9_fd_close,
.request = p9_fd_request, .request = p9_fd_request,
@ -1128,7 +1027,8 @@ MODULE_ALIAS_9P("unix");
static struct p9_trans_module p9_fd_trans = { static struct p9_trans_module p9_fd_trans = {
.name = "fd", .name = "fd",
.maxsize = MAX_SOCK_BUF, .maxsize = MAX_SOCK_BUF,
.def = 0, .def = false,
.supports_vmalloc = true,
.create = p9_fd_create, .create = p9_fd_create,
.close = p9_fd_close, .close = p9_fd_close,
.request = p9_fd_request, .request = p9_fd_request,

View File

@ -22,7 +22,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/parser.h> #include <linux/fs_context.h>
#include <linux/semaphore.h> #include <linux/semaphore.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
@ -32,14 +32,10 @@
#include <rdma/ib_verbs.h> #include <rdma/ib_verbs.h>
#include <rdma/rdma_cm.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_SEND_SGE 4
#define P9_RDMA_RECV_SGE 4 #define P9_RDMA_RECV_SGE 4
#define P9_RDMA_IRD 0 #define P9_RDMA_IRD 0
#define P9_RDMA_ORD 0 #define P9_RDMA_ORD 0
#define P9_RDMA_TIMEOUT 30000 /* 30 seconds */
#define P9_RDMA_MAXSIZE (1024*1024) /* 1MB */ #define P9_RDMA_MAXSIZE (1024*1024) /* 1MB */
/** /**
@ -110,48 +106,11 @@ 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)
*/
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) static int p9_rdma_show_options(struct seq_file *m, struct p9_client *clnt)
{ {
struct p9_trans_rdma *rdma = clnt->trans; 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); seq_printf(m, ",port=%u", rdma->port);
if (rdma->sq_depth != P9_RDMA_SQ_DEPTH) if (rdma->sq_depth != P9_RDMA_SQ_DEPTH)
seq_printf(m, ",sq=%u", rdma->sq_depth); seq_printf(m, ",sq=%u", rdma->sq_depth);
@ -164,77 +123,6 @@ static int p9_rdma_show_options(struct seq_file *m, struct p9_client *clnt)
return 0; 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_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 static int
p9_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) p9_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event)
{ {
@ -628,14 +516,15 @@ static int p9_rdma_bind_privport(struct p9_trans_rdma *rdma)
/** /**
* rdma_create_trans - Transport method for creating a transport instance * rdma_create_trans - Transport method for creating a transport instance
* @client: client instance * @client: client instance
* @addr: IP address string * @fc: The filesystem context
* @args: Mount options string
*/ */
static int 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; int err;
struct p9_rdma_opts opts;
struct p9_trans_rdma *rdma; struct p9_trans_rdma *rdma;
struct rdma_conn_param conn_param; struct rdma_conn_param conn_param;
struct ib_qp_init_attr qp_attr; struct ib_qp_init_attr qp_attr;
@ -643,10 +532,8 @@ rdma_create_trans(struct p9_client *client, const char *addr, char *args)
if (addr == NULL) if (addr == NULL)
return -EINVAL; return -EINVAL;
/* Parse the transport specific mount options */ /* options are already parsed, in the fs context */
err = parse_opts(args, &opts); opts = ctx->rdma_opts;
if (err < 0)
return err;
/* Create and initialize the RDMA transport structure */ /* Create and initialize the RDMA transport structure */
rdma = alloc_rdma(&opts); rdma = alloc_rdma(&opts);
@ -748,7 +635,8 @@ static struct p9_trans_module p9_rdma_trans = {
.name = "rdma", .name = "rdma",
.maxsize = P9_RDMA_MAXSIZE, .maxsize = P9_RDMA_MAXSIZE,
.pooled_rbuffers = true, .pooled_rbuffers = true,
.def = 0, .def = false,
.supports_vmalloc = false,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.create = rdma_create_trans, .create = rdma_create_trans,
.close = rdma_close, .close = rdma_close,

View File

@ -27,6 +27,7 @@
#include <linux/cleanup.h> #include <linux/cleanup.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/fs_context.h>
#include <linux/usb/composite.h> #include <linux/usb/composite.h>
#include <linux/usb/func_utils.h> #include <linux/usb/func_utils.h>
@ -376,8 +377,9 @@ out:
return ret; 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_dev *dev;
struct f_usb9pfs *usb9pfs; struct f_usb9pfs *usb9pfs;
int ret = -ENOENT; int ret = -ENOENT;
@ -514,6 +516,7 @@ static struct p9_trans_module p9_usbg_trans = {
.close = p9_usbg_close, .close = p9_usbg_close,
.request = p9_usbg_request, .request = p9_usbg_request,
.cancel = p9_usbg_cancel, .cancel = p9_usbg_cancel,
.supports_vmalloc = false,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };

View File

@ -26,7 +26,7 @@
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <net/9p/9p.h> #include <net/9p/9p.h>
#include <linux/parser.h> #include <linux/fs_context.h>
#include <net/9p/client.h> #include <net/9p/client.h>
#include <net/9p/transport.h> #include <net/9p/transport.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
@ -679,8 +679,7 @@ fail:
/** /**
* p9_virtio_create - allocate a new virtio channel * p9_virtio_create - allocate a new virtio channel
* @client: client instance invoking this transport * @client: client instance invoking this transport
* @devname: string identifying the channel to connect to (unused) * @fc: the filesystem context
* @args: args passed from sys_mount() for per-transport options (unused)
* *
* This sets up a transport channel for 9p communication. Right now * This sets up a transport channel for 9p communication. Right now
* we only match the first available channel, but eventually we could look up * we only match the first available channel, but eventually we could look up
@ -691,8 +690,9 @@ fail:
*/ */
static int 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; struct virtio_chan *chan;
int ret = -ENOENT; int ret = -ENOENT;
int found = 0; int found = 0;
@ -802,7 +802,8 @@ static struct p9_trans_module p9_virtio_trans = {
*/ */
.maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3), .maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3),
.pooled_rbuffers = false, .pooled_rbuffers = false,
.def = 1, .def = true,
.supports_vmalloc = false,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };

View File

@ -15,6 +15,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/fs_context.h>
#include <net/9p/9p.h> #include <net/9p/9p.h>
#include <net/9p/client.h> #include <net/9p/client.h>
#include <net/9p/transport.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; 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; struct xen_9pfs_front_priv *priv;
if (addr == NULL) if (addr == NULL)
@ -257,7 +259,8 @@ static struct p9_trans_module p9_xen_trans = {
.name = "xen", .name = "xen",
.maxsize = 1 << (XEN_9PFS_RING_ORDER + XEN_PAGE_SHIFT - 2), .maxsize = 1 << (XEN_9PFS_RING_ORDER + XEN_PAGE_SHIFT - 2),
.pooled_rbuffers = false, .pooled_rbuffers = false,
.def = 1, .def = true,
.supports_vmalloc = false,
.create = p9_xen_create, .create = p9_xen_create,
.close = p9_xen_close, .close = p9_xen_close,
.request = p9_xen_request, .request = p9_xen_request,