aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/9p/Kconfig21
-rw-r--r--net/9p/Makefile13
-rw-r--r--net/9p/client.c965
-rw-r--r--net/9p/conv.c903
-rw-r--r--net/9p/error.c240
-rw-r--r--net/9p/fcprint.c358
-rw-r--r--net/9p/mod.c85
-rw-r--r--net/9p/mux.c1054
-rw-r--r--net/9p/sysctl.c86
-rw-r--r--net/9p/trans_fd.c363
-rw-r--r--net/9p/util.c125
-rw-r--r--net/Kconfig1
-rw-r--r--net/Makefile1
13 files changed, 4215 insertions, 0 deletions
diff --git a/net/9p/Kconfig b/net/9p/Kconfig
new file mode 100644
index 000000000000..66821cd64a76
--- /dev/null
+++ b/net/9p/Kconfig
@@ -0,0 +1,21 @@
1#
2# 9P protocol configuration
3#
4
5menuconfig NET_9P
6 depends on NET && EXPERIMENTAL
7 tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
8 help
9 If you say Y here, you will get experimental support for
10 Plan 9 resource sharing via the 9P2000 protocol.
11
12 See <http://v9fs.sf.net> for more information.
13
14 If unsure, say N.
15
16config NET_9P_DEBUG
17 bool "Debug information"
18 depends on NET_9P
19 help
20 Say Y if you want the 9P subsistem to log debug information.
21
diff --git a/net/9p/Makefile b/net/9p/Makefile
new file mode 100644
index 000000000000..85b3a7838acf
--- /dev/null
+++ b/net/9p/Makefile
@@ -0,0 +1,13 @@
1obj-$(CONFIG_NET_9P) := 9pnet.o
2
39pnet-objs := \
4 mod.o \
5 trans_fd.o \
6 mux.o \
7 client.o \
8 conv.o \
9 error.o \
10 fcprint.o \
11 util.o \
12
139pnet-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/net/9p/client.c b/net/9p/client.c
new file mode 100644
index 000000000000..cb170750337c
--- /dev/null
+++ b/net/9p/client.c
@@ -0,0 +1,965 @@
1/*
2 * net/9p/clnt.c
3 *
4 * 9P Client
5 *
6 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to:
19 * Free Software Foundation
20 * 51 Franklin Street, Fifth Floor
21 * Boston, MA 02111-1301 USA
22 *
23 */
24
25#include <linux/module.h>
26#include <linux/errno.h>
27#include <linux/fs.h>
28#include <linux/idr.h>
29#include <linux/mutex.h>
30#include <linux/sched.h>
31#include <linux/uaccess.h>
32#include <net/9p/9p.h>
33#include <net/9p/transport.h>
34#include <net/9p/conn.h>
35#include <net/9p/client.h>
36
37static struct p9_fid *p9_fid_create(struct p9_client *clnt);
38static void p9_fid_destroy(struct p9_fid *fid);
39static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
40
41struct p9_client *p9_client_create(struct p9_transport *trans, int msize,
42 int dotu)
43{
44 int err, n;
45 struct p9_client *clnt;
46 struct p9_fcall *tc, *rc;
47 struct p9_str *version;
48
49 err = 0;
50 tc = NULL;
51 rc = NULL;
52 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
53 if (!clnt)
54 return ERR_PTR(-ENOMEM);
55
56 P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n",
57 clnt, trans, msize, dotu);
58 spin_lock_init(&clnt->lock);
59 clnt->trans = trans;
60 clnt->msize = msize;
61 clnt->dotu = dotu;
62 INIT_LIST_HEAD(&clnt->fidlist);
63 clnt->fidpool = p9_idpool_create();
64 if (!clnt->fidpool) {
65 err = PTR_ERR(clnt->fidpool);
66 clnt->fidpool = NULL;
67 goto error;
68 }
69
70 clnt->conn = p9_conn_create(clnt->trans, clnt->msize, &clnt->dotu);
71 if (IS_ERR(clnt->conn)) {
72 err = PTR_ERR(clnt->conn);
73 clnt->conn = NULL;
74 goto error;
75 }
76
77 tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000");
78 if (IS_ERR(tc)) {
79 err = PTR_ERR(tc);
80 tc = NULL;
81 goto error;
82 }
83
84 err = p9_conn_rpc(clnt->conn, tc, &rc);
85 if (err)
86 goto error;
87
88 version = &rc->params.rversion.version;
89 if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8))
90 clnt->dotu = 1;
91 else if (version->len == 6 && !memcmp(version->str, "9P2000", 6))
92 clnt->dotu = 0;
93 else {
94 err = -EREMOTEIO;
95 goto error;
96 }
97
98 n = rc->params.rversion.msize;
99 if (n < clnt->msize)
100 clnt->msize = n;
101
102 kfree(tc);
103 kfree(rc);
104 return clnt;
105
106error:
107 kfree(tc);
108 kfree(rc);
109 p9_client_destroy(clnt);
110 return ERR_PTR(err);
111}
112EXPORT_SYMBOL(p9_client_create);
113
114void p9_client_destroy(struct p9_client *clnt)
115{
116 struct p9_fid *fid, *fidptr;
117
118 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
119 if (clnt->conn) {
120 p9_conn_destroy(clnt->conn);
121 clnt->conn = NULL;
122 }
123
124 if (clnt->trans) {
125 clnt->trans->close(clnt->trans);
126 kfree(clnt->trans);
127 clnt->trans = NULL;
128 }
129
130 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
131 p9_fid_destroy(fid);
132
133 if (clnt->fidpool)
134 p9_idpool_destroy(clnt->fidpool);
135
136 kfree(clnt);
137}
138EXPORT_SYMBOL(p9_client_destroy);
139
140void p9_client_disconnect(struct p9_client *clnt)
141{
142 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
143 clnt->trans->status = Disconnected;
144 p9_conn_cancel(clnt->conn, -EIO);
145}
146EXPORT_SYMBOL(p9_client_disconnect);
147
148struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
149 char *uname, char *aname)
150{
151 int err;
152 struct p9_fcall *tc, *rc;
153 struct p9_fid *fid;
154
155 P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n",
156 clnt, afid?afid->fid:-1, uname, aname);
157 err = 0;
158 tc = NULL;
159 rc = NULL;
160
161 fid = p9_fid_create(clnt);
162 if (IS_ERR(fid)) {
163 err = PTR_ERR(fid);
164 fid = NULL;
165 goto error;
166 }
167
168 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname);
169 if (IS_ERR(tc)) {
170 err = PTR_ERR(tc);
171 tc = NULL;
172 goto error;
173 }
174
175 err = p9_conn_rpc(clnt->conn, tc, &rc);
176 if (err)
177 goto error;
178
179 memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid));
180 kfree(tc);
181 kfree(rc);
182 return fid;
183
184error:
185 kfree(tc);
186 kfree(rc);
187 if (fid)
188 p9_fid_destroy(fid);
189 return ERR_PTR(err);
190}
191EXPORT_SYMBOL(p9_client_attach);
192
193struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname)
194{
195 int err;
196 struct p9_fcall *tc, *rc;
197 struct p9_fid *fid;
198
199 P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname,
200 aname);
201 err = 0;
202 tc = NULL;
203 rc = NULL;
204
205 fid = p9_fid_create(clnt);
206 if (IS_ERR(fid)) {
207 err = PTR_ERR(fid);
208 fid = NULL;
209 goto error;
210 }
211
212 tc = p9_create_tauth(fid->fid, uname, aname);
213 if (IS_ERR(tc)) {
214 err = PTR_ERR(tc);
215 tc = NULL;
216 goto error;
217 }
218
219 err = p9_conn_rpc(clnt->conn, tc, &rc);
220 if (err)
221 goto error;
222
223 memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid));
224 kfree(tc);
225 kfree(rc);
226 return fid;
227
228error:
229 kfree(tc);
230 kfree(rc);
231 if (fid)
232 p9_fid_destroy(fid);
233 return ERR_PTR(err);
234}
235EXPORT_SYMBOL(p9_client_auth);
236
237struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
238 int clone)
239{
240 int err;
241 struct p9_fcall *tc, *rc;
242 struct p9_client *clnt;
243 struct p9_fid *fid;
244
245 P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n",
246 oldfid->fid, nwname, wnames?wnames[0]:NULL);
247 err = 0;
248 tc = NULL;
249 rc = NULL;
250 clnt = oldfid->clnt;
251 if (clone) {
252 fid = p9_fid_create(clnt);
253 if (IS_ERR(fid)) {
254 err = PTR_ERR(fid);
255 fid = NULL;
256 goto error;
257 }
258
259 fid->uid = oldfid->uid;
260 } else
261 fid = oldfid;
262
263 tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames);
264 if (IS_ERR(tc)) {
265 err = PTR_ERR(tc);
266 tc = NULL;
267 goto error;
268 }
269
270 err = p9_conn_rpc(clnt->conn, tc, &rc);
271 if (err) {
272 if (rc && rc->id == P9_RWALK)
273 goto clunk_fid;
274 else
275 goto error;
276 }
277
278 if (rc->params.rwalk.nwqid != nwname) {
279 err = -ENOENT;
280 goto clunk_fid;
281 }
282
283 if (nwname)
284 memmove(&fid->qid,
285 &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1],
286 sizeof(struct p9_qid));
287 else
288 fid->qid = oldfid->qid;
289
290 kfree(tc);
291 kfree(rc);
292 return fid;
293
294clunk_fid:
295 kfree(tc);
296 kfree(rc);
297 rc = NULL;
298 tc = p9_create_tclunk(fid->fid);
299 if (IS_ERR(tc)) {
300 err = PTR_ERR(tc);
301 tc = NULL;
302 goto error;
303 }
304
305 p9_conn_rpc(clnt->conn, tc, &rc);
306
307error:
308 kfree(tc);
309 kfree(rc);
310 if (fid && (fid != oldfid))
311 p9_fid_destroy(fid);
312
313 return ERR_PTR(err);
314}
315EXPORT_SYMBOL(p9_client_walk);
316
317int p9_client_open(struct p9_fid *fid, int mode)
318{
319 int err;
320 struct p9_fcall *tc, *rc;
321 struct p9_client *clnt;
322
323 P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode);
324 err = 0;
325 tc = NULL;
326 rc = NULL;
327 clnt = fid->clnt;
328
329 if (fid->mode != -1)
330 return -EINVAL;
331
332 tc = p9_create_topen(fid->fid, mode);
333 if (IS_ERR(tc)) {
334 err = PTR_ERR(tc);
335 tc = NULL;
336 goto done;
337 }
338
339 err = p9_conn_rpc(clnt->conn, tc, &rc);
340 if (err)
341 goto done;
342
343 fid->mode = mode;
344 fid->iounit = rc->params.ropen.iounit;
345
346done:
347 kfree(tc);
348 kfree(rc);
349 return err;
350}
351EXPORT_SYMBOL(p9_client_open);
352
353int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
354 char *extension)
355{
356 int err;
357 struct p9_fcall *tc, *rc;
358 struct p9_client *clnt;
359
360 P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid,
361 name, perm, mode);
362 err = 0;
363 tc = NULL;
364 rc = NULL;
365 clnt = fid->clnt;
366
367 if (fid->mode != -1)
368 return -EINVAL;
369
370 tc = p9_create_tcreate(fid->fid, name, perm, mode, extension,
371 clnt->dotu);
372 if (IS_ERR(tc)) {
373 err = PTR_ERR(tc);
374 tc = NULL;
375 goto done;
376 }
377
378 err = p9_conn_rpc(clnt->conn, tc, &rc);
379 if (err)
380 goto done;
381
382 fid->mode = mode;
383 fid->iounit = rc->params.ropen.iounit;
384
385done:
386 kfree(tc);
387 kfree(rc);
388 return err;
389}
390EXPORT_SYMBOL(p9_client_fcreate);
391
392int p9_client_clunk(struct p9_fid *fid)
393{
394 int err;
395 struct p9_fcall *tc, *rc;
396 struct p9_client *clnt;
397
398 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
399 err = 0;
400 tc = NULL;
401 rc = NULL;
402 clnt = fid->clnt;
403
404 tc = p9_create_tclunk(fid->fid);
405 if (IS_ERR(tc)) {
406 err = PTR_ERR(tc);
407 tc = NULL;
408 goto done;
409 }
410
411 err = p9_conn_rpc(clnt->conn, tc, &rc);
412 if (err)
413 goto done;
414
415 p9_fid_destroy(fid);
416
417done:
418 kfree(tc);
419 kfree(rc);
420 return err;
421}
422EXPORT_SYMBOL(p9_client_clunk);
423
424int p9_client_remove(struct p9_fid *fid)
425{
426 int err;
427 struct p9_fcall *tc, *rc;
428 struct p9_client *clnt;
429
430 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
431 err = 0;
432 tc = NULL;
433 rc = NULL;
434 clnt = fid->clnt;
435
436 tc = p9_create_tremove(fid->fid);
437 if (IS_ERR(tc)) {
438 err = PTR_ERR(tc);
439 tc = NULL;
440 goto done;
441 }
442
443 err = p9_conn_rpc(clnt->conn, tc, &rc);
444 if (err)
445 goto done;
446
447 p9_fid_destroy(fid);
448
449done:
450 kfree(tc);
451 kfree(rc);
452 return err;
453}
454EXPORT_SYMBOL(p9_client_remove);
455
456int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
457{
458 int err, n, rsize, total;
459 struct p9_fcall *tc, *rc;
460 struct p9_client *clnt;
461
462 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid,
463 (long long unsigned) offset, count);
464 err = 0;
465 tc = NULL;
466 rc = NULL;
467 clnt = fid->clnt;
468 total = 0;
469
470 rsize = fid->iounit;
471 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
472 rsize = clnt->msize - P9_IOHDRSZ;
473
474 do {
475 if (count < rsize)
476 rsize = count;
477
478 tc = p9_create_tread(fid->fid, offset, rsize);
479 if (IS_ERR(tc)) {
480 err = PTR_ERR(tc);
481 tc = NULL;
482 goto error;
483 }
484
485 err = p9_conn_rpc(clnt->conn, tc, &rc);
486 if (err)
487 goto error;
488
489 n = rc->params.rread.count;
490 if (n > count)
491 n = count;
492
493 memmove(data, rc->params.rread.data, n);
494 count -= n;
495 data += n;
496 offset += n;
497 total += n;
498 kfree(tc);
499 tc = NULL;
500 kfree(rc);
501 rc = NULL;
502 } while (count > 0 && n == rsize);
503
504 return total;
505
506error:
507 kfree(tc);
508 kfree(rc);
509 return err;
510}
511EXPORT_SYMBOL(p9_client_read);
512
513int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
514{
515 int err, n, rsize, total;
516 struct p9_fcall *tc, *rc;
517 struct p9_client *clnt;
518
519 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
520 (long long unsigned) offset, count);
521 err = 0;
522 tc = NULL;
523 rc = NULL;
524 clnt = fid->clnt;
525 total = 0;
526
527 rsize = fid->iounit;
528 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
529 rsize = clnt->msize - P9_IOHDRSZ;
530
531 do {
532 if (count < rsize)
533 rsize = count;
534
535 tc = p9_create_twrite(fid->fid, offset, rsize, data);
536 if (IS_ERR(tc)) {
537 err = PTR_ERR(tc);
538 tc = NULL;
539 goto error;
540 }
541
542 err = p9_conn_rpc(clnt->conn, tc, &rc);
543 if (err)
544 goto error;
545
546 n = rc->params.rread.count;
547 count -= n;
548 data += n;
549 offset += n;
550 total += n;
551 kfree(tc);
552 tc = NULL;
553 kfree(rc);
554 rc = NULL;
555 } while (count > 0);
556
557 return total;
558
559error:
560 kfree(tc);
561 kfree(rc);
562 return err;
563}
564EXPORT_SYMBOL(p9_client_write);
565
566int
567p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
568{
569 int err, n, rsize, total;
570 struct p9_fcall *tc, *rc;
571 struct p9_client *clnt;
572
573 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
574 (long long unsigned) offset, count);
575 err = 0;
576 tc = NULL;
577 rc = NULL;
578 clnt = fid->clnt;
579 total = 0;
580
581 rsize = fid->iounit;
582 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
583 rsize = clnt->msize - P9_IOHDRSZ;
584
585 do {
586 if (count < rsize)
587 rsize = count;
588
589 tc = p9_create_tread(fid->fid, offset, rsize);
590 if (IS_ERR(tc)) {
591 err = PTR_ERR(tc);
592 tc = NULL;
593 goto error;
594 }
595
596 err = p9_conn_rpc(clnt->conn, tc, &rc);
597 if (err)
598 goto error;
599
600 n = rc->params.rread.count;
601 if (n > count)
602 n = count;
603
604 err = copy_to_user(data, rc->params.rread.data, n);
605 if (err) {
606 err = -EFAULT;
607 goto error;
608 }
609
610 count -= n;
611 data += n;
612 offset += n;
613 total += n;
614 kfree(tc);
615 tc = NULL;
616 kfree(rc);
617 rc = NULL;
618 } while (count > 0 && n == rsize);
619
620 return total;
621
622error:
623 kfree(tc);
624 kfree(rc);
625 return err;
626}
627EXPORT_SYMBOL(p9_client_uread);
628
629int
630p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
631 u32 count)
632{
633 int err, n, rsize, total;
634 struct p9_fcall *tc, *rc;
635 struct p9_client *clnt;
636
637 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
638 (long long unsigned) offset, count);
639 err = 0;
640 tc = NULL;
641 rc = NULL;
642 clnt = fid->clnt;
643 total = 0;
644
645 rsize = fid->iounit;
646 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
647 rsize = clnt->msize - P9_IOHDRSZ;
648
649 do {
650 if (count < rsize)
651 rsize = count;
652
653 tc = p9_create_twrite_u(fid->fid, offset, rsize, data);
654 if (IS_ERR(tc)) {
655 err = PTR_ERR(tc);
656 tc = NULL;
657 goto error;
658 }
659
660 err = p9_conn_rpc(clnt->conn, tc, &rc);
661 if (err)
662 goto error;
663
664 n = rc->params.rread.count;
665 count -= n;
666 data += n;
667 offset += n;
668 total += n;
669 kfree(tc);
670 tc = NULL;
671 kfree(rc);
672 rc = NULL;
673 } while (count > 0);
674
675 return total;
676
677error:
678 kfree(tc);
679 kfree(rc);
680 return err;
681}
682EXPORT_SYMBOL(p9_client_uwrite);
683
684int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count)
685{
686 int n, total;
687
688 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
689 (long long unsigned) offset, count);
690 n = 0;
691 total = 0;
692 while (count) {
693 n = p9_client_read(fid, data, offset, count);
694 if (n <= 0)
695 break;
696
697 data += n;
698 offset += n;
699 count -= n;
700 total += n;
701 }
702
703 if (n < 0)
704 total = n;
705
706 return total;
707}
708EXPORT_SYMBOL(p9_client_readn);
709
710struct p9_stat *p9_client_stat(struct p9_fid *fid)
711{
712 int err;
713 struct p9_fcall *tc, *rc;
714 struct p9_client *clnt;
715 struct p9_stat *ret;
716
717 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
718 err = 0;
719 tc = NULL;
720 rc = NULL;
721 ret = NULL;
722 clnt = fid->clnt;
723
724 tc = p9_create_tstat(fid->fid);
725 if (IS_ERR(tc)) {
726 err = PTR_ERR(tc);
727 tc = NULL;
728 goto error;
729 }
730
731 err = p9_conn_rpc(clnt->conn, tc, &rc);
732 if (err)
733 goto error;
734
735 ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu);
736 if (IS_ERR(ret)) {
737 err = PTR_ERR(ret);
738 ret = NULL;
739 goto error;
740 }
741
742 kfree(tc);
743 kfree(rc);
744 return ret;
745
746error:
747 kfree(tc);
748 kfree(rc);
749 kfree(ret);
750 return ERR_PTR(err);
751}
752EXPORT_SYMBOL(p9_client_stat);
753
754int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
755{
756 int err;
757 struct p9_fcall *tc, *rc;
758 struct p9_client *clnt;
759
760 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
761 err = 0;
762 tc = NULL;
763 rc = NULL;
764 clnt = fid->clnt;
765
766 tc = p9_create_twstat(fid->fid, wst, clnt->dotu);
767 if (IS_ERR(tc)) {
768 err = PTR_ERR(tc);
769 tc = NULL;
770 goto done;
771 }
772
773 err = p9_conn_rpc(clnt->conn, tc, &rc);
774
775done:
776 kfree(tc);
777 kfree(rc);
778 return err;
779}
780EXPORT_SYMBOL(p9_client_wstat);
781
782struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
783{
784 int err, n, m;
785 struct p9_fcall *tc, *rc;
786 struct p9_client *clnt;
787 struct p9_stat st, *ret;
788
789 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid,
790 (long long unsigned) offset);
791 err = 0;
792 tc = NULL;
793 rc = NULL;
794 ret = NULL;
795 clnt = fid->clnt;
796
797 /* if the offset is below or above the current response, free it */
798 if (offset < fid->rdir_fpos || (fid->rdir_fcall &&
799 offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) {
800 fid->rdir_pos = 0;
801 if (fid->rdir_fcall)
802 fid->rdir_fpos += fid->rdir_fcall->params.rread.count;
803
804 kfree(fid->rdir_fcall);
805 fid->rdir_fcall = NULL;
806 if (offset < fid->rdir_fpos)
807 fid->rdir_fpos = 0;
808 }
809
810 if (!fid->rdir_fcall) {
811 n = fid->iounit;
812 if (!n || n > clnt->msize-P9_IOHDRSZ)
813 n = clnt->msize - P9_IOHDRSZ;
814
815 while (1) {
816 if (fid->rdir_fcall) {
817 fid->rdir_fpos +=
818 fid->rdir_fcall->params.rread.count;
819 kfree(fid->rdir_fcall);
820 fid->rdir_fcall = NULL;
821 }
822
823 tc = p9_create_tread(fid->fid, fid->rdir_fpos, n);
824 if (IS_ERR(tc)) {
825 err = PTR_ERR(tc);
826 tc = NULL;
827 goto error;
828 }
829
830 err = p9_conn_rpc(clnt->conn, tc, &rc);
831 if (err)
832 goto error;
833
834 n = rc->params.rread.count;
835 if (n == 0)
836 goto done;
837
838 fid->rdir_fcall = rc;
839 rc = NULL;
840 if (offset >= fid->rdir_fpos &&
841 offset < fid->rdir_fpos+n)
842 break;
843 }
844
845 fid->rdir_pos = 0;
846 }
847
848 m = offset - fid->rdir_fpos;
849 if (m < 0)
850 goto done;
851
852 n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m,
853 fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu);
854
855 if (!n) {
856 err = -EIO;
857 goto error;
858 }
859
860 fid->rdir_pos += n;
861 st.size = n;
862 ret = p9_clone_stat(&st, clnt->dotu);
863 if (IS_ERR(ret)) {
864 err = PTR_ERR(ret);
865 ret = NULL;
866 goto error;
867 }
868
869done:
870 kfree(tc);
871 kfree(rc);
872 return ret;
873
874error:
875 kfree(tc);
876 kfree(rc);
877 kfree(ret);
878 return ERR_PTR(err);
879}
880EXPORT_SYMBOL(p9_client_dirread);
881
882static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
883{
884 int n;
885 char *p;
886 struct p9_stat *ret;
887
888 n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len +
889 st->muid.len;
890
891 if (dotu)
892 n += st->extension.len;
893
894 ret = kmalloc(n, GFP_KERNEL);
895 if (!ret)
896 return ERR_PTR(-ENOMEM);
897
898 memmove(ret, st, sizeof(struct p9_stat));
899 p = ((char *) ret) + sizeof(struct p9_stat);
900 memmove(p, st->name.str, st->name.len);
901 p += st->name.len;
902 memmove(p, st->uid.str, st->uid.len);
903 p += st->uid.len;
904 memmove(p, st->gid.str, st->gid.len);
905 p += st->gid.len;
906 memmove(p, st->muid.str, st->muid.len);
907 p += st->muid.len;
908
909 if (dotu) {
910 memmove(p, st->extension.str, st->extension.len);
911 p += st->extension.len;
912 }
913
914 return ret;
915}
916
917static struct p9_fid *p9_fid_create(struct p9_client *clnt)
918{
919 int err;
920 struct p9_fid *fid;
921
922 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
923 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
924 if (!fid)
925 return ERR_PTR(-ENOMEM);
926
927 fid->fid = p9_idpool_get(clnt->fidpool);
928 if (fid->fid < 0) {
929 err = -ENOSPC;
930 goto error;
931 }
932
933 memset(&fid->qid, 0, sizeof(struct p9_qid));
934 fid->mode = -1;
935 fid->rdir_fpos = 0;
936 fid->rdir_pos = 0;
937 fid->rdir_fcall = NULL;
938 fid->uid = current->fsuid;
939 fid->clnt = clnt;
940 fid->aux = NULL;
941
942 spin_lock(&clnt->lock);
943 list_add(&fid->flist, &clnt->fidlist);
944 spin_unlock(&clnt->lock);
945
946 return fid;
947
948error:
949 kfree(fid);
950 return ERR_PTR(err);
951}
952
953static void p9_fid_destroy(struct p9_fid *fid)
954{
955 struct p9_client *clnt;
956
957 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
958 clnt = fid->clnt;
959 p9_idpool_put(fid->fid, clnt->fidpool);
960 spin_lock(&clnt->lock);
961 list_del(&fid->flist);
962 spin_unlock(&clnt->lock);
963 kfree(fid->rdir_fcall);
964 kfree(fid);
965}
diff --git a/net/9p/conv.c b/net/9p/conv.c
new file mode 100644
index 000000000000..37451178e761
--- /dev/null
+++ b/net/9p/conv.c
@@ -0,0 +1,903 @@
1/*
2 * net/9p/conv.c
3 *
4 * 9P protocol conversion functions
5 *
6 * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net>
7 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/fs.h>
30#include <linux/sched.h>
31#include <linux/idr.h>
32#include <linux/uaccess.h>
33#include <net/9p/9p.h>
34
35/*
36 * Buffer to help with string parsing
37 */
38struct cbuf {
39 unsigned char *sp;
40 unsigned char *p;
41 unsigned char *ep;
42};
43
44static inline void buf_init(struct cbuf *buf, void *data, int datalen)
45{
46 buf->sp = buf->p = data;
47 buf->ep = data + datalen;
48}
49
50static inline int buf_check_overflow(struct cbuf *buf)
51{
52 return buf->p > buf->ep;
53}
54
55static int buf_check_size(struct cbuf *buf, int len)
56{
57 if (buf->p + len > buf->ep) {
58 if (buf->p < buf->ep) {
59 P9_EPRINTK(KERN_ERR,
60 "buffer overflow: want %d has %d\n", len,
61 (int)(buf->ep - buf->p));
62 dump_stack();
63 buf->p = buf->ep + 1;
64 }
65
66 return 0;
67 }
68
69 return 1;
70}
71
72static void *buf_alloc(struct cbuf *buf, int len)
73{
74 void *ret = NULL;
75
76 if (buf_check_size(buf, len)) {
77 ret = buf->p;
78 buf->p += len;
79 }
80
81 return ret;
82}
83
84static void buf_put_int8(struct cbuf *buf, u8 val)
85{
86 if (buf_check_size(buf, 1)) {
87 buf->p[0] = val;
88 buf->p++;
89 }
90}
91
92static void buf_put_int16(struct cbuf *buf, u16 val)
93{
94 if (buf_check_size(buf, 2)) {
95 *(__le16 *) buf->p = cpu_to_le16(val);
96 buf->p += 2;
97 }
98}
99
100static void buf_put_int32(struct cbuf *buf, u32 val)
101{
102 if (buf_check_size(buf, 4)) {
103 *(__le32 *)buf->p = cpu_to_le32(val);
104 buf->p += 4;
105 }
106}
107
108static void buf_put_int64(struct cbuf *buf, u64 val)
109{
110 if (buf_check_size(buf, 8)) {
111 *(__le64 *)buf->p = cpu_to_le64(val);
112 buf->p += 8;
113 }
114}
115
116static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
117{
118 char *ret;
119
120 ret = NULL;
121 if (buf_check_size(buf, slen + 2)) {
122 buf_put_int16(buf, slen);
123 ret = buf->p;
124 memcpy(buf->p, s, slen);
125 buf->p += slen;
126 }
127
128 return ret;
129}
130
131static inline void buf_put_string(struct cbuf *buf, const char *s)
132{
133 buf_put_stringn(buf, s, strlen(s));
134}
135
136static u8 buf_get_int8(struct cbuf *buf)
137{
138 u8 ret = 0;
139
140 if (buf_check_size(buf, 1)) {
141 ret = buf->p[0];
142 buf->p++;
143 }
144
145 return ret;
146}
147
148static u16 buf_get_int16(struct cbuf *buf)
149{
150 u16 ret = 0;
151
152 if (buf_check_size(buf, 2)) {
153 ret = le16_to_cpu(*(__le16 *)buf->p);
154 buf->p += 2;
155 }
156
157 return ret;
158}
159
160static u32 buf_get_int32(struct cbuf *buf)
161{
162 u32 ret = 0;
163
164 if (buf_check_size(buf, 4)) {
165 ret = le32_to_cpu(*(__le32 *)buf->p);
166 buf->p += 4;
167 }
168
169 return ret;
170}
171
172static u64 buf_get_int64(struct cbuf *buf)
173{
174 u64 ret = 0;
175
176 if (buf_check_size(buf, 8)) {
177 ret = le64_to_cpu(*(__le64 *)buf->p);
178 buf->p += 8;
179 }
180
181 return ret;
182}
183
184static void buf_get_str(struct cbuf *buf, struct p9_str *vstr)
185{
186 vstr->len = buf_get_int16(buf);
187 if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
188 vstr->str = buf->p;
189 buf->p += vstr->len;
190 } else {
191 vstr->len = 0;
192 vstr->str = NULL;
193 }
194}
195
196static void buf_get_qid(struct cbuf *bufp, struct p9_qid *qid)
197{
198 qid->type = buf_get_int8(bufp);
199 qid->version = buf_get_int32(bufp);
200 qid->path = buf_get_int64(bufp);
201}
202
203/**
204 * p9_size_wstat - calculate the size of a variable length stat struct
205 * @stat: metadata (stat) structure
206 * @dotu: non-zero if 9P2000.u
207 *
208 */
209
210static int p9_size_wstat(struct p9_wstat *wstat, int dotu)
211{
212 int size = 0;
213
214 if (wstat == NULL) {
215 P9_EPRINTK(KERN_ERR, "p9_size_stat: got a NULL stat pointer\n");
216 return 0;
217 }
218
219 size = /* 2 + *//* size[2] */
220 2 + /* type[2] */
221 4 + /* dev[4] */
222 1 + /* qid.type[1] */
223 4 + /* qid.vers[4] */
224 8 + /* qid.path[8] */
225 4 + /* mode[4] */
226 4 + /* atime[4] */
227 4 + /* mtime[4] */
228 8 + /* length[8] */
229 8; /* minimum sum of string lengths */
230
231 if (wstat->name)
232 size += strlen(wstat->name);
233 if (wstat->uid)
234 size += strlen(wstat->uid);
235 if (wstat->gid)
236 size += strlen(wstat->gid);
237 if (wstat->muid)
238 size += strlen(wstat->muid);
239
240 if (dotu) {
241 size += 4 + /* n_uid[4] */
242 4 + /* n_gid[4] */
243 4 + /* n_muid[4] */
244 2; /* string length of extension[4] */
245 if (wstat->extension)
246 size += strlen(wstat->extension);
247 }
248
249 return size;
250}
251
252/**
253 * buf_get_stat - safely decode a recieved metadata (stat) structure
254 * @bufp: buffer to deserialize
255 * @stat: metadata (stat) structure
256 * @dotu: non-zero if 9P2000.u
257 *
258 */
259
260static void
261buf_get_stat(struct cbuf *bufp, struct p9_stat *stat, int dotu)
262{
263 stat->size = buf_get_int16(bufp);
264 stat->type = buf_get_int16(bufp);
265 stat->dev = buf_get_int32(bufp);
266 stat->qid.type = buf_get_int8(bufp);
267 stat->qid.version = buf_get_int32(bufp);
268 stat->qid.path = buf_get_int64(bufp);
269 stat->mode = buf_get_int32(bufp);
270 stat->atime = buf_get_int32(bufp);
271 stat->mtime = buf_get_int32(bufp);
272 stat->length = buf_get_int64(bufp);
273 buf_get_str(bufp, &stat->name);
274 buf_get_str(bufp, &stat->uid);
275 buf_get_str(bufp, &stat->gid);
276 buf_get_str(bufp, &stat->muid);
277
278 if (dotu) {
279 buf_get_str(bufp, &stat->extension);
280 stat->n_uid = buf_get_int32(bufp);
281 stat->n_gid = buf_get_int32(bufp);
282 stat->n_muid = buf_get_int32(bufp);
283 }
284}
285
286/**
287 * p9_deserialize_stat - decode a received metadata structure
288 * @buf: buffer to deserialize
289 * @buflen: length of received buffer
290 * @stat: metadata structure to decode into
291 * @dotu: non-zero if 9P2000.u
292 *
293 * Note: stat will point to the buf region.
294 */
295
296int
297p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat,
298 int dotu)
299{
300 struct cbuf buffer;
301 struct cbuf *bufp = &buffer;
302 unsigned char *p;
303
304 buf_init(bufp, buf, buflen);
305 p = bufp->p;
306 buf_get_stat(bufp, stat, dotu);
307
308 if (buf_check_overflow(bufp))
309 return 0;
310 else
311 return bufp->p - p;
312}
313EXPORT_SYMBOL(p9_deserialize_stat);
314
315/**
316 * deserialize_fcall - unmarshal a response
317 * @buf: recieved buffer
318 * @buflen: length of received buffer
319 * @rcall: fcall structure to populate
320 * @rcalllen: length of fcall structure to populate
321 * @dotu: non-zero if 9P2000.u
322 *
323 */
324
325int
326p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *rcall,
327 int dotu)
328{
329
330 struct cbuf buffer;
331 struct cbuf *bufp = &buffer;
332 int i = 0;
333
334 buf_init(bufp, buf, buflen);
335
336 rcall->size = buf_get_int32(bufp);
337 rcall->id = buf_get_int8(bufp);
338 rcall->tag = buf_get_int16(bufp);
339
340 P9_DPRINTK(P9_DEBUG_CONV, "size %d id %d tag %d\n", rcall->size,
341 rcall->id, rcall->tag);
342
343 switch (rcall->id) {
344 default:
345 P9_EPRINTK(KERN_ERR, "unknown message type: %d\n", rcall->id);
346 return -EPROTO;
347 case P9_RVERSION:
348 rcall->params.rversion.msize = buf_get_int32(bufp);
349 buf_get_str(bufp, &rcall->params.rversion.version);
350 break;
351 case P9_RFLUSH:
352 break;
353 case P9_RATTACH:
354 rcall->params.rattach.qid.type = buf_get_int8(bufp);
355 rcall->params.rattach.qid.version = buf_get_int32(bufp);
356 rcall->params.rattach.qid.path = buf_get_int64(bufp);
357 break;
358 case P9_RWALK:
359 rcall->params.rwalk.nwqid = buf_get_int16(bufp);
360 if (rcall->params.rwalk.nwqid > P9_MAXWELEM) {
361 P9_EPRINTK(KERN_ERR,
362 "Rwalk with more than %d qids: %d\n",
363 P9_MAXWELEM, rcall->params.rwalk.nwqid);
364 return -EPROTO;
365 }
366
367 for (i = 0; i < rcall->params.rwalk.nwqid; i++)
368 buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
369 break;
370 case P9_ROPEN:
371 buf_get_qid(bufp, &rcall->params.ropen.qid);
372 rcall->params.ropen.iounit = buf_get_int32(bufp);
373 break;
374 case P9_RCREATE:
375 buf_get_qid(bufp, &rcall->params.rcreate.qid);
376 rcall->params.rcreate.iounit = buf_get_int32(bufp);
377 break;
378 case P9_RREAD:
379 rcall->params.rread.count = buf_get_int32(bufp);
380 rcall->params.rread.data = bufp->p;
381 buf_check_size(bufp, rcall->params.rread.count);
382 break;
383 case P9_RWRITE:
384 rcall->params.rwrite.count = buf_get_int32(bufp);
385 break;
386 case P9_RCLUNK:
387 break;
388 case P9_RREMOVE:
389 break;
390 case P9_RSTAT:
391 buf_get_int16(bufp);
392 buf_get_stat(bufp, &rcall->params.rstat.stat, dotu);
393 break;
394 case P9_RWSTAT:
395 break;
396 case P9_RERROR:
397 buf_get_str(bufp, &rcall->params.rerror.error);
398 if (dotu)
399 rcall->params.rerror.errno = buf_get_int16(bufp);
400 break;
401 }
402
403 if (buf_check_overflow(bufp)) {
404 P9_DPRINTK(P9_DEBUG_ERROR, "buffer overflow\n");
405 return -EIO;
406 }
407
408 return bufp->p - bufp->sp;
409}
410EXPORT_SYMBOL(p9_deserialize_fcall);
411
412static inline void p9_put_int8(struct cbuf *bufp, u8 val, u8 * p)
413{
414 *p = val;
415 buf_put_int8(bufp, val);
416}
417
418static inline void p9_put_int16(struct cbuf *bufp, u16 val, u16 * p)
419{
420 *p = val;
421 buf_put_int16(bufp, val);
422}
423
424static inline void p9_put_int32(struct cbuf *bufp, u32 val, u32 * p)
425{
426 *p = val;
427 buf_put_int32(bufp, val);
428}
429
430static inline void p9_put_int64(struct cbuf *bufp, u64 val, u64 * p)
431{
432 *p = val;
433 buf_put_int64(bufp, val);
434}
435
436static void
437p9_put_str(struct cbuf *bufp, char *data, struct p9_str *str)
438{
439 int len;
440 char *s;
441
442 if (data)
443 len = strlen(data);
444 else
445 len = 0;
446
447 s = buf_put_stringn(bufp, data, len);
448 if (str) {
449 str->len = len;
450 str->str = s;
451 }
452}
453
454static int
455p9_put_data(struct cbuf *bufp, const char *data, int count,
456 unsigned char **pdata)
457{
458 *pdata = buf_alloc(bufp, count);
459 memmove(*pdata, data, count);
460 return count;
461}
462
463static int
464p9_put_user_data(struct cbuf *bufp, const char __user *data, int count,
465 unsigned char **pdata)
466{
467 *pdata = buf_alloc(bufp, count);
468 return copy_from_user(*pdata, data, count);
469}
470
471static void
472p9_put_wstat(struct cbuf *bufp, struct p9_wstat *wstat,
473 struct p9_stat *stat, int statsz, int dotu)
474{
475 p9_put_int16(bufp, statsz, &stat->size);
476 p9_put_int16(bufp, wstat->type, &stat->type);
477 p9_put_int32(bufp, wstat->dev, &stat->dev);
478 p9_put_int8(bufp, wstat->qid.type, &stat->qid.type);
479 p9_put_int32(bufp, wstat->qid.version, &stat->qid.version);
480 p9_put_int64(bufp, wstat->qid.path, &stat->qid.path);
481 p9_put_int32(bufp, wstat->mode, &stat->mode);
482 p9_put_int32(bufp, wstat->atime, &stat->atime);
483 p9_put_int32(bufp, wstat->mtime, &stat->mtime);
484 p9_put_int64(bufp, wstat->length, &stat->length);
485
486 p9_put_str(bufp, wstat->name, &stat->name);
487 p9_put_str(bufp, wstat->uid, &stat->uid);
488 p9_put_str(bufp, wstat->gid, &stat->gid);
489 p9_put_str(bufp, wstat->muid, &stat->muid);
490
491 if (dotu) {
492 p9_put_str(bufp, wstat->extension, &stat->extension);
493 p9_put_int32(bufp, wstat->n_uid, &stat->n_uid);
494 p9_put_int32(bufp, wstat->n_gid, &stat->n_gid);
495 p9_put_int32(bufp, wstat->n_muid, &stat->n_muid);
496 }
497}
498
499static struct p9_fcall *
500p9_create_common(struct cbuf *bufp, u32 size, u8 id)
501{
502 struct p9_fcall *fc;
503
504 size += 4 + 1 + 2; /* size[4] id[1] tag[2] */
505 fc = kmalloc(sizeof(struct p9_fcall) + size, GFP_KERNEL);
506 if (!fc)
507 return ERR_PTR(-ENOMEM);
508
509 fc->sdata = (char *)fc + sizeof(*fc);
510
511 buf_init(bufp, (char *)fc->sdata, size);
512 p9_put_int32(bufp, size, &fc->size);
513 p9_put_int8(bufp, id, &fc->id);
514 p9_put_int16(bufp, P9_NOTAG, &fc->tag);
515
516 return fc;
517}
518
519void p9_set_tag(struct p9_fcall *fc, u16 tag)
520{
521 fc->tag = tag;
522 *(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
523}
524EXPORT_SYMBOL(p9_set_tag);
525
526struct p9_fcall *p9_create_tversion(u32 msize, char *version)
527{
528 int size;
529 struct p9_fcall *fc;
530 struct cbuf buffer;
531 struct cbuf *bufp = &buffer;
532
533 size = 4 + 2 + strlen(version); /* msize[4] version[s] */
534 fc = p9_create_common(bufp, size, P9_TVERSION);
535 if (IS_ERR(fc))
536 goto error;
537
538 p9_put_int32(bufp, msize, &fc->params.tversion.msize);
539 p9_put_str(bufp, version, &fc->params.tversion.version);
540
541 if (buf_check_overflow(bufp)) {
542 kfree(fc);
543 fc = ERR_PTR(-ENOMEM);
544 }
545error:
546 return fc;
547}
548EXPORT_SYMBOL(p9_create_tversion);
549
550struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname)
551{
552 int size;
553 struct p9_fcall *fc;
554 struct cbuf buffer;
555 struct cbuf *bufp = &buffer;
556
557 /* afid[4] uname[s] aname[s] */
558 size = 4 + 2 + strlen(uname) + 2 + strlen(aname);
559 fc = p9_create_common(bufp, size, P9_TAUTH);
560 if (IS_ERR(fc))
561 goto error;
562
563 p9_put_int32(bufp, afid, &fc->params.tauth.afid);
564 p9_put_str(bufp, uname, &fc->params.tauth.uname);
565 p9_put_str(bufp, aname, &fc->params.tauth.aname);
566
567 if (buf_check_overflow(bufp)) {
568 kfree(fc);
569 fc = ERR_PTR(-ENOMEM);
570 }
571error:
572 return fc;
573}
574EXPORT_SYMBOL(p9_create_tauth);
575
576struct p9_fcall *
577p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
578{
579 int size;
580 struct p9_fcall *fc;
581 struct cbuf buffer;
582 struct cbuf *bufp = &buffer;
583
584 /* fid[4] afid[4] uname[s] aname[s] */
585 size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname);
586 fc = p9_create_common(bufp, size, P9_TATTACH);
587 if (IS_ERR(fc))
588 goto error;
589
590 p9_put_int32(bufp, fid, &fc->params.tattach.fid);
591 p9_put_int32(bufp, afid, &fc->params.tattach.afid);
592 p9_put_str(bufp, uname, &fc->params.tattach.uname);
593 p9_put_str(bufp, aname, &fc->params.tattach.aname);
594
595error:
596 return fc;
597}
598EXPORT_SYMBOL(p9_create_tattach);
599
600struct p9_fcall *p9_create_tflush(u16 oldtag)
601{
602 int size;
603 struct p9_fcall *fc;
604 struct cbuf buffer;
605 struct cbuf *bufp = &buffer;
606
607 size = 2; /* oldtag[2] */
608 fc = p9_create_common(bufp, size, P9_TFLUSH);
609 if (IS_ERR(fc))
610 goto error;
611
612 p9_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
613
614 if (buf_check_overflow(bufp)) {
615 kfree(fc);
616 fc = ERR_PTR(-ENOMEM);
617 }
618error:
619 return fc;
620}
621EXPORT_SYMBOL(p9_create_tflush);
622
623struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname,
624 char **wnames)
625{
626 int i, size;
627 struct p9_fcall *fc;
628 struct cbuf buffer;
629 struct cbuf *bufp = &buffer;
630
631 if (nwname > P9_MAXWELEM) {
632 P9_DPRINTK(P9_DEBUG_ERROR, "nwname > %d\n", P9_MAXWELEM);
633 return NULL;
634 }
635
636 size = 4 + 4 + 2; /* fid[4] newfid[4] nwname[2] ... */
637 for (i = 0; i < nwname; i++) {
638 size += 2 + strlen(wnames[i]); /* wname[s] */
639 }
640
641 fc = p9_create_common(bufp, size, P9_TWALK);
642 if (IS_ERR(fc))
643 goto error;
644
645 p9_put_int32(bufp, fid, &fc->params.twalk.fid);
646 p9_put_int32(bufp, newfid, &fc->params.twalk.newfid);
647 p9_put_int16(bufp, nwname, &fc->params.twalk.nwname);
648 for (i = 0; i < nwname; i++) {
649 p9_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
650 }
651
652 if (buf_check_overflow(bufp)) {
653 kfree(fc);
654 fc = ERR_PTR(-ENOMEM);
655 }
656error:
657 return fc;
658}
659EXPORT_SYMBOL(p9_create_twalk);
660
661struct p9_fcall *p9_create_topen(u32 fid, u8 mode)
662{
663 int size;
664 struct p9_fcall *fc;
665 struct cbuf buffer;
666 struct cbuf *bufp = &buffer;
667
668 size = 4 + 1; /* fid[4] mode[1] */
669 fc = p9_create_common(bufp, size, P9_TOPEN);
670 if (IS_ERR(fc))
671 goto error;
672
673 p9_put_int32(bufp, fid, &fc->params.topen.fid);
674 p9_put_int8(bufp, mode, &fc->params.topen.mode);
675
676 if (buf_check_overflow(bufp)) {
677 kfree(fc);
678 fc = ERR_PTR(-ENOMEM);
679 }
680error:
681 return fc;
682}
683EXPORT_SYMBOL(p9_create_topen);
684
685struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
686 char *extension, int dotu)
687{
688 int size;
689 struct p9_fcall *fc;
690 struct cbuf buffer;
691 struct cbuf *bufp = &buffer;
692
693 /* fid[4] name[s] perm[4] mode[1] */
694 size = 4 + 2 + strlen(name) + 4 + 1;
695 if (dotu) {
696 size += 2 + /* extension[s] */
697 (extension == NULL ? 0 : strlen(extension));
698 }
699
700 fc = p9_create_common(bufp, size, P9_TCREATE);
701 if (IS_ERR(fc))
702 goto error;
703
704 p9_put_int32(bufp, fid, &fc->params.tcreate.fid);
705 p9_put_str(bufp, name, &fc->params.tcreate.name);
706 p9_put_int32(bufp, perm, &fc->params.tcreate.perm);
707 p9_put_int8(bufp, mode, &fc->params.tcreate.mode);
708 if (dotu)
709 p9_put_str(bufp, extension, &fc->params.tcreate.extension);
710
711 if (buf_check_overflow(bufp)) {
712 kfree(fc);
713 fc = ERR_PTR(-ENOMEM);
714 }
715error:
716 return fc;
717}
718EXPORT_SYMBOL(p9_create_tcreate);
719
720struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count)
721{
722 int size;
723 struct p9_fcall *fc;
724 struct cbuf buffer;
725 struct cbuf *bufp = &buffer;
726
727 size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */
728 fc = p9_create_common(bufp, size, P9_TREAD);
729 if (IS_ERR(fc))
730 goto error;
731
732 p9_put_int32(bufp, fid, &fc->params.tread.fid);
733 p9_put_int64(bufp, offset, &fc->params.tread.offset);
734 p9_put_int32(bufp, count, &fc->params.tread.count);
735
736 if (buf_check_overflow(bufp)) {
737 kfree(fc);
738 fc = ERR_PTR(-ENOMEM);
739 }
740error:
741 return fc;
742}
743EXPORT_SYMBOL(p9_create_tread);
744
745struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count,
746 const char *data)
747{
748 int size, err;
749 struct p9_fcall *fc;
750 struct cbuf buffer;
751 struct cbuf *bufp = &buffer;
752
753 /* fid[4] offset[8] count[4] data[count] */
754 size = 4 + 8 + 4 + count;
755 fc = p9_create_common(bufp, size, P9_TWRITE);
756 if (IS_ERR(fc))
757 goto error;
758
759 p9_put_int32(bufp, fid, &fc->params.twrite.fid);
760 p9_put_int64(bufp, offset, &fc->params.twrite.offset);
761 p9_put_int32(bufp, count, &fc->params.twrite.count);
762 err = p9_put_data(bufp, data, count, &fc->params.twrite.data);
763 if (err) {
764 kfree(fc);
765 fc = ERR_PTR(err);
766 }
767
768 if (buf_check_overflow(bufp)) {
769 kfree(fc);
770 fc = ERR_PTR(-ENOMEM);
771 }
772error:
773 return fc;
774}
775EXPORT_SYMBOL(p9_create_twrite);
776
777struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count,
778 const char __user *data)
779{
780 int size, err;
781 struct p9_fcall *fc;
782 struct cbuf buffer;
783 struct cbuf *bufp = &buffer;
784
785 /* fid[4] offset[8] count[4] data[count] */
786 size = 4 + 8 + 4 + count;
787 fc = p9_create_common(bufp, size, P9_TWRITE);
788 if (IS_ERR(fc))
789 goto error;
790
791 p9_put_int32(bufp, fid, &fc->params.twrite.fid);
792 p9_put_int64(bufp, offset, &fc->params.twrite.offset);
793 p9_put_int32(bufp, count, &fc->params.twrite.count);
794 err = p9_put_user_data(bufp, data, count, &fc->params.twrite.data);
795 if (err) {
796 kfree(fc);
797 fc = ERR_PTR(err);
798 }
799
800 if (buf_check_overflow(bufp)) {
801 kfree(fc);
802 fc = ERR_PTR(-ENOMEM);
803 }
804error:
805 return fc;
806}
807EXPORT_SYMBOL(p9_create_twrite_u);
808
809struct p9_fcall *p9_create_tclunk(u32 fid)
810{
811 int size;
812 struct p9_fcall *fc;
813 struct cbuf buffer;
814 struct cbuf *bufp = &buffer;
815
816 size = 4; /* fid[4] */
817 fc = p9_create_common(bufp, size, P9_TCLUNK);
818 if (IS_ERR(fc))
819 goto error;
820
821 p9_put_int32(bufp, fid, &fc->params.tclunk.fid);
822
823 if (buf_check_overflow(bufp)) {
824 kfree(fc);
825 fc = ERR_PTR(-ENOMEM);
826 }
827error:
828 return fc;
829}
830EXPORT_SYMBOL(p9_create_tclunk);
831
832struct p9_fcall *p9_create_tremove(u32 fid)
833{
834 int size;
835 struct p9_fcall *fc;
836 struct cbuf buffer;
837 struct cbuf *bufp = &buffer;
838
839 size = 4; /* fid[4] */
840 fc = p9_create_common(bufp, size, P9_TREMOVE);
841 if (IS_ERR(fc))
842 goto error;
843
844 p9_put_int32(bufp, fid, &fc->params.tremove.fid);
845
846 if (buf_check_overflow(bufp)) {
847 kfree(fc);
848 fc = ERR_PTR(-ENOMEM);
849 }
850error:
851 return fc;
852}
853EXPORT_SYMBOL(p9_create_tremove);
854
855struct p9_fcall *p9_create_tstat(u32 fid)
856{
857 int size;
858 struct p9_fcall *fc;
859 struct cbuf buffer;
860 struct cbuf *bufp = &buffer;
861
862 size = 4; /* fid[4] */
863 fc = p9_create_common(bufp, size, P9_TSTAT);
864 if (IS_ERR(fc))
865 goto error;
866
867 p9_put_int32(bufp, fid, &fc->params.tstat.fid);
868
869 if (buf_check_overflow(bufp)) {
870 kfree(fc);
871 fc = ERR_PTR(-ENOMEM);
872 }
873error:
874 return fc;
875}
876EXPORT_SYMBOL(p9_create_tstat);
877
878struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat,
879 int dotu)
880{
881 int size, statsz;
882 struct p9_fcall *fc;
883 struct cbuf buffer;
884 struct cbuf *bufp = &buffer;
885
886 statsz = p9_size_wstat(wstat, dotu);
887 size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */
888 fc = p9_create_common(bufp, size, P9_TWSTAT);
889 if (IS_ERR(fc))
890 goto error;
891
892 p9_put_int32(bufp, fid, &fc->params.twstat.fid);
893 buf_put_int16(bufp, statsz + 2);
894 p9_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, dotu);
895
896 if (buf_check_overflow(bufp)) {
897 kfree(fc);
898 fc = ERR_PTR(-ENOMEM);
899 }
900error:
901 return fc;
902}
903EXPORT_SYMBOL(p9_create_twstat);
diff --git a/net/9p/error.c b/net/9p/error.c
new file mode 100644
index 000000000000..ab2458b6c903
--- /dev/null
+++ b/net/9p/error.c
@@ -0,0 +1,240 @@
1/*
2 * linux/fs/9p/error.c
3 *
4 * Error string handling
5 *
6 * Plan 9 uses error strings, Unix uses error numbers. These functions
7 * try to help manage that and provide for dynamically adding error
8 * mappings.
9 *
10 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
11 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2
15 * as published by the Free Software Foundation.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to:
24 * Free Software Foundation
25 * 51 Franklin Street, Fifth Floor
26 * Boston, MA 02111-1301 USA
27 *
28 */
29
30#include <linux/module.h>
31#include <linux/list.h>
32#include <linux/jhash.h>
33#include <linux/errno.h>
34#include <net/9p/9p.h>
35
36struct errormap {
37 char *name;
38 int val;
39
40 int namelen;
41 struct hlist_node list;
42};
43
44#define ERRHASHSZ 32
45static struct hlist_head hash_errmap[ERRHASHSZ];
46
47/* FixMe - reduce to a reasonable size */
48static struct errormap errmap[] = {
49 {"Operation not permitted", EPERM},
50 {"wstat prohibited", EPERM},
51 {"No such file or directory", ENOENT},
52 {"directory entry not found", ENOENT},
53 {"file not found", ENOENT},
54 {"Interrupted system call", EINTR},
55 {"Input/output error", EIO},
56 {"No such device or address", ENXIO},
57 {"Argument list too long", E2BIG},
58 {"Bad file descriptor", EBADF},
59 {"Resource temporarily unavailable", EAGAIN},
60 {"Cannot allocate memory", ENOMEM},
61 {"Permission denied", EACCES},
62 {"Bad address", EFAULT},
63 {"Block device required", ENOTBLK},
64 {"Device or resource busy", EBUSY},
65 {"File exists", EEXIST},
66 {"Invalid cross-device link", EXDEV},
67 {"No such device", ENODEV},
68 {"Not a directory", ENOTDIR},
69 {"Is a directory", EISDIR},
70 {"Invalid argument", EINVAL},
71 {"Too many open files in system", ENFILE},
72 {"Too many open files", EMFILE},
73 {"Text file busy", ETXTBSY},
74 {"File too large", EFBIG},
75 {"No space left on device", ENOSPC},
76 {"Illegal seek", ESPIPE},
77 {"Read-only file system", EROFS},
78 {"Too many links", EMLINK},
79 {"Broken pipe", EPIPE},
80 {"Numerical argument out of domain", EDOM},
81 {"Numerical result out of range", ERANGE},
82 {"Resource deadlock avoided", EDEADLK},
83 {"File name too long", ENAMETOOLONG},
84 {"No locks available", ENOLCK},
85 {"Function not implemented", ENOSYS},
86 {"Directory not empty", ENOTEMPTY},
87 {"Too many levels of symbolic links", ELOOP},
88 {"No message of desired type", ENOMSG},
89 {"Identifier removed", EIDRM},
90 {"No data available", ENODATA},
91 {"Machine is not on the network", ENONET},
92 {"Package not installed", ENOPKG},
93 {"Object is remote", EREMOTE},
94 {"Link has been severed", ENOLINK},
95 {"Communication error on send", ECOMM},
96 {"Protocol error", EPROTO},
97 {"Bad message", EBADMSG},
98 {"File descriptor in bad state", EBADFD},
99 {"Streams pipe error", ESTRPIPE},
100 {"Too many users", EUSERS},
101 {"Socket operation on non-socket", ENOTSOCK},
102 {"Message too long", EMSGSIZE},
103 {"Protocol not available", ENOPROTOOPT},
104 {"Protocol not supported", EPROTONOSUPPORT},
105 {"Socket type not supported", ESOCKTNOSUPPORT},
106 {"Operation not supported", EOPNOTSUPP},
107 {"Protocol family not supported", EPFNOSUPPORT},
108 {"Network is down", ENETDOWN},
109 {"Network is unreachable", ENETUNREACH},
110 {"Network dropped connection on reset", ENETRESET},
111 {"Software caused connection abort", ECONNABORTED},
112 {"Connection reset by peer", ECONNRESET},
113 {"No buffer space available", ENOBUFS},
114 {"Transport endpoint is already connected", EISCONN},
115 {"Transport endpoint is not connected", ENOTCONN},
116 {"Cannot send after transport endpoint shutdown", ESHUTDOWN},
117 {"Connection timed out", ETIMEDOUT},
118 {"Connection refused", ECONNREFUSED},
119 {"Host is down", EHOSTDOWN},
120 {"No route to host", EHOSTUNREACH},
121 {"Operation already in progress", EALREADY},
122 {"Operation now in progress", EINPROGRESS},
123 {"Is a named type file", EISNAM},
124 {"Remote I/O error", EREMOTEIO},
125 {"Disk quota exceeded", EDQUOT},
126/* errors from fossil, vacfs, and u9fs */
127 {"fid unknown or out of range", EBADF},
128 {"permission denied", EACCES},
129 {"file does not exist", ENOENT},
130 {"authentication failed", ECONNREFUSED},
131 {"bad offset in directory read", ESPIPE},
132 {"bad use of fid", EBADF},
133 {"wstat can't convert between files and directories", EPERM},
134 {"directory is not empty", ENOTEMPTY},
135 {"file exists", EEXIST},
136 {"file already exists", EEXIST},
137 {"file or directory already exists", EEXIST},
138 {"fid already in use", EBADF},
139 {"file in use", ETXTBSY},
140 {"i/o error", EIO},
141 {"file already open for I/O", ETXTBSY},
142 {"illegal mode", EINVAL},
143 {"illegal name", ENAMETOOLONG},
144 {"not a directory", ENOTDIR},
145 {"not a member of proposed group", EPERM},
146 {"not owner", EACCES},
147 {"only owner can change group in wstat", EACCES},
148 {"read only file system", EROFS},
149 {"no access to special file", EPERM},
150 {"i/o count too large", EIO},
151 {"unknown group", EINVAL},
152 {"unknown user", EINVAL},
153 {"bogus wstat buffer", EPROTO},
154 {"exclusive use file already open", EAGAIN},
155 {"corrupted directory entry", EIO},
156 {"corrupted file entry", EIO},
157 {"corrupted block label", EIO},
158 {"corrupted meta data", EIO},
159 {"illegal offset", EINVAL},
160 {"illegal path element", ENOENT},
161 {"root of file system is corrupted", EIO},
162 {"corrupted super block", EIO},
163 {"protocol botch", EPROTO},
164 {"file system is full", ENOSPC},
165 {"file is in use", EAGAIN},
166 {"directory entry is not allocated", ENOENT},
167 {"file is read only", EROFS},
168 {"file has been removed", EIDRM},
169 {"only support truncation to zero length", EPERM},
170 {"cannot remove root", EPERM},
171 {"file too big", EFBIG},
172 {"venti i/o error", EIO},
173 /* these are not errors */
174 {"u9fs rhostsauth: no authentication required", 0},
175 {"u9fs authnone: no authentication required", 0},
176 {NULL, -1}
177};
178
179/**
180 * p9_error_init - preload
181 * @errstr: error string
182 *
183 */
184
185int p9_error_init(void)
186{
187 struct errormap *c;
188 int bucket;
189
190 /* initialize hash table */
191 for (bucket = 0; bucket < ERRHASHSZ; bucket++)
192 INIT_HLIST_HEAD(&hash_errmap[bucket]);
193
194 /* load initial error map into hash table */
195 for (c = errmap; c->name != NULL; c++) {
196 c->namelen = strlen(c->name);
197 bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ;
198 INIT_HLIST_NODE(&c->list);
199 hlist_add_head(&c->list, &hash_errmap[bucket]);
200 }
201
202 return 1;
203}
204EXPORT_SYMBOL(p9_error_init);
205
206/**
207 * errstr2errno - convert error string to error number
208 * @errstr: error string
209 *
210 */
211
212int p9_errstr2errno(char *errstr, int len)
213{
214 int errno;
215 struct hlist_node *p;
216 struct errormap *c;
217 int bucket;
218
219 errno = 0;
220 p = NULL;
221 c = NULL;
222 bucket = jhash(errstr, len, 0) % ERRHASHSZ;
223 hlist_for_each_entry(c, p, &hash_errmap[bucket], list) {
224 if (c->namelen == len && !memcmp(c->name, errstr, len)) {
225 errno = c->val;
226 break;
227 }
228 }
229
230 if (errno == 0) {
231 /* TODO: if error isn't found, add it dynamically */
232 errstr[len] = 0;
233 printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__,
234 errstr);
235 errno = 1;
236 }
237
238 return -errno;
239}
240EXPORT_SYMBOL(p9_errstr2errno);
diff --git a/net/9p/fcprint.c b/net/9p/fcprint.c
new file mode 100644
index 000000000000..b1ae8ec57d54
--- /dev/null
+++ b/net/9p/fcprint.c
@@ -0,0 +1,358 @@
1/*
2 * net/9p/fcprint.c
3 *
4 * Print 9P call.
5 *
6 * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to:
19 * Free Software Foundation
20 * 51 Franklin Street, Fifth Floor
21 * Boston, MA 02111-1301 USA
22 *
23 */
24#include <linux/module.h>
25#include <linux/errno.h>
26#include <linux/fs.h>
27#include <linux/idr.h>
28#include <net/9p/9p.h>
29
30#ifdef CONFIG_NET_9P_DEBUG
31
32static int
33p9_printqid(char *buf, int buflen, struct p9_qid *q)
34{
35 int n;
36 char b[10];
37
38 n = 0;
39 if (q->type & P9_QTDIR)
40 b[n++] = 'd';
41 if (q->type & P9_QTAPPEND)
42 b[n++] = 'a';
43 if (q->type & P9_QTAUTH)
44 b[n++] = 'A';
45 if (q->type & P9_QTEXCL)
46 b[n++] = 'l';
47 if (q->type & P9_QTTMP)
48 b[n++] = 't';
49 if (q->type & P9_QTSYMLINK)
50 b[n++] = 'L';
51 b[n] = '\0';
52
53 return scnprintf(buf, buflen, "(%.16llx %x %s)",
54 (long long int) q->path, q->version, b);
55}
56
57static int
58p9_printperm(char *buf, int buflen, int perm)
59{
60 int n;
61 char b[15];
62
63 n = 0;
64 if (perm & P9_DMDIR)
65 b[n++] = 'd';
66 if (perm & P9_DMAPPEND)
67 b[n++] = 'a';
68 if (perm & P9_DMAUTH)
69 b[n++] = 'A';
70 if (perm & P9_DMEXCL)
71 b[n++] = 'l';
72 if (perm & P9_DMTMP)
73 b[n++] = 't';
74 if (perm & P9_DMDEVICE)
75 b[n++] = 'D';
76 if (perm & P9_DMSOCKET)
77 b[n++] = 'S';
78 if (perm & P9_DMNAMEDPIPE)
79 b[n++] = 'P';
80 if (perm & P9_DMSYMLINK)
81 b[n++] = 'L';
82 b[n] = '\0';
83
84 return scnprintf(buf, buflen, "%s%03o", b, perm&077);
85}
86
87static int
88p9_printstat(char *buf, int buflen, struct p9_stat *st, int extended)
89{
90 int n;
91
92 n = scnprintf(buf, buflen, "'%.*s' '%.*s'", st->name.len,
93 st->name.str, st->uid.len, st->uid.str);
94 if (extended)
95 n += scnprintf(buf+n, buflen-n, "(%d)", st->n_uid);
96
97 n += scnprintf(buf+n, buflen-n, " '%.*s'", st->gid.len, st->gid.str);
98 if (extended)
99 n += scnprintf(buf+n, buflen-n, "(%d)", st->n_gid);
100
101 n += scnprintf(buf+n, buflen-n, " '%.*s'", st->muid.len, st->muid.str);
102 if (extended)
103 n += scnprintf(buf+n, buflen-n, "(%d)", st->n_muid);
104
105 n += scnprintf(buf+n, buflen-n, " q ");
106 n += p9_printqid(buf+n, buflen-n, &st->qid);
107 n += scnprintf(buf+n, buflen-n, " m ");
108 n += p9_printperm(buf+n, buflen-n, st->mode);
109 n += scnprintf(buf+n, buflen-n, " at %d mt %d l %lld",
110 st->atime, st->mtime, (long long int) st->length);
111
112 if (extended)
113 n += scnprintf(buf+n, buflen-n, " ext '%.*s'",
114 st->extension.len, st->extension.str);
115
116 return n;
117}
118
119static int
120p9_dumpdata(char *buf, int buflen, u8 *data, int datalen)
121{
122 int i, n;
123
124 i = n = 0;
125 while (i < datalen) {
126 n += scnprintf(buf + n, buflen - n, "%02x", data[i]);
127 if (i%4 == 3)
128 n += scnprintf(buf + n, buflen - n, " ");
129 if (i%32 == 31)
130 n += scnprintf(buf + n, buflen - n, "\n");
131
132 i++;
133 }
134 n += scnprintf(buf + n, buflen - n, "\n");
135
136 return n;
137}
138
139static int
140p9_printdata(char *buf, int buflen, u8 *data, int datalen)
141{
142 return p9_dumpdata(buf, buflen, data, datalen < 16?datalen:16);
143}
144
145int
146p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
147{
148 int i, ret, type, tag;
149
150 if (!fc)
151 return scnprintf(buf, buflen, "<NULL>");
152
153 type = fc->id;
154 tag = fc->tag;
155
156 ret = 0;
157 switch (type) {
158 case P9_TVERSION:
159 ret += scnprintf(buf+ret, buflen-ret,
160 "Tversion tag %u msize %u version '%.*s'", tag,
161 fc->params.tversion.msize,
162 fc->params.tversion.version.len,
163 fc->params.tversion.version.str);
164 break;
165
166 case P9_RVERSION:
167 ret += scnprintf(buf+ret, buflen-ret,
168 "Rversion tag %u msize %u version '%.*s'", tag,
169 fc->params.rversion.msize,
170 fc->params.rversion.version.len,
171 fc->params.rversion.version.str);
172 break;
173
174 case P9_TAUTH:
175 ret += scnprintf(buf+ret, buflen-ret,
176 "Tauth tag %u afid %d uname '%.*s' aname '%.*s'", tag,
177 fc->params.tauth.afid, fc->params.tauth.uname.len,
178 fc->params.tauth.uname.str, fc->params.tauth.aname.len,
179 fc->params.tauth.aname.str);
180 break;
181
182 case P9_RAUTH:
183 ret += scnprintf(buf+ret, buflen-ret, "Rauth tag %u qid ", tag);
184 p9_printqid(buf+ret, buflen-ret, &fc->params.rauth.qid);
185 break;
186
187 case P9_TATTACH:
188 ret += scnprintf(buf+ret, buflen-ret,
189 "Tattach tag %u fid %d afid %d uname '%.*s' aname '%.*s'", tag,
190 fc->params.tattach.fid, fc->params.tattach.afid,
191 fc->params.tattach.uname.len, fc->params.tattach.uname.str,
192 fc->params.tattach.aname.len, fc->params.tattach.aname.str);
193 break;
194
195 case P9_RATTACH:
196 ret += scnprintf(buf+ret, buflen-ret, "Rattach tag %u qid ",
197 tag);
198 p9_printqid(buf+ret, buflen-ret, &fc->params.rattach.qid);
199 break;
200
201 case P9_RERROR:
202 ret += scnprintf(buf+ret, buflen-ret,
203 "Rerror tag %u ename '%.*s'", tag,
204 fc->params.rerror.error.len,
205 fc->params.rerror.error.str);
206 if (extended)
207 ret += scnprintf(buf+ret, buflen-ret, " ecode %d\n",
208 fc->params.rerror.errno);
209 break;
210
211 case P9_TFLUSH:
212 ret += scnprintf(buf+ret, buflen-ret, "Tflush tag %u oldtag %u",
213 tag, fc->params.tflush.oldtag);
214 break;
215
216 case P9_RFLUSH:
217 ret += scnprintf(buf+ret, buflen-ret, "Rflush tag %u", tag);
218 break;
219
220 case P9_TWALK:
221 ret += scnprintf(buf+ret, buflen-ret,
222 "Twalk tag %u fid %d newfid %d nwname %d", tag,
223 fc->params.twalk.fid, fc->params.twalk.newfid,
224 fc->params.twalk.nwname);
225 for (i = 0; i < fc->params.twalk.nwname; i++)
226 ret += scnprintf(buf+ret, buflen-ret, " '%.*s'",
227 fc->params.twalk.wnames[i].len,
228 fc->params.twalk.wnames[i].str);
229 break;
230
231 case P9_RWALK:
232 ret += scnprintf(buf+ret, buflen-ret, "Rwalk tag %u nwqid %d",
233 tag, fc->params.rwalk.nwqid);
234 for (i = 0; i < fc->params.rwalk.nwqid; i++)
235 ret += p9_printqid(buf+ret, buflen-ret,
236 &fc->params.rwalk.wqids[i]);
237 break;
238
239 case P9_TOPEN:
240 ret += scnprintf(buf+ret, buflen-ret,
241 "Topen tag %u fid %d mode %d", tag,
242 fc->params.topen.fid, fc->params.topen.mode);
243 break;
244
245 case P9_ROPEN:
246 ret += scnprintf(buf+ret, buflen-ret, "Ropen tag %u", tag);
247 ret += p9_printqid(buf+ret, buflen-ret, &fc->params.ropen.qid);
248 ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
249 fc->params.ropen.iounit);
250 break;
251
252 case P9_TCREATE:
253 ret += scnprintf(buf+ret, buflen-ret,
254 "Tcreate tag %u fid %d name '%.*s' perm ", tag,
255 fc->params.tcreate.fid, fc->params.tcreate.name.len,
256 fc->params.tcreate.name.str);
257
258 ret += p9_printperm(buf+ret, buflen-ret,
259 fc->params.tcreate.perm);
260 ret += scnprintf(buf+ret, buflen-ret, " mode %d",
261 fc->params.tcreate.mode);
262 break;
263
264 case P9_RCREATE:
265 ret += scnprintf(buf+ret, buflen-ret, "Rcreate tag %u", tag);
266 ret += p9_printqid(buf+ret, buflen-ret,
267 &fc->params.rcreate.qid);
268 ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
269 fc->params.rcreate.iounit);
270 break;
271
272 case P9_TREAD:
273 ret += scnprintf(buf+ret, buflen-ret,
274 "Tread tag %u fid %d offset %lld count %u", tag,
275 fc->params.tread.fid,
276 (long long int) fc->params.tread.offset,
277 fc->params.tread.count);
278 break;
279
280 case P9_RREAD:
281 ret += scnprintf(buf+ret, buflen-ret,
282 "Rread tag %u count %u data ", tag,
283 fc->params.rread.count);
284 ret += p9_printdata(buf+ret, buflen-ret, fc->params.rread.data,
285 fc->params.rread.count);
286 break;
287
288 case P9_TWRITE:
289 ret += scnprintf(buf+ret, buflen-ret,
290 "Twrite tag %u fid %d offset %lld count %u data ",
291 tag, fc->params.twrite.fid,
292 (long long int) fc->params.twrite.offset,
293 fc->params.twrite.count);
294 ret += p9_printdata(buf+ret, buflen-ret, fc->params.twrite.data,
295 fc->params.twrite.count);
296 break;
297
298 case P9_RWRITE:
299 ret += scnprintf(buf+ret, buflen-ret, "Rwrite tag %u count %u",
300 tag, fc->params.rwrite.count);
301 break;
302
303 case P9_TCLUNK:
304 ret += scnprintf(buf+ret, buflen-ret, "Tclunk tag %u fid %d",
305 tag, fc->params.tclunk.fid);
306 break;
307
308 case P9_RCLUNK:
309 ret += scnprintf(buf+ret, buflen-ret, "Rclunk tag %u", tag);
310 break;
311
312 case P9_TREMOVE:
313 ret += scnprintf(buf+ret, buflen-ret, "Tremove tag %u fid %d",
314 tag, fc->params.tremove.fid);
315 break;
316
317 case P9_RREMOVE:
318 ret += scnprintf(buf+ret, buflen-ret, "Rremove tag %u", tag);
319 break;
320
321 case P9_TSTAT:
322 ret += scnprintf(buf+ret, buflen-ret, "Tstat tag %u fid %d",
323 tag, fc->params.tstat.fid);
324 break;
325
326 case P9_RSTAT:
327 ret += scnprintf(buf+ret, buflen-ret, "Rstat tag %u ", tag);
328 ret += p9_printstat(buf+ret, buflen-ret, &fc->params.rstat.stat,
329 extended);
330 break;
331
332 case P9_TWSTAT:
333 ret += scnprintf(buf+ret, buflen-ret, "Twstat tag %u fid %d ",
334 tag, fc->params.twstat.fid);
335 ret += p9_printstat(buf+ret, buflen-ret,
336 &fc->params.twstat.stat, extended);
337 break;
338
339 case P9_RWSTAT:
340 ret += scnprintf(buf+ret, buflen-ret, "Rwstat tag %u", tag);
341 break;
342
343 default:
344 ret += scnprintf(buf+ret, buflen-ret, "unknown type %d", type);
345 break;
346 }
347
348 return ret;
349}
350
351#else
352int
353p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
354{
355 return 0;
356}
357EXPORT_SYMBOL(p9_printfcall);
358#endif /* CONFIG_NET_9P_DEBUG */
diff --git a/net/9p/mod.c b/net/9p/mod.c
new file mode 100644
index 000000000000..4f9e1d2ac257
--- /dev/null
+++ b/net/9p/mod.c
@@ -0,0 +1,85 @@
1/*
2 * net/9p/9p.c
3 *
4 * 9P entry point
5 *
6 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
7 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/moduleparam.h>
29#include <net/9p/9p.h>
30
31#ifdef CONFIG_NET_9P_DEBUG
32unsigned int p9_debug_level = 0; /* feature-rific global debug level */
33EXPORT_SYMBOL(p9_debug_level);
34module_param_named(debug, p9_debug_level, uint, 0);
35MODULE_PARM_DESC(debug, "9P debugging level");
36#endif
37
38extern int p9_mux_global_init(void);
39extern void p9_mux_global_exit(void);
40extern int p9_sysctl_register(void);
41extern void p9_sysctl_unregister(void);
42
43/**
44 * v9fs_init - Initialize module
45 *
46 */
47static int __init init_p9(void)
48{
49 int ret;
50
51 p9_error_init();
52 printk(KERN_INFO "Installing 9P2000 support\n");
53 ret = p9_mux_global_init();
54 if (ret) {
55 printk(KERN_WARNING "9p: starting mux failed\n");
56 return ret;
57 }
58
59 ret = p9_sysctl_register();
60 if (ret) {
61 printk(KERN_WARNING "9p: registering sysctl failed\n");
62 return ret;
63 }
64
65 return ret;
66}
67
68/**
69 * v9fs_init - shutdown module
70 *
71 */
72
73static void __exit exit_p9(void)
74{
75 p9_sysctl_unregister();
76 p9_mux_global_exit();
77}
78
79module_init(init_p9)
80module_exit(exit_p9)
81
82MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
83MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
84MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
85MODULE_LICENSE("GPL");
diff --git a/net/9p/mux.c b/net/9p/mux.c
new file mode 100644
index 000000000000..acb038810f39
--- /dev/null
+++ b/net/9p/mux.c
@@ -0,0 +1,1054 @@
1/*
2 * net/9p/mux.c
3 *
4 * Protocol Multiplexer
5 *
6 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to:
20 * Free Software Foundation
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02111-1301 USA
23 *
24 */
25
26#include <linux/module.h>
27#include <linux/errno.h>
28#include <linux/fs.h>
29#include <linux/poll.h>
30#include <linux/kthread.h>
31#include <linux/idr.h>
32#include <linux/mutex.h>
33#include <net/9p/9p.h>
34#include <net/9p/transport.h>
35#include <net/9p/conn.h>
36
37#define ERREQFLUSH 1
38#define SCHED_TIMEOUT 10
39#define MAXPOLLWADDR 2
40
41enum {
42 Rworksched = 1, /* read work scheduled or running */
43 Rpending = 2, /* can read */
44 Wworksched = 4, /* write work scheduled or running */
45 Wpending = 8, /* can write */
46};
47
48enum {
49 None,
50 Flushing,
51 Flushed,
52};
53
54struct p9_mux_poll_task;
55
56struct p9_req {
57 spinlock_t lock; /* protect request structure */
58 int tag;
59 struct p9_fcall *tcall;
60 struct p9_fcall *rcall;
61 int err;
62 p9_conn_req_callback cb;
63 void *cba;
64 int flush;
65 struct list_head req_list;
66};
67
68struct p9_conn {
69 spinlock_t lock; /* protect lock structure */
70 struct list_head mux_list;
71 struct p9_mux_poll_task *poll_task;
72 int msize;
73 unsigned char *extended;
74 struct p9_transport *trans;
75 struct p9_idpool *tagpool;
76 int err;
77 wait_queue_head_t equeue;
78 struct list_head req_list;
79 struct list_head unsent_req_list;
80 struct p9_fcall *rcall;
81 int rpos;
82 char *rbuf;
83 int wpos;
84 int wsize;
85 char *wbuf;
86 wait_queue_t poll_wait[MAXPOLLWADDR];
87 wait_queue_head_t *poll_waddr[MAXPOLLWADDR];
88 poll_table pt;
89 struct work_struct rq;
90 struct work_struct wq;
91 unsigned long wsched;
92};
93
94struct p9_mux_poll_task {
95 struct task_struct *task;
96 struct list_head mux_list;
97 int muxnum;
98};
99
100struct p9_mux_rpc {
101 struct p9_conn *m;
102 int err;
103 struct p9_fcall *tcall;
104 struct p9_fcall *rcall;
105 wait_queue_head_t wqueue;
106};
107
108static int p9_poll_proc(void *);
109static void p9_read_work(struct work_struct *work);
110static void p9_write_work(struct work_struct *work);
111static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
112 poll_table * p);
113static u16 p9_mux_get_tag(struct p9_conn *);
114static void p9_mux_put_tag(struct p9_conn *, u16);
115
116static DEFINE_MUTEX(p9_mux_task_lock);
117static struct workqueue_struct *p9_mux_wq;
118
119static int p9_mux_num;
120static int p9_mux_poll_task_num;
121static struct p9_mux_poll_task p9_mux_poll_tasks[100];
122
123int p9_mux_global_init(void)
124{
125 int i;
126
127 for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
128 p9_mux_poll_tasks[i].task = NULL;
129
130 p9_mux_wq = create_workqueue("v9fs");
131 if (!p9_mux_wq) {
132 printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
133 return -ENOMEM;
134 }
135
136 return 0;
137}
138
139void p9_mux_global_exit(void)
140{
141 destroy_workqueue(p9_mux_wq);
142}
143
144/**
145 * p9_mux_calc_poll_procs - calculates the number of polling procs
146 * based on the number of mounted v9fs filesystems.
147 *
148 * The current implementation returns sqrt of the number of mounts.
149 */
150static int p9_mux_calc_poll_procs(int muxnum)
151{
152 int n;
153
154 if (p9_mux_poll_task_num)
155 n = muxnum / p9_mux_poll_task_num +
156 (muxnum % p9_mux_poll_task_num ? 1 : 0);
157 else
158 n = 1;
159
160 if (n > ARRAY_SIZE(p9_mux_poll_tasks))
161 n = ARRAY_SIZE(p9_mux_poll_tasks);
162
163 return n;
164}
165
166static int p9_mux_poll_start(struct p9_conn *m)
167{
168 int i, n;
169 struct p9_mux_poll_task *vpt, *vptlast;
170 struct task_struct *pproc;
171
172 P9_DPRINTK(P9_DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, p9_mux_num,
173 p9_mux_poll_task_num);
174 mutex_lock(&p9_mux_task_lock);
175
176 n = p9_mux_calc_poll_procs(p9_mux_num + 1);
177 if (n > p9_mux_poll_task_num) {
178 for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
179 if (p9_mux_poll_tasks[i].task == NULL) {
180 vpt = &p9_mux_poll_tasks[i];
181 P9_DPRINTK(P9_DEBUG_MUX, "create proc %p\n",
182 vpt);
183 pproc = kthread_create(p9_poll_proc, vpt,
184 "v9fs-poll");
185
186 if (!IS_ERR(pproc)) {
187 vpt->task = pproc;
188 INIT_LIST_HEAD(&vpt->mux_list);
189 vpt->muxnum = 0;
190 p9_mux_poll_task_num++;
191 wake_up_process(vpt->task);
192 }
193 break;
194 }
195 }
196
197 if (i >= ARRAY_SIZE(p9_mux_poll_tasks))
198 P9_DPRINTK(P9_DEBUG_ERROR,
199 "warning: no free poll slots\n");
200 }
201
202 n = (p9_mux_num + 1) / p9_mux_poll_task_num +
203 ((p9_mux_num + 1) % p9_mux_poll_task_num ? 1 : 0);
204
205 vptlast = NULL;
206 for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
207 vpt = &p9_mux_poll_tasks[i];
208 if (vpt->task != NULL) {
209 vptlast = vpt;
210 if (vpt->muxnum < n) {
211 P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
212 list_add(&m->mux_list, &vpt->mux_list);
213 vpt->muxnum++;
214 m->poll_task = vpt;
215 memset(&m->poll_waddr, 0,
216 sizeof(m->poll_waddr));
217 init_poll_funcptr(&m->pt, p9_pollwait);
218 break;
219 }
220 }
221 }
222
223 if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) {
224 if (vptlast == NULL)
225 return -ENOMEM;
226
227 P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
228 list_add(&m->mux_list, &vptlast->mux_list);
229 vptlast->muxnum++;
230 m->poll_task = vptlast;
231 memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
232 init_poll_funcptr(&m->pt, p9_pollwait);
233 }
234
235 p9_mux_num++;
236 mutex_unlock(&p9_mux_task_lock);
237
238 return 0;
239}
240
241static void p9_mux_poll_stop(struct p9_conn *m)
242{
243 int i;
244 struct p9_mux_poll_task *vpt;
245
246 mutex_lock(&p9_mux_task_lock);
247 vpt = m->poll_task;
248 list_del(&m->mux_list);
249 for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
250 if (m->poll_waddr[i] != NULL) {
251 remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]);
252 m->poll_waddr[i] = NULL;
253 }
254 }
255 vpt->muxnum--;
256 if (!vpt->muxnum) {
257 P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt);
258 kthread_stop(vpt->task);
259 vpt->task = NULL;
260 p9_mux_poll_task_num--;
261 }
262 p9_mux_num--;
263 mutex_unlock(&p9_mux_task_lock);
264}
265
266/**
267 * p9_conn_create - allocate and initialize the per-session mux data
268 * Creates the polling task if this is the first session.
269 *
270 * @trans - transport structure
271 * @msize - maximum message size
272 * @extended - pointer to the extended flag
273 */
274struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize,
275 unsigned char *extended)
276{
277 int i, n;
278 struct p9_conn *m, *mtmp;
279
280 P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans, msize);
281 m = kmalloc(sizeof(struct p9_conn), GFP_KERNEL);
282 if (!m)
283 return ERR_PTR(-ENOMEM);
284
285 spin_lock_init(&m->lock);
286 INIT_LIST_HEAD(&m->mux_list);
287 m->msize = msize;
288 m->extended = extended;
289 m->trans = trans;
290 m->tagpool = p9_idpool_create();
291 if (!m->tagpool) {
292 kfree(m);
293 return ERR_PTR(PTR_ERR(m->tagpool));
294 }
295
296 m->err = 0;
297 init_waitqueue_head(&m->equeue);
298 INIT_LIST_HEAD(&m->req_list);
299 INIT_LIST_HEAD(&m->unsent_req_list);
300 m->rcall = NULL;
301 m->rpos = 0;
302 m->rbuf = NULL;
303 m->wpos = m->wsize = 0;
304 m->wbuf = NULL;
305 INIT_WORK(&m->rq, p9_read_work);
306 INIT_WORK(&m->wq, p9_write_work);
307 m->wsched = 0;
308 memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
309 m->poll_task = NULL;
310 n = p9_mux_poll_start(m);
311 if (n)
312 return ERR_PTR(n);
313
314 n = trans->poll(trans, &m->pt);
315 if (n & POLLIN) {
316 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
317 set_bit(Rpending, &m->wsched);
318 }
319
320 if (n & POLLOUT) {
321 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
322 set_bit(Wpending, &m->wsched);
323 }
324
325 for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
326 if (IS_ERR(m->poll_waddr[i])) {
327 p9_mux_poll_stop(m);
328 mtmp = (void *)m->poll_waddr; /* the error code */
329 kfree(m);
330 m = mtmp;
331 break;
332 }
333 }
334
335 return m;
336}
337EXPORT_SYMBOL(p9_conn_create);
338
339/**
340 * p9_mux_destroy - cancels all pending requests and frees mux resources
341 */
342void p9_conn_destroy(struct p9_conn *m)
343{
344 P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m,
345 m->mux_list.prev, m->mux_list.next);
346 p9_conn_cancel(m, -ECONNRESET);
347
348 if (!list_empty(&m->req_list)) {
349 /* wait until all processes waiting on this session exit */
350 P9_DPRINTK(P9_DEBUG_MUX,
351 "mux %p waiting for empty request queue\n", m);
352 wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
353 P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m,
354 list_empty(&m->req_list));
355 }
356
357 p9_mux_poll_stop(m);
358 m->trans = NULL;
359 p9_idpool_destroy(m->tagpool);
360 kfree(m);
361}
362EXPORT_SYMBOL(p9_conn_destroy);
363
364/**
365 * p9_pollwait - called by files poll operation to add v9fs-poll task
366 * to files wait queue
367 */
368static void
369p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
370 poll_table * p)
371{
372 int i;
373 struct p9_conn *m;
374
375 m = container_of(p, struct p9_conn, pt);
376 for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
377 if (m->poll_waddr[i] == NULL)
378 break;
379
380 if (i >= ARRAY_SIZE(m->poll_waddr)) {
381 P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
382 return;
383 }
384
385 m->poll_waddr[i] = wait_address;
386
387 if (!wait_address) {
388 P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n");
389 m->poll_waddr[i] = ERR_PTR(-EIO);
390 return;
391 }
392
393 init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task);
394 add_wait_queue(wait_address, &m->poll_wait[i]);
395}
396
397/**
398 * p9_poll_mux - polls a mux and schedules read or write works if necessary
399 */
400static void p9_poll_mux(struct p9_conn *m)
401{
402 int n;
403
404 if (m->err < 0)
405 return;
406
407 n = m->trans->poll(m->trans, NULL);
408 if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
409 P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n);
410 if (n >= 0)
411 n = -ECONNRESET;
412 p9_conn_cancel(m, n);
413 }
414
415 if (n & POLLIN) {
416 set_bit(Rpending, &m->wsched);
417 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
418 if (!test_and_set_bit(Rworksched, &m->wsched)) {
419 P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
420 queue_work(p9_mux_wq, &m->rq);
421 }
422 }
423
424 if (n & POLLOUT) {
425 set_bit(Wpending, &m->wsched);
426 P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
427 if ((m->wsize || !list_empty(&m->unsent_req_list))
428 && !test_and_set_bit(Wworksched, &m->wsched)) {
429 P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
430 queue_work(p9_mux_wq, &m->wq);
431 }
432 }
433}
434
435/**
436 * p9_poll_proc - polls all v9fs transports for new events and queues
437 * the appropriate work to the work queue
438 */
439static int p9_poll_proc(void *a)
440{
441 struct p9_conn *m, *mtmp;
442 struct p9_mux_poll_task *vpt;
443
444 vpt = a;
445 P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt);
446 while (!kthread_should_stop()) {
447 set_current_state(TASK_INTERRUPTIBLE);
448
449 list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) {
450 p9_poll_mux(m);
451 }
452
453 P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n");
454 schedule_timeout(SCHED_TIMEOUT * HZ);
455 }
456
457 __set_current_state(TASK_RUNNING);
458 P9_DPRINTK(P9_DEBUG_MUX, "finish\n");
459 return 0;
460}
461
462/**
463 * p9_write_work - called when a transport can send some data
464 */
465static void p9_write_work(struct work_struct *work)
466{
467 int n, err;
468 struct p9_conn *m;
469 struct p9_req *req;
470
471 m = container_of(work, struct p9_conn, wq);
472
473 if (m->err < 0) {
474 clear_bit(Wworksched, &m->wsched);
475 return;
476 }
477
478 if (!m->wsize) {
479 if (list_empty(&m->unsent_req_list)) {
480 clear_bit(Wworksched, &m->wsched);
481 return;
482 }
483
484 spin_lock(&m->lock);
485again:
486 req = list_entry(m->unsent_req_list.next, struct p9_req,
487 req_list);
488 list_move_tail(&req->req_list, &m->req_list);
489 if (req->err == ERREQFLUSH)
490 goto again;
491
492 m->wbuf = req->tcall->sdata;
493 m->wsize = req->tcall->size;
494 m->wpos = 0;
495 spin_unlock(&m->lock);
496 }
497
498 P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos,
499 m->wsize);
500 clear_bit(Wpending, &m->wsched);
501 err = m->trans->write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos);
502 P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
503 if (err == -EAGAIN) {
504 clear_bit(Wworksched, &m->wsched);
505 return;
506 }
507
508 if (err < 0)
509 goto error;
510 else if (err == 0) {
511 err = -EREMOTEIO;
512 goto error;
513 }
514
515 m->wpos += err;
516 if (m->wpos == m->wsize)
517 m->wpos = m->wsize = 0;
518
519 if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) {
520 if (test_and_clear_bit(Wpending, &m->wsched))
521 n = POLLOUT;
522 else
523 n = m->trans->poll(m->trans, NULL);
524
525 if (n & POLLOUT) {
526 P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
527 queue_work(p9_mux_wq, &m->wq);
528 } else
529 clear_bit(Wworksched, &m->wsched);
530 } else
531 clear_bit(Wworksched, &m->wsched);
532
533 return;
534
535error:
536 p9_conn_cancel(m, err);
537 clear_bit(Wworksched, &m->wsched);
538}
539
540static void process_request(struct p9_conn *m, struct p9_req *req)
541{
542 int ecode;
543 struct p9_str *ename;
544
545 if (!req->err && req->rcall->id == P9_RERROR) {
546 ecode = req->rcall->params.rerror.errno;
547 ename = &req->rcall->params.rerror.error;
548
549 P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
550 ename->str);
551
552 if (*m->extended)
553 req->err = -ecode;
554
555 if (!req->err) {
556 req->err = p9_errstr2errno(ename->str, ename->len);
557
558 if (!req->err) { /* string match failed */
559 PRINT_FCALL_ERROR("unknown error", req->rcall);
560 }
561
562 if (!req->err)
563 req->err = -ESERVERFAULT;
564 }
565 } else if (req->tcall && req->rcall->id != req->tcall->id + 1) {
566 P9_DPRINTK(P9_DEBUG_ERROR,
567 "fcall mismatch: expected %d, got %d\n",
568 req->tcall->id + 1, req->rcall->id);
569 if (!req->err)
570 req->err = -EIO;
571 }
572}
573
574/**
575 * p9_read_work - called when there is some data to be read from a transport
576 */
577static void p9_read_work(struct work_struct *work)
578{
579 int n, err;
580 struct p9_conn *m;
581 struct p9_req *req, *rptr, *rreq;
582 struct p9_fcall *rcall;
583 char *rbuf;
584
585 m = container_of(work, struct p9_conn, rq);
586
587 if (m->err < 0)
588 return;
589
590 rcall = NULL;
591 P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
592
593 if (!m->rcall) {
594 m->rcall =
595 kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL);
596 if (!m->rcall) {
597 err = -ENOMEM;
598 goto error;
599 }
600
601 m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
602 m->rpos = 0;
603 }
604
605 clear_bit(Rpending, &m->wsched);
606 err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
607 P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err);
608 if (err == -EAGAIN) {
609 clear_bit(Rworksched, &m->wsched);
610 return;
611 }
612
613 if (err <= 0)
614 goto error;
615
616 m->rpos += err;
617 while (m->rpos > 4) {
618 n = le32_to_cpu(*(__le32 *) m->rbuf);
619 if (n >= m->msize) {
620 P9_DPRINTK(P9_DEBUG_ERROR,
621 "requested packet size too big: %d\n", n);
622 err = -EIO;
623 goto error;
624 }
625
626 if (m->rpos < n)
627 break;
628
629 err =
630 p9_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended);
631 if (err < 0) {
632 goto error;
633 }
634
635#ifdef CONFIG_NET_9P_DEBUG
636 if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
637 char buf[150];
638
639 p9_printfcall(buf, sizeof(buf), m->rcall,
640 *m->extended);
641 printk(KERN_NOTICE ">>> %p %s\n", m, buf);
642 }
643#endif
644
645 rcall = m->rcall;
646 rbuf = m->rbuf;
647 if (m->rpos > n) {
648 m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize,
649 GFP_KERNEL);
650 if (!m->rcall) {
651 err = -ENOMEM;
652 goto error;
653 }
654
655 m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
656 memmove(m->rbuf, rbuf + n, m->rpos - n);
657 m->rpos -= n;
658 } else {
659 m->rcall = NULL;
660 m->rbuf = NULL;
661 m->rpos = 0;
662 }
663
664 P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m,
665 rcall->id, rcall->tag);
666
667 req = NULL;
668 spin_lock(&m->lock);
669 list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
670 if (rreq->tag == rcall->tag) {
671 req = rreq;
672 if (req->flush != Flushing)
673 list_del(&req->req_list);
674 break;
675 }
676 }
677 spin_unlock(&m->lock);
678
679 if (req) {
680 req->rcall = rcall;
681 process_request(m, req);
682
683 if (req->flush != Flushing) {
684 if (req->cb)
685 (*req->cb) (req, req->cba);
686 else
687 kfree(req->rcall);
688
689 wake_up(&m->equeue);
690 }
691 } else {
692 if (err >= 0 && rcall->id != P9_RFLUSH)
693 P9_DPRINTK(P9_DEBUG_ERROR,
694 "unexpected response mux %p id %d tag %d\n",
695 m, rcall->id, rcall->tag);
696 kfree(rcall);
697 }
698 }
699
700 if (!list_empty(&m->req_list)) {
701 if (test_and_clear_bit(Rpending, &m->wsched))
702 n = POLLIN;
703 else
704 n = m->trans->poll(m->trans, NULL);
705
706 if (n & POLLIN) {
707 P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
708 queue_work(p9_mux_wq, &m->rq);
709 } else
710 clear_bit(Rworksched, &m->wsched);
711 } else
712 clear_bit(Rworksched, &m->wsched);
713
714 return;
715
716error:
717 p9_conn_cancel(m, err);
718 clear_bit(Rworksched, &m->wsched);
719}
720
721/**
722 * p9_send_request - send 9P request
723 * The function can sleep until the request is scheduled for sending.
724 * The function can be interrupted. Return from the function is not
725 * a guarantee that the request is sent successfully. Can return errors
726 * that can be retrieved by PTR_ERR macros.
727 *
728 * @m: mux data
729 * @tc: request to be sent
730 * @cb: callback function to call when response is received
731 * @cba: parameter to pass to the callback function
732 */
733static struct p9_req *p9_send_request(struct p9_conn *m,
734 struct p9_fcall *tc,
735 p9_conn_req_callback cb, void *cba)
736{
737 int n;
738 struct p9_req *req;
739
740 P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
741 tc, tc->id);
742 if (m->err < 0)
743 return ERR_PTR(m->err);
744
745 req = kmalloc(sizeof(struct p9_req), GFP_KERNEL);
746 if (!req)
747 return ERR_PTR(-ENOMEM);
748
749 if (tc->id == P9_TVERSION)
750 n = P9_NOTAG;
751 else
752 n = p9_mux_get_tag(m);
753
754 if (n < 0)
755 return ERR_PTR(-ENOMEM);
756
757 p9_set_tag(tc, n);
758
759#ifdef CONFIG_NET_9P_DEBUG
760 if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
761 char buf[150];
762
763 p9_printfcall(buf, sizeof(buf), tc, *m->extended);
764 printk(KERN_NOTICE "<<< %p %s\n", m, buf);
765 }
766#endif
767
768 spin_lock_init(&req->lock);
769 req->tag = n;
770 req->tcall = tc;
771 req->rcall = NULL;
772 req->err = 0;
773 req->cb = cb;
774 req->cba = cba;
775 req->flush = None;
776
777 spin_lock(&m->lock);
778 list_add_tail(&req->req_list, &m->unsent_req_list);
779 spin_unlock(&m->lock);
780
781 if (test_and_clear_bit(Wpending, &m->wsched))
782 n = POLLOUT;
783 else
784 n = m->trans->poll(m->trans, NULL);
785
786 if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
787 queue_work(p9_mux_wq, &m->wq);
788
789 return req;
790}
791
792static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req)
793{
794 p9_mux_put_tag(m, req->tag);
795 kfree(req);
796}
797
798static void p9_mux_flush_cb(struct p9_req *freq, void *a)
799{
800 p9_conn_req_callback cb;
801 int tag;
802 struct p9_conn *m;
803 struct p9_req *req, *rreq, *rptr;
804
805 m = a;
806 P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
807 freq->tcall, freq->rcall, freq->err,
808 freq->tcall->params.tflush.oldtag);
809
810 spin_lock(&m->lock);
811 cb = NULL;
812 tag = freq->tcall->params.tflush.oldtag;
813 req = NULL;
814 list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) {
815 if (rreq->tag == tag) {
816 req = rreq;
817 list_del(&req->req_list);
818 break;
819 }
820 }
821 spin_unlock(&m->lock);
822
823 if (req) {
824 spin_lock(&req->lock);
825 req->flush = Flushed;
826 spin_unlock(&req->lock);
827
828 if (req->cb)
829 (*req->cb) (req, req->cba);
830 else
831 kfree(req->rcall);
832
833 wake_up(&m->equeue);
834 }
835
836 kfree(freq->tcall);
837 kfree(freq->rcall);
838 p9_mux_free_request(m, freq);
839}
840
841static int
842p9_mux_flush_request(struct p9_conn *m, struct p9_req *req)
843{
844 struct p9_fcall *fc;
845 struct p9_req *rreq, *rptr;
846
847 P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
848
849 /* if a response was received for a request, do nothing */
850 spin_lock(&req->lock);
851 if (req->rcall || req->err) {
852 spin_unlock(&req->lock);
853 P9_DPRINTK(P9_DEBUG_MUX,
854 "mux %p req %p response already received\n", m, req);
855 return 0;
856 }
857
858 req->flush = Flushing;
859 spin_unlock(&req->lock);
860
861 spin_lock(&m->lock);
862 /* if the request is not sent yet, just remove it from the list */
863 list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) {
864 if (rreq->tag == req->tag) {
865 P9_DPRINTK(P9_DEBUG_MUX,
866 "mux %p req %p request is not sent yet\n", m, req);
867 list_del(&rreq->req_list);
868 req->flush = Flushed;
869 spin_unlock(&m->lock);
870 if (req->cb)
871 (*req->cb) (req, req->cba);
872 return 0;
873 }
874 }
875 spin_unlock(&m->lock);
876
877 clear_thread_flag(TIF_SIGPENDING);
878 fc = p9_create_tflush(req->tag);
879 p9_send_request(m, fc, p9_mux_flush_cb, m);
880 return 1;
881}
882
883static void
884p9_conn_rpc_cb(struct p9_req *req, void *a)
885{
886 struct p9_mux_rpc *r;
887
888 P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a);
889 r = a;
890 r->rcall = req->rcall;
891 r->err = req->err;
892
893 if (req->flush != None && !req->err)
894 r->err = -ERESTARTSYS;
895
896 wake_up(&r->wqueue);
897}
898
899/**
900 * p9_mux_rpc - sends 9P request and waits until a response is available.
901 * The function can be interrupted.
902 * @m: mux data
903 * @tc: request to be sent
904 * @rc: pointer where a pointer to the response is stored
905 */
906int
907p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc,
908 struct p9_fcall **rc)
909{
910 int err, sigpending;
911 unsigned long flags;
912 struct p9_req *req;
913 struct p9_mux_rpc r;
914
915 r.err = 0;
916 r.tcall = tc;
917 r.rcall = NULL;
918 r.m = m;
919 init_waitqueue_head(&r.wqueue);
920
921 if (rc)
922 *rc = NULL;
923
924 sigpending = 0;
925 if (signal_pending(current)) {
926 sigpending = 1;
927 clear_thread_flag(TIF_SIGPENDING);
928 }
929
930 req = p9_send_request(m, tc, p9_conn_rpc_cb, &r);
931 if (IS_ERR(req)) {
932 err = PTR_ERR(req);
933 P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
934 return err;
935 }
936
937 err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0);
938 if (r.err < 0)
939 err = r.err;
940
941 if (err == -ERESTARTSYS && m->trans->status == Connected
942 && m->err == 0) {
943 if (p9_mux_flush_request(m, req)) {
944 /* wait until we get response of the flush message */
945 do {
946 clear_thread_flag(TIF_SIGPENDING);
947 err = wait_event_interruptible(r.wqueue,
948 r.rcall || r.err);
949 } while (!r.rcall && !r.err && err == -ERESTARTSYS &&
950 m->trans->status == Connected && !m->err);
951
952 err = -ERESTARTSYS;
953 }
954 sigpending = 1;
955 }
956
957 if (sigpending) {
958 spin_lock_irqsave(&current->sighand->siglock, flags);
959 recalc_sigpending();
960 spin_unlock_irqrestore(&current->sighand->siglock, flags);
961 }
962
963 if (rc)
964 *rc = r.rcall;
965 else
966 kfree(r.rcall);
967
968 p9_mux_free_request(m, req);
969 if (err > 0)
970 err = -EIO;
971
972 return err;
973}
974EXPORT_SYMBOL(p9_conn_rpc);
975
976#ifdef P9_NONBLOCK
977/**
978 * p9_conn_rpcnb - sends 9P request without waiting for response.
979 * @m: mux data
980 * @tc: request to be sent
981 * @cb: callback function to be called when response arrives
982 * @cba: value to pass to the callback function
983 */
984int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
985 p9_conn_req_callback cb, void *a)
986{
987 int err;
988 struct p9_req *req;
989
990 req = p9_send_request(m, tc, cb, a);
991 if (IS_ERR(req)) {
992 err = PTR_ERR(req);
993 P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
994 return PTR_ERR(req);
995 }
996
997 P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);
998 return 0;
999}
1000EXPORT_SYMBOL(p9_conn_rpcnb);
1001#endif /* P9_NONBLOCK */
1002
1003/**
1004 * p9_conn_cancel - cancel all pending requests with error
1005 * @m: mux data
1006 * @err: error code
1007 */
1008void p9_conn_cancel(struct p9_conn *m, int err)
1009{
1010 struct p9_req *req, *rtmp;
1011 LIST_HEAD(cancel_list);
1012
1013 P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
1014 m->err = err;
1015 spin_lock(&m->lock);
1016 list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
1017 list_move(&req->req_list, &cancel_list);
1018 }
1019 list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) {
1020 list_move(&req->req_list, &cancel_list);
1021 }
1022 spin_unlock(&m->lock);
1023
1024 list_for_each_entry_safe(req, rtmp, &cancel_list, req_list) {
1025 list_del(&req->req_list);
1026 if (!req->err)
1027 req->err = err;
1028
1029 if (req->cb)
1030 (*req->cb) (req, req->cba);
1031 else
1032 kfree(req->rcall);
1033 }
1034
1035 wake_up(&m->equeue);
1036}
1037EXPORT_SYMBOL(p9_conn_cancel);
1038
1039static u16 p9_mux_get_tag(struct p9_conn *m)
1040{
1041 int tag;
1042
1043 tag = p9_idpool_get(m->tagpool);
1044 if (tag < 0)
1045 return P9_NOTAG;
1046 else
1047 return (u16) tag;
1048}
1049
1050static void p9_mux_put_tag(struct p9_conn *m, u16 tag)
1051{
1052 if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool))
1053 p9_idpool_put(tag, m->tagpool);
1054}
diff --git a/net/9p/sysctl.c b/net/9p/sysctl.c
new file mode 100644
index 000000000000..e7fe706ab95a
--- /dev/null
+++ b/net/9p/sysctl.c
@@ -0,0 +1,86 @@
1/*
2 * net/9p/sysctl.c
3 *
4 * 9P sysctl interface
5 *
6 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to:
19 * Free Software Foundation
20 * 51 Franklin Street, Fifth Floor
21 * Boston, MA 02111-1301 USA
22 *
23 */
24
25#include <linux/kernel.h>
26#include <linux/mm.h>
27#include <linux/sysctl.h>
28#include <linux/init.h>
29#include <net/9p/9p.h>
30
31enum {
32 P9_SYSCTL_NET = 487,
33 P9_SYSCTL_DEBUG = 1,
34};
35
36static ctl_table p9_table[] = {
37#ifdef CONFIG_NET_9P_DEBUG
38 {
39 .ctl_name = P9_SYSCTL_DEBUG,
40 .procname = "debug",
41 .data = &p9_debug_level,
42 .maxlen = sizeof(int),
43 .mode = 0644,
44 .proc_handler = &proc_dointvec
45 },
46#endif
47 { .ctl_name = 0 },
48};
49
50static ctl_table p9_net_table[] = {
51 {
52 .ctl_name = P9_SYSCTL_NET,
53 .procname = "9p",
54 .maxlen = 0,
55 .mode = 0555,
56 .child = p9_table,
57 },
58 { .ctl_name = 0 },
59};
60
61static ctl_table p9_ctl_table[] = {
62 {
63 .ctl_name = CTL_NET,
64 .procname = "net",
65 .maxlen = 0,
66 .mode = 0555,
67 .child = p9_net_table,
68 },
69 { .ctl_name = 0 },
70};
71
72static struct ctl_table_header *p9_table_header;
73
74int __init p9_sysctl_register(void)
75{
76 p9_table_header = register_sysctl_table(p9_ctl_table);
77 if (!p9_table_header)
78 return -ENOMEM;
79
80 return 0;
81}
82
83void __exit p9_sysctl_unregister(void)
84{
85 unregister_sysctl_table(p9_table_header);
86}
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
new file mode 100644
index 000000000000..fd636e94358f
--- /dev/null
+++ b/net/9p/trans_fd.c
@@ -0,0 +1,363 @@
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-2005 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 <net/9p/9p.h>
40#include <net/9p/transport.h>
41
42#define P9_PORT 564
43
44struct p9_trans_fd {
45 struct file *rd;
46 struct file *wr;
47};
48
49static int p9_socket_open(struct p9_transport *trans, struct socket *csocket);
50static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd);
51static int p9_fd_read(struct p9_transport *trans, void *v, int len);
52static int p9_fd_write(struct p9_transport *trans, void *v, int len);
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
99 return trans;
100
101error:
102 if (csocket)
103 sock_release(csocket);
104
105 kfree(trans);
106 return ERR_PTR(err);
107}
108EXPORT_SYMBOL(p9_trans_create_tcp);
109
110struct p9_transport *p9_trans_create_unix(const char *addr)
111{
112 int err;
113 struct socket *csocket;
114 struct sockaddr_un sun_server;
115 struct p9_transport *trans;
116
117 csocket = NULL;
118 trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
119 if (!trans)
120 return ERR_PTR(-ENOMEM);
121
122 trans->write = p9_fd_write;
123 trans->read = p9_fd_read;
124 trans->close = p9_fd_close;
125 trans->poll = p9_fd_poll;
126
127 if (strlen(addr) > UNIX_PATH_MAX) {
128 P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
129 addr);
130 err = -ENAMETOOLONG;
131 goto error;
132 }
133
134 sun_server.sun_family = PF_UNIX;
135 strcpy(sun_server.sun_path, addr);
136 sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
137 err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
138 sizeof(struct sockaddr_un) - 1, 0);
139 if (err < 0) {
140 P9_EPRINTK(KERN_ERR,
141 "p9_trans_unix: problem connecting socket: %s: %d\n",
142 addr, err);
143 goto error;
144 }
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}
159EXPORT_SYMBOL(p9_trans_create_unix);
160
161struct p9_transport *p9_trans_create_fd(int rfd, int wfd)
162{
163 int err;
164 struct p9_transport *trans;
165
166 if (rfd == ~0 || wfd == ~0) {
167 printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
168 return ERR_PTR(-ENOPROTOOPT);
169 }
170
171 trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
172 if (!trans)
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
186error:
187 kfree(trans);
188 return ERR_PTR(err);
189}
190EXPORT_SYMBOL(p9_trans_create_fd);
191
192static int p9_socket_open(struct p9_transport *trans, struct socket *csocket)
193{
194 int fd, ret;
195
196 csocket->sk->sk_allocation = GFP_NOIO;
197 fd = sock_map_fd(csocket);
198 if (fd < 0) {
199 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
200 return fd;
201 }
202
203 ret = p9_fd_open(trans, fd, fd);
204 if (ret < 0) {
205 P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n");
206 sockfd_put(csocket);
207 return ret;
208 }
209
210 ((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK;
211
212 return 0;
213}
214
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/**
240 * p9_fd_read- read from a fd
241 * @v9ses: session information
242 * @v: buffer to receive data into
243 * @len: size of receive buffer
244 *
245 */
246static int p9_fd_read(struct p9_transport *trans, void *v, int len)
247{
248 int ret;
249 struct p9_trans_fd *ts = NULL;
250
251 if (trans && trans->status != Disconnected)
252 ts = trans->priv;
253
254 if (!ts)
255 return -EREMOTEIO;
256
257 if (!(ts->rd->f_flags & O_NONBLOCK))
258 P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
259
260 ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
261 if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
262 trans->status = Disconnected;
263 return ret;
264}
265
266/**
267 * p9_fd_write - write to a socket
268 * @v9ses: session information
269 * @v: buffer to send data from
270 * @len: size of send buffer
271 *
272 */
273static int p9_fd_write(struct p9_transport *trans, void *v, int len)
274{
275 int ret;
276 mm_segment_t oldfs;
277 struct p9_trans_fd *ts = NULL;
278
279 if (trans && trans->status != Disconnected)
280 ts = trans->priv;
281
282 if (!ts)
283 return -EREMOTEIO;
284
285 if (!(ts->wr->f_flags & O_NONBLOCK))
286 P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
287
288 oldfs = get_fs();
289 set_fs(get_ds());
290 /* The cast to a user pointer is valid due to the set_fs() */
291 ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
292 set_fs(oldfs);
293
294 if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
295 trans->status = Disconnected;
296 return ret;
297}
298
299static unsigned int
300p9_fd_poll(struct p9_transport *trans, struct poll_table_struct *pt)
301{
302 int ret, n;
303 struct p9_trans_fd *ts = NULL;
304 mm_segment_t oldfs;
305
306 if (trans && trans->status == Connected)
307 ts = trans->priv;
308
309 if (!ts)
310 return -EREMOTEIO;
311
312 if (!ts->rd->f_op || !ts->rd->f_op->poll)
313 return -EIO;
314
315 if (!ts->wr->f_op || !ts->wr->f_op->poll)
316 return -EIO;
317
318 oldfs = get_fs();
319 set_fs(get_ds());
320
321 ret = ts->rd->f_op->poll(ts->rd, pt);
322 if (ret < 0)
323 goto end;
324
325 if (ts->rd != ts->wr) {
326 n = ts->wr->f_op->poll(ts->wr, pt);
327 if (n < 0) {
328 ret = n;
329 goto end;
330 }
331 ret = (ret & ~POLLOUT) | (n & ~POLLIN);
332 }
333
334end:
335 set_fs(oldfs);
336 return ret;
337}
338
339/**
340 * p9_sock_close - shutdown socket
341 * @trans: private socket structure
342 *
343 */
344static void p9_fd_close(struct p9_transport *trans)
345{
346 struct p9_trans_fd *ts;
347
348 if (!trans)
349 return;
350
351 ts = xchg(&trans->priv, NULL);
352
353 if (!ts)
354 return;
355
356 trans->status = Disconnected;
357 if (ts->rd)
358 fput(ts->rd);
359 if (ts->wr)
360 fput(ts->wr);
361 kfree(ts);
362}
363
diff --git a/net/9p/util.c b/net/9p/util.c
new file mode 100644
index 000000000000..22077b79395d
--- /dev/null
+++ b/net/9p/util.c
@@ -0,0 +1,125 @@
1/*
2 * net/9p/util.c
3 *
4 * This file contains some helper functions
5 *
6 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
7 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to:
21 * Free Software Foundation
22 * 51 Franklin Street, Fifth Floor
23 * Boston, MA 02111-1301 USA
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/errno.h>
29#include <linux/fs.h>
30#include <linux/sched.h>
31#include <linux/parser.h>
32#include <linux/idr.h>
33#include <net/9p/9p.h>
34
35struct p9_idpool {
36 struct semaphore lock;
37 struct idr pool;
38};
39
40struct p9_idpool *p9_idpool_create(void)
41{
42 struct p9_idpool *p;
43
44 p = kmalloc(sizeof(struct p9_idpool), GFP_KERNEL);
45 if (!p)
46 return ERR_PTR(-ENOMEM);
47
48 init_MUTEX(&p->lock);
49 idr_init(&p->pool);
50
51 return p;
52}
53EXPORT_SYMBOL(p9_idpool_create);
54
55void p9_idpool_destroy(struct p9_idpool *p)
56{
57 idr_destroy(&p->pool);
58 kfree(p);
59}
60EXPORT_SYMBOL(p9_idpool_destroy);
61
62/**
63 * p9_idpool_get - allocate numeric id from pool
64 * @p - pool to allocate from
65 *
66 * XXX - This seems to be an awful generic function, should it be in idr.c with
67 * the lock included in struct idr?
68 */
69
70int p9_idpool_get(struct p9_idpool *p)
71{
72 int i = 0;
73 int error;
74
75retry:
76 if (idr_pre_get(&p->pool, GFP_KERNEL) == 0)
77 return 0;
78
79 if (down_interruptible(&p->lock) == -EINTR) {
80 P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n");
81 return -1;
82 }
83
84 /* no need to store exactly p, we just need something non-null */
85 error = idr_get_new(&p->pool, p, &i);
86 up(&p->lock);
87
88 if (error == -EAGAIN)
89 goto retry;
90 else if (error)
91 return -1;
92
93 return i;
94}
95EXPORT_SYMBOL(p9_idpool_get);
96
97/**
98 * p9_idpool_put - release numeric id from pool
99 * @p - pool to allocate from
100 *
101 * XXX - This seems to be an awful generic function, should it be in idr.c with
102 * the lock included in struct idr?
103 */
104
105void p9_idpool_put(int id, struct p9_idpool *p)
106{
107 if (down_interruptible(&p->lock) == -EINTR) {
108 P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n");
109 return;
110 }
111 idr_remove(&p->pool, id);
112 up(&p->lock);
113}
114EXPORT_SYMBOL(p9_idpool_put);
115
116/**
117 * p9_idpool_check - check if the specified id is available
118 * @id - id to check
119 * @p - pool
120 */
121int p9_idpool_check(int id, struct p9_idpool *p)
122{
123 return idr_find(&p->pool, id) != NULL;
124}
125EXPORT_SYMBOL(p9_idpool_check);
diff --git a/net/Kconfig b/net/Kconfig
index f3de72978ab6..cdba08ca2efe 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -227,6 +227,7 @@ source "net/ieee80211/Kconfig"
227endmenu 227endmenu
228 228
229source "net/rfkill/Kconfig" 229source "net/rfkill/Kconfig"
230source "net/9p/Kconfig"
230 231
231endif # if NET 232endif # if NET
232endmenu # Networking 233endmenu # Networking
diff --git a/net/Makefile b/net/Makefile
index a87a88963432..bbe7d2a41486 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_TIPC) += tipc/
51obj-$(CONFIG_NETLABEL) += netlabel/ 51obj-$(CONFIG_NETLABEL) += netlabel/
52obj-$(CONFIG_IUCV) += iucv/ 52obj-$(CONFIG_IUCV) += iucv/
53obj-$(CONFIG_RFKILL) += rfkill/ 53obj-$(CONFIG_RFKILL) += rfkill/
54obj-$(CONFIG_NET_9P) += 9p/
54 55
55ifeq ($(CONFIG_NET),y) 56ifeq ($(CONFIG_NET),y)
56obj-$(CONFIG_SYSCTL) += sysctl_net.o 57obj-$(CONFIG_SYSCTL) += sysctl_net.o