Merge branch 'fixes-davem' of master.kernel.org:/pub/scm/linux/kernel/git/linville...
[sfrench/cifs-2.6.git] / net / 9p / trans_fd.c
1 /*
2  * linux/fs/9p/trans_fd.c
3  *
4  * Fd transport layer.  Includes deprecated socket layer.
5  *
6  *  Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
7  *  Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
8  *  Copyright (C) 2004-2007 by Eric Van Hensbergen <ericvh@gmail.com>
9  *  Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License version 2
13  *  as published by the Free Software Foundation.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to:
22  *  Free Software Foundation
23  *  51 Franklin Street, Fifth Floor
24  *  Boston, MA  02111-1301  USA
25  *
26  */
27
28 #include <linux/in.h>
29 #include <linux/module.h>
30 #include <linux/net.h>
31 #include <linux/ipv6.h>
32 #include <linux/errno.h>
33 #include <linux/kernel.h>
34 #include <linux/un.h>
35 #include <linux/uaccess.h>
36 #include <linux/inet.h>
37 #include <linux/idr.h>
38 #include <linux/file.h>
39 #include <linux/parser.h>
40 #include <net/9p/9p.h>
41 #include <net/9p/transport.h>
42
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 };
52
53 struct p9_trans_fd {
54         struct file *rd;
55         struct file *wr;
56 };
57
58 /*
59   * Option Parsing (code inspired by NFS code)
60   *  - a little lazy - parse all fd-transport options
61   */
62
63 enum {
64         /* Options that take integer arguments */
65         Opt_port, Opt_rfdno, Opt_wfdno,
66 };
67
68 static match_table_t tokens = {
69         {Opt_port, "port=%u"},
70         {Opt_rfdno, "rfdno=%u"},
71         {Opt_wfdno, "wfdno=%u"},
72 };
73
74 /**
75  * v9fs_parse_options - parse mount options into session structure
76  * @options: options string passed from mount
77  * @v9ses: existing v9fs session information
78  *
79  */
80
81 static void parse_opts(char *options, struct p9_fd_opts *opts)
82 {
83         char *p;
84         substring_t args[MAX_OPT_ARGS];
85         int option;
86         int ret;
87
88         opts->port = P9_PORT;
89         opts->rfd = ~0;
90         opts->wfd = ~0;
91
92         if (!options)
93                 return;
94
95         while ((p = strsep(&options, ",")) != NULL) {
96                 int token;
97                 if (!*p)
98                         continue;
99                 token = match_token(p, tokens, args);
100                 ret = match_int(&args[0], &option);
101                 if (ret < 0) {
102                         P9_DPRINTK(P9_DEBUG_ERROR,
103                          "integer field, but no integer?\n");
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                 }
119         }
120 }
121
122 static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd)
123 {
124         struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
125                                            GFP_KERNEL);
126         if (!ts)
127                 return -ENOMEM;
128
129         ts->rd = fget(rfd);
130         ts->wr = fget(wfd);
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;
138         }
139
140         trans->priv = ts;
141         trans->status = Connected;
142
143         return 0;
144 }
145
146 static int p9_socket_open(struct p9_trans *trans, struct socket *csocket)
147 {
148         int fd, ret;
149
150         csocket->sk->sk_allocation = GFP_NOIO;
151         fd = sock_map_fd(csocket);
152         if (fd < 0) {
153                 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
154                 return fd;
155         }
156
157         ret = p9_fd_open(trans, fd, fd);
158         if (ret < 0) {
159                 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n");
160                 sockfd_put(csocket);
161                 return ret;
162         }
163
164         ((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK;
165
166         return 0;
167 }
168
169 /**
170  * p9_fd_read- read from a fd
171  * @v9ses: session information
172  * @v: buffer to receive data into
173  * @len: size of receive buffer
174  *
175  */
176 static int p9_fd_read(struct p9_trans *trans, void *v, int len)
177 {
178         int ret;
179         struct p9_trans_fd *ts = NULL;
180
181         if (trans && trans->status != Disconnected)
182                 ts = trans->priv;
183
184         if (!ts)
185                 return -EREMOTEIO;
186
187         if (!(ts->rd->f_flags & O_NONBLOCK))
188                 P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
189
190         ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
191         if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
192                 trans->status = Disconnected;
193         return ret;
194 }
195
196 /**
197  * p9_fd_write - write to a socket
198  * @v9ses: session information
199  * @v: buffer to send data from
200  * @len: size of send buffer
201  *
202  */
203 static int p9_fd_write(struct p9_trans *trans, void *v, int len)
204 {
205         int ret;
206         mm_segment_t oldfs;
207         struct p9_trans_fd *ts = NULL;
208
209         if (trans && trans->status != Disconnected)
210                 ts = trans->priv;
211
212         if (!ts)
213                 return -EREMOTEIO;
214
215         if (!(ts->wr->f_flags & O_NONBLOCK))
216                 P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
217
218         oldfs = get_fs();
219         set_fs(get_ds());
220         /* The cast to a user pointer is valid due to the set_fs() */
221         ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
222         set_fs(oldfs);
223
224         if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
225                 trans->status = Disconnected;
226         return ret;
227 }
228
229 static unsigned int
230 p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt)
231 {
232         int ret, n;
233         struct p9_trans_fd *ts = NULL;
234         mm_segment_t oldfs;
235
236         if (trans && trans->status == Connected)
237                 ts = trans->priv;
238
239         if (!ts)
240                 return -EREMOTEIO;
241
242         if (!ts->rd->f_op || !ts->rd->f_op->poll)
243                 return -EIO;
244
245         if (!ts->wr->f_op || !ts->wr->f_op->poll)
246                 return -EIO;
247
248         oldfs = get_fs();
249         set_fs(get_ds());
250
251         ret = ts->rd->f_op->poll(ts->rd, pt);
252         if (ret < 0)
253                 goto end;
254
255         if (ts->rd != ts->wr) {
256                 n = ts->wr->f_op->poll(ts->wr, pt);
257                 if (n < 0) {
258                         ret = n;
259                         goto end;
260                 }
261                 ret = (ret & ~POLLOUT) | (n & ~POLLIN);
262         }
263
264 end:
265         set_fs(oldfs);
266         return ret;
267 }
268
269 /**
270  * p9_sock_close - shutdown socket
271  * @trans: private socket structure
272  *
273  */
274 static void p9_fd_close(struct p9_trans *trans)
275 {
276         struct p9_trans_fd *ts;
277
278         if (!trans)
279                 return;
280
281         ts = xchg(&trans->priv, NULL);
282
283         if (!ts)
284                 return;
285
286         trans->status = Disconnected;
287         if (ts->rd)
288                 fput(ts->rd);
289         if (ts->wr)
290                 fput(ts->wr);
291         kfree(ts);
292 }
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");