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 <net/9p/transport.h>
34 #include <net/9p/conn.h>
35 #include <net/9p/client.h>
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);
41 struct p9_client *p9_client_create(struct p9_trans *trans, int msize,
45 struct p9_client *clnt;
46 struct p9_fcall *tc, *rc;
47 struct p9_str *version;
52 clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
54 return ERR_PTR(-ENOMEM);
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);
62 INIT_LIST_HEAD(&clnt->fidlist);
63 clnt->fidpool = p9_idpool_create();
65 err = PTR_ERR(clnt->fidpool);
70 clnt->conn = p9_conn_create(clnt->trans, clnt->msize, &clnt->dotu);
71 if (IS_ERR(clnt->conn)) {
72 err = PTR_ERR(clnt->conn);
77 tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000");
84 err = p9_conn_rpc(clnt->conn, tc, &rc);
88 version = &rc->params.rversion.version;
89 if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8))
91 else if (version->len == 6 && !memcmp(version->str, "9P2000", 6))
98 n = rc->params.rversion.msize;
109 p9_client_destroy(clnt);
112 EXPORT_SYMBOL(p9_client_create);
114 void p9_client_destroy(struct p9_client *clnt)
116 struct p9_fid *fid, *fidptr;
118 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
120 p9_conn_destroy(clnt->conn);
125 clnt->trans->close(clnt->trans);
130 list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
134 p9_idpool_destroy(clnt->fidpool);
138 EXPORT_SYMBOL(p9_client_destroy);
140 void p9_client_disconnect(struct p9_client *clnt)
142 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
143 clnt->trans->status = Disconnected;
144 p9_conn_cancel(clnt->conn, -EIO);
146 EXPORT_SYMBOL(p9_client_disconnect);
148 struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
149 char *uname, u32 n_uname, char *aname)
152 struct p9_fcall *tc, *rc;
155 P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n",
156 clnt, afid?afid->fid:-1, uname, aname);
161 fid = p9_fid_create(clnt);
168 tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname,
169 n_uname, clnt->dotu);
176 err = p9_conn_rpc(clnt->conn, tc, &rc);
180 memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid));
192 EXPORT_SYMBOL(p9_client_attach);
194 struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname,
195 u32 n_uname, char *aname)
198 struct p9_fcall *tc, *rc;
201 P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname,
207 fid = p9_fid_create(clnt);
214 tc = p9_create_tauth(fid->fid, uname, aname, n_uname, clnt->dotu);
221 err = p9_conn_rpc(clnt->conn, tc, &rc);
225 memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid));
237 EXPORT_SYMBOL(p9_client_auth);
239 struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
243 struct p9_fcall *tc, *rc;
244 struct p9_client *clnt;
247 P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n",
248 oldfid->fid, nwname, wnames?wnames[0]:NULL);
254 fid = p9_fid_create(clnt);
261 fid->uid = oldfid->uid;
265 tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames);
272 err = p9_conn_rpc(clnt->conn, tc, &rc);
274 if (rc && rc->id == P9_RWALK)
280 if (rc->params.rwalk.nwqid != nwname) {
287 &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1],
288 sizeof(struct p9_qid));
290 fid->qid = oldfid->qid;
300 tc = p9_create_tclunk(fid->fid);
307 p9_conn_rpc(clnt->conn, tc, &rc);
312 if (fid && (fid != oldfid))
317 EXPORT_SYMBOL(p9_client_walk);
319 int p9_client_open(struct p9_fid *fid, int mode)
322 struct p9_fcall *tc, *rc;
323 struct p9_client *clnt;
325 P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode);
334 tc = p9_create_topen(fid->fid, mode);
341 err = p9_conn_rpc(clnt->conn, tc, &rc);
346 fid->iounit = rc->params.ropen.iounit;
353 EXPORT_SYMBOL(p9_client_open);
355 int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
359 struct p9_fcall *tc, *rc;
360 struct p9_client *clnt;
362 P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid,
372 tc = p9_create_tcreate(fid->fid, name, perm, mode, extension,
380 err = p9_conn_rpc(clnt->conn, tc, &rc);
385 fid->iounit = rc->params.ropen.iounit;
392 EXPORT_SYMBOL(p9_client_fcreate);
394 int p9_client_clunk(struct p9_fid *fid)
397 struct p9_fcall *tc, *rc;
398 struct p9_client *clnt;
400 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
406 tc = p9_create_tclunk(fid->fid);
413 err = p9_conn_rpc(clnt->conn, tc, &rc);
424 EXPORT_SYMBOL(p9_client_clunk);
426 int p9_client_remove(struct p9_fid *fid)
429 struct p9_fcall *tc, *rc;
430 struct p9_client *clnt;
432 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
438 tc = p9_create_tremove(fid->fid);
445 err = p9_conn_rpc(clnt->conn, tc, &rc);
456 EXPORT_SYMBOL(p9_client_remove);
458 int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
460 int err, n, rsize, total;
461 struct p9_fcall *tc, *rc;
462 struct p9_client *clnt;
464 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid,
465 (long long unsigned) offset, count);
473 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
474 rsize = clnt->msize - P9_IOHDRSZ;
480 tc = p9_create_tread(fid->fid, offset, rsize);
487 err = p9_conn_rpc(clnt->conn, tc, &rc);
491 n = rc->params.rread.count;
495 memmove(data, rc->params.rread.data, n);
504 } while (count > 0 && n == rsize);
513 EXPORT_SYMBOL(p9_client_read);
515 int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
517 int err, n, rsize, total;
518 struct p9_fcall *tc, *rc;
519 struct p9_client *clnt;
521 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
522 (long long unsigned) offset, count);
530 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
531 rsize = clnt->msize - P9_IOHDRSZ;
537 tc = p9_create_twrite(fid->fid, offset, rsize, data);
544 err = p9_conn_rpc(clnt->conn, tc, &rc);
548 n = rc->params.rread.count;
566 EXPORT_SYMBOL(p9_client_write);
569 p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
571 int err, n, rsize, total;
572 struct p9_fcall *tc, *rc;
573 struct p9_client *clnt;
575 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
576 (long long unsigned) offset, count);
584 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
585 rsize = clnt->msize - P9_IOHDRSZ;
591 tc = p9_create_tread(fid->fid, offset, rsize);
598 err = p9_conn_rpc(clnt->conn, tc, &rc);
602 n = rc->params.rread.count;
606 err = copy_to_user(data, rc->params.rread.data, n);
620 } while (count > 0 && n == rsize);
629 EXPORT_SYMBOL(p9_client_uread);
632 p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
635 int err, n, rsize, total;
636 struct p9_fcall *tc, *rc;
637 struct p9_client *clnt;
639 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
640 (long long unsigned) offset, count);
648 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
649 rsize = clnt->msize - P9_IOHDRSZ;
655 tc = p9_create_twrite_u(fid->fid, offset, rsize, data);
662 err = p9_conn_rpc(clnt->conn, tc, &rc);
666 n = rc->params.rread.count;
684 EXPORT_SYMBOL(p9_client_uwrite);
686 int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count)
690 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
691 (long long unsigned) offset, count);
695 n = p9_client_read(fid, data, offset, count);
710 EXPORT_SYMBOL(p9_client_readn);
712 struct p9_stat *p9_client_stat(struct p9_fid *fid)
715 struct p9_fcall *tc, *rc;
716 struct p9_client *clnt;
719 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
726 tc = p9_create_tstat(fid->fid);
733 err = p9_conn_rpc(clnt->conn, tc, &rc);
737 ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu);
754 EXPORT_SYMBOL(p9_client_stat);
756 int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
759 struct p9_fcall *tc, *rc;
760 struct p9_client *clnt;
762 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
768 tc = p9_create_twstat(fid->fid, wst, clnt->dotu);
775 err = p9_conn_rpc(clnt->conn, tc, &rc);
782 EXPORT_SYMBOL(p9_client_wstat);
784 struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
787 struct p9_fcall *tc, *rc;
788 struct p9_client *clnt;
789 struct p9_stat st, *ret;
791 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid,
792 (long long unsigned) offset);
799 /* if the offset is below or above the current response, free it */
800 if (offset < fid->rdir_fpos || (fid->rdir_fcall &&
801 offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) {
804 fid->rdir_fpos += fid->rdir_fcall->params.rread.count;
806 kfree(fid->rdir_fcall);
807 fid->rdir_fcall = NULL;
808 if (offset < fid->rdir_fpos)
812 if (!fid->rdir_fcall) {
814 if (!n || n > clnt->msize-P9_IOHDRSZ)
815 n = clnt->msize - P9_IOHDRSZ;
818 if (fid->rdir_fcall) {
820 fid->rdir_fcall->params.rread.count;
821 kfree(fid->rdir_fcall);
822 fid->rdir_fcall = NULL;
825 tc = p9_create_tread(fid->fid, fid->rdir_fpos, n);
832 err = p9_conn_rpc(clnt->conn, tc, &rc);
836 n = rc->params.rread.count;
840 fid->rdir_fcall = rc;
842 if (offset >= fid->rdir_fpos &&
843 offset < fid->rdir_fpos+n)
850 m = offset - fid->rdir_fpos;
854 n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m,
855 fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu);
864 ret = p9_clone_stat(&st, clnt->dotu);
882 EXPORT_SYMBOL(p9_client_dirread);
884 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
890 n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len +
894 n += st->extension.len;
896 ret = kmalloc(n, GFP_KERNEL);
898 return ERR_PTR(-ENOMEM);
900 memmove(ret, st, sizeof(struct p9_stat));
901 p = ((char *) ret) + sizeof(struct p9_stat);
902 memmove(p, st->name.str, st->name.len);
904 memmove(p, st->uid.str, st->uid.len);
906 memmove(p, st->gid.str, st->gid.len);
908 memmove(p, st->muid.str, st->muid.len);
912 memmove(p, st->extension.str, st->extension.len);
913 p += st->extension.len;
919 static struct p9_fid *p9_fid_create(struct p9_client *clnt)
924 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
925 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
927 return ERR_PTR(-ENOMEM);
929 fid->fid = p9_idpool_get(clnt->fidpool);
935 memset(&fid->qid, 0, sizeof(struct p9_qid));
939 fid->rdir_fcall = NULL;
940 fid->uid = current->fsuid;
944 spin_lock(&clnt->lock);
945 list_add(&fid->flist, &clnt->fidlist);
946 spin_unlock(&clnt->lock);
955 static void p9_fid_destroy(struct p9_fid *fid)
957 struct p9_client *clnt;
959 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
961 p9_idpool_put(fid->fid, clnt->fidpool);
962 spin_lock(&clnt->lock);
963 list_del(&fid->flist);
964 spin_unlock(&clnt->lock);
965 kfree(fid->rdir_fcall);