diff options
author | Eric Van Hensbergen <ericvh@opteron.(none)> | 2007-10-17 15:31:07 -0400 |
---|---|---|
committer | Eric Van Hensbergen <ericvh@ericvh-desktop.austin.ibm.com> | 2007-10-17 15:31:07 -0400 |
commit | a80d923e1321a7ed69a0918de37e39871bb536a0 (patch) | |
tree | 8294e5f14a0e938ae4675ef912a32fbade0f832b | |
parent | 0eafaae84e21ac033815cc9f33c3ae889cd7ccfe (diff) |
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>
-rw-r--r-- | Documentation/filesystems/9p.txt | 8 | ||||
-rw-r--r-- | fs/9p/v9fs.c | 149 | ||||
-rw-r--r-- | fs/9p/v9fs.h | 15 | ||||
-rw-r--r-- | fs/9p/vfs_super.c | 19 | ||||
-rw-r--r-- | include/net/9p/client.h | 4 | ||||
-rw-r--r-- | include/net/9p/conn.h | 4 | ||||
-rw-r--r-- | include/net/9p/transport.h | 25 | ||||
-rw-r--r-- | net/9p/Kconfig | 10 | ||||
-rw-r--r-- | net/9p/Makefile | 5 | ||||
-rw-r--r-- | net/9p/client.c | 2 | ||||
-rw-r--r-- | net/9p/mux.c | 4 | ||||
-rw-r--r-- | net/9p/trans_fd.c | 419 |
12 files changed, 379 insertions, 285 deletions
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt index cda6905cbe49..1a5f50d35544 100644 --- a/Documentation/filesystems/9p.txt +++ b/Documentation/filesystems/9p.txt | |||
@@ -35,12 +35,12 @@ For remote file server: | |||
35 | 35 | ||
36 | For Plan 9 From User Space applications (http://swtch.com/plan9) | 36 | For Plan 9 From User Space applications (http://swtch.com/plan9) |
37 | 37 | ||
38 | mount -t 9p `namespace`/acme /mnt/9 -o proto=unix,uname=$USER | 38 | mount -t 9p `namespace`/acme /mnt/9 -o trans=unix,uname=$USER |
39 | 39 | ||
40 | OPTIONS | 40 | OPTIONS |
41 | ======= | 41 | ======= |
42 | 42 | ||
43 | proto=name select an alternative transport. Valid options are | 43 | trans=name select an alternative transport. Valid options are |
44 | currently: | 44 | currently: |
45 | unix - specifying a named pipe mount point | 45 | unix - specifying a named pipe mount point |
46 | tcp - specifying a normal TCP/IP connection | 46 | tcp - specifying a normal TCP/IP connection |
@@ -68,9 +68,9 @@ OPTIONS | |||
68 | 0x40 = display transport debug | 68 | 0x40 = display transport debug |
69 | 0x80 = display allocation debug | 69 | 0x80 = display allocation debug |
70 | 70 | ||
71 | rfdno=n the file descriptor for reading with proto=fd | 71 | rfdno=n the file descriptor for reading with trans=fd |
72 | 72 | ||
73 | wfdno=n the file descriptor for writing with proto=fd | 73 | wfdno=n the file descriptor for writing with trans=fd |
74 | 74 | ||
75 | maxdata=n the number of bytes to use for 9p packet payload (msize) | 75 | maxdata=n the number of bytes to use for 9p packet payload (msize) |
76 | 76 | ||
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 @@ | |||
37 | #include "v9fs_vfs.h" | 37 | #include "v9fs_vfs.h" |
38 | 38 | ||
39 | /* | 39 | /* |
40 | * Dynamic Transport Registration Routines | ||
41 | * | ||
42 | */ | ||
43 | |||
44 | static LIST_HEAD(v9fs_trans_list); | ||
45 | static struct p9_trans_module *v9fs_default_trans; | ||
46 | |||
47 | /** | ||
48 | * v9fs_register_trans - register a new transport with 9p | ||
49 | * @m - structure describing the transport module and entry points | ||
50 | * | ||
51 | */ | ||
52 | void v9fs_register_trans(struct p9_trans_module *m) | ||
53 | { | ||
54 | list_add_tail(&m->list, &v9fs_trans_list); | ||
55 | if (m->def) | ||
56 | v9fs_default_trans = m; | ||
57 | } | ||
58 | EXPORT_SYMBOL(v9fs_register_trans); | ||
59 | |||
60 | /** | ||
61 | * v9fs_match_trans - match transport versus registered transports | ||
62 | * @arg: string identifying transport | ||
63 | * | ||
64 | */ | ||
65 | static struct p9_trans_module *v9fs_match_trans(const substring_t *name) | ||
66 | { | ||
67 | struct list_head *p; | ||
68 | struct p9_trans_module *t = NULL; | ||
69 | |||
70 | list_for_each(p, &v9fs_trans_list) { | ||
71 | t = list_entry(p, struct p9_trans_module, list); | ||
72 | if (strncmp(t->name, name->from, name->to-name->from) == 0) { | ||
73 | P9_DPRINTK(P9_DEBUG_TRANS, "trans=%s\n", t->name); | ||
74 | break; | ||
75 | } | ||
76 | } | ||
77 | return t; | ||
78 | } | ||
79 | |||
80 | /* | ||
40 | * Option Parsing (code inspired by NFS code) | 81 | * Option Parsing (code inspired by NFS code) |
41 | * | 82 | * NOTE: each transport will parse its own options |
42 | */ | 83 | */ |
43 | 84 | ||
44 | enum { | 85 | enum { |
45 | /* Options that take integer arguments */ | 86 | /* Options that take integer arguments */ |
46 | Opt_debug, Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, | 87 | Opt_debug, Opt_msize, Opt_uid, Opt_gid, Opt_afid, |
47 | Opt_rfdno, Opt_wfdno, | ||
48 | /* String options */ | 88 | /* String options */ |
49 | Opt_uname, Opt_remotename, | 89 | Opt_uname, Opt_remotename, Opt_trans, |
50 | /* Options that take no arguments */ | 90 | /* Options that take no arguments */ |
51 | Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, Opt_pci, | 91 | Opt_legacy, Opt_nodevmap, |
52 | /* Cache options */ | 92 | /* Cache options */ |
53 | Opt_cache_loose, | 93 | Opt_cache_loose, |
54 | /* Error token */ | 94 | /* Error token */ |
@@ -57,24 +97,13 @@ enum { | |||
57 | 97 | ||
58 | static match_table_t tokens = { | 98 | static match_table_t tokens = { |
59 | {Opt_debug, "debug=%x"}, | 99 | {Opt_debug, "debug=%x"}, |
60 | {Opt_port, "port=%u"}, | ||
61 | {Opt_msize, "msize=%u"}, | 100 | {Opt_msize, "msize=%u"}, |
62 | {Opt_uid, "uid=%u"}, | 101 | {Opt_uid, "uid=%u"}, |
63 | {Opt_gid, "gid=%u"}, | 102 | {Opt_gid, "gid=%u"}, |
64 | {Opt_afid, "afid=%u"}, | 103 | {Opt_afid, "afid=%u"}, |
65 | {Opt_rfdno, "rfdno=%u"}, | ||
66 | {Opt_wfdno, "wfdno=%u"}, | ||
67 | {Opt_uname, "uname=%s"}, | 104 | {Opt_uname, "uname=%s"}, |
68 | {Opt_remotename, "aname=%s"}, | 105 | {Opt_remotename, "aname=%s"}, |
69 | {Opt_unix, "proto=unix"}, | 106 | {Opt_trans, "trans=%s"}, |
70 | {Opt_tcp, "proto=tcp"}, | ||
71 | {Opt_fd, "proto=fd"}, | ||
72 | #ifdef CONFIG_PCI_9P | ||
73 | {Opt_pci, "proto=pci"}, | ||
74 | #endif | ||
75 | {Opt_tcp, "tcp"}, | ||
76 | {Opt_unix, "unix"}, | ||
77 | {Opt_fd, "fd"}, | ||
78 | {Opt_legacy, "noextend"}, | 107 | {Opt_legacy, "noextend"}, |
79 | {Opt_nodevmap, "nodevmap"}, | 108 | {Opt_nodevmap, "nodevmap"}, |
80 | {Opt_cache_loose, "cache=loose"}, | 109 | {Opt_cache_loose, "cache=loose"}, |
@@ -82,12 +111,6 @@ static match_table_t tokens = { | |||
82 | {Opt_err, NULL} | 111 | {Opt_err, NULL} |
83 | }; | 112 | }; |
84 | 113 | ||
85 | extern struct p9_transport *p9pci_trans_create(void); | ||
86 | |||
87 | /* | ||
88 | * Parse option string. | ||
89 | */ | ||
90 | |||
91 | /** | 114 | /** |
92 | * v9fs_parse_options - parse mount options into session structure | 115 | * v9fs_parse_options - parse mount options into session structure |
93 | * @options: options string passed from mount | 116 | * @options: options string passed from mount |
@@ -95,23 +118,21 @@ extern struct p9_transport *p9pci_trans_create(void); | |||
95 | * | 118 | * |
96 | */ | 119 | */ |
97 | 120 | ||
98 | static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) | 121 | static void v9fs_parse_options(struct v9fs_session_info *v9ses) |
99 | { | 122 | { |
100 | char *p; | 123 | char *options = v9ses->options; |
101 | substring_t args[MAX_OPT_ARGS]; | 124 | substring_t args[MAX_OPT_ARGS]; |
125 | char *p; | ||
102 | int option; | 126 | int option; |
103 | int ret; | 127 | int ret; |
104 | 128 | ||
105 | /* setup defaults */ | 129 | /* setup defaults */ |
106 | v9ses->port = V9FS_PORT; | 130 | v9ses->maxdata = 8192; |
107 | v9ses->maxdata = 9000; | ||
108 | v9ses->proto = PROTO_TCP; | ||
109 | v9ses->extended = 1; | 131 | v9ses->extended = 1; |
110 | v9ses->afid = ~0; | 132 | v9ses->afid = ~0; |
111 | v9ses->debug = 0; | 133 | v9ses->debug = 0; |
112 | v9ses->rfdno = ~0; | ||
113 | v9ses->wfdno = ~0; | ||
114 | v9ses->cache = 0; | 134 | v9ses->cache = 0; |
135 | v9ses->trans = v9fs_default_trans; | ||
115 | 136 | ||
116 | if (!options) | 137 | if (!options) |
117 | return; | 138 | return; |
@@ -135,9 +156,6 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) | |||
135 | p9_debug_level = option; | 156 | p9_debug_level = option; |
136 | #endif | 157 | #endif |
137 | break; | 158 | break; |
138 | case Opt_port: | ||
139 | v9ses->port = option; | ||
140 | break; | ||
141 | case Opt_msize: | 159 | case Opt_msize: |
142 | v9ses->maxdata = option; | 160 | v9ses->maxdata = option; |
143 | break; | 161 | break; |
@@ -150,23 +168,8 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) | |||
150 | case Opt_afid: | 168 | case Opt_afid: |
151 | v9ses->afid = option; | 169 | v9ses->afid = option; |
152 | break; | 170 | break; |
153 | case Opt_rfdno: | 171 | case Opt_trans: |
154 | v9ses->rfdno = option; | 172 | v9ses->trans = v9fs_match_trans(&args[0]); |
155 | break; | ||
156 | case Opt_wfdno: | ||
157 | v9ses->wfdno = option; | ||
158 | break; | ||
159 | case Opt_tcp: | ||
160 | v9ses->proto = PROTO_TCP; | ||
161 | break; | ||
162 | case Opt_unix: | ||
163 | v9ses->proto = PROTO_UNIX; | ||
164 | break; | ||
165 | case Opt_pci: | ||
166 | v9ses->proto = PROTO_PCI; | ||
167 | break; | ||
168 | case Opt_fd: | ||
169 | v9ses->proto = PROTO_FD; | ||
170 | break; | 173 | break; |
171 | case Opt_uname: | 174 | case Opt_uname: |
172 | match_strcpy(v9ses->name, &args[0]); | 175 | match_strcpy(v9ses->name, &args[0]); |
@@ -201,7 +204,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||
201 | const char *dev_name, char *data) | 204 | const char *dev_name, char *data) |
202 | { | 205 | { |
203 | int retval = -EINVAL; | 206 | int retval = -EINVAL; |
204 | struct p9_transport *trans; | 207 | struct p9_trans *trans = NULL; |
205 | struct p9_fid *fid; | 208 | struct p9_fid *fid; |
206 | 209 | ||
207 | v9ses->name = __getname(); | 210 | v9ses->name = __getname(); |
@@ -217,39 +220,30 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||
217 | strcpy(v9ses->name, V9FS_DEFUSER); | 220 | strcpy(v9ses->name, V9FS_DEFUSER); |
218 | strcpy(v9ses->remotename, V9FS_DEFANAME); | 221 | strcpy(v9ses->remotename, V9FS_DEFANAME); |
219 | 222 | ||
220 | v9fs_parse_options(data, v9ses); | 223 | v9ses->options = kstrdup(data, GFP_KERNEL); |
221 | 224 | v9fs_parse_options(v9ses); | |
222 | switch (v9ses->proto) { | 225 | |
223 | case PROTO_TCP: | 226 | if ((v9ses->trans == NULL) && !list_empty(&v9fs_trans_list)) |
224 | trans = p9_trans_create_tcp(dev_name, v9ses->port); | 227 | v9ses->trans = list_first_entry(&v9fs_trans_list, |
225 | break; | 228 | struct p9_trans_module, list); |
226 | case PROTO_UNIX: | 229 | |
227 | trans = p9_trans_create_unix(dev_name); | 230 | if (v9ses->trans == NULL) { |
228 | *v9ses->remotename = 0; | 231 | retval = -EPROTONOSUPPORT; |
229 | break; | 232 | P9_DPRINTK(P9_DEBUG_ERROR, |
230 | case PROTO_FD: | 233 | "No transport defined or default transport\n"); |
231 | trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno); | ||
232 | *v9ses->remotename = 0; | ||
233 | break; | ||
234 | #ifdef CONFIG_PCI_9P | ||
235 | case PROTO_PCI: | ||
236 | trans = p9pci_trans_create(); | ||
237 | *v9ses->remotename = 0; | ||
238 | break; | ||
239 | #endif | ||
240 | default: | ||
241 | printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); | ||
242 | retval = -ENOPROTOOPT; | ||
243 | goto error; | 234 | goto error; |
244 | }; | 235 | } |
245 | 236 | ||
237 | trans = v9ses->trans->create(dev_name, v9ses->options); | ||
246 | if (IS_ERR(trans)) { | 238 | if (IS_ERR(trans)) { |
247 | retval = PTR_ERR(trans); | 239 | retval = PTR_ERR(trans); |
248 | trans = NULL; | 240 | trans = NULL; |
249 | goto error; | 241 | goto error; |
250 | } | 242 | } |
243 | if ((v9ses->maxdata+P9_IOHDRSZ) > v9ses->trans->maxsize) | ||
244 | v9ses->maxdata = v9ses->trans->maxsize-P9_IOHDRSZ; | ||
251 | 245 | ||
252 | v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ, | 246 | v9ses->clnt = p9_client_create(trans, v9ses->maxdata+P9_IOHDRSZ, |
253 | v9ses->extended); | 247 | v9ses->extended); |
254 | 248 | ||
255 | if (IS_ERR(v9ses->clnt)) { | 249 | if (IS_ERR(v9ses->clnt)) { |
@@ -290,6 +284,7 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) | |||
290 | 284 | ||
291 | __putname(v9ses->name); | 285 | __putname(v9ses->name); |
292 | __putname(v9ses->remotename); | 286 | __putname(v9ses->remotename); |
287 | kfree(v9ses->options); | ||
293 | } | 288 | } |
294 | 289 | ||
295 | /** | 290 | /** |
@@ -311,7 +306,7 @@ extern int v9fs_error_init(void); | |||
311 | static int __init init_v9fs(void) | 306 | static int __init init_v9fs(void) |
312 | { | 307 | { |
313 | printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); | 308 | printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); |
314 | 309 | /* TODO: Setup list of registered trasnport modules */ | |
315 | return register_filesystem(&v9fs_fs_type); | 310 | return register_filesystem(&v9fs_fs_type); |
316 | } | 311 | } |
317 | 312 | ||
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index abc4b1668ace..7eb135cf60ca 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h | |||
@@ -31,31 +31,20 @@ struct v9fs_session_info { | |||
31 | unsigned int maxdata; | 31 | unsigned int maxdata; |
32 | unsigned char extended; /* set to 1 if we are using UNIX extensions */ | 32 | unsigned char extended; /* set to 1 if we are using UNIX extensions */ |
33 | unsigned char nodev; /* set to 1 if no disable device mapping */ | 33 | unsigned char nodev; /* set to 1 if no disable device mapping */ |
34 | unsigned short port; /* port to connect to */ | ||
35 | unsigned short debug; /* debug level */ | 34 | unsigned short debug; /* debug level */ |
36 | unsigned short proto; /* protocol to use */ | ||
37 | unsigned int afid; /* authentication fid */ | 35 | unsigned int afid; /* authentication fid */ |
38 | unsigned int rfdno; /* read file descriptor number */ | ||
39 | unsigned int wfdno; /* write file descriptor number */ | ||
40 | unsigned int cache; /* cache mode */ | 36 | unsigned int cache; /* cache mode */ |
41 | 37 | ||
38 | char *options; /* copy of mount options */ | ||
42 | char *name; /* user name to mount as */ | 39 | char *name; /* user name to mount as */ |
43 | char *remotename; /* name of remote hierarchy being mounted */ | 40 | char *remotename; /* name of remote hierarchy being mounted */ |
44 | unsigned int uid; /* default uid/muid for legacy support */ | 41 | unsigned int uid; /* default uid/muid for legacy support */ |
45 | unsigned int gid; /* default gid for legacy support */ | 42 | unsigned int gid; /* default gid for legacy support */ |
46 | 43 | struct p9_trans_module *trans; /* 9p transport */ | |
47 | struct p9_client *clnt; /* 9p client */ | 44 | struct p9_client *clnt; /* 9p client */ |
48 | struct dentry *debugfs_dir; | 45 | struct dentry *debugfs_dir; |
49 | }; | 46 | }; |
50 | 47 | ||
51 | /* possible values of ->proto */ | ||
52 | enum { | ||
53 | PROTO_TCP, | ||
54 | PROTO_UNIX, | ||
55 | PROTO_FD, | ||
56 | PROTO_PCI, | ||
57 | }; | ||
58 | |||
59 | /* possible values of ->cache */ | 48 | /* possible values of ->cache */ |
60 | /* eventually support loose, tight, time, session, default always none */ | 49 | /* eventually support loose, tight, time, session, default always none */ |
61 | enum { | 50 | enum { |
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index ba904371218b..bb0cef9a6b8a 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c | |||
@@ -216,24 +216,7 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
216 | { | 216 | { |
217 | struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info; | 217 | struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info; |
218 | 218 | ||
219 | if (v9ses->debug != 0) | 219 | seq_printf(m, "%s", v9ses->options); |
220 | seq_printf(m, ",debug=%x", v9ses->debug); | ||
221 | if (v9ses->port != V9FS_PORT) | ||
222 | seq_printf(m, ",port=%u", v9ses->port); | ||
223 | if (v9ses->maxdata != 9000) | ||
224 | seq_printf(m, ",msize=%u", v9ses->maxdata); | ||
225 | if (v9ses->afid != ~0) | ||
226 | seq_printf(m, ",afid=%u", v9ses->afid); | ||
227 | if (v9ses->proto == PROTO_UNIX) | ||
228 | seq_puts(m, ",proto=unix"); | ||
229 | if (v9ses->extended == 0) | ||
230 | seq_puts(m, ",noextend"); | ||
231 | if (v9ses->nodev == 1) | ||
232 | seq_puts(m, ",nodevmap"); | ||
233 | seq_printf(m, ",name=%s", v9ses->name); | ||
234 | seq_printf(m, ",aname=%s", v9ses->remotename); | ||
235 | seq_printf(m, ",uid=%u", v9ses->uid); | ||
236 | seq_printf(m, ",gid=%u", v9ses->gid); | ||
237 | return 0; | 220 | return 0; |
238 | } | 221 | } |
239 | 222 | ||
diff --git a/include/net/9p/client.h b/include/net/9p/client.h index d65ed7c69063..0adafdb273f0 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h | |||
@@ -29,7 +29,7 @@ struct p9_client { | |||
29 | spinlock_t lock; /* protect client structure */ | 29 | spinlock_t lock; /* protect client structure */ |
30 | int msize; | 30 | int msize; |
31 | unsigned char dotu; | 31 | unsigned char dotu; |
32 | struct p9_transport *trans; | 32 | struct p9_trans *trans; |
33 | struct p9_conn *conn; | 33 | struct p9_conn *conn; |
34 | 34 | ||
35 | struct p9_idpool *fidpool; | 35 | struct p9_idpool *fidpool; |
@@ -52,7 +52,7 @@ struct p9_fid { | |||
52 | struct list_head dlist; /* list of all fids attached to a dentry */ | 52 | struct list_head dlist; /* list of all fids attached to a dentry */ |
53 | }; | 53 | }; |
54 | 54 | ||
55 | struct p9_client *p9_client_create(struct p9_transport *trans, int msize, | 55 | struct p9_client *p9_client_create(struct p9_trans *trans, int msize, |
56 | int dotu); | 56 | int dotu); |
57 | void p9_client_destroy(struct p9_client *clnt); | 57 | void p9_client_destroy(struct p9_client *clnt); |
58 | void p9_client_disconnect(struct p9_client *clnt); | 58 | void p9_client_disconnect(struct p9_client *clnt); |
diff --git a/include/net/9p/conn.h b/include/net/9p/conn.h index 583b6a2cb3df..756d8784f953 100644 --- a/include/net/9p/conn.h +++ b/include/net/9p/conn.h | |||
@@ -42,8 +42,8 @@ struct p9_req; | |||
42 | */ | 42 | */ |
43 | typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a); | 43 | typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a); |
44 | 44 | ||
45 | struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize, | 45 | struct p9_conn *p9_conn_create(struct p9_trans *trans, int msize, |
46 | unsigned char *dotu); | 46 | unsigned char *dotu); |
47 | void p9_conn_destroy(struct p9_conn *); | 47 | void p9_conn_destroy(struct p9_conn *); |
48 | int p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc, struct p9_fcall **rc); | 48 | int p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc, struct p9_fcall **rc); |
49 | 49 | ||
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h index 462d42279fb0..7c68b3e8e78c 100644 --- a/include/net/9p/transport.h +++ b/include/net/9p/transport.h | |||
@@ -26,24 +26,29 @@ | |||
26 | #ifndef NET_9P_TRANSPORT_H | 26 | #ifndef NET_9P_TRANSPORT_H |
27 | #define NET_9P_TRANSPORT_H | 27 | #define NET_9P_TRANSPORT_H |
28 | 28 | ||
29 | enum p9_transport_status { | 29 | enum p9_trans_status { |
30 | Connected, | 30 | Connected, |
31 | Disconnected, | 31 | Disconnected, |
32 | Hung, | 32 | Hung, |
33 | }; | 33 | }; |
34 | 34 | ||
35 | struct p9_transport { | 35 | struct p9_trans { |
36 | enum p9_transport_status status; | 36 | enum p9_trans_status status; |
37 | void *priv; | 37 | void *priv; |
38 | int (*write) (struct p9_trans *, void *, int); | ||
39 | int (*read) (struct p9_trans *, void *, int); | ||
40 | void (*close) (struct p9_trans *); | ||
41 | unsigned int (*poll)(struct p9_trans *, struct poll_table_struct *); | ||
42 | }; | ||
38 | 43 | ||
39 | int (*write) (struct p9_transport *, void *, int); | 44 | struct p9_trans_module { |
40 | int (*read) (struct p9_transport *, void *, int); | 45 | struct list_head list; |
41 | void (*close) (struct p9_transport *); | 46 | char *name; /* name of transport */ |
42 | unsigned int (*poll)(struct p9_transport *, struct poll_table_struct *); | 47 | int maxsize; /* max message size of transport */ |
48 | int def; /* this transport should be default */ | ||
49 | struct p9_trans * (*create)(const char *devname, char *options); | ||
43 | }; | 50 | }; |
44 | 51 | ||
45 | struct p9_transport *p9_trans_create_tcp(const char *addr, int port); | 52 | void v9fs_register_trans(struct p9_trans_module *m); |
46 | struct p9_transport *p9_trans_create_unix(const char *addr); | ||
47 | struct p9_transport *p9_trans_create_fd(int rfd, int wfd); | ||
48 | 53 | ||
49 | #endif /* NET_9P_TRANSPORT_H */ | 54 | #endif /* NET_9P_TRANSPORT_H */ |
diff --git a/net/9p/Kconfig b/net/9p/Kconfig index 66821cd64a76..eecbf12f6393 100644 --- a/net/9p/Kconfig +++ b/net/9p/Kconfig | |||
@@ -13,6 +13,16 @@ menuconfig NET_9P | |||
13 | 13 | ||
14 | If unsure, say N. | 14 | If unsure, say N. |
15 | 15 | ||
16 | config NET_9P_FD | ||
17 | depends on NET_9P | ||
18 | default y if NET_9P | ||
19 | tristate "9P File Descriptor Transports (Experimental)" | ||
20 | help | ||
21 | This builds support for file descriptor transports for 9p | ||
22 | which includes support for TCP/IP, named pipes, or passed | ||
23 | file descriptors. TCP/IP is the default transport for 9p, | ||
24 | so if you are going to use 9p, you'll likely want this. | ||
25 | |||
16 | config NET_9P_DEBUG | 26 | config NET_9P_DEBUG |
17 | bool "Debug information" | 27 | bool "Debug information" |
18 | depends on NET_9P | 28 | depends on NET_9P |
diff --git a/net/9p/Makefile b/net/9p/Makefile index 85b3a7838acf..7b2a67abc0a0 100644 --- a/net/9p/Makefile +++ b/net/9p/Makefile | |||
@@ -1,8 +1,8 @@ | |||
1 | obj-$(CONFIG_NET_9P) := 9pnet.o | 1 | obj-$(CONFIG_NET_9P) := 9pnet.o |
2 | obj-$(CONFIG_NET_9P_FD) += 9pnet_fd.o | ||
2 | 3 | ||
3 | 9pnet-objs := \ | 4 | 9pnet-objs := \ |
4 | mod.o \ | 5 | mod.o \ |
5 | trans_fd.o \ | ||
6 | mux.o \ | 6 | mux.o \ |
7 | client.o \ | 7 | client.o \ |
8 | conv.o \ | 8 | conv.o \ |
@@ -11,3 +11,6 @@ obj-$(CONFIG_NET_9P) := 9pnet.o | |||
11 | util.o \ | 11 | util.o \ |
12 | 12 | ||
13 | 9pnet-$(CONFIG_SYSCTL) += sysctl.o | 13 | 9pnet-$(CONFIG_SYSCTL) += sysctl.o |
14 | |||
15 | 9pnet_fd-objs := \ | ||
16 | trans_fd.o \ | ||
diff --git a/net/9p/client.c b/net/9p/client.c index cb170750337c..e1610125a882 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -38,7 +38,7 @@ static struct p9_fid *p9_fid_create(struct p9_client *clnt); | |||
38 | static void p9_fid_destroy(struct p9_fid *fid); | 38 | static void p9_fid_destroy(struct p9_fid *fid); |
39 | static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu); | 39 | static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu); |
40 | 40 | ||
41 | struct p9_client *p9_client_create(struct p9_transport *trans, int msize, | 41 | struct p9_client *p9_client_create(struct p9_trans *trans, int msize, |
42 | int dotu) | 42 | int dotu) |
43 | { | 43 | { |
44 | int err, n; | 44 | int err, n; |
diff --git a/net/9p/mux.c b/net/9p/mux.c index 5d70558c4c61..934e2ea86e2c 100644 --- a/net/9p/mux.c +++ b/net/9p/mux.c | |||
@@ -71,7 +71,7 @@ struct p9_conn { | |||
71 | struct p9_mux_poll_task *poll_task; | 71 | struct p9_mux_poll_task *poll_task; |
72 | int msize; | 72 | int msize; |
73 | unsigned char *extended; | 73 | unsigned char *extended; |
74 | struct p9_transport *trans; | 74 | struct p9_trans *trans; |
75 | struct p9_idpool *tagpool; | 75 | struct p9_idpool *tagpool; |
76 | int err; | 76 | int err; |
77 | wait_queue_head_t equeue; | 77 | wait_queue_head_t equeue; |
@@ -271,7 +271,7 @@ static void p9_mux_poll_stop(struct p9_conn *m) | |||
271 | * @msize - maximum message size | 271 | * @msize - maximum message size |
272 | * @extended - pointer to the extended flag | 272 | * @extended - pointer to the extended flag |
273 | */ | 273 | */ |
274 | struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize, | 274 | struct p9_conn *p9_conn_create(struct p9_trans *trans, int msize, |
275 | unsigned char *extended) | 275 | unsigned char *extended) |
276 | { | 276 | { |
277 | int i, n; | 277 | int i, n; |
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c index fd636e94358f..30269a4ff22a 100644 --- a/net/9p/trans_fd.c +++ b/net/9p/trans_fd.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> | 6 | * Copyright (C) 2006 by Russ Cox <rsc@swtch.com> |
7 | * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> | 7 | * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> |
8 | * Copyright (C) 2004-2005 by Eric Van Hensbergen <ericvh@gmail.com> | 8 | * Copyright (C) 2004-2007 by Eric Van Hensbergen <ericvh@gmail.com> |
9 | * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> | 9 | * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com> |
10 | * | 10 | * |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
@@ -36,160 +36,114 @@ | |||
36 | #include <linux/inet.h> | 36 | #include <linux/inet.h> |
37 | #include <linux/idr.h> | 37 | #include <linux/idr.h> |
38 | #include <linux/file.h> | 38 | #include <linux/file.h> |
39 | #include <linux/parser.h> | ||
39 | #include <net/9p/9p.h> | 40 | #include <net/9p/9p.h> |
40 | #include <net/9p/transport.h> | 41 | #include <net/9p/transport.h> |
41 | 42 | ||
42 | #define P9_PORT 564 | 43 | #define P9_PORT 564 |
44 | #define MAX_SOCK_BUF (64*1024) | ||
45 | |||
46 | |||
47 | struct p9_fd_opts { | ||
48 | int rfd; | ||
49 | int wfd; | ||
50 | u16 port; | ||
51 | }; | ||
43 | 52 | ||
44 | struct p9_trans_fd { | 53 | struct p9_trans_fd { |
45 | struct file *rd; | 54 | struct file *rd; |
46 | struct file *wr; | 55 | struct file *wr; |
47 | }; | 56 | }; |
48 | 57 | ||
49 | static int p9_socket_open(struct p9_transport *trans, struct socket *csocket); | 58 | /* |
50 | static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd); | 59 | * Option Parsing (code inspired by NFS code) |
51 | static int p9_fd_read(struct p9_transport *trans, void *v, int len); | 60 | * - a little lazy - parse all fd-transport options |
52 | static int p9_fd_write(struct p9_transport *trans, void *v, int len); | 61 | */ |
53 | static unsigned int p9_fd_poll(struct p9_transport *trans, | ||
54 | struct poll_table_struct *pt); | ||
55 | static void p9_fd_close(struct p9_transport *trans); | ||
56 | |||
57 | struct p9_transport *p9_trans_create_tcp(const char *addr, int port) | ||
58 | { | ||
59 | int err; | ||
60 | struct p9_transport *trans; | ||
61 | struct socket *csocket; | ||
62 | struct sockaddr_in sin_server; | ||
63 | |||
64 | csocket = NULL; | ||
65 | trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL); | ||
66 | if (!trans) | ||
67 | return ERR_PTR(-ENOMEM); | ||
68 | |||
69 | trans->write = p9_fd_write; | ||
70 | trans->read = p9_fd_read; | ||
71 | trans->close = p9_fd_close; | ||
72 | trans->poll = p9_fd_poll; | ||
73 | |||
74 | sin_server.sin_family = AF_INET; | ||
75 | sin_server.sin_addr.s_addr = in_aton(addr); | ||
76 | sin_server.sin_port = htons(port); | ||
77 | sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); | ||
78 | |||
79 | if (!csocket) { | ||
80 | P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n"); | ||
81 | err = -EIO; | ||
82 | goto error; | ||
83 | } | ||
84 | |||
85 | err = csocket->ops->connect(csocket, | ||
86 | (struct sockaddr *)&sin_server, | ||
87 | sizeof(struct sockaddr_in), 0); | ||
88 | if (err < 0) { | ||
89 | P9_EPRINTK(KERN_ERR, | ||
90 | "p9_trans_tcp: problem connecting socket to %s\n", | ||
91 | addr); | ||
92 | goto error; | ||
93 | } | ||
94 | |||
95 | err = p9_socket_open(trans, csocket); | ||
96 | if (err < 0) | ||
97 | goto error; | ||
98 | 62 | ||
99 | return trans; | 63 | enum { |
64 | /* Options that take integer arguments */ | ||
65 | Opt_port, Opt_rfdno, Opt_wfdno, | ||
66 | }; | ||
100 | 67 | ||
101 | error: | 68 | static match_table_t tokens = { |
102 | if (csocket) | 69 | {Opt_port, "port=%u"}, |
103 | sock_release(csocket); | 70 | {Opt_rfdno, "rfdno=%u"}, |
71 | {Opt_wfdno, "wfdno=%u"}, | ||
72 | }; | ||
104 | 73 | ||
105 | kfree(trans); | 74 | /** |
106 | return ERR_PTR(err); | 75 | * v9fs_parse_options - parse mount options into session structure |
107 | } | 76 | * @options: options string passed from mount |
108 | EXPORT_SYMBOL(p9_trans_create_tcp); | 77 | * @v9ses: existing v9fs session information |
78 | * | ||
79 | */ | ||
109 | 80 | ||
110 | struct p9_transport *p9_trans_create_unix(const char *addr) | 81 | static void parse_opts(char *options, struct p9_fd_opts *opts) |
111 | { | 82 | { |
112 | int err; | 83 | char *p; |
113 | struct socket *csocket; | 84 | substring_t args[MAX_OPT_ARGS]; |
114 | struct sockaddr_un sun_server; | 85 | int option; |
115 | struct p9_transport *trans; | 86 | int ret; |
116 | |||
117 | csocket = NULL; | ||
118 | trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL); | ||
119 | if (!trans) | ||
120 | return ERR_PTR(-ENOMEM); | ||
121 | 87 | ||
122 | trans->write = p9_fd_write; | 88 | opts->port = P9_PORT; |
123 | trans->read = p9_fd_read; | 89 | opts->rfd = ~0; |
124 | trans->close = p9_fd_close; | 90 | opts->wfd = ~0; |
125 | trans->poll = p9_fd_poll; | ||
126 | 91 | ||
127 | if (strlen(addr) > UNIX_PATH_MAX) { | 92 | if (!options) |
128 | P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", | 93 | return; |
129 | addr); | ||
130 | err = -ENAMETOOLONG; | ||
131 | goto error; | ||
132 | } | ||
133 | 94 | ||
134 | sun_server.sun_family = PF_UNIX; | 95 | while ((p = strsep(&options, ",")) != NULL) { |
135 | strcpy(sun_server.sun_path, addr); | 96 | int token; |
136 | sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); | 97 | if (!*p) |
137 | err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, | 98 | continue; |
138 | sizeof(struct sockaddr_un) - 1, 0); | 99 | token = match_token(p, tokens, args); |
139 | if (err < 0) { | 100 | ret = match_int(&args[0], &option); |
140 | P9_EPRINTK(KERN_ERR, | 101 | if (ret < 0) { |
141 | "p9_trans_unix: problem connecting socket: %s: %d\n", | 102 | P9_DPRINTK(P9_DEBUG_ERROR, |
142 | addr, err); | 103 | "integer field, but no integer?\n"); |
143 | goto error; | 104 | continue; |
105 | } | ||
106 | switch (token) { | ||
107 | case Opt_port: | ||
108 | opts->port = option; | ||
109 | break; | ||
110 | case Opt_rfdno: | ||
111 | opts->rfd = option; | ||
112 | break; | ||
113 | case Opt_wfdno: | ||
114 | opts->wfd = option; | ||
115 | break; | ||
116 | default: | ||
117 | continue; | ||
118 | } | ||
144 | } | 119 | } |
145 | |||
146 | err = p9_socket_open(trans, csocket); | ||
147 | if (err < 0) | ||
148 | goto error; | ||
149 | |||
150 | return trans; | ||
151 | |||
152 | error: | ||
153 | if (csocket) | ||
154 | sock_release(csocket); | ||
155 | |||
156 | kfree(trans); | ||
157 | return ERR_PTR(err); | ||
158 | } | 120 | } |
159 | EXPORT_SYMBOL(p9_trans_create_unix); | ||
160 | 121 | ||
161 | struct p9_transport *p9_trans_create_fd(int rfd, int wfd) | 122 | static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd) |
162 | { | 123 | { |
163 | int err; | 124 | struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd), |
164 | struct p9_transport *trans; | 125 | GFP_KERNEL); |
126 | if (!ts) | ||
127 | return -ENOMEM; | ||
165 | 128 | ||
166 | if (rfd == ~0 || wfd == ~0) { | 129 | ts->rd = fget(rfd); |
167 | printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); | 130 | ts->wr = fget(wfd); |
168 | return ERR_PTR(-ENOPROTOOPT); | 131 | if (!ts->rd || !ts->wr) { |
132 | if (ts->rd) | ||
133 | fput(ts->rd); | ||
134 | if (ts->wr) | ||
135 | fput(ts->wr); | ||
136 | kfree(ts); | ||
137 | return -EIO; | ||
169 | } | 138 | } |
170 | 139 | ||
171 | trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL); | 140 | trans->priv = ts; |
172 | if (!trans) | 141 | trans->status = Connected; |
173 | return ERR_PTR(-ENOMEM); | ||
174 | |||
175 | trans->write = p9_fd_write; | ||
176 | trans->read = p9_fd_read; | ||
177 | trans->close = p9_fd_close; | ||
178 | trans->poll = p9_fd_poll; | ||
179 | |||
180 | err = p9_fd_open(trans, rfd, wfd); | ||
181 | if (err < 0) | ||
182 | goto error; | ||
183 | |||
184 | return trans; | ||
185 | 142 | ||
186 | error: | 143 | return 0; |
187 | kfree(trans); | ||
188 | return ERR_PTR(err); | ||
189 | } | 144 | } |
190 | EXPORT_SYMBOL(p9_trans_create_fd); | ||
191 | 145 | ||
192 | static int p9_socket_open(struct p9_transport *trans, struct socket *csocket) | 146 | static int p9_socket_open(struct p9_trans *trans, struct socket *csocket) |
193 | { | 147 | { |
194 | int fd, ret; | 148 | int fd, ret; |
195 | 149 | ||
@@ -212,30 +166,6 @@ static int p9_socket_open(struct p9_transport *trans, struct socket *csocket) | |||
212 | return 0; | 166 | return 0; |
213 | } | 167 | } |
214 | 168 | ||
215 | static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd) | ||
216 | { | ||
217 | struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd), | ||
218 | GFP_KERNEL); | ||
219 | if (!ts) | ||
220 | return -ENOMEM; | ||
221 | |||
222 | ts->rd = fget(rfd); | ||
223 | ts->wr = fget(wfd); | ||
224 | if (!ts->rd || !ts->wr) { | ||
225 | if (ts->rd) | ||
226 | fput(ts->rd); | ||
227 | if (ts->wr) | ||
228 | fput(ts->wr); | ||
229 | kfree(ts); | ||
230 | return -EIO; | ||
231 | } | ||
232 | |||
233 | trans->priv = ts; | ||
234 | trans->status = Connected; | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | /** | 169 | /** |
240 | * p9_fd_read- read from a fd | 170 | * p9_fd_read- read from a fd |
241 | * @v9ses: session information | 171 | * @v9ses: session information |
@@ -243,7 +173,7 @@ static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd) | |||
243 | * @len: size of receive buffer | 173 | * @len: size of receive buffer |
244 | * | 174 | * |
245 | */ | 175 | */ |
246 | static int p9_fd_read(struct p9_transport *trans, void *v, int len) | 176 | static int p9_fd_read(struct p9_trans *trans, void *v, int len) |
247 | { | 177 | { |
248 | int ret; | 178 | int ret; |
249 | struct p9_trans_fd *ts = NULL; | 179 | struct p9_trans_fd *ts = NULL; |
@@ -270,7 +200,7 @@ static int p9_fd_read(struct p9_transport *trans, void *v, int len) | |||
270 | * @len: size of send buffer | 200 | * @len: size of send buffer |
271 | * | 201 | * |
272 | */ | 202 | */ |
273 | static int p9_fd_write(struct p9_transport *trans, void *v, int len) | 203 | static int p9_fd_write(struct p9_trans *trans, void *v, int len) |
274 | { | 204 | { |
275 | int ret; | 205 | int ret; |
276 | mm_segment_t oldfs; | 206 | mm_segment_t oldfs; |
@@ -297,7 +227,7 @@ static int p9_fd_write(struct p9_transport *trans, void *v, int len) | |||
297 | } | 227 | } |
298 | 228 | ||
299 | static unsigned int | 229 | static unsigned int |
300 | p9_fd_poll(struct p9_transport *trans, struct poll_table_struct *pt) | 230 | p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt) |
301 | { | 231 | { |
302 | int ret, n; | 232 | int ret, n; |
303 | struct p9_trans_fd *ts = NULL; | 233 | struct p9_trans_fd *ts = NULL; |
@@ -341,7 +271,7 @@ end: | |||
341 | * @trans: private socket structure | 271 | * @trans: private socket structure |
342 | * | 272 | * |
343 | */ | 273 | */ |
344 | static void p9_fd_close(struct p9_transport *trans) | 274 | static void p9_fd_close(struct p9_trans *trans) |
345 | { | 275 | { |
346 | struct p9_trans_fd *ts; | 276 | struct p9_trans_fd *ts; |
347 | 277 | ||
@@ -361,3 +291,182 @@ static void p9_fd_close(struct p9_transport *trans) | |||
361 | kfree(ts); | 291 | kfree(ts); |
362 | } | 292 | } |
363 | 293 | ||
294 | static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args) | ||
295 | { | ||
296 | int err; | ||
297 | struct p9_trans *trans; | ||
298 | struct socket *csocket; | ||
299 | struct sockaddr_in sin_server; | ||
300 | struct p9_fd_opts opts; | ||
301 | |||
302 | parse_opts(args, &opts); | ||
303 | |||
304 | csocket = NULL; | ||
305 | trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); | ||
306 | if (!trans) | ||
307 | return ERR_PTR(-ENOMEM); | ||
308 | |||
309 | trans->write = p9_fd_write; | ||
310 | trans->read = p9_fd_read; | ||
311 | trans->close = p9_fd_close; | ||
312 | trans->poll = p9_fd_poll; | ||
313 | |||
314 | sin_server.sin_family = AF_INET; | ||
315 | sin_server.sin_addr.s_addr = in_aton(addr); | ||
316 | sin_server.sin_port = htons(opts.port); | ||
317 | sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket); | ||
318 | |||
319 | if (!csocket) { | ||
320 | P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n"); | ||
321 | err = -EIO; | ||
322 | goto error; | ||
323 | } | ||
324 | |||
325 | err = csocket->ops->connect(csocket, | ||
326 | (struct sockaddr *)&sin_server, | ||
327 | sizeof(struct sockaddr_in), 0); | ||
328 | if (err < 0) { | ||
329 | P9_EPRINTK(KERN_ERR, | ||
330 | "p9_trans_tcp: problem connecting socket to %s\n", | ||
331 | addr); | ||
332 | goto error; | ||
333 | } | ||
334 | |||
335 | err = p9_socket_open(trans, csocket); | ||
336 | if (err < 0) | ||
337 | goto error; | ||
338 | |||
339 | return trans; | ||
340 | |||
341 | error: | ||
342 | if (csocket) | ||
343 | sock_release(csocket); | ||
344 | |||
345 | kfree(trans); | ||
346 | return ERR_PTR(err); | ||
347 | } | ||
348 | |||
349 | static struct p9_trans *p9_trans_create_unix(const char *addr, char *args) | ||
350 | { | ||
351 | int err; | ||
352 | struct socket *csocket; | ||
353 | struct sockaddr_un sun_server; | ||
354 | struct p9_trans *trans; | ||
355 | |||
356 | csocket = NULL; | ||
357 | trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); | ||
358 | if (!trans) | ||
359 | return ERR_PTR(-ENOMEM); | ||
360 | |||
361 | trans->write = p9_fd_write; | ||
362 | trans->read = p9_fd_read; | ||
363 | trans->close = p9_fd_close; | ||
364 | trans->poll = p9_fd_poll; | ||
365 | |||
366 | if (strlen(addr) > UNIX_PATH_MAX) { | ||
367 | P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n", | ||
368 | addr); | ||
369 | err = -ENAMETOOLONG; | ||
370 | goto error; | ||
371 | } | ||
372 | |||
373 | sun_server.sun_family = PF_UNIX; | ||
374 | strcpy(sun_server.sun_path, addr); | ||
375 | sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket); | ||
376 | err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server, | ||
377 | sizeof(struct sockaddr_un) - 1, 0); | ||
378 | if (err < 0) { | ||
379 | P9_EPRINTK(KERN_ERR, | ||
380 | "p9_trans_unix: problem connecting socket: %s: %d\n", | ||
381 | addr, err); | ||
382 | goto error; | ||
383 | } | ||
384 | |||
385 | err = p9_socket_open(trans, csocket); | ||
386 | if (err < 0) | ||
387 | goto error; | ||
388 | |||
389 | return trans; | ||
390 | |||
391 | error: | ||
392 | if (csocket) | ||
393 | sock_release(csocket); | ||
394 | |||
395 | kfree(trans); | ||
396 | return ERR_PTR(err); | ||
397 | } | ||
398 | |||
399 | static struct p9_trans *p9_trans_create_fd(const char *name, char *args) | ||
400 | { | ||
401 | int err; | ||
402 | struct p9_trans *trans; | ||
403 | struct p9_fd_opts opts; | ||
404 | |||
405 | parse_opts(args, &opts); | ||
406 | |||
407 | if (opts.rfd == ~0 || opts.wfd == ~0) { | ||
408 | printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n"); | ||
409 | return ERR_PTR(-ENOPROTOOPT); | ||
410 | } | ||
411 | |||
412 | trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL); | ||
413 | if (!trans) | ||
414 | return ERR_PTR(-ENOMEM); | ||
415 | |||
416 | trans->write = p9_fd_write; | ||
417 | trans->read = p9_fd_read; | ||
418 | trans->close = p9_fd_close; | ||
419 | trans->poll = p9_fd_poll; | ||
420 | |||
421 | err = p9_fd_open(trans, opts.rfd, opts.wfd); | ||
422 | if (err < 0) | ||
423 | goto error; | ||
424 | |||
425 | return trans; | ||
426 | |||
427 | error: | ||
428 | kfree(trans); | ||
429 | return ERR_PTR(err); | ||
430 | } | ||
431 | |||
432 | static struct p9_trans_module p9_tcp_trans = { | ||
433 | .name = "tcp", | ||
434 | .maxsize = MAX_SOCK_BUF, | ||
435 | .def = 1, | ||
436 | .create = p9_trans_create_tcp, | ||
437 | }; | ||
438 | |||
439 | static struct p9_trans_module p9_unix_trans = { | ||
440 | .name = "unix", | ||
441 | .maxsize = MAX_SOCK_BUF, | ||
442 | .def = 0, | ||
443 | .create = p9_trans_create_unix, | ||
444 | }; | ||
445 | |||
446 | static struct p9_trans_module p9_fd_trans = { | ||
447 | .name = "fd", | ||
448 | .maxsize = MAX_SOCK_BUF, | ||
449 | .def = 0, | ||
450 | .create = p9_trans_create_fd, | ||
451 | }; | ||
452 | |||
453 | static int __init p9_trans_fd_init(void) | ||
454 | { | ||
455 | v9fs_register_trans(&p9_tcp_trans); | ||
456 | v9fs_register_trans(&p9_unix_trans); | ||
457 | v9fs_register_trans(&p9_fd_trans); | ||
458 | |||
459 | return 1; | ||
460 | } | ||
461 | |||
462 | static void __exit p9_trans_fd_exit(void) { | ||
463 | printk(KERN_ERR "Removal of 9p transports not implemented\n"); | ||
464 | BUG(); | ||
465 | } | ||
466 | |||
467 | module_init(p9_trans_fd_init); | ||
468 | module_exit(p9_trans_fd_exit); | ||
469 | |||
470 | MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>"); | ||
471 | MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>"); | ||
472 | MODULE_LICENSE("GPL"); | ||