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
);
42 struct p9_client
*p9_client_create(struct p9_trans
*trans
, int msize
,
46 struct p9_client
*clnt
;
47 struct p9_fcall
*tc
, *rc
;
48 struct p9_str
*version
;
53 clnt
= kmalloc(sizeof(struct p9_client
), GFP_KERNEL
);
55 return ERR_PTR(-ENOMEM
);
57 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p trans %p msize %d dotu %d\n",
58 clnt
, trans
, msize
, dotu
);
59 spin_lock_init(&clnt
->lock
);
63 INIT_LIST_HEAD(&clnt
->fidlist
);
64 clnt
->fidpool
= p9_idpool_create();
66 err
= PTR_ERR(clnt
->fidpool
);
71 clnt
->conn
= p9_conn_create(clnt
->trans
, clnt
->msize
, &clnt
->dotu
);
72 if (IS_ERR(clnt
->conn
)) {
73 err
= PTR_ERR(clnt
->conn
);
78 tc
= p9_create_tversion(clnt
->msize
, clnt
->dotu
?"9P2000.u":"9P2000");
85 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
89 version
= &rc
->params
.rversion
.version
;
90 if (version
->len
== 8 && !memcmp(version
->str
, "9P2000.u", 8))
92 else if (version
->len
== 6 && !memcmp(version
->str
, "9P2000", 6))
99 n
= rc
->params
.rversion
.msize
;
110 p9_client_destroy(clnt
);
113 EXPORT_SYMBOL(p9_client_create
);
115 void p9_client_destroy(struct p9_client
*clnt
)
117 struct p9_fid
*fid
, *fidptr
;
119 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
121 p9_conn_destroy(clnt
->conn
);
126 clnt
->trans
->close(clnt
->trans
);
131 list_for_each_entry_safe(fid
, fidptr
, &clnt
->fidlist
, flist
)
135 p9_idpool_destroy(clnt
->fidpool
);
139 EXPORT_SYMBOL(p9_client_destroy
);
141 void p9_client_disconnect(struct p9_client
*clnt
)
143 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
144 clnt
->trans
->status
= Disconnected
;
145 p9_conn_cancel(clnt
->conn
, -EIO
);
147 EXPORT_SYMBOL(p9_client_disconnect
);
149 struct p9_fid
*p9_client_attach(struct p9_client
*clnt
, struct p9_fid
*afid
,
150 char *uname
, u32 n_uname
, char *aname
)
153 struct p9_fcall
*tc
, *rc
;
156 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p afid %d uname %s aname %s\n",
157 clnt
, afid
?afid
->fid
:-1, uname
, aname
);
162 fid
= p9_fid_create(clnt
);
169 tc
= p9_create_tattach(fid
->fid
, afid
?afid
->fid
:P9_NOFID
, uname
, aname
,
170 n_uname
, clnt
->dotu
);
177 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
181 memmove(&fid
->qid
, &rc
->params
.rattach
.qid
, sizeof(struct p9_qid
));
193 EXPORT_SYMBOL(p9_client_attach
);
195 struct p9_fid
*p9_client_auth(struct p9_client
*clnt
, char *uname
,
196 u32 n_uname
, char *aname
)
199 struct p9_fcall
*tc
, *rc
;
202 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p uname %s aname %s\n", clnt
, uname
,
208 fid
= p9_fid_create(clnt
);
215 tc
= p9_create_tauth(fid
->fid
, uname
, aname
, n_uname
, clnt
->dotu
);
222 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
226 memmove(&fid
->qid
, &rc
->params
.rauth
.qid
, sizeof(struct p9_qid
));
238 EXPORT_SYMBOL(p9_client_auth
);
240 struct p9_fid
*p9_client_walk(struct p9_fid
*oldfid
, int nwname
, char **wnames
,
244 struct p9_fcall
*tc
, *rc
;
245 struct p9_client
*clnt
;
248 P9_DPRINTK(P9_DEBUG_9P
, "fid %d nwname %d wname[0] %s\n",
249 oldfid
->fid
, nwname
, wnames
?wnames
[0]:NULL
);
255 fid
= p9_fid_create(clnt
);
262 fid
->uid
= oldfid
->uid
;
266 tc
= p9_create_twalk(oldfid
->fid
, fid
->fid
, nwname
, wnames
);
273 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
275 if (rc
&& rc
->id
== P9_RWALK
)
281 if (rc
->params
.rwalk
.nwqid
!= nwname
) {
288 &rc
->params
.rwalk
.wqids
[rc
->params
.rwalk
.nwqid
- 1],
289 sizeof(struct p9_qid
));
291 fid
->qid
= oldfid
->qid
;
301 tc
= p9_create_tclunk(fid
->fid
);
308 p9_conn_rpc(clnt
->conn
, tc
, &rc
);
313 if (fid
&& (fid
!= oldfid
))
318 EXPORT_SYMBOL(p9_client_walk
);
320 int p9_client_open(struct p9_fid
*fid
, int mode
)
323 struct p9_fcall
*tc
, *rc
;
324 struct p9_client
*clnt
;
326 P9_DPRINTK(P9_DEBUG_9P
, "fid %d mode %d\n", fid
->fid
, mode
);
335 tc
= p9_create_topen(fid
->fid
, mode
);
342 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
347 fid
->iounit
= rc
->params
.ropen
.iounit
;
354 EXPORT_SYMBOL(p9_client_open
);
356 int p9_client_fcreate(struct p9_fid
*fid
, char *name
, u32 perm
, int mode
,
360 struct p9_fcall
*tc
, *rc
;
361 struct p9_client
*clnt
;
363 P9_DPRINTK(P9_DEBUG_9P
, "fid %d name %s perm %d mode %d\n", fid
->fid
,
373 tc
= p9_create_tcreate(fid
->fid
, name
, perm
, mode
, extension
,
381 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
386 fid
->iounit
= rc
->params
.ropen
.iounit
;
393 EXPORT_SYMBOL(p9_client_fcreate
);
395 int p9_client_clunk(struct p9_fid
*fid
)
398 struct p9_fcall
*tc
, *rc
;
399 struct p9_client
*clnt
;
401 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
407 tc
= p9_create_tclunk(fid
->fid
);
414 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
425 EXPORT_SYMBOL(p9_client_clunk
);
427 int p9_client_remove(struct p9_fid
*fid
)
430 struct p9_fcall
*tc
, *rc
;
431 struct p9_client
*clnt
;
433 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
439 tc
= p9_create_tremove(fid
->fid
);
446 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
457 EXPORT_SYMBOL(p9_client_remove
);
459 int p9_client_read(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
461 int err
, n
, rsize
, total
;
462 struct p9_fcall
*tc
, *rc
;
463 struct p9_client
*clnt
;
465 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu %d\n", fid
->fid
,
466 (long long unsigned) offset
, count
);
474 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
475 rsize
= clnt
->msize
- P9_IOHDRSZ
;
481 tc
= p9_create_tread(fid
->fid
, offset
, rsize
);
488 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
492 n
= rc
->params
.rread
.count
;
496 memmove(data
, rc
->params
.rread
.data
, n
);
505 } while (count
> 0 && n
== rsize
);
514 EXPORT_SYMBOL(p9_client_read
);
516 int p9_client_write(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
518 int err
, n
, rsize
, total
;
519 struct p9_fcall
*tc
, *rc
;
520 struct p9_client
*clnt
;
522 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
523 (long long unsigned) offset
, count
);
531 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
532 rsize
= clnt
->msize
- P9_IOHDRSZ
;
538 tc
= p9_create_twrite(fid
->fid
, offset
, rsize
, data
);
545 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
549 n
= rc
->params
.rread
.count
;
567 EXPORT_SYMBOL(p9_client_write
);
570 p9_client_uread(struct p9_fid
*fid
, char __user
*data
, u64 offset
, u32 count
)
572 int err
, n
, rsize
, total
;
573 struct p9_fcall
*tc
, *rc
;
574 struct p9_client
*clnt
;
576 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
577 (long long unsigned) offset
, count
);
585 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
586 rsize
= clnt
->msize
- P9_IOHDRSZ
;
592 tc
= p9_create_tread(fid
->fid
, offset
, rsize
);
599 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
603 n
= rc
->params
.rread
.count
;
607 err
= copy_to_user(data
, rc
->params
.rread
.data
, n
);
621 } while (count
> 0 && n
== rsize
);
630 EXPORT_SYMBOL(p9_client_uread
);
633 p9_client_uwrite(struct p9_fid
*fid
, const char __user
*data
, u64 offset
,
636 int err
, n
, rsize
, total
;
637 struct p9_fcall
*tc
, *rc
;
638 struct p9_client
*clnt
;
640 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
641 (long long unsigned) offset
, count
);
649 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
650 rsize
= clnt
->msize
- P9_IOHDRSZ
;
656 tc
= p9_create_twrite_u(fid
->fid
, offset
, rsize
, data
);
663 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
667 n
= rc
->params
.rread
.count
;
685 EXPORT_SYMBOL(p9_client_uwrite
);
687 int p9_client_readn(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
691 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
692 (long long unsigned) offset
, count
);
696 n
= p9_client_read(fid
, data
, offset
, count
);
711 EXPORT_SYMBOL(p9_client_readn
);
713 struct p9_stat
*p9_client_stat(struct p9_fid
*fid
)
716 struct p9_fcall
*tc
, *rc
;
717 struct p9_client
*clnt
;
720 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
727 tc
= p9_create_tstat(fid
->fid
);
734 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
738 ret
= p9_clone_stat(&rc
->params
.rstat
.stat
, clnt
->dotu
);
755 EXPORT_SYMBOL(p9_client_stat
);
757 int p9_client_wstat(struct p9_fid
*fid
, struct p9_wstat
*wst
)
760 struct p9_fcall
*tc
, *rc
;
761 struct p9_client
*clnt
;
763 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
769 tc
= p9_create_twstat(fid
->fid
, wst
, clnt
->dotu
);
776 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
783 EXPORT_SYMBOL(p9_client_wstat
);
785 struct p9_stat
*p9_client_dirread(struct p9_fid
*fid
, u64 offset
)
788 struct p9_fcall
*tc
, *rc
;
789 struct p9_client
*clnt
;
790 struct p9_stat st
, *ret
;
792 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu\n", fid
->fid
,
793 (long long unsigned) offset
);
800 /* if the offset is below or above the current response, free it */
801 if (offset
< fid
->rdir_fpos
|| (fid
->rdir_fcall
&&
802 offset
>= fid
->rdir_fpos
+fid
->rdir_fcall
->params
.rread
.count
)) {
805 fid
->rdir_fpos
+= fid
->rdir_fcall
->params
.rread
.count
;
807 kfree(fid
->rdir_fcall
);
808 fid
->rdir_fcall
= NULL
;
809 if (offset
< fid
->rdir_fpos
)
813 if (!fid
->rdir_fcall
) {
815 if (!n
|| n
> clnt
->msize
-P9_IOHDRSZ
)
816 n
= clnt
->msize
- P9_IOHDRSZ
;
819 if (fid
->rdir_fcall
) {
821 fid
->rdir_fcall
->params
.rread
.count
;
822 kfree(fid
->rdir_fcall
);
823 fid
->rdir_fcall
= NULL
;
826 tc
= p9_create_tread(fid
->fid
, fid
->rdir_fpos
, n
);
833 err
= p9_conn_rpc(clnt
->conn
, tc
, &rc
);
837 n
= rc
->params
.rread
.count
;
841 fid
->rdir_fcall
= rc
;
843 if (offset
>= fid
->rdir_fpos
&&
844 offset
< fid
->rdir_fpos
+n
)
851 m
= offset
- fid
->rdir_fpos
;
855 n
= p9_deserialize_stat(fid
->rdir_fcall
->params
.rread
.data
+ m
,
856 fid
->rdir_fcall
->params
.rread
.count
- m
, &st
, clnt
->dotu
);
865 ret
= p9_clone_stat(&st
, clnt
->dotu
);
883 EXPORT_SYMBOL(p9_client_dirread
);
885 static struct p9_stat
*p9_clone_stat(struct p9_stat
*st
, int dotu
)
891 n
= sizeof(struct p9_stat
) + st
->name
.len
+ st
->uid
.len
+ st
->gid
.len
+
895 n
+= st
->extension
.len
;
897 ret
= kmalloc(n
, GFP_KERNEL
);
899 return ERR_PTR(-ENOMEM
);
901 memmove(ret
, st
, sizeof(struct p9_stat
));
902 p
= ((char *) ret
) + sizeof(struct p9_stat
);
903 memmove(p
, st
->name
.str
, st
->name
.len
);
905 memmove(p
, st
->uid
.str
, st
->uid
.len
);
907 memmove(p
, st
->gid
.str
, st
->gid
.len
);
909 memmove(p
, st
->muid
.str
, st
->muid
.len
);
913 memmove(p
, st
->extension
.str
, st
->extension
.len
);
914 p
+= st
->extension
.len
;
920 static struct p9_fid
*p9_fid_create(struct p9_client
*clnt
)
925 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
926 fid
= kmalloc(sizeof(struct p9_fid
), GFP_KERNEL
);
928 return ERR_PTR(-ENOMEM
);
930 fid
->fid
= p9_idpool_get(clnt
->fidpool
);
936 memset(&fid
->qid
, 0, sizeof(struct p9_qid
));
940 fid
->rdir_fcall
= NULL
;
941 fid
->uid
= current
->fsuid
;
945 spin_lock(&clnt
->lock
);
946 list_add(&fid
->flist
, &clnt
->fidlist
);
947 spin_unlock(&clnt
->lock
);
956 static void p9_fid_destroy(struct p9_fid
*fid
)
958 struct p9_client
*clnt
;
960 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
962 p9_idpool_put(fid
->fid
, clnt
->fidpool
);
963 spin_lock(&clnt
->lock
);
964 list_del(&fid
->flist
);
965 spin_unlock(&clnt
->lock
);
966 kfree(fid
->rdir_fcall
);