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