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
);