9p: block-based virtio client
[linux-2.6.git] / net / 9p / client.c
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 <linux/parser.h>
34 #include <net/9p/transport.h>
35 #include <net/9p/conn.h>
36 #include <net/9p/client.h>
37
38 static struct p9_fid *p9_fid_create(struct p9_client *clnt);
39 static void p9_fid_destroy(struct p9_fid *fid);
40 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
41
42 /**
43  * p9_client_rpc - sends 9P request and waits until a response is available.
44  *      The function can be interrupted.
45  * @c: client data
46  * @tc: request to be sent
47  * @rc: pointer where a pointer to the response is stored
48  */
49 int
50 p9_client_rpc(struct p9_client *c, struct p9_fcall *tc,
51         struct p9_fcall **rc)
52 {
53         if (c->trans->rpc)
54                 return c->trans->rpc(c->trans, tc, rc, c->msize, c->dotu);
55         else
56                 return p9_conn_rpc(c->conn, tc, rc);
57 }
58
59 struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
60                                                                    int dotu)
61 {
62         int err, n;
63         struct p9_client *clnt;
64         struct p9_fcall *tc, *rc;
65         struct p9_str *version;
66
67         err = 0;
68         tc = NULL;
69         rc = NULL;
70         clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
71         if (!clnt)
72                 return ERR_PTR(-ENOMEM);
73
74         P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n",
75                 clnt, trans, msize, dotu);
76         spin_lock_init(&clnt->lock);
77         clnt->trans = trans;
78         clnt->msize = msize;
79         clnt->dotu = dotu;
80         INIT_LIST_HEAD(&clnt->fidlist);
81         clnt->fidpool = p9_idpool_create();
82         if (!clnt->fidpool) {
83                 err = PTR_ERR(clnt->fidpool);
84                 clnt->fidpool = NULL;
85                 goto error;
86         }
87
88         clnt->conn = p9_conn_create(clnt->trans, clnt->msize, &clnt->dotu);
89         if (IS_ERR(clnt->conn)) {
90                 err = PTR_ERR(clnt->conn);
91                 clnt->conn = NULL;
92                 goto error;
93         }
94
95         tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000");
96         if (IS_ERR(tc)) {
97                 err = PTR_ERR(tc);
98                 tc = NULL;
99                 goto error;
100         }
101
102         err = p9_client_rpc(clnt, tc, &rc);
103         if (err)
104                 goto error;
105
106         version = &rc->params.rversion.version;
107         if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8))
108                 clnt->dotu = 1;
109         else if (version->len == 6 && !memcmp(version->str, "9P2000", 6))
110                 clnt->dotu = 0;
111         else {
112                 err = -EREMOTEIO;
113                 goto error;
114         }
115
116         n = rc->params.rversion.msize;
117         if (n < clnt->msize)
118                 clnt->msize = n;
119
120         kfree(tc);
121         kfree(rc);
122         return clnt;
123
124 error:
125         kfree(tc);
126         kfree(rc);
127         p9_client_destroy(clnt);
128         return ERR_PTR(err);
129 }
130 EXPORT_SYMBOL(p9_client_create);
131
132 void p9_client_destroy(struct p9_client *clnt)
133 {
134         struct p9_fid *fid, *fidptr;
135
136         P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
137         if (clnt->conn) {
138                 p9_conn_destroy(clnt->conn);
139                 clnt->conn = NULL;
140         }
141
142         if (clnt->trans) {
143                 clnt->trans->close(clnt->trans);
144                 kfree(clnt->trans);
145                 clnt->trans = NULL;
146         }
147
148         list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
149                 p9_fid_destroy(fid);
150
151         if (clnt->fidpool)
152                 p9_idpool_destroy(clnt->fidpool);
153
154         kfree(clnt);
155 }
156 EXPORT_SYMBOL(p9_client_destroy);
157
158 void p9_client_disconnect(struct p9_client *clnt)
159 {
160         P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
161         clnt->trans->status = Disconnected;
162         p9_conn_cancel(clnt->conn, -EIO);
163 }
164 EXPORT_SYMBOL(p9_client_disconnect);
165
166 struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
167         char *uname, u32 n_uname, char *aname)
168 {
169         int err;
170         struct p9_fcall *tc, *rc;
171         struct p9_fid *fid;
172
173         P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n",
174                 clnt, afid?afid->fid:-1, uname, aname);
175         err = 0;
176         tc = NULL;
177         rc = NULL;
178
179         fid = p9_fid_create(clnt);
180         if (IS_ERR(fid)) {
181                 err = PTR_ERR(fid);
182                 fid = NULL;
183                 goto error;
184         }
185
186         tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname,
187                 n_uname, clnt->dotu);
188         if (IS_ERR(tc)) {
189                 err = PTR_ERR(tc);
190                 tc = NULL;
191                 goto error;
192         }
193
194         err = p9_client_rpc(clnt, tc, &rc);
195         if (err)
196                 goto error;
197
198         memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid));
199         kfree(tc);
200         kfree(rc);
201         return fid;
202
203 error:
204         kfree(tc);
205         kfree(rc);
206         if (fid)
207                 p9_fid_destroy(fid);
208         return ERR_PTR(err);
209 }
210 EXPORT_SYMBOL(p9_client_attach);
211
212 struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
213         u32 n_uname, char *aname)
214 {
215         int err;
216         struct p9_fcall *tc, *rc;
217         struct p9_fid *fid;
218
219         P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname,
220                                                                         aname);
221         err = 0;
222         tc = NULL;
223         rc = NULL;
224
225         fid = p9_fid_create(clnt);
226         if (IS_ERR(fid)) {
227                 err = PTR_ERR(fid);
228                 fid = NULL;
229                 goto error;
230         }
231
232         tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu);
233         if (IS_ERR(tc)) {
234                 err = PTR_ERR(tc);
235                 tc = NULL;
236                 goto error;
237         }
238
239         err = p9_client_rpc(clnt, tc, &rc);
240         if (err)
241                 goto error;
242
243         memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid));
244         kfree(tc);
245         kfree(rc);
246         return fid;
247
248 error:
249         kfree(tc);
250         kfree(rc);
251         if (fid)
252                 p9_fid_destroy(fid);
253         return ERR_PTR(err);
254 }
255 EXPORT_SYMBOL(p9_client_auth);
256
257 struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
258         int clone)
259 {
260         int err;
261         struct p9_fcall *tc, *rc;
262         struct p9_client *clnt;
263         struct p9_fid *fid;
264
265         P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n",
266                 oldfid->fid, nwname, wnames?wnames[0]:NULL);
267         err = 0;
268         tc = NULL;
269         rc = NULL;
270         clnt = oldfid->clnt;
271         if (clone) {
272                 fid = p9_fid_create(clnt);
273                 if (IS_ERR(fid)) {
274                         err = PTR_ERR(fid);
275                         fid = NULL;
276                         goto error;
277                 }
278
279                 fid->uid = oldfid->uid;
280         } else
281                 fid = oldfid;
282
283         tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames);
284         if (IS_ERR(tc)) {
285                 err = PTR_ERR(tc);
286                 tc = NULL;
287                 goto error;
288         }
289
290         err = p9_client_rpc(clnt, tc, &rc);
291         if (err) {
292                 if (rc && rc->id == P9_RWALK)
293                         goto clunk_fid;
294                 else
295                         goto error;
296         }
297
298         if (rc->params.rwalk.nwqid != nwname) {
299                 err = -ENOENT;
300                 goto clunk_fid;
301         }
302
303         if (nwname)
304                 memmove(&fid->qid,
305                         &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1],
306                         sizeof(struct p9_qid));
307         else
308                 fid->qid = oldfid->qid;
309
310         kfree(tc);
311         kfree(rc);
312         return fid;
313
314 clunk_fid:
315         kfree(tc);
316         kfree(rc);
317         rc = NULL;
318         tc = p9_create_tclunk(fid->fid);
319         if (IS_ERR(tc)) {
320                 err = PTR_ERR(tc);
321                 tc = NULL;
322                 goto error;
323         }
324
325         p9_client_rpc(clnt, tc, &rc);
326
327 error:
328         kfree(tc);
329         kfree(rc);
330         if (fid && (fid != oldfid))
331                 p9_fid_destroy(fid);
332
333         return ERR_PTR(err);
334 }
335 EXPORT_SYMBOL(p9_client_walk);
336
337 int p9_client_open(struct p9_fid *fid, int mode)
338 {
339         int err;
340         struct p9_fcall *tc, *rc;
341         struct p9_client *clnt;
342
343         P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode);
344         err = 0;
345         tc = NULL;
346         rc = NULL;
347         clnt = fid->clnt;
348
349         if (fid->mode != -1)
350                 return -EINVAL;
351
352         tc = p9_create_topen(fid->fid, mode);
353         if (IS_ERR(tc)) {
354                 err = PTR_ERR(tc);
355                 tc = NULL;
356                 goto done;
357         }
358
359         err = p9_client_rpc(clnt, tc, &rc);
360         if (err)
361                 goto done;
362
363         fid->mode = mode;
364         fid->iounit = rc->params.ropen.iounit;
365
366 done:
367         kfree(tc);
368         kfree(rc);
369         return err;
370 }
371 EXPORT_SYMBOL(p9_client_open);
372
373 int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
374                      char *extension)
375 {
376         int err;
377         struct p9_fcall *tc, *rc;
378         struct p9_client *clnt;
379
380         P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid,
381                 name, perm, mode);
382         err = 0;
383         tc = NULL;
384         rc = NULL;
385         clnt = fid->clnt;
386
387         if (fid->mode != -1)
388                 return -EINVAL;
389
390         tc = p9_create_tcreate(fid->fid, name, perm, mode, extension,
391                                                                clnt->dotu);
392         if (IS_ERR(tc)) {
393                 err = PTR_ERR(tc);
394                 tc = NULL;
395                 goto done;
396         }
397
398         err = p9_client_rpc(clnt, tc, &rc);
399         if (err)
400                 goto done;
401
402         fid->mode = mode;
403         fid->iounit = rc->params.ropen.iounit;
404
405 done:
406         kfree(tc);
407         kfree(rc);
408         return err;
409 }
410 EXPORT_SYMBOL(p9_client_fcreate);
411
412 int p9_client_clunk(struct p9_fid *fid)
413 {
414         int err;
415         struct p9_fcall *tc, *rc;
416         struct p9_client *clnt;
417
418         P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
419         err = 0;
420         tc = NULL;
421         rc = NULL;
422         clnt = fid->clnt;
423
424         tc = p9_create_tclunk(fid->fid);
425         if (IS_ERR(tc)) {
426                 err = PTR_ERR(tc);
427                 tc = NULL;
428                 goto done;
429         }
430
431         err = p9_client_rpc(clnt, tc, &rc);
432         if (err)
433                 goto done;
434
435         p9_fid_destroy(fid);
436
437 done:
438         kfree(tc);
439         kfree(rc);
440         return err;
441 }
442 EXPORT_SYMBOL(p9_client_clunk);
443
444 int p9_client_remove(struct p9_fid *fid)
445 {
446         int err;
447         struct p9_fcall *tc, *rc;
448         struct p9_client *clnt;
449
450         P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
451         err = 0;
452         tc = NULL;
453         rc = NULL;
454         clnt = fid->clnt;
455
456         tc = p9_create_tremove(fid->fid);
457         if (IS_ERR(tc)) {
458                 err = PTR_ERR(tc);
459                 tc = NULL;
460                 goto done;
461         }
462
463         err = p9_client_rpc(clnt, tc, &rc);
464         if (err)
465                 goto done;
466
467         p9_fid_destroy(fid);
468
469 done:
470         kfree(tc);
471         kfree(rc);
472         return err;
473 }
474 EXPORT_SYMBOL(p9_client_remove);
475
476 int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
477 {
478         int err, n, rsize, total;
479         struct p9_fcall *tc, *rc;
480         struct p9_client *clnt;
481
482         P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid,
483                                         (long long unsigned) offset, count);
484         err = 0;
485         tc = NULL;
486         rc = NULL;
487         clnt = fid->clnt;
488         total = 0;
489
490         rsize = fid->iounit;
491         if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
492                 rsize = clnt->msize - P9_IOHDRSZ;
493
494         do {
495                 if (count < rsize)
496                         rsize = count;
497
498                 tc = p9_create_tread(fid->fid, offset, rsize);
499                 if (IS_ERR(tc)) {
500                         err = PTR_ERR(tc);
501                         tc = NULL;
502                         goto error;
503                 }
504
505                 err = p9_client_rpc(clnt, tc, &rc);
506                 if (err)
507                         goto error;
508
509                 n = rc->params.rread.count;
510                 if (n > count)
511                         n = count;
512
513                 memmove(data, rc->params.rread.data, n);
514                 count -= n;
515                 data += n;
516                 offset += n;
517                 total += n;
518                 kfree(tc);
519                 tc = NULL;
520                 kfree(rc);
521                 rc = NULL;
522         } while (count > 0 && n == rsize);
523
524         return total;
525
526 error:
527         kfree(tc);
528         kfree(rc);
529         return err;
530 }
531 EXPORT_SYMBOL(p9_client_read);
532
533 int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
534 {
535         int err, n, rsize, total;
536         struct p9_fcall *tc, *rc;
537         struct p9_client *clnt;
538
539         P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
540                                         (long long unsigned) offset, count);
541         err = 0;
542         tc = NULL;
543         rc = NULL;
544         clnt = fid->clnt;
545         total = 0;
546
547         rsize = fid->iounit;
548         if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
549                 rsize = clnt->msize - P9_IOHDRSZ;
550
551         do {
552                 if (count < rsize)
553                         rsize = count;
554
555                 tc = p9_create_twrite(fid->fid, offset, rsize, data);
556                 if (IS_ERR(tc)) {
557                         err = PTR_ERR(tc);
558                         tc = NULL;
559                         goto error;
560                 }
561
562                 err = p9_client_rpc(clnt, tc, &rc);
563                 if (err)
564                         goto error;
565
566                 n = rc->params.rread.count;
567                 count -= n;
568                 data += n;
569                 offset += n;
570                 total += n;
571                 kfree(tc);
572                 tc = NULL;
573                 kfree(rc);
574                 rc = NULL;
575         } while (count > 0);
576
577         return total;
578
579 error:
580         kfree(tc);
581         kfree(rc);
582         return err;
583 }
584 EXPORT_SYMBOL(p9_client_write);
585
586 int
587 p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
588 {
589         int err, n, rsize, total;
590         struct p9_fcall *tc, *rc;
591         struct p9_client *clnt;
592
593         P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
594                                         (long long unsigned) offset, count);
595         err = 0;
596         tc = NULL;
597         rc = NULL;
598         clnt = fid->clnt;
599         total = 0;
600
601         rsize = fid->iounit;
602         if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
603                 rsize = clnt->msize - P9_IOHDRSZ;
604
605         do {
606                 if (count < rsize)
607                         rsize = count;
608
609                 tc = p9_create_tread(fid->fid, offset, rsize);
610                 if (IS_ERR(tc)) {
611                         err = PTR_ERR(tc);
612                         tc = NULL;
613                         goto error;
614                 }
615
616                 err = p9_client_rpc(clnt, tc, &rc);
617                 if (err)
618                         goto error;
619
620                 n = rc->params.rread.count;
621                 if (n > count)
622                         n = count;
623
624                 err = copy_to_user(data, rc->params.rread.data, n);
625                 if (err) {
626                         err = -EFAULT;
627                         goto error;
628                 }
629
630                 count -= n;
631                 data += n;
632                 offset += n;
633                 total += n;
634                 kfree(tc);
635                 tc = NULL;
636                 kfree(rc);
637                 rc = NULL;
638         } while (count > 0 && n == rsize);
639
640         return total;
641
642 error:
643         kfree(tc);
644         kfree(rc);
645         return err;
646 }
647 EXPORT_SYMBOL(p9_client_uread);
648
649 int
650 p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
651                                                                    u32 count)
652 {
653         int err, n, rsize, total;
654         struct p9_fcall *tc, *rc;
655         struct p9_client *clnt;
656
657         P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
658                                         (long long unsigned) offset, count);
659         err = 0;
660         tc = NULL;
661         rc = NULL;
662         clnt = fid->clnt;
663         total = 0;
664
665         rsize = fid->iounit;
666         if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
667                 rsize = clnt->msize - P9_IOHDRSZ;
668
669         do {
670                 if (count < rsize)
671                         rsize = count;
672
673                 tc = p9_create_twrite_u(fid->fid, offset, rsize, data);
674                 if (IS_ERR(tc)) {
675                         err = PTR_ERR(tc);
676                         tc = NULL;
677                         goto error;
678                 }
679
680                 err = p9_client_rpc(clnt, tc, &rc);
681                 if (err)
682                         goto error;
683
684                 n = rc->params.rread.count;
685                 count -= n;
686                 data += n;
687                 offset += n;
688                 total += n;
689                 kfree(tc);
690                 tc = NULL;
691                 kfree(rc);
692                 rc = NULL;
693         } while (count > 0);
694
695         return total;
696
697 error:
698         kfree(tc);
699         kfree(rc);
700         return err;
701 }
702 EXPORT_SYMBOL(p9_client_uwrite);
703
704 int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count)
705 {
706         int n, total;
707
708         P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
709                                         (long long unsigned) offset, count);
710         n = 0;
711         total = 0;
712         while (count) {
713                 n = p9_client_read(fid, data, offset, count);
714                 if (n <= 0)
715                         break;
716
717                 data += n;
718                 offset += n;
719                 count -= n;
720                 total += n;
721         }
722
723         if (n < 0)
724                 total = n;
725
726         return total;
727 }
728 EXPORT_SYMBOL(p9_client_readn);
729
730 struct p9_stat *p9_client_stat(struct p9_fid *fid)
731 {
732         int err;
733         struct p9_fcall *tc, *rc;
734         struct p9_client *clnt;
735         struct p9_stat *ret;
736
737         P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
738         err = 0;
739         tc = NULL;
740         rc = NULL;
741         ret = NULL;
742         clnt = fid->clnt;
743
744         tc = p9_create_tstat(fid->fid);
745         if (IS_ERR(tc)) {
746                 err = PTR_ERR(tc);
747                 tc = NULL;
748                 goto error;
749         }
750
751         err = p9_client_rpc(clnt, tc, &rc);
752         if (err)
753                 goto error;
754
755         ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu);
756         if (IS_ERR(ret)) {
757                 err = PTR_ERR(ret);
758                 ret = NULL;
759                 goto error;
760         }
761
762         kfree(tc);
763         kfree(rc);
764         return ret;
765
766 error:
767         kfree(tc);
768         kfree(rc);
769         kfree(ret);
770         return ERR_PTR(err);
771 }
772 EXPORT_SYMBOL(p9_client_stat);
773
774 int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
775 {
776         int err;
777         struct p9_fcall *tc, *rc;
778         struct p9_client *clnt;
779
780         P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
781         err = 0;
782         tc = NULL;
783         rc = NULL;
784         clnt = fid->clnt;
785
786         tc = p9_create_twstat(fid->fid, wst, clnt->dotu);
787         if (IS_ERR(tc)) {
788                 err = PTR_ERR(tc);
789                 tc = NULL;
790                 goto done;
791         }
792
793         err = p9_client_rpc(clnt, tc, &rc);
794
795 done:
796         kfree(tc);
797         kfree(rc);
798         return err;
799 }
800 EXPORT_SYMBOL(p9_client_wstat);
801
802 struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
803 {
804         int err, n, m;
805         struct p9_fcall *tc, *rc;
806         struct p9_client *clnt;
807         struct p9_stat st, *ret;
808
809         P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid,
810                                                 (long long unsigned) offset);
811         err = 0;
812         tc = NULL;
813         rc = NULL;
814         ret = NULL;
815         clnt = fid->clnt;
816
817         /* if the offset is below or above the current response, free it */
818         if (offset < fid->rdir_fpos || (fid->rdir_fcall &&
819                 offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) {
820                 fid->rdir_pos = 0;
821                 if (fid->rdir_fcall)
822                         fid->rdir_fpos += fid->rdir_fcall->params.rread.count;
823
824                 kfree(fid->rdir_fcall);
825                 fid->rdir_fcall = NULL;
826                 if (offset < fid->rdir_fpos)
827                         fid->rdir_fpos = 0;
828         }
829
830         if (!fid->rdir_fcall) {
831                 n = fid->iounit;
832                 if (!n || n > clnt->msize-P9_IOHDRSZ)
833                         n = clnt->msize - P9_IOHDRSZ;
834
835                 while (1) {
836                         if (fid->rdir_fcall) {
837                                 fid->rdir_fpos +=
838                                         fid->rdir_fcall->params.rread.count;
839                                 kfree(fid->rdir_fcall);
840                                 fid->rdir_fcall = NULL;
841                         }
842
843                         tc = p9_create_tread(fid->fid, fid->rdir_fpos, n);
844                         if (IS_ERR(tc)) {
845                                 err = PTR_ERR(tc);
846                                 tc = NULL;
847                                 goto error;
848                         }
849
850                         err = p9_client_rpc(clnt, tc, &rc);
851                         if (err)
852                                 goto error;
853
854                         n = rc->params.rread.count;
855                         if (n == 0)
856                                 goto done;
857
858                         fid->rdir_fcall = rc;
859                         rc = NULL;
860                         if (offset >= fid->rdir_fpos &&
861                                                 offset < fid->rdir_fpos+n)
862                                 break;
863                 }
864
865                 fid->rdir_pos = 0;
866         }
867
868         m = offset - fid->rdir_fpos;
869         if (m < 0)
870                 goto done;
871
872         n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m,
873                 fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu);
874
875         if (!n) {
876                 err = -EIO;
877                 goto error;
878         }
879
880         fid->rdir_pos += n;
881         st.size = n;
882         ret = p9_clone_stat(&st, clnt->dotu);
883         if (IS_ERR(ret)) {
884                 err = PTR_ERR(ret);
885                 ret = NULL;
886                 goto error;
887         }
888
889 done:
890         kfree(tc);
891         kfree(rc);
892         return ret;
893
894 error:
895         kfree(tc);
896         kfree(rc);
897         kfree(ret);
898         return ERR_PTR(err);
899 }
900 EXPORT_SYMBOL(p9_client_dirread);
901
902 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
903 {
904         int n;
905         char *p;
906         struct p9_stat *ret;
907
908         n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len +
909                 st->muid.len;
910
911         if (dotu)
912                 n += st->extension.len;
913
914         ret = kmalloc(n, GFP_KERNEL);
915         if (!ret)
916                 return ERR_PTR(-ENOMEM);
917
918         memmove(ret, st, sizeof(struct p9_stat));
919         p = ((char *) ret) + sizeof(struct p9_stat);
920         memmove(p, st->name.str, st->name.len);
921         ret->name.str = p;
922         p += st->name.len;
923         memmove(p, st->uid.str, st->uid.len);
924         ret->uid.str = p;
925         p += st->uid.len;
926         memmove(p, st->gid.str, st->gid.len);
927         ret->gid.str = p;
928         p += st->gid.len;
929         memmove(p, st->muid.str, st->muid.len);
930         ret->muid.str = p;
931         p += st->muid.len;
932
933         if (dotu) {
934                 memmove(p, st->extension.str, st->extension.len);
935                 ret->extension.str = p;
936                 p += st->extension.len;
937         }
938
939         return ret;
940 }
941
942 static struct p9_fid *p9_fid_create(struct p9_client *clnt)
943 {
944         int err;
945         struct p9_fid *fid;
946
947         P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
948         fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
949         if (!fid)
950                 return ERR_PTR(-ENOMEM);
951
952         fid->fid = p9_idpool_get(clnt->fidpool);
953         if (fid->fid < 0) {
954                 err = -ENOSPC;
955                 goto error;
956         }
957
958         memset(&fid->qid, 0, sizeof(struct p9_qid));
959         fid->mode = -1;
960         fid->rdir_fpos = 0;
961         fid->rdir_pos = 0;
962         fid->rdir_fcall = NULL;
963         fid->uid = current->fsuid;
964         fid->clnt = clnt;
965         fid->aux = NULL;
966
967         spin_lock(&clnt->lock);
968         list_add(&fid->flist, &clnt->fidlist);
969         spin_unlock(&clnt->lock);
970
971         return fid;
972
973 error:
974         kfree(fid);
975         return ERR_PTR(err);
976 }
977
978 static void p9_fid_destroy(struct p9_fid *fid)
979 {
980         struct p9_client *clnt;
981
982         P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
983         clnt = fid->clnt;
984         p9_idpool_put(fid->fid, clnt->fidpool);
985         spin_lock(&clnt->lock);
986         list_del(&fid->flist);
987         spin_unlock(&clnt->lock);
988         kfree(fid->rdir_fcall);
989         kfree(fid);
990 }