blob: f1a52a7ed7248d5fc919cd6420f195334386a6a3 [file] [log] [blame]
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001/*
2 * net/9p/clnt.c
3 *
4 * 9P Client
5 *
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -06006 * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05007 * 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>
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060029#include <linux/poll.h>
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050030#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>
Eric Van Hensbergenfb0466c2007-10-17 14:31:07 -050035#include <linux/parser.h>
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050036#include <net/9p/client.h>
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -050037#include <net/9p/transport.h>
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -050038
39static struct p9_fid *p9_fid_create(struct p9_client *clnt);
40static void p9_fid_destroy(struct p9_fid *fid);
41static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
42
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060043/*
44 * Client Option Parsing (code inspired by NFS code)
45 * - a little lazy - parse all client options
46 */
47
48enum {
49 Opt_msize,
50 Opt_trans,
51 Opt_legacy,
52 Opt_err,
53};
54
Steven Whitehousea447c092008-10-13 10:46:57 +010055static const match_table_t tokens = {
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060056 {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 *
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -060067 * Return 0 upon success, -ERRNO upon failure
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060068 */
69
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -060070static int parse_opts(char *opts, struct p9_client *clnt)
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060071{
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -060072 char *options;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060073 char *p;
74 substring_t args[MAX_OPT_ARGS];
75 int option;
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -060076 int ret = 0;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060077
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060078 clnt->dotu = 1;
79 clnt->msize = 8192;
80
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -060081 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 }
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060090
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) {
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -060097 int r = match_int(&args[0], &option);
98 if (r < 0) {
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -060099 P9_DPRINTK(P9_DEBUG_ERROR,
100 "integer field, but no integer?\n");
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600101 ret = r;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600102 continue;
103 }
104 }
105 switch (token) {
106 case Opt_msize:
107 clnt->msize = option;
108 break;
109 case Opt_trans:
Tejun Heo72029fe2008-09-24 16:22:23 -0500110 clnt->trans_mod = v9fs_get_trans_by_name(&args[0]);
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600111 break;
112 case Opt_legacy:
113 clnt->dotu = 0;
114 break;
115 default:
116 continue;
117 }
118 }
Tejun Heo72029fe2008-09-24 16:22:23 -0500119
120 if (!clnt->trans_mod)
121 clnt->trans_mod = v9fs_get_default_trans();
122
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600123 kfree(options);
124 return ret;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600125}
126
127
Eric Van Hensbergen043aba42008-02-06 19:25:09 -0600128/**
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 */
135int
136p9_client_rpc(struct p9_client *c, struct p9_fcall *tc,
137 struct p9_fcall **rc)
138{
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500139 return c->trans_mod->rpc(c, tc, rc);
Eric Van Hensbergen043aba42008-02-06 19:25:09 -0600140}
141
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600142struct p9_client *p9_client_create(const char *dev_name, char *options)
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500143{
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
Tejun Heo72029fe2008-09-24 16:22:23 -0500156 clnt->trans_mod = NULL;
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600157 clnt->trans = NULL;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500158 spin_lock_init(&clnt->lock);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500159 INIT_LIST_HEAD(&clnt->fidlist);
160 clnt->fidpool = p9_idpool_create();
Josef 'Jeff' Sipek728fc4e2008-03-07 11:40:33 -0600161 if (IS_ERR(clnt->fidpool)) {
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500162 err = PTR_ERR(clnt->fidpool);
163 clnt->fidpool = NULL;
164 goto error;
165 }
166
Eric Van Hensbergenbb8ffdf2008-03-07 10:53:53 -0600167 err = parse_opts(options, clnt);
168 if (err < 0)
169 goto error;
170
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600171 if (clnt->trans_mod == NULL) {
172 err = -EPROTONOSUPPORT;
173 P9_DPRINTK(P9_DEBUG_ERROR,
174 "No transport defined or default transport\n");
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500175 goto error;
176 }
177
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600178 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
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500182 err = clnt->trans_mod->create(clnt, dev_name, options);
183 if (err)
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600184 goto error;
Eric Van Hensbergen8a0dc952008-02-06 19:25:03 -0600185
186 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
187 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
188
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500189 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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600196 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500197 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
218error:
219 kfree(tc);
220 kfree(rc);
221 p9_client_destroy(clnt);
222 return ERR_PTR(err);
223}
224EXPORT_SYMBOL(p9_client_create);
225
226void 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);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500231
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500232 if (clnt->trans_mod)
233 clnt->trans_mod->close(clnt);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500234
Tejun Heo72029fe2008-09-24 16:22:23 -0500235 v9fs_put_trans(clnt->trans_mod);
236
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500237 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
238 p9_fid_destroy(fid);
239
Eric Van Hensbergen0af88872007-07-13 16:47:58 -0500240 if (clnt->fidpool)
241 p9_idpool_destroy(clnt->fidpool);
242
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500243 kfree(clnt);
244}
245EXPORT_SYMBOL(p9_client_destroy);
246
247void p9_client_disconnect(struct p9_client *clnt)
248{
249 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
Eric Van Hensbergen8b81ef52008-10-13 18:45:25 -0500250 clnt->status = Disconnected;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500251}
252EXPORT_SYMBOL(p9_client_disconnect);
253
254struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
Latchesar Ionkovba176742007-10-17 14:31:07 -0500255 char *uname, u32 n_uname, char *aname)
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500256{
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
Latchesar Ionkovba176742007-10-17 14:31:07 -0500274 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname,
275 n_uname, clnt->dotu);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500276 if (IS_ERR(tc)) {
277 err = PTR_ERR(tc);
278 tc = NULL;
279 goto error;
280 }
281
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600282 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500283 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
291error:
292 kfree(tc);
293 kfree(rc);
294 if (fid)
295 p9_fid_destroy(fid);
296 return ERR_PTR(err);
297}
298EXPORT_SYMBOL(p9_client_attach);
299
Latchesar Ionkovba176742007-10-17 14:31:07 -0500300struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
301 u32 n_uname, char *aname)
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500302{
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
Latchesar Ionkovba176742007-10-17 14:31:07 -0500320 tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500321 if (IS_ERR(tc)) {
322 err = PTR_ERR(tc);
323 tc = NULL;
324 goto error;
325 }
326
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600327 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500328 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
336error:
337 kfree(tc);
338 kfree(rc);
339 if (fid)
340 p9_fid_destroy(fid);
341 return ERR_PTR(err);
342}
343EXPORT_SYMBOL(p9_client_auth);
344
345struct 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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600378 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500379 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
402clunk_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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600413 p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500414
415error:
416 kfree(tc);
417 kfree(rc);
418 if (fid && (fid != oldfid))
419 p9_fid_destroy(fid);
420
421 return ERR_PTR(err);
422}
423EXPORT_SYMBOL(p9_client_walk);
424
425int 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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600447 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500448 if (err)
449 goto done;
450
451 fid->mode = mode;
452 fid->iounit = rc->params.ropen.iounit;
453
454done:
455 kfree(tc);
456 kfree(rc);
457 return err;
458}
459EXPORT_SYMBOL(p9_client_open);
460
461int 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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600486 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500487 if (err)
488 goto done;
489
490 fid->mode = mode;
491 fid->iounit = rc->params.ropen.iounit;
492
493done:
494 kfree(tc);
495 kfree(rc);
496 return err;
497}
498EXPORT_SYMBOL(p9_client_fcreate);
499
500int 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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600519 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500520 if (err)
521 goto done;
522
523 p9_fid_destroy(fid);
524
525done:
526 kfree(tc);
527 kfree(rc);
528 return err;
529}
530EXPORT_SYMBOL(p9_client_clunk);
531
532int 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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600551 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500552 if (err)
553 goto done;
554
555 p9_fid_destroy(fid);
556
557done:
558 kfree(tc);
559 kfree(rc);
560 return err;
561}
562EXPORT_SYMBOL(p9_client_remove);
563
564int 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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600593 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500594 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
614error:
615 kfree(tc);
616 kfree(rc);
617 return err;
618}
619EXPORT_SYMBOL(p9_client_read);
620
621int 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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600650 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500651 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
667error:
668 kfree(tc);
669 kfree(rc);
670 return err;
671}
672EXPORT_SYMBOL(p9_client_write);
673
674int
675p9_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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600704 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500705 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
730error:
731 kfree(tc);
732 kfree(rc);
733 return err;
734}
735EXPORT_SYMBOL(p9_client_uread);
736
737int
738p9_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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600768 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500769 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
785error:
786 kfree(tc);
787 kfree(rc);
788 return err;
789}
790EXPORT_SYMBOL(p9_client_uwrite);
791
792int 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}
816EXPORT_SYMBOL(p9_client_readn);
817
818struct 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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600839 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500840 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
854error:
855 kfree(tc);
856 kfree(rc);
857 kfree(ret);
858 return ERR_PTR(err);
859}
860EXPORT_SYMBOL(p9_client_stat);
861
862int 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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600881 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500882
883done:
884 kfree(tc);
885 kfree(rc);
886 return err;
887}
888EXPORT_SYMBOL(p9_client_wstat);
889
890struct 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
Eric Van Hensbergene2735b72008-02-06 19:25:58 -0600938 err = p9_client_rpc(clnt, tc, &rc);
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -0500939 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
977done:
978 kfree(tc);
979 kfree(rc);
980 return ret;
981
982error:
983 kfree(tc);
984 kfree(rc);
985 kfree(ret);
986 return ERR_PTR(err);
987}
988EXPORT_SYMBOL(p9_client_dirread);
989
990static 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);
Martin Stavaafcf0c12008-02-05 09:27:09 -06001009 ret->name.str = p;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001010 p += st->name.len;
1011 memmove(p, st->uid.str, st->uid.len);
Martin Stavaafcf0c12008-02-05 09:27:09 -06001012 ret->uid.str = p;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001013 p += st->uid.len;
1014 memmove(p, st->gid.str, st->gid.len);
Martin Stavaafcf0c12008-02-05 09:27:09 -06001015 ret->gid.str = p;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001016 p += st->gid.len;
1017 memmove(p, st->muid.str, st->muid.len);
Martin Stavaafcf0c12008-02-05 09:27:09 -06001018 ret->muid.str = p;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001019 p += st->muid.len;
1020
1021 if (dotu) {
1022 memmove(p, st->extension.str, st->extension.len);
Martin Stavaafcf0c12008-02-05 09:27:09 -06001023 ret->extension.str = p;
Latchesar Ionkovbd238fb2007-07-10 17:57:28 -05001024 p += st->extension.len;
1025 }
1026
1027 return ret;
1028}
1029
1030static 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
1061error:
1062 kfree(fid);
1063 return ERR_PTR(err);
1064}
1065
1066static 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}