6 * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
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.
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.
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
26 #include <linux/module.h>
27 #include <linux/errno.h>
29 #include <linux/poll.h>
30 #include <linux/idr.h>
31 #include <linux/mutex.h>
32 #include <linux/sched.h>
33 #include <linux/uaccess.h>
34 #include <net/9p/9p.h>
35 #include <linux/parser.h>
36 #include <net/9p/client.h>
37 #include <net/9p/transport.h>
40 * Client Option Parsing (code inspired by NFS code)
41 * - a little lazy - parse all client options
51 static const match_table_t tokens = {
52 {Opt_msize, "msize=%u"},
53 {Opt_legacy, "noextend"},
54 {Opt_trans, "trans=%s"},
59 p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc);
62 * v9fs_parse_options - parse mount options into session structure
63 * @options: options string passed from mount
64 * @v9ses: existing v9fs session information
66 * Return 0 upon success, -ERRNO upon failure
69 static int parse_opts(char *opts, struct p9_client *clnt)
73 substring_t args[MAX_OPT_ARGS];
83 options = kstrdup(opts, GFP_KERNEL);
85 P9_DPRINTK(P9_DEBUG_ERROR,
86 "failed to allocate copy of option string\n");
90 while ((p = strsep(&options, ",")) != NULL) {
94 token = match_token(p, tokens, args);
95 if (token < Opt_trans) {
96 int r = match_int(&args[0], &option);
98 P9_DPRINTK(P9_DEBUG_ERROR,
99 "integer field, but no integer?\n");
106 clnt->msize = option;
109 clnt->trans_mod = v9fs_get_trans_by_name(&args[0]);
119 if (!clnt->trans_mod)
120 clnt->trans_mod = v9fs_get_default_trans();
127 * p9_tag_alloc - lookup/allocate a request by tag
128 * @c: client session to lookup tag within
129 * @tag: numeric id for transaction
131 * this is a simple array lookup, but will grow the
132 * request_slots as necessary to accomodate transaction
133 * ids which did not previously have a slot.
135 * this code relies on the client spinlock to manage locks, its
136 * possible we should switch to something else, but I'd rather
137 * stick with something low-overhead for the common case.
141 struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
146 /* This looks up the original request by tag so we know which
147 * buffer to read the data into */
150 if (tag >= c->max_tag) {
151 spin_lock_irqsave(&c->lock, flags);
152 /* check again since original check was outside of lock */
153 while (tag >= c->max_tag) {
154 row = (tag / P9_ROW_MAXTAG);
155 c->reqs[row] = kcalloc(P9_ROW_MAXTAG,
156 sizeof(struct p9_req_t), GFP_ATOMIC);
159 printk(KERN_ERR "Couldn't grow tag array\n");
162 for (col = 0; col < P9_ROW_MAXTAG; col++) {
163 c->reqs[row][col].status = REQ_STATUS_IDLE;
164 c->reqs[row][col].flush_tag = P9_NOTAG;
165 c->reqs[row][col].wq = kmalloc(
166 sizeof(wait_queue_head_t), GFP_ATOMIC);
167 if (!c->reqs[row][col].wq) {
169 "Couldn't grow tag array\n");
172 init_waitqueue_head(c->reqs[row][col].wq);
174 c->max_tag += P9_ROW_MAXTAG;
176 spin_unlock_irqrestore(&c->lock, flags);
178 row = tag / P9_ROW_MAXTAG;
179 col = tag % P9_ROW_MAXTAG;
181 c->reqs[row][col].status = REQ_STATUS_ALLOC;
182 c->reqs[row][col].flush_tag = P9_NOTAG;
184 return &c->reqs[row][col];
186 EXPORT_SYMBOL(p9_tag_alloc);
189 * p9_tag_lookup - lookup a request by tag
190 * @c: client session to lookup tag within
191 * @tag: numeric id for transaction
195 struct p9_req_t *p9_tag_lookup(struct p9_client *c, u16 tag)
199 /* This looks up the original request by tag so we know which
200 * buffer to read the data into */
203 BUG_ON(tag >= c->max_tag);
205 row = tag / P9_ROW_MAXTAG;
206 col = tag % P9_ROW_MAXTAG;
208 return &c->reqs[row][col];
210 EXPORT_SYMBOL(p9_tag_lookup);
213 * p9_tag_init - setup tags structure and contents
214 * @tags: tags structure from the client struct
216 * This initializes the tags structure for each client instance.
220 static int p9_tag_init(struct p9_client *c)
224 c->tagpool = p9_idpool_create();
225 if (IS_ERR(c->tagpool)) {
226 err = PTR_ERR(c->tagpool);
231 p9_idpool_get(c->tagpool); /* reserve tag 0 */
239 * p9_tag_cleanup - cleans up tags structure and reclaims resources
240 * @tags: tags structure from the client struct
242 * This frees resources associated with the tags structure
245 static void p9_tag_cleanup(struct p9_client *c)
249 /* check to insure all requests are idle */
250 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
251 for (col = 0; col < P9_ROW_MAXTAG; col++) {
252 if (c->reqs[row][col].status != REQ_STATUS_IDLE) {
253 P9_DPRINTK(P9_DEBUG_MUX,
254 "Attempting to cleanup non-free tag %d,%d\n",
256 /* TODO: delay execution of cleanup */
263 p9_idpool_destroy(c->tagpool);
265 /* free requests associated with tags */
266 for (row = 0; row < (c->max_tag/P9_ROW_MAXTAG); row++) {
267 for (col = 0; col < P9_ROW_MAXTAG; col++)
268 kfree(c->reqs[row][col].wq);
275 * p9_client_flush - flush (cancel) a request
277 * req: request to cancel
279 * This sents a flush for a particular requests and links
280 * the flush request to the original request. The current
281 * code only supports a single flush request although the protocol
282 * allows for multiple flush requests to be sent for a single request.
286 static int p9_client_flush(struct p9_client *c, struct p9_req_t *req)
288 struct p9_fcall *tc, *rc = NULL;
291 P9_DPRINTK(P9_DEBUG_9P, "client %p tag %d\n", c, req->tc->tag);
293 tc = p9_create_tflush(req->tc->tag);
297 err = p9_client_rpc(c, tc, &rc);
299 /* we don't free anything here because RPC isn't complete */
305 * p9_free_req - free a request and clean-up as necessary
307 * r: request to release
311 void p9_free_req(struct p9_client *c, struct p9_req_t *r)
313 r->flush_tag = P9_NOTAG;
314 r->status = REQ_STATUS_IDLE;
315 if (r->tc->tag != P9_NOTAG && p9_idpool_check(r->tc->tag, c->tagpool))
316 p9_idpool_put(r->tc->tag, c->tagpool);
318 /* if this was a flush request we have to free response fcall */
319 if (r->tc->id == P9_TFLUSH) {
326 * p9_client_cb - call back from transport to client
328 * req: request received
331 void p9_client_cb(struct p9_client *c, struct p9_req_t *req)
333 struct p9_req_t *other_req;
336 P9_DPRINTK(P9_DEBUG_MUX, ": %d\n", req->tc->tag);
338 if (req->status == REQ_STATUS_ERROR)
341 if (req->tc->id == P9_TFLUSH) { /* flush receive path */
342 P9_DPRINTK(P9_DEBUG_MUX, "flush: %d\n", req->tc->tag);
343 spin_lock_irqsave(&c->lock, flags);
344 other_req = p9_tag_lookup(c, req->tc->params.tflush.oldtag);
345 if (other_req->flush_tag != req->tc->tag) /* stale flush */
346 spin_unlock_irqrestore(&c->lock, flags);
348 BUG_ON(other_req->status != REQ_STATUS_FLSH);
349 other_req->status = REQ_STATUS_FLSHD;
350 spin_unlock_irqrestore(&c->lock, flags);
351 wake_up(other_req->wq);
354 } else { /* normal receive path */
355 P9_DPRINTK(P9_DEBUG_MUX, "normal: %d\n", req->tc->tag);
356 spin_lock_irqsave(&c->lock, flags);
357 if (req->status != REQ_STATUS_FLSHD)
358 req->status = REQ_STATUS_RCVD;
359 req->flush_tag = P9_NOTAG;
360 spin_unlock_irqrestore(&c->lock, flags);
362 P9_DPRINTK(P9_DEBUG_MUX, "wakeup: %d\n", req->tc->tag);
365 EXPORT_SYMBOL(p9_client_cb);
368 * p9_client_rpc - issue a request and wait for a response
370 * @tc: &p9_fcall request to transmit
371 * @rc: &p9_fcall to put reponse into
373 * Returns 0 on success, error code on failure
377 p9_client_rpc(struct p9_client *c, struct p9_fcall *tc, struct p9_fcall **rc)
381 struct p9_req_t *req;
386 P9_DPRINTK(P9_DEBUG_9P, "client %p tc %p rc %p\n", c, tc, rc);
388 if (c->status != Connected)
391 if (signal_pending(current)) {
393 clear_thread_flag(TIF_SIGPENDING);
398 if (tc->id != P9_TVERSION) {
399 tag = p9_idpool_get(c->tagpool);
404 req = p9_tag_alloc(c, tag);
406 /* if this is a flush request, backlink flush request now to
407 * avoid race conditions later. */
408 if (tc->id == P9_TFLUSH) {
409 struct p9_req_t *other_req =
410 p9_tag_lookup(c, tc->params.tflush.oldtag);
411 if (other_req->status == REQ_STATUS_FLSH)
412 other_req->flush_tag = tag;
418 * if client passed in a pre-allocated response fcall struct
419 * then we just use that, otherwise we allocate one.
426 if (req->rc == NULL) {
427 req->rc = kmalloc(sizeof(struct p9_fcall) + c->msize,
431 p9_idpool_put(tag, c->tagpool);
438 rdata = (char *)req->rc+sizeof(struct p9_fcall);
441 P9_DPRINTK(P9_DEBUG_9P, "request: tc: %p rc: %p\n", req->tc, req->rc);
443 err = c->trans_mod->request(c, req);
445 c->status = Disconnected;
449 /* if it was a flush we just transmitted, return our tag */
450 if (tc->id == P9_TFLUSH)
453 P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d\n", req->wq, tag);
454 err = wait_event_interruptible(*req->wq,
455 req->status >= REQ_STATUS_RCVD);
456 P9_DPRINTK(P9_DEBUG_9P, "wait %p tag: %d returned %d (flushed=%d)\n",
457 req->wq, tag, err, flushed);
459 if (req->status == REQ_STATUS_ERROR) {
460 P9_DPRINTK(P9_DEBUG_9P, "req_status error %d\n", req->t_err);
462 } else if (err == -ERESTARTSYS && flushed) {
463 P9_DPRINTK(P9_DEBUG_9P, "flushed - going again\n");
465 } else if (req->status == REQ_STATUS_FLSHD) {
466 P9_DPRINTK(P9_DEBUG_9P, "flushed - erestartsys\n");
470 if ((err == -ERESTARTSYS) && (c->status == Connected) && (!flushed)) {
471 P9_DPRINTK(P9_DEBUG_9P, "flushing\n");
472 spin_lock_irqsave(&c->lock, flags);
473 if (req->status == REQ_STATUS_SENT)
474 req->status = REQ_STATUS_FLSH;
475 spin_unlock_irqrestore(&c->lock, flags);
478 clear_thread_flag(TIF_SIGPENDING);
480 if (c->trans_mod->cancel(c, req)) {
481 err = p9_client_flush(c, req);
488 spin_lock_irqsave(¤t->sighand->siglock, flags);
490 spin_unlock_irqrestore(¤t->sighand->siglock, flags);
496 size = le32_to_cpu(*(__le32 *) rdata);
498 err = p9_deserialize_fcall(rdata, size, req->rc, c->dotu);
500 P9_DPRINTK(P9_DEBUG_9P,
501 "9p debug: client rpc deserialize returned %d\n", err);
505 #ifdef CONFIG_NET_9P_DEBUG
506 if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
509 p9_printfcall(buf, sizeof(buf), req->rc, c->dotu);
510 printk(KERN_NOTICE ">>> %p %s\n", c, buf);
514 if (req->rc->id == P9_RERROR) {
515 int ecode = req->rc->params.rerror.errno;
516 struct p9_str *ename = &req->rc->params.rerror.error;
518 P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
525 err = p9_errstr2errno(ename->str, ename->len);
527 /* string match failed */
529 PRINT_FCALL_ERROR("unknown error", req->rc);
539 P9_DPRINTK(P9_DEBUG_9P, "returning %d\n", err);
543 static struct p9_fid *p9_fid_create(struct p9_client *clnt)
548 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
549 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
551 return ERR_PTR(-ENOMEM);
553 fid->fid = p9_idpool_get(clnt->fidpool);
559 memset(&fid->qid, 0, sizeof(struct p9_qid));
563 fid->rdir_fcall = NULL;
564 fid->uid = current->fsuid;
568 spin_lock(&clnt->lock);
569 list_add(&fid->flist, &clnt->fidlist);
570 spin_unlock(&clnt->lock);
579 static void p9_fid_destroy(struct p9_fid *fid)
581 struct p9_client *clnt;
583 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
585 p9_idpool_put(fid->fid, clnt->fidpool);
586 spin_lock(&clnt->lock);
587 list_del(&fid->flist);
588 spin_unlock(&clnt->lock);
589 kfree(fid->rdir_fcall);
593 struct p9_client *p9_client_create(const char *dev_name, char *options)
596 struct p9_client *clnt;
597 struct p9_fcall *tc, *rc;
598 struct p9_str *version;
603 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
605 return ERR_PTR(-ENOMEM);
607 clnt->trans_mod = NULL;
609 spin_lock_init(&clnt->lock);
610 INIT_LIST_HEAD(&clnt->fidlist);
611 clnt->fidpool = p9_idpool_create();
612 if (IS_ERR(clnt->fidpool)) {
613 err = PTR_ERR(clnt->fidpool);
614 clnt->fidpool = NULL;
620 err = parse_opts(options, clnt);
624 if (clnt->trans_mod == NULL) {
625 err = -EPROTONOSUPPORT;
626 P9_DPRINTK(P9_DEBUG_ERROR,
627 "No transport defined or default transport\n");
631 P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n",
632 clnt, clnt->trans_mod, clnt->msize, clnt->dotu);
635 err = clnt->trans_mod->create(clnt, dev_name, options);
639 if ((clnt->msize+P9_IOHDRSZ) > clnt->trans_mod->maxsize)
640 clnt->msize = clnt->trans_mod->maxsize-P9_IOHDRSZ;
642 tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000");
649 err = p9_client_rpc(clnt, tc, &rc);
653 version = &rc->params.rversion.version;
654 if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8))
656 else if (version->len == 6 && !memcmp(version->str, "9P2000", 6))
663 n = rc->params.rversion.msize;
674 p9_client_destroy(clnt);
677 EXPORT_SYMBOL(p9_client_create);
679 void p9_client_destroy(struct p9_client *clnt)
681 struct p9_fid *fid, *fidptr;
683 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
686 clnt->trans_mod->close(clnt);
688 v9fs_put_trans(clnt->trans_mod);
690 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
694 p9_idpool_destroy(clnt->fidpool);
696 p9_tag_cleanup(clnt);
700 EXPORT_SYMBOL(p9_client_destroy);
702 void p9_client_disconnect(struct p9_client *clnt)
704 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
705 clnt->status = Disconnected;
707 EXPORT_SYMBOL(p9_client_disconnect);
709 struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
710 char *uname, u32 n_uname, char *aname)
713 struct p9_fcall *tc, *rc;
716 P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n",
717 clnt, afid?afid->fid:-1, uname, aname);
722 fid = p9_fid_create(clnt);
729 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname,
730 n_uname, clnt->dotu);
737 err = p9_client_rpc(clnt, tc, &rc);
741 memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid));
753 EXPORT_SYMBOL(p9_client_attach);
755 struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
756 u32 n_uname, char *aname)
759 struct p9_fcall *tc, *rc;
762 P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname,
768 fid = p9_fid_create(clnt);
775 tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu);
782 err = p9_client_rpc(clnt, tc, &rc);
786 memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid));
798 EXPORT_SYMBOL(p9_client_auth);
800 struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
804 struct p9_fcall *tc, *rc;
805 struct p9_client *clnt;
808 P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n",
809 oldfid->fid, nwname, wnames?wnames[0]:NULL);
815 fid = p9_fid_create(clnt);
822 fid->uid = oldfid->uid;
826 tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames);
833 err = p9_client_rpc(clnt, tc, &rc);
835 if (rc && rc->id == P9_RWALK)
841 if (rc->params.rwalk.nwqid != nwname) {
848 &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1],
849 sizeof(struct p9_qid));
851 fid->qid = oldfid->qid;
861 tc = p9_create_tclunk(fid->fid);
868 p9_client_rpc(clnt, tc, &rc);
873 if (fid && (fid != oldfid))
878 EXPORT_SYMBOL(p9_client_walk);
880 int p9_client_open(struct p9_fid *fid, int mode)
883 struct p9_fcall *tc, *rc;
884 struct p9_client *clnt;
886 P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode);
895 tc = p9_create_topen(fid->fid, mode);
902 err = p9_client_rpc(clnt, tc, &rc);
907 fid->iounit = rc->params.ropen.iounit;
914 EXPORT_SYMBOL(p9_client_open);
916 int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
920 struct p9_fcall *tc, *rc;
921 struct p9_client *clnt;
923 P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid,
933 tc = p9_create_tcreate(fid->fid, name, perm, mode, extension,
941 err = p9_client_rpc(clnt, tc, &rc);
946 fid->iounit = rc->params.ropen.iounit;
953 EXPORT_SYMBOL(p9_client_fcreate);
955 int p9_client_clunk(struct p9_fid *fid)
958 struct p9_fcall *tc, *rc;
959 struct p9_client *clnt;
961 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
967 tc = p9_create_tclunk(fid->fid);
974 err = p9_client_rpc(clnt, tc, &rc);
985 EXPORT_SYMBOL(p9_client_clunk);
987 int p9_client_remove(struct p9_fid *fid)
990 struct p9_fcall *tc, *rc;
991 struct p9_client *clnt;
993 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
999 tc = p9_create_tremove(fid->fid);
1006 err = p9_client_rpc(clnt, tc, &rc);
1010 p9_fid_destroy(fid);
1017 EXPORT_SYMBOL(p9_client_remove);
1019 int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
1021 int err, n, rsize, total;
1022 struct p9_fcall *tc, *rc;
1023 struct p9_client *clnt;
1025 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid,
1026 (long long unsigned) offset, count);
1033 rsize = fid->iounit;
1034 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
1035 rsize = clnt->msize - P9_IOHDRSZ;
1041 tc = p9_create_tread(fid->fid, offset, rsize);
1048 err = p9_client_rpc(clnt, tc, &rc);
1052 n = rc->params.rread.count;
1056 memmove(data, rc->params.rread.data, n);
1065 } while (count > 0 && n == rsize);
1074 EXPORT_SYMBOL(p9_client_read);
1076 int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
1078 int err, n, rsize, total;
1079 struct p9_fcall *tc, *rc;
1080 struct p9_client *clnt;
1082 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
1083 (long long unsigned) offset, count);
1090 rsize = fid->iounit;
1091 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
1092 rsize = clnt->msize - P9_IOHDRSZ;
1098 tc = p9_create_twrite(fid->fid, offset, rsize, data);
1105 err = p9_client_rpc(clnt, tc, &rc);
1109 n = rc->params.rread.count;
1118 } while (count > 0);
1127 EXPORT_SYMBOL(p9_client_write);
1130 p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
1132 int err, n, rsize, total;
1133 struct p9_fcall *tc, *rc;
1134 struct p9_client *clnt;
1136 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
1137 (long long unsigned) offset, count);
1144 rsize = fid->iounit;
1145 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
1146 rsize = clnt->msize - P9_IOHDRSZ;
1152 tc = p9_create_tread(fid->fid, offset, rsize);
1159 err = p9_client_rpc(clnt, tc, &rc);
1163 n = rc->params.rread.count;
1167 err = copy_to_user(data, rc->params.rread.data, n);
1181 } while (count > 0 && n == rsize);
1190 EXPORT_SYMBOL(p9_client_uread);
1193 p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
1196 int err, n, rsize, total;
1197 struct p9_fcall *tc, *rc;
1198 struct p9_client *clnt;
1200 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
1201 (long long unsigned) offset, count);
1208 rsize = fid->iounit;
1209 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
1210 rsize = clnt->msize - P9_IOHDRSZ;
1216 tc = p9_create_twrite_u(fid->fid, offset, rsize, data);
1223 err = p9_client_rpc(clnt, tc, &rc);
1227 n = rc->params.rread.count;
1236 } while (count > 0);
1245 EXPORT_SYMBOL(p9_client_uwrite);
1247 int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count)
1251 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
1252 (long long unsigned) offset, count);
1256 n = p9_client_read(fid, data, offset, count);
1271 EXPORT_SYMBOL(p9_client_readn);
1273 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
1277 struct p9_stat *ret;
1279 n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len +
1283 n += st->extension.len;
1285 ret = kmalloc(n, GFP_KERNEL);
1287 return ERR_PTR(-ENOMEM);
1289 memmove(ret, st, sizeof(struct p9_stat));
1290 p = ((char *) ret) + sizeof(struct p9_stat);
1291 memmove(p, st->name.str, st->name.len);
1294 memmove(p, st->uid.str, st->uid.len);
1297 memmove(p, st->gid.str, st->gid.len);
1300 memmove(p, st->muid.str, st->muid.len);
1305 memmove(p, st->extension.str, st->extension.len);
1306 ret->extension.str = p;
1307 p += st->extension.len;
1313 struct p9_stat *p9_client_stat(struct p9_fid *fid)
1316 struct p9_fcall *tc, *rc;
1317 struct p9_client *clnt;
1318 struct p9_stat *ret;
1320 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
1327 tc = p9_create_tstat(fid->fid);
1334 err = p9_client_rpc(clnt, tc, &rc);
1338 ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu);
1353 return ERR_PTR(err);
1355 EXPORT_SYMBOL(p9_client_stat);
1357 int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
1360 struct p9_fcall *tc, *rc;
1361 struct p9_client *clnt;
1363 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
1369 tc = p9_create_twstat(fid->fid, wst, clnt->dotu);
1376 err = p9_client_rpc(clnt, tc, &rc);
1383 EXPORT_SYMBOL(p9_client_wstat);
1385 struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
1388 struct p9_fcall *tc, *rc;
1389 struct p9_client *clnt;
1390 struct p9_stat st, *ret;
1392 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid,
1393 (long long unsigned) offset);
1400 /* if the offset is below or above the current response, free it */
1401 if (offset < fid->rdir_fpos || (fid->rdir_fcall &&
1402 offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) {
1404 if (fid->rdir_fcall)
1405 fid->rdir_fpos += fid->rdir_fcall->params.rread.count;
1407 kfree(fid->rdir_fcall);
1408 fid->rdir_fcall = NULL;
1409 if (offset < fid->rdir_fpos)
1413 if (!fid->rdir_fcall) {
1415 if (!n || n > clnt->msize-P9_IOHDRSZ)
1416 n = clnt->msize - P9_IOHDRSZ;
1419 if (fid->rdir_fcall) {
1421 fid->rdir_fcall->params.rread.count;
1422 kfree(fid->rdir_fcall);
1423 fid->rdir_fcall = NULL;
1426 tc = p9_create_tread(fid->fid, fid->rdir_fpos, n);
1433 err = p9_client_rpc(clnt, tc, &rc);
1437 n = rc->params.rread.count;
1441 fid->rdir_fcall = rc;
1443 if (offset >= fid->rdir_fpos &&
1444 offset < fid->rdir_fpos+n)
1451 m = offset - fid->rdir_fpos;
1455 n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m,
1456 fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu);
1465 ret = p9_clone_stat(&st, clnt->dotu);
1481 return ERR_PTR(err);
1483 EXPORT_SYMBOL(p9_client_dirread);