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_transport *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, 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);
175 err = p9_conn_rpc(clnt->conn, tc, &rc);
179 memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid));
191 EXPORT_SYMBOL(p9_client_attach);
193 struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname)
196 struct p9_fcall *tc, *rc;
199 P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname,
205 fid = p9_fid_create(clnt);
212 tc = p9_create_tauth(fid->fid, uname, aname);
219 err = p9_conn_rpc(clnt->conn, tc, &rc);
223 memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid));
235 EXPORT_SYMBOL(p9_client_auth);
237 struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
241 struct p9_fcall *tc, *rc;
242 struct p9_client *clnt;
245 P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n",
246 oldfid->fid, nwname, wnames?wnames[0]:NULL);
252 fid = p9_fid_create(clnt);
259 fid->uid = oldfid->uid;
263 tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames);
270 err = p9_conn_rpc(clnt->conn, tc, &rc);
272 if (rc && rc->id == P9_RWALK)
278 if (rc->params.rwalk.nwqid != nwname) {
285 &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1],
286 sizeof(struct p9_qid));
288 fid->qid = oldfid->qid;
298 tc = p9_create_tclunk(fid->fid);
305 p9_conn_rpc(clnt->conn, tc, &rc);
310 if (fid && (fid != oldfid))
315 EXPORT_SYMBOL(p9_client_walk);
317 int p9_client_open(struct p9_fid *fid, int mode)
320 struct p9_fcall *tc, *rc;
321 struct p9_client *clnt;
323 P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode);
332 tc = p9_create_topen(fid->fid, mode);
339 err = p9_conn_rpc(clnt->conn, tc, &rc);
344 fid->iounit = rc->params.ropen.iounit;
351 EXPORT_SYMBOL(p9_client_open);
353 int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
357 struct p9_fcall *tc, *rc;
358 struct p9_client *clnt;
360 P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid,
370 tc = p9_create_tcreate(fid->fid, name, perm, mode, extension,
378 err = p9_conn_rpc(clnt->conn, tc, &rc);
383 fid->iounit = rc->params.ropen.iounit;
390 EXPORT_SYMBOL(p9_client_fcreate);
392 int p9_client_clunk(struct p9_fid *fid)
395 struct p9_fcall *tc, *rc;
396 struct p9_client *clnt;
398 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
404 tc = p9_create_tclunk(fid->fid);
411 err = p9_conn_rpc(clnt->conn, tc, &rc);
422 EXPORT_SYMBOL(p9_client_clunk);
424 int p9_client_remove(struct p9_fid *fid)
427 struct p9_fcall *tc, *rc;
428 struct p9_client *clnt;
430 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
436 tc = p9_create_tremove(fid->fid);
443 err = p9_conn_rpc(clnt->conn, tc, &rc);
454 EXPORT_SYMBOL(p9_client_remove);
456 int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
458 int err, n, rsize, total;
459 struct p9_fcall *tc, *rc;
460 struct p9_client *clnt;
462 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid,
463 (long long unsigned) offset, count);
471 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
472 rsize = clnt->msize - P9_IOHDRSZ;
478 tc = p9_create_tread(fid->fid, offset, rsize);
485 err = p9_conn_rpc(clnt->conn, tc, &rc);
489 n = rc->params.rread.count;
493 memmove(data, rc->params.rread.data, n);
502 } while (count > 0 && n == rsize);
511 EXPORT_SYMBOL(p9_client_read);
513 int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
515 int err, n, rsize, total;
516 struct p9_fcall *tc, *rc;
517 struct p9_client *clnt;
519 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
520 (long long unsigned) offset, count);
528 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
529 rsize = clnt->msize - P9_IOHDRSZ;
535 tc = p9_create_twrite(fid->fid, offset, rsize, data);
542 err = p9_conn_rpc(clnt->conn, tc, &rc);
546 n = rc->params.rread.count;
564 EXPORT_SYMBOL(p9_client_write);
567 p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
569 int err, n, rsize, total;
570 struct p9_fcall *tc, *rc;
571 struct p9_client *clnt;
573 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
574 (long long unsigned) offset, count);
582 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
583 rsize = clnt->msize - P9_IOHDRSZ;
589 tc = p9_create_tread(fid->fid, offset, rsize);
596 err = p9_conn_rpc(clnt->conn, tc, &rc);
600 n = rc->params.rread.count;
604 err = copy_to_user(data, rc->params.rread.data, n);
618 } while (count > 0 && n == rsize);
627 EXPORT_SYMBOL(p9_client_uread);
630 p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
633 int err, n, rsize, total;
634 struct p9_fcall *tc, *rc;
635 struct p9_client *clnt;
637 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
638 (long long unsigned) offset, count);
646 if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
647 rsize = clnt->msize - P9_IOHDRSZ;
653 tc = p9_create_twrite_u(fid->fid, offset, rsize, data);
660 err = p9_conn_rpc(clnt->conn, tc, &rc);
664 n = rc->params.rread.count;
682 EXPORT_SYMBOL(p9_client_uwrite);
684 int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count)
688 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
689 (long long unsigned) offset, count);
693 n = p9_client_read(fid, data, offset, count);
708 EXPORT_SYMBOL(p9_client_readn);
710 struct p9_stat *p9_client_stat(struct p9_fid *fid)
713 struct p9_fcall *tc, *rc;
714 struct p9_client *clnt;
717 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
724 tc = p9_create_tstat(fid->fid);
731 err = p9_conn_rpc(clnt->conn, tc, &rc);
735 ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu);
752 EXPORT_SYMBOL(p9_client_stat);
754 int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
757 struct p9_fcall *tc, *rc;
758 struct p9_client *clnt;
760 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
766 tc = p9_create_twstat(fid->fid, wst, clnt->dotu);
773 err = p9_conn_rpc(clnt->conn, tc, &rc);
780 EXPORT_SYMBOL(p9_client_wstat);
782 struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
785 struct p9_fcall *tc, *rc;
786 struct p9_client *clnt;
787 struct p9_stat st, *ret;
789 P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid,
790 (long long unsigned) offset);
797 /* if the offset is below or above the current response, free it */
798 if (offset < fid->rdir_fpos || (fid->rdir_fcall &&
799 offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) {
802 fid->rdir_fpos += fid->rdir_fcall->params.rread.count;
804 kfree(fid->rdir_fcall);
805 fid->rdir_fcall = NULL;
806 if (offset < fid->rdir_fpos)
810 if (!fid->rdir_fcall) {
812 if (!n || n > clnt->msize-P9_IOHDRSZ)
813 n = clnt->msize - P9_IOHDRSZ;
816 if (fid->rdir_fcall) {
818 fid->rdir_fcall->params.rread.count;
819 kfree(fid->rdir_fcall);
820 fid->rdir_fcall = NULL;
823 tc = p9_create_tread(fid->fid, fid->rdir_fpos, n);
830 err = p9_conn_rpc(clnt->conn, tc, &rc);
834 n = rc->params.rread.count;
838 fid->rdir_fcall = rc;
840 if (offset >= fid->rdir_fpos &&
841 offset < fid->rdir_fpos+n)
848 m = offset - fid->rdir_fpos;
852 n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m,
853 fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu);
862 ret = p9_clone_stat(&st, clnt->dotu);
880 EXPORT_SYMBOL(p9_client_dirread);
882 static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
888 n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len +
892 n += st->extension.len;
894 ret = kmalloc(n, GFP_KERNEL);
896 return ERR_PTR(-ENOMEM);
898 memmove(ret, st, sizeof(struct p9_stat));
899 p = ((char *) ret) + sizeof(struct p9_stat);
900 memmove(p, st->name.str, st->name.len);
902 memmove(p, st->uid.str, st->uid.len);
904 memmove(p, st->gid.str, st->gid.len);
906 memmove(p, st->muid.str, st->muid.len);
910 memmove(p, st->extension.str, st->extension.len);
911 p += st->extension.len;
917 static struct p9_fid *p9_fid_create(struct p9_client *clnt)
922 P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
923 fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
925 return ERR_PTR(-ENOMEM);
927 fid->fid = p9_idpool_get(clnt->fidpool);
933 memset(&fid->qid, 0, sizeof(struct p9_qid));
937 fid->rdir_fcall = NULL;
938 fid->uid = current->fsuid;
942 spin_lock(&clnt->lock);
943 list_add(&fid->flist, &clnt->fidlist);
944 spin_unlock(&clnt->lock);
953 static void p9_fid_destroy(struct p9_fid *fid)
955 struct p9_client *clnt;
957 P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
959 p9_idpool_put(fid->fid, clnt->fidpool);
960 spin_lock(&clnt->lock);
961 list_del(&fid->flist);
962 spin_unlock(&clnt->lock);
963 kfree(fid->rdir_fcall);