xref: /linux/net/9p/client.c (revision 2b8232ce512105e28453f301d1510de8363bccd1)
1 /*
2  * net/9p/clnt.c
3  *
4  * 9P Client
5  *
6  *  Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License version 2
10  *  as published by the Free Software Foundation.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to:
19  *  Free Software Foundation
20  *  51 Franklin Street, Fifth Floor
21  *  Boston, MA  02111-1301  USA
22  *
23  */
24 
25 #include <linux/module.h>
26 #include <linux/errno.h>
27 #include <linux/fs.h>
28 #include <linux/idr.h>
29 #include <linux/mutex.h>
30 #include <linux/sched.h>
31 #include <linux/uaccess.h>
32 #include <net/9p/9p.h>
33 #include <net/9p/transport.h>
34 #include <net/9p/conn.h>
35 #include <net/9p/client.h>
36 
37 static struct p9_fid *p9_fid_create(struct p9_client *clnt);
38 static void p9_fid_destroy(struct p9_fid *fid);
39 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
40 
41 struct 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 
106 error:
107 	kfree(tc);
108 	kfree(rc);
109 	p9_client_destroy(clnt);
110 	return ERR_PTR(err);
111 }
112 EXPORT_SYMBOL(p9_client_create);
113 
114 void p9_client_destroy(struct p9_client *clnt)
115 {
116 	struct p9_fid *fid, *fidptr;
117 
118 	P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
119 	if (clnt->conn) {
120 		p9_conn_destroy(clnt->conn);
121 		clnt->conn = NULL;
122 	}
123 
124 	if (clnt->trans) {
125 		clnt->trans->close(clnt->trans);
126 		kfree(clnt->trans);
127 		clnt->trans = NULL;
128 	}
129 
130 	list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
131 		p9_fid_destroy(fid);
132 
133 	if (clnt->fidpool)
134 		p9_idpool_destroy(clnt->fidpool);
135 
136 	kfree(clnt);
137 }
138 EXPORT_SYMBOL(p9_client_destroy);
139 
140 void 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 }
146 EXPORT_SYMBOL(p9_client_disconnect);
147 
148 struct 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 
184 error:
185 	kfree(tc);
186 	kfree(rc);
187 	if (fid)
188 		p9_fid_destroy(fid);
189 	return ERR_PTR(err);
190 }
191 EXPORT_SYMBOL(p9_client_attach);
192 
193 struct 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 
228 error:
229 	kfree(tc);
230 	kfree(rc);
231 	if (fid)
232 		p9_fid_destroy(fid);
233 	return ERR_PTR(err);
234 }
235 EXPORT_SYMBOL(p9_client_auth);
236 
237 struct 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 
294 clunk_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 
307 error:
308 	kfree(tc);
309 	kfree(rc);
310 	if (fid && (fid != oldfid))
311 		p9_fid_destroy(fid);
312 
313 	return ERR_PTR(err);
314 }
315 EXPORT_SYMBOL(p9_client_walk);
316 
317 int 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 
346 done:
347 	kfree(tc);
348 	kfree(rc);
349 	return err;
350 }
351 EXPORT_SYMBOL(p9_client_open);
352 
353 int 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 
385 done:
386 	kfree(tc);
387 	kfree(rc);
388 	return err;
389 }
390 EXPORT_SYMBOL(p9_client_fcreate);
391 
392 int 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 
417 done:
418 	kfree(tc);
419 	kfree(rc);
420 	return err;
421 }
422 EXPORT_SYMBOL(p9_client_clunk);
423 
424 int 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 
449 done:
450 	kfree(tc);
451 	kfree(rc);
452 	return err;
453 }
454 EXPORT_SYMBOL(p9_client_remove);
455 
456 int 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 
506 error:
507 	kfree(tc);
508 	kfree(rc);
509 	return err;
510 }
511 EXPORT_SYMBOL(p9_client_read);
512 
513 int 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 
559 error:
560 	kfree(tc);
561 	kfree(rc);
562 	return err;
563 }
564 EXPORT_SYMBOL(p9_client_write);
565 
566 int
567 p9_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 
622 error:
623 	kfree(tc);
624 	kfree(rc);
625 	return err;
626 }
627 EXPORT_SYMBOL(p9_client_uread);
628 
629 int
630 p9_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 
677 error:
678 	kfree(tc);
679 	kfree(rc);
680 	return err;
681 }
682 EXPORT_SYMBOL(p9_client_uwrite);
683 
684 int 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 }
708 EXPORT_SYMBOL(p9_client_readn);
709 
710 struct 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 
746 error:
747 	kfree(tc);
748 	kfree(rc);
749 	kfree(ret);
750 	return ERR_PTR(err);
751 }
752 EXPORT_SYMBOL(p9_client_stat);
753 
754 int 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 
775 done:
776 	kfree(tc);
777 	kfree(rc);
778 	return err;
779 }
780 EXPORT_SYMBOL(p9_client_wstat);
781 
782 struct 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 
869 done:
870 	kfree(tc);
871 	kfree(rc);
872 	return ret;
873 
874 error:
875 	kfree(tc);
876 	kfree(rc);
877 	kfree(ret);
878 	return ERR_PTR(err);
879 }
880 EXPORT_SYMBOL(p9_client_dirread);
881 
882 static 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 
917 static 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 
948 error:
949 	kfree(fid);
950 	return ERR_PTR(err);
951 }
952 
953 static 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 }
966