diff options
author | Eric Van Hensbergen <ericvh@opteron.(none)> | 2007-10-17 14:31:07 -0500 |
---|---|---|
committer | Eric Van Hensbergen <ericvh@ericvh-desktop.austin.ibm.com> | 2007-10-17 14:31:07 -0500 |
commit | a80d923e1321a7ed69a0918de37e39871bb536a0 (patch) | |
tree | 8294e5f14a0e938ae4675ef912a32fbade0f832b /fs/9p/v9fs.c | |
parent | 0eafaae84e21ac033815cc9f33c3ae889cd7ccfe (diff) | |
download | lwn-a80d923e1321a7ed69a0918de37e39871bb536a0.tar.gz lwn-a80d923e1321a7ed69a0918de37e39871bb536a0.zip |
9p: Make transports dynamic
This patch abstracts out the interfaces to underlying transports so that
new transports can be added as modules. This should also allow kernel
configuration of transports without ifdef-hell.
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
Diffstat (limited to 'fs/9p/v9fs.c')
-rw-r--r-- | fs/9p/v9fs.c | 149 |
1 files changed, 72 insertions, 77 deletions
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 0a7068e30ecb..08d880fb5b6a 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -37,18 +37,58 @@ #include "v9fs_vfs.h" /* + * Dynamic Transport Registration Routines + * + */ + +static LIST_HEAD(v9fs_trans_list); +static struct p9_trans_module *v9fs_default_trans; + +/** + * v9fs_register_trans - register a new transport with 9p + * @m - structure describing the transport module and entry points + * + */ +void v9fs_register_trans(struct p9_trans_module *m) +{ + list_add_tail(&m->list, &v9fs_trans_list); + if (m->def) + v9fs_default_trans = m; +} +EXPORT_SYMBOL(v9fs_register_trans); + +/** + * v9fs_match_trans - match transport versus registered transports + * @arg: string identifying transport + * + */ +static struct p9_trans_module *v9fs_match_trans(const substring_t *name) +{ + struct list_head *p; + struct p9_trans_module *t = NULL; + + list_for_each(p, &v9fs_trans_list) { + t = list_entry(p, struct p9_trans_module, list); + if (strncmp(t->name, name->from, name->to-name->from) == 0) { + P9_DPRINTK(P9_DEBUG_TRANS, "trans=%s\n", t->name); + break; + } + } + return t; +} + +/* * Option Parsing (code inspired by NFS code) - * + * NOTE: each transport will parse its own options */ enum { /* Options that take integer arguments */ - Opt_debug, Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, - Opt_rfdno, Opt_wfdno, + Opt_debug, Opt_msize, Opt_uid, Opt_gid, Opt_afid, /* String options */ - Opt_uname, Opt_remotename, + Opt_uname, Opt_remotename, Opt_trans, /* Options that take no arguments */ - Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, Opt_pci, + Opt_legacy, Opt_nodevmap, /* Cache options */ Opt_cache_loose, /* Error token */ @@ -57,24 +97,13 @@ enum { static match_table_t tokens = { {Opt_debug, "debug=%x"}, - {Opt_port, "port=%u"}, {Opt_msize, "msize=%u"}, {Opt_uid, "uid=%u"}, {Opt_gid, "gid=%u"}, {Opt_afid, "afid=%u"}, - {Opt_rfdno, "rfdno=%u"}, - {Opt_wfdno, "wfdno=%u"}, {Opt_uname, "uname=%s"}, {Opt_remotename, "aname=%s"}, - {Opt_unix, "proto=unix"}, - {Opt_tcp, "proto=tcp"}, - {Opt_fd, "proto=fd"}, -#ifdef CONFIG_PCI_9P - {Opt_pci, "proto=pci"}, -#endif - {Opt_tcp, "tcp"}, - {Opt_unix, "unix"}, - {Opt_fd, "fd"}, + {Opt_trans, "trans=%s"}, {Opt_legacy, "noextend"}, {Opt_nodevmap, "nodevmap"}, {Opt_cache_loose, "cache=loose"}, @@ -82,12 +111,6 @@ static match_table_t tokens = { {Opt_err, NULL} }; -extern struct p9_transport *p9pci_trans_create(void); - -/* - * Parse option string. - */ - /** * v9fs_parse_options - parse mount options into session structure * @options: options string passed from mount @@ -95,23 +118,21 @@ extern struct p9_transport *p9pci_trans_create(void); * */ -static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) +static void v9fs_parse_options(struct v9fs_session_info *v9ses) { - char *p; + char *options = v9ses->options; substring_t args[MAX_OPT_ARGS]; + char *p; int option; int ret; /* setup defaults */ - v9ses->port = V9FS_PORT; - v9ses->maxdata = 9000; - v9ses->proto = PROTO_TCP; + v9ses->maxdata = 8192; v9ses->extended = 1; v9ses->afid = ~0; v9ses->debug = 0; - v9ses->rfdno = ~0; - v9ses->wfdno = ~0; v9ses->cache = 0; + v9ses->trans = v9fs_default_trans; if (!options) return; @@ -135,9 +156,6 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) p9_debug_level = option; #endif break; - case Opt_port: - v9ses->port = option; - break; case Opt_msize: v9ses->maxdata = option; break; @@ -150,23 +168,8 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) case Opt_afid: v9ses->afid = option; break; - case Opt_rfdno: - v9ses->rfdno = option; - break; - case Opt_wfdno: - v9ses->wfdno = option; - break; - case Opt_tcp: - v9ses->proto = PROTO_TCP; - break; - case Opt_unix: - v9ses->proto = PROTO_UNIX; - break; - case Opt_pci: - v9ses->proto = PROTO_PCI; - break; - case Opt_fd: - v9ses->proto = PROTO_FD; + case Opt_trans: + v9ses->trans = v9fs_match_trans(&args[0]); break; case Opt_uname: match_strcpy(v9ses->name, &args[0]); @@ -201,7 +204,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, const char *dev_name, char *data) { int retval = -EINVAL; - struct p9_transport *trans; + struct p9_trans *trans = NULL; struct p9_fid *fid; v9ses->name = __getname(); @@ -217,39 +220,30 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, strcpy(v9ses->name, V9FS_DEFUSER); strcpy(v9ses->remotename, V9FS_DEFANAME); - v9fs_parse_options(data, v9ses); - - switch (v9ses->proto) { - case PROTO_TCP: - trans = p9_trans_create_tcp(dev_name, v9ses->port); - break; - case PROTO_UNIX: - trans = p9_trans_create_unix(dev_name); - *v9ses->remotename = 0; - break; - case PROTO_FD: - trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno); - *v9ses->remotename = 0; - break; -#ifdef CONFIG_PCI_9P - case PROTO_PCI: - trans = p9pci_trans_create(); - *v9ses->remotename = 0; - break; -#endif - default: - printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); - retval = -ENOPROTOOPT; + v9ses->options = kstrdup(data, GFP_KERNEL); + v9fs_parse_options(v9ses); + + if ((v9ses->trans == NULL) && !list_empty(&v9fs_trans_list)) + v9ses->trans = list_first_entry(&v9fs_trans_list, + struct p9_trans_module, list); + + if (v9ses->trans == NULL) { + retval = -EPROTONOSUPPORT; + P9_DPRINTK(P9_DEBUG_ERROR, + "No transport defined or default transport\n"); goto error; - }; + } + trans = v9ses->trans->create(dev_name, v9ses->options); if (IS_ERR(trans)) { retval = PTR_ERR(trans); trans = NULL; goto error; } + if ((v9ses->maxdata+P9_IOHDRSZ) > v9ses->trans->maxsize) + v9ses->maxdata = v9ses->trans->maxsize-P9_IOHDRSZ; - v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ, + v9ses->clnt = p9_client_create(trans, v9ses->maxdata+P9_IOHDRSZ, v9ses->extended); if (IS_ERR(v9ses->clnt)) { @@ -290,6 +284,7 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) __putname(v9ses->name); __putname(v9ses->remotename); + kfree(v9ses->options); } /** @@ -311,7 +306,7 @@ extern int v9fs_error_init(void); static int __init init_v9fs(void) { printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); - + /* TODO: Setup list of registered trasnport modules */ return register_filesystem(&v9fs_fs_type); } |