6 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
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.
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.
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
25 #include <linux/module.h>
26 #include <linux/errno.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>
38 static struct p9_fid *p9_fid_create(struct p9_client *clnt);
39 static void p9_fid_destroy(struct p9_fid *fid);
40 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
43 * p9_client_rpc - sends 9P request and waits until a response is available.
44 * The function can be interrupted.
46 * @tc: request to be sent
47 * @rc: pointer where a pointer to the response is stored
50 p9_client_rpc(struct p9_client *c, struct p9_fcall *tc,
54 return c->trans->rpc(c->trans, tc, rc);
56 return p9_conn_rpc(c->conn, tc, rc);
59 struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
63 struct p9_client *clnt;
64 struct p9_fcall *tc, *rc;
65 struct p9_str *version;
70 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
72 return ERR_PTR(-ENOMEM);
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);
80 INIT_LIST_HEAD(&clnt->fidlist);
81 clnt->fidpool = p9_idpool_create();
83 err = PTR_ERR(clnt->fidpool);
88 clnt->conn = p9_conn_create(clnt->trans, clnt->msize, &clnt->dotu);
89 if (IS_ERR(clnt->conn)) {
90 err = PTR_ERR(clnt->conn);
95 tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000");
102 err = p9_client_rpc(clnt->conn, tc, &rc);
106 version = &rc->params.rversion.version;
107 if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8))
109 else if (version->len == 6 && !memcmp(version->str, "9P2000", 6))
116 n = rc->params.rversion.msize;
127 p9_client_destroy(clnt);
130 EXPORT_SYMBOL(p9_client_create);
132 void p9_client_destroy(struct p9_client *clnt)
134 struct p9_fid *fid, *fidptr;
136 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
138 p9_conn_destroy(clnt->conn);
143 clnt->trans->close(clnt->trans);
148 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
152 p9_idpool_destroy(clnt->fidpool);
156 EXPORT_SYMBOL(p9_client_destroy);
158 void p9_client_disconnect(struct p9_client *clnt)
160 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
161 clnt->trans->status = Disconnected;
162 p9_conn_cancel(clnt->conn, -EIO);
164 EXPORT_SYMBOL(p9_client_disconnect);
166 struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
167 char *uname, u32 n_uname, char *aname)
170 struct p9_fcall *tc, *rc;
173 P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n",
174 clnt, afid?afid->fid:-1, uname, aname);
179 fid = p9_fid_create(clnt);
186 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname,
187 n_uname, clnt->dotu);
194 err = p9_client_rpc(clnt->conn, tc, &rc);
198 memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid));
210 EXPORT_SYMBOL(p9_client_attach);
212 struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
213 u32 n_uname, char *aname)
216 struct p9_fcall *tc, *rc;
219 P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname,
225 fid = p9_fid_create(clnt);
232 tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu);
239 err = p9_client_rpc(clnt->conn, tc, &rc);
243 memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid));
255 EXPORT_SYMBOL(p9_client_auth);
257 struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
261 struct p9_fcall *tc, *rc;
262 struct p9_client *clnt;
265 P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n",
266 oldfid->fid, nwname, wnames?wnames[0]:NULL);
272 fid = p9_fid_create(clnt);
279 fid->uid = oldfid->uid;
283 tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames);
290 err = p9_client_rpc(clnt->conn, tc, &rc);
292 if (rc && rc->id == P9_RWALK)
298 if (rc->params.rwalk.nwqid != nwname) {
305 &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1],
306 sizeof(struct p9_qid));
308 fid->qid = oldfid->qid;
318 tc = p9_create_tclunk(fid->fid);
325 p9_client_rpc(clnt->conn, tc, &rc);
330 if (fid && (fid != oldfid))
335 EXPORT_SYMBOL(p9_client_walk);
337 int p9_client_open(struct p9_fid *fid, int mode)
340 struct p9_fcall *tc, *rc;
341 struct p9_client *clnt;
343 P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode);
352 tc = p9_create_topen(fid->fid, mode);
359 err = p9_client_rpc(clnt->conn, tc, &rc);
364 fid->iounit = rc->params.ropen.iounit;
371 EXPORT_SYMBOL(p9_client_open);
373 int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
377 struct p9_fcall *tc, *rc;
378 struct p9_client *clnt;
380 P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid,
390 tc = p9_create_tcreate(fid->fid, name, perm, mode, extension,
398 err = p9_client_rpc(clnt->conn, tc, &rc);
403 fid->iounit = rc->params.ropen.iounit;
410 EXPORT_SYMBOL(p9_client_fcreate);
412 int p9_client_clunk(struct p9_fid *fid)
415 struct p9_fcall *tc, *rc;
416 struct p9_client *clnt;
418 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
424 tc = p9_create_tclunk(fid->fid);
431 err = p9_client_rpc(clnt->conn, tc, &rc);
442 EXPORT_SYMBOL(p9_client_clunk);
444 int p9_client_remove(struct p9_fid *fid)
447 struct p9_fcall *tc, *rc;
448 struct p9_client *clnt;
450 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
456 tc = p9_create_tremove(fid->fid);
463 err = p9_client_rpc(clnt->conn, tc, &rc);
474 EXPORT_SYMBOL(p9_client_remove);
476 int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
478 int err, n, rsize, total;
479 struct p9_fcall *tc, *rc;
480 struct p9_client *clnt;
482 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid,
483 (long long unsigned) offset, count);
491 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
492 rsize = clnt->msize - P9_IOHDRSZ;
498 tc = p9_create_tread(fid->fid, offset, rsize);
505 err = p9_client_rpc(clnt->conn, tc, &rc);
509 n = rc->params.rread.count;
513 memmove(data, rc->params.rread.data, n);
522 } while (count > 0 && n == rsize);
531 EXPORT_SYMBOL(p9_client_read);
533 int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
535 int err, n, rsize, total;
536 struct p9_fcall *tc, *rc;
537 struct p9_client *clnt;
539 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
540 (long long unsigned) offset, count);
548 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
549 rsize = clnt->msize - P9_IOHDRSZ;
555 tc = p9_create_twrite(fid->fid, offset, rsize, data);
562 err = p9_client_rpc(clnt->conn, tc, &rc);
566 n = rc->params.rread.count;
584 EXPORT_SYMBOL(p9_client_write);
587 p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
589 int err, n, rsize, total;
590 struct p9_fcall *tc, *rc;
591 struct p9_client *clnt;
593 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
594 (long long unsigned) offset, count);
602 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
603 rsize = clnt->msize - P9_IOHDRSZ;
609 tc = p9_create_tread(fid->fid, offset, rsize);
616 err = p9_client_rpc(clnt->conn, tc, &rc);
620 n = rc->params.rread.count;
624 err = copy_to_user(data, rc->params.rread.data, n);
638 } while (count > 0 && n == rsize);
647 EXPORT_SYMBOL(p9_client_uread);
650 p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
653 int err, n, rsize, total;
654 struct p9_fcall *tc, *rc;
655 struct p9_client *clnt;
657 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
658 (long long unsigned) offset, count);
666 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
667 rsize = clnt->msize - P9_IOHDRSZ;
673 tc = p9_create_twrite_u(fid->fid, offset, rsize, data);
680 err = p9_client_rpc(clnt->conn, tc, &rc);
684 n = rc->params.rread.count;
702 EXPORT_SYMBOL(p9_client_uwrite);
704 int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count)
708 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
709 (long long unsigned) offset, count);
713 n = p9_client_read(fid, data, offset, count);
728 EXPORT_SYMBOL(p9_client_readn);
730 struct p9_stat *p9_client_stat(struct p9_fid *fid)
733 struct p9_fcall *tc, *rc;
734 struct p9_client *clnt;
737 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
744 tc = p9_create_tstat(fid->fid);
751 err = p9_client_rpc(clnt->conn, tc, &rc);
755 ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu);
772 EXPORT_SYMBOL(p9_client_stat);
774 int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
777 struct p9_fcall *tc, *rc;
778 struct p9_client *clnt;
780 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
786 tc = p9_create_twstat(fid->fid, wst, clnt->dotu);
793 err = p9_client_rpc(clnt->conn, tc, &rc);
800 EXPORT_SYMBOL(p9_client_wstat);
802 struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
805 struct p9_fcall *tc, *rc;
806 struct p9_client *clnt;
807 struct p9_stat st, *ret;
809 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid,
810 (long long unsigned) offset);
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)) {
822 fid->rdir_fpos += fid->rdir_fcall->params.rread.count;
824 kfree(fid->rdir_fcall);
825 fid->rdir_fcall = NULL;
826 if (offset < fid->rdir_fpos)
830 if (!fid->rdir_fcall) {
832 if (!n || n > clnt->msize-P9_IOHDRSZ)
833 n = clnt->msize - P9_IOHDRSZ;
836 if (fid->rdir_fcall) {
838 fid->rdir_fcall->params.rread.count;
839 kfree(fid->rdir_fcall);
840 fid->rdir_fcall = NULL;
843 tc = p9_create_tread(fid->fid, fid->rdir_fpos, n);
850 err = p9_client_rpc(clnt->conn, tc, &rc);
854 n = rc->params.rread.count;
858 fid->rdir_fcall = rc;
860 if (offset >= fid->rdir_fpos &&
861 offset < fid->rdir_fpos+n)
868 m = offset - fid->rdir_fpos;
872 n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m,
873 fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu);
882 ret = p9_clone_stat(&st, clnt->dotu);
900 EXPORT_SYMBOL(p9_client_dirread);
902 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
908 n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len +
912 n += st->extension.len;
914 ret = kmalloc(n, GFP_KERNEL);
916 return ERR_PTR(-ENOMEM);
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);
923 memmove(p, st->uid.str, st->uid.len);
926 memmove(p, st->gid.str, st->gid.len);
929 memmove(p, st->muid.str, st->muid.len);
934 memmove(p, st->extension.str, st->extension.len);
935 ret->extension.str = p;
936 p += st->extension.len;
942 static struct p9_fid *p9_fid_create(struct p9_client *clnt)
947 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
948 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
950 return ERR_PTR(-ENOMEM);
952 fid->fid = p9_idpool_get(clnt->fidpool);
958 memset(&fid->qid, 0, sizeof(struct p9_qid));
962 fid->rdir_fcall = NULL;
963 fid->uid = current->fsuid;
967 spin_lock(&clnt->lock);
968 list_add(&fid->flist, &clnt->fidlist);
969 spin_unlock(&clnt->lock);
978 static void p9_fid_destroy(struct p9_fid *fid)
980 struct p9_client *clnt;
982 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
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);