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