aboutsummaryrefslogtreecommitdiffstats
path: root/net/9p/trans_fd.c
diff options
context:
space:
mode:
authorEric Van Hensbergen <ericvh@opteron.(none)>2007-10-17 15:31:07 -0400
committerEric Van Hensbergen <ericvh@ericvh-desktop.austin.ibm.com>2007-10-17 15:31:07 -0400
commita80d923e1321a7ed69a0918de37e39871bb536a0 (patch)
tree8294e5f14a0e938ae4675ef912a32fbade0f832b /net/9p/trans_fd.c
parent0eafaae84e21ac033815cc9f33c3ae889cd7ccfe (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>
Diffstat (limited to 'net/9p/trans_fd.c')
-rw-r--r--net/9p/trans_fd.c419
1 files changed, 264 insertions, 155 deletions
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
47struct p9_fd_opts {
48 int rfd;
49 int wfd;
50 u16 port;
51};
43 52
44struct p9_trans_fd { 53struct p9_trans_fd {
45 struct file *rd; 54 struct file *rd;
46 struct file *wr; 55 struct file *wr;
47}; 56};
48 57
49static int p9_socket_open(struct p9_transport *trans, struct socket *csocket); 58/*
50static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd); 59 * Option Parsing (code inspired by NFS code)
51static int p9_fd_read(struct p9_transport *trans, void *v, int len); 60 * - a little lazy - parse all fd-transport options
52static int p9_fd_write(struct p9_transport *trans, void *v, int len); 61 */
53static unsigned int p9_fd_poll(struct p9_transport *trans,
54 struct poll_table_struct *pt);
55static void p9_fd_close(struct p9_transport *trans);
56
57struct 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; 63enum {
64 /* Options that take integer arguments */
65 Opt_port, Opt_rfdno, Opt_wfdno,
66};
100 67
101error: 68static 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
108EXPORT_SYMBOL(p9_trans_create_tcp); 77 * @v9ses: existing v9fs session information
78 *
79 */
109 80
110struct p9_transport *p9_trans_create_unix(const char *addr) 81static 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
152error:
153 if (csocket)
154 sock_release(csocket);
155
156 kfree(trans);
157 return ERR_PTR(err);
158} 120}
159EXPORT_SYMBOL(p9_trans_create_unix);
160 121
161struct p9_transport *p9_trans_create_fd(int rfd, int wfd) 122static 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
186error: 143 return 0;
187 kfree(trans);
188 return ERR_PTR(err);
189} 144}
190EXPORT_SYMBOL(p9_trans_create_fd);
191 145
192static int p9_socket_open(struct p9_transport *trans, struct socket *csocket) 146static 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
215static 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 */
246static int p9_fd_read(struct p9_transport *trans, void *v, int len) 176static 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 */
273static int p9_fd_write(struct p9_transport *trans, void *v, int len) 203static 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
299static unsigned int 229static unsigned int
300p9_fd_poll(struct p9_transport *trans, struct poll_table_struct *pt) 230p9_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 */
344static void p9_fd_close(struct p9_transport *trans) 274static 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
294static 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
341error:
342 if (csocket)
343 sock_release(csocket);
344
345 kfree(trans);
346 return ERR_PTR(err);
347}
348
349static 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
391error:
392 if (csocket)
393 sock_release(csocket);
394
395 kfree(trans);
396 return ERR_PTR(err);
397}
398
399static 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
427error:
428 kfree(trans);
429 return ERR_PTR(err);
430}
431
432static 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
439static 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
446static 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
453static 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
462static void __exit p9_trans_fd_exit(void) {
463 printk(KERN_ERR "Removal of 9p transports not implemented\n");
464 BUG();
465}
466
467module_init(p9_trans_fd_init);
468module_exit(p9_trans_fd_exit);
469
470MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
471MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
472MODULE_LICENSE("GPL");