OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [net/] [9p/] [trans_fd.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
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, Opt_err,
66
};
67
 
68
static match_table_t tokens = {
69
        {Opt_port, "port=%u"},
70
        {Opt_rfdno, "rfdno=%u"},
71
        {Opt_wfdno, "wfdno=%u"},
72
        {Opt_err, NULL},
73
};
74
 
75
/**
76
 * v9fs_parse_options - parse mount options into session structure
77
 * @options: options string passed from mount
78
 * @v9ses: existing v9fs session information
79
 *
80
 */
81
 
82
static void parse_opts(char *options, struct p9_fd_opts *opts)
83
{
84
        char *p;
85
        substring_t args[MAX_OPT_ARGS];
86
        int option;
87
        int ret;
88
 
89
        opts->port = P9_PORT;
90
        opts->rfd = ~0;
91
        opts->wfd = ~0;
92
 
93
        if (!options)
94
                return;
95
 
96
        while ((p = strsep(&options, ",")) != NULL) {
97
                int token;
98
                if (!*p)
99
                        continue;
100
                token = match_token(p, tokens, args);
101
                ret = match_int(&args[0], &option);
102
                if (ret < 0) {
103
                        P9_DPRINTK(P9_DEBUG_ERROR,
104
                         "integer field, but no integer?\n");
105
                        continue;
106
                }
107
                switch (token) {
108
                case Opt_port:
109
                        opts->port = option;
110
                        break;
111
                case Opt_rfdno:
112
                        opts->rfd = option;
113
                        break;
114
                case Opt_wfdno:
115
                        opts->wfd = option;
116
                        break;
117
                default:
118
                        continue;
119
                }
120
        }
121
}
122
 
123
static int p9_fd_open(struct p9_trans *trans, int rfd, int wfd)
124
{
125
        struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
126
                                           GFP_KERNEL);
127
        if (!ts)
128
                return -ENOMEM;
129
 
130
        ts->rd = fget(rfd);
131
        ts->wr = fget(wfd);
132
        if (!ts->rd || !ts->wr) {
133
                if (ts->rd)
134
                        fput(ts->rd);
135
                if (ts->wr)
136
                        fput(ts->wr);
137
                kfree(ts);
138
                return -EIO;
139
        }
140
 
141
        trans->priv = ts;
142
        trans->status = Connected;
143
 
144
        return 0;
145
}
146
 
147
static int p9_socket_open(struct p9_trans *trans, struct socket *csocket)
148
{
149
        int fd, ret;
150
 
151
        csocket->sk->sk_allocation = GFP_NOIO;
152
        fd = sock_map_fd(csocket);
153
        if (fd < 0) {
154
                P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
155
                return fd;
156
        }
157
 
158
        ret = p9_fd_open(trans, fd, fd);
159
        if (ret < 0) {
160
                P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n");
161
                sockfd_put(csocket);
162
                return ret;
163
        }
164
 
165
        ((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK;
166
 
167
        return 0;
168
}
169
 
170
/**
171
 * p9_fd_read- read from a fd
172
 * @v9ses: session information
173
 * @v: buffer to receive data into
174
 * @len: size of receive buffer
175
 *
176
 */
177
static int p9_fd_read(struct p9_trans *trans, void *v, int len)
178
{
179
        int ret;
180
        struct p9_trans_fd *ts = NULL;
181
 
182
        if (trans && trans->status != Disconnected)
183
                ts = trans->priv;
184
 
185
        if (!ts)
186
                return -EREMOTEIO;
187
 
188
        if (!(ts->rd->f_flags & O_NONBLOCK))
189
                P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
190
 
191
        ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
192
        if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
193
                trans->status = Disconnected;
194
        return ret;
195
}
196
 
197
/**
198
 * p9_fd_write - write to a socket
199
 * @v9ses: session information
200
 * @v: buffer to send data from
201
 * @len: size of send buffer
202
 *
203
 */
204
static int p9_fd_write(struct p9_trans *trans, void *v, int len)
205
{
206
        int ret;
207
        mm_segment_t oldfs;
208
        struct p9_trans_fd *ts = NULL;
209
 
210
        if (trans && trans->status != Disconnected)
211
                ts = trans->priv;
212
 
213
        if (!ts)
214
                return -EREMOTEIO;
215
 
216
        if (!(ts->wr->f_flags & O_NONBLOCK))
217
                P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
218
 
219
        oldfs = get_fs();
220
        set_fs(get_ds());
221
        /* The cast to a user pointer is valid due to the set_fs() */
222
        ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
223
        set_fs(oldfs);
224
 
225
        if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
226
                trans->status = Disconnected;
227
        return ret;
228
}
229
 
230
static unsigned int
231
p9_fd_poll(struct p9_trans *trans, struct poll_table_struct *pt)
232
{
233
        int ret, n;
234
        struct p9_trans_fd *ts = NULL;
235
        mm_segment_t oldfs;
236
 
237
        if (trans && trans->status == Connected)
238
                ts = trans->priv;
239
 
240
        if (!ts)
241
                return -EREMOTEIO;
242
 
243
        if (!ts->rd->f_op || !ts->rd->f_op->poll)
244
                return -EIO;
245
 
246
        if (!ts->wr->f_op || !ts->wr->f_op->poll)
247
                return -EIO;
248
 
249
        oldfs = get_fs();
250
        set_fs(get_ds());
251
 
252
        ret = ts->rd->f_op->poll(ts->rd, pt);
253
        if (ret < 0)
254
                goto end;
255
 
256
        if (ts->rd != ts->wr) {
257
                n = ts->wr->f_op->poll(ts->wr, pt);
258
                if (n < 0) {
259
                        ret = n;
260
                        goto end;
261
                }
262
                ret = (ret & ~POLLOUT) | (n & ~POLLIN);
263
        }
264
 
265
end:
266
        set_fs(oldfs);
267
        return ret;
268
}
269
 
270
/**
271
 * p9_sock_close - shutdown socket
272
 * @trans: private socket structure
273
 *
274
 */
275
static void p9_fd_close(struct p9_trans *trans)
276
{
277
        struct p9_trans_fd *ts;
278
 
279
        if (!trans)
280
                return;
281
 
282
        ts = xchg(&trans->priv, NULL);
283
 
284
        if (!ts)
285
                return;
286
 
287
        trans->status = Disconnected;
288
        if (ts->rd)
289
                fput(ts->rd);
290
        if (ts->wr)
291
                fput(ts->wr);
292
        kfree(ts);
293
}
294
 
295
static struct p9_trans *p9_trans_create_tcp(const char *addr, char *args)
296
{
297
        int err;
298
        struct p9_trans *trans;
299
        struct socket *csocket;
300
        struct sockaddr_in sin_server;
301
        struct p9_fd_opts opts;
302
 
303
        parse_opts(args, &opts);
304
 
305
        csocket = NULL;
306
        trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
307
        if (!trans)
308
                return ERR_PTR(-ENOMEM);
309
 
310
        trans->write = p9_fd_write;
311
        trans->read = p9_fd_read;
312
        trans->close = p9_fd_close;
313
        trans->poll = p9_fd_poll;
314
 
315
        sin_server.sin_family = AF_INET;
316
        sin_server.sin_addr.s_addr = in_aton(addr);
317
        sin_server.sin_port = htons(opts.port);
318
        sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
319
 
320
        if (!csocket) {
321
                P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
322
                err = -EIO;
323
                goto error;
324
        }
325
 
326
        err = csocket->ops->connect(csocket,
327
                                    (struct sockaddr *)&sin_server,
328
                                    sizeof(struct sockaddr_in), 0);
329
        if (err < 0) {
330
                P9_EPRINTK(KERN_ERR,
331
                        "p9_trans_tcp: problem connecting socket to %s\n",
332
                        addr);
333
                goto error;
334
        }
335
 
336
        err = p9_socket_open(trans, csocket);
337
        if (err < 0)
338
                goto error;
339
 
340
        return trans;
341
 
342
error:
343
        if (csocket)
344
                sock_release(csocket);
345
 
346
        kfree(trans);
347
        return ERR_PTR(err);
348
}
349
 
350
static struct p9_trans *p9_trans_create_unix(const char *addr, char *args)
351
{
352
        int err;
353
        struct socket *csocket;
354
        struct sockaddr_un sun_server;
355
        struct p9_trans *trans;
356
 
357
        csocket = NULL;
358
        trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
359
        if (!trans)
360
                return ERR_PTR(-ENOMEM);
361
 
362
        trans->write = p9_fd_write;
363
        trans->read = p9_fd_read;
364
        trans->close = p9_fd_close;
365
        trans->poll = p9_fd_poll;
366
 
367
        if (strlen(addr) > UNIX_PATH_MAX) {
368
                P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
369
                        addr);
370
                err = -ENAMETOOLONG;
371
                goto error;
372
        }
373
 
374
        sun_server.sun_family = PF_UNIX;
375
        strcpy(sun_server.sun_path, addr);
376
        sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
377
        err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
378
                        sizeof(struct sockaddr_un) - 1, 0);
379
        if (err < 0) {
380
                P9_EPRINTK(KERN_ERR,
381
                        "p9_trans_unix: problem connecting socket: %s: %d\n",
382
                        addr, err);
383
                goto error;
384
        }
385
 
386
        err = p9_socket_open(trans, csocket);
387
        if (err < 0)
388
                goto error;
389
 
390
        return trans;
391
 
392
error:
393
        if (csocket)
394
                sock_release(csocket);
395
 
396
        kfree(trans);
397
        return ERR_PTR(err);
398
}
399
 
400
static struct p9_trans *p9_trans_create_fd(const char *name, char *args)
401
{
402
        int err;
403
        struct p9_trans *trans;
404
        struct p9_fd_opts opts;
405
 
406
        parse_opts(args, &opts);
407
 
408
        if (opts.rfd == ~0 || opts.wfd == ~0) {
409
                printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
410
                return ERR_PTR(-ENOPROTOOPT);
411
        }
412
 
413
        trans = kmalloc(sizeof(struct p9_trans), GFP_KERNEL);
414
        if (!trans)
415
                return ERR_PTR(-ENOMEM);
416
 
417
        trans->write = p9_fd_write;
418
        trans->read = p9_fd_read;
419
        trans->close = p9_fd_close;
420
        trans->poll = p9_fd_poll;
421
 
422
        err = p9_fd_open(trans, opts.rfd, opts.wfd);
423
        if (err < 0)
424
                goto error;
425
 
426
        return trans;
427
 
428
error:
429
        kfree(trans);
430
        return ERR_PTR(err);
431
}
432
 
433
static struct p9_trans_module p9_tcp_trans = {
434
        .name = "tcp",
435
        .maxsize = MAX_SOCK_BUF,
436
        .def = 1,
437
        .create = p9_trans_create_tcp,
438
};
439
 
440
static struct p9_trans_module p9_unix_trans = {
441
        .name = "unix",
442
        .maxsize = MAX_SOCK_BUF,
443
        .def = 0,
444
        .create = p9_trans_create_unix,
445
};
446
 
447
static struct p9_trans_module p9_fd_trans = {
448
        .name = "fd",
449
        .maxsize = MAX_SOCK_BUF,
450
        .def = 0,
451
        .create = p9_trans_create_fd,
452
};
453
 
454
static int __init p9_trans_fd_init(void)
455
{
456
        v9fs_register_trans(&p9_tcp_trans);
457
        v9fs_register_trans(&p9_unix_trans);
458
        v9fs_register_trans(&p9_fd_trans);
459
 
460
        return 1;
461
}
462
 
463
static void __exit p9_trans_fd_exit(void) {
464
        printk(KERN_ERR "Removal of 9p transports not implemented\n");
465
        BUG();
466
}
467
 
468
module_init(p9_trans_fd_init);
469
module_exit(p9_trans_fd_exit);
470
 
471
MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
472
MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
473
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.