client.c revision 043aba403e9958c6526c9279b63919273cb09c13
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
38static struct p9_fid *p9_fid_create(struct p9_client *clnt);
39static void p9_fid_destroy(struct p9_fid *fid);
40static 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 */
49int
50p9_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);
55	else
56		return p9_conn_rpc(c->conn, tc, rc);
57}
58
59struct 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->conn, 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
124error:
125	kfree(tc);
126	kfree(rc);
127	p9_client_destroy(clnt);
128	return ERR_PTR(err);
129}
130EXPORT_SYMBOL(p9_client_create);
131
132void 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}
156EXPORT_SYMBOL(p9_client_destroy);
157
158void 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}
164EXPORT_SYMBOL(p9_client_disconnect);
165
166struct 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->conn, 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
203error:
204	kfree(tc);
205	kfree(rc);
206	if (fid)
207		p9_fid_destroy(fid);
208	return ERR_PTR(err);
209}
210EXPORT_SYMBOL(p9_client_attach);
211
212struct 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->conn, 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
248error:
249	kfree(tc);
250	kfree(rc);
251	if (fid)
252		p9_fid_destroy(fid);
253	return ERR_PTR(err);
254}
255EXPORT_SYMBOL(p9_client_auth);
256
257struct 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->conn, 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
314clunk_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->conn, tc, &rc);
326
327error:
328	kfree(tc);
329	kfree(rc);
330	if (fid && (fid != oldfid))
331		p9_fid_destroy(fid);
332
333	return ERR_PTR(err);
334}
335EXPORT_SYMBOL(p9_client_walk);
336
337int 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->conn, tc, &rc);
360	if (err)
361		goto done;
362
363	fid->mode = mode;
364	fid->iounit = rc->params.ropen.iounit;
365
366done:
367	kfree(tc);
368	kfree(rc);
369	return err;
370}
371EXPORT_SYMBOL(p9_client_open);
372
373int 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->conn, tc, &rc);
399	if (err)
400		goto done;
401
402	fid->mode = mode;
403	fid->iounit = rc->params.ropen.iounit;
404
405done:
406	kfree(tc);
407	kfree(rc);
408	return err;
409}
410EXPORT_SYMBOL(p9_client_fcreate);
411
412int 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->conn, tc, &rc);
432	if (err)
433		goto done;
434
435	p9_fid_destroy(fid);
436
437done:
438	kfree(tc);
439	kfree(rc);
440	return err;
441}
442EXPORT_SYMBOL(p9_client_clunk);
443
444int 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->conn, tc, &rc);
464	if (err)
465		goto done;
466
467	p9_fid_destroy(fid);
468
469done:
470	kfree(tc);
471	kfree(rc);
472	return err;
473}
474EXPORT_SYMBOL(p9_client_remove);
475
476int 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->conn, 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
526error:
527	kfree(tc);
528	kfree(rc);
529	return err;
530}
531EXPORT_SYMBOL(p9_client_read);
532
533int 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->conn, 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
579error:
580	kfree(tc);
581	kfree(rc);
582	return err;
583}
584EXPORT_SYMBOL(p9_client_write);
585
586int
587p9_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->conn, 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
642error:
643	kfree(tc);
644	kfree(rc);
645	return err;
646}
647EXPORT_SYMBOL(p9_client_uread);
648
649int
650p9_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->conn, 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
697error:
698	kfree(tc);
699	kfree(rc);
700	return err;
701}
702EXPORT_SYMBOL(p9_client_uwrite);
703
704int 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}
728EXPORT_SYMBOL(p9_client_readn);
729
730struct 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->conn, 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
766error:
767	kfree(tc);
768	kfree(rc);
769	kfree(ret);
770	return ERR_PTR(err);
771}
772EXPORT_SYMBOL(p9_client_stat);
773
774int 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->conn, tc, &rc);
794
795done:
796	kfree(tc);
797	kfree(rc);
798	return err;
799}
800EXPORT_SYMBOL(p9_client_wstat);
801
802struct 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->conn, 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
889done:
890	kfree(tc);
891	kfree(rc);
892	return ret;
893
894error:
895	kfree(tc);
896	kfree(rc);
897	kfree(ret);
898	return ERR_PTR(err);
899}
900EXPORT_SYMBOL(p9_client_dirread);
901
902static 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
942static 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
973error:
974	kfree(fid);
975	return ERR_PTR(err);
976}
977
978static 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}
991