blob: cb170750337c02047ea0b1ff41dc36a028f105dc [file] [log] [blame]
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001/*
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
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500130 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
131 p9_fid_destroy(fid);
132
Eric Van Hensbergen0af88872007-07-13 16:47:58 -0500133 if (clnt->fidpool)
134 p9_idpool_destroy(clnt->fidpool);
135
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500136 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}