6 * Copyright (C) 2008 by Eric Van Hensbergen <ericvh@gmail.com>
7 * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to:
20 * Free Software Foundation
21 * 51 Franklin Street, Fifth Floor
22 * Boston, MA 02111-1301 USA
26 #include <linux/module.h>
27 #include <linux/errno.h>
29 #include <linux/poll.h>
30 #include <linux/idr.h>
31 #include <linux/mutex.h>
32 #include <linux/sched.h>
33 #include <linux/uaccess.h>
34 #include <net/9p/9p.h>
35 #include <linux/parser.h>
36 #include <net/9p/transport.h>
37 #include <net/9p/client.h>
39 static struct p9_fid
*p9_fid_create(struct p9_client
*clnt
);
40 static void p9_fid_destroy(struct p9_fid
*fid
);
41 static struct p9_stat
*p9_clone_stat(struct p9_stat
*st
, int dotu
);
44 * Client Option Parsing (code inspired by NFS code)
45 * - a little lazy - parse all client options
55 static match_table_t tokens
= {
56 {Opt_msize
, "msize=%u"},
57 {Opt_legacy
, "noextend"},
58 {Opt_trans
, "trans=%s"},
63 * v9fs_parse_options - parse mount options into session structure
64 * @options: options string passed from mount
65 * @v9ses: existing v9fs session information
69 static void parse_opts(char *options
, struct p9_client
*clnt
)
72 substring_t args
[MAX_OPT_ARGS
];
76 clnt
->trans_mod
= v9fs_default_trans();
83 while ((p
= strsep(&options
, ",")) != NULL
) {
87 token
= match_token(p
, tokens
, args
);
88 if (token
< Opt_trans
) {
89 ret
= match_int(&args
[0], &option
);
91 P9_DPRINTK(P9_DEBUG_ERROR
,
92 "integer field, but no integer?\n");
101 clnt
->trans_mod
= v9fs_match_trans(&args
[0]);
114 * p9_client_rpc - sends 9P request and waits until a response is available.
115 * The function can be interrupted.
117 * @tc: request to be sent
118 * @rc: pointer where a pointer to the response is stored
121 p9_client_rpc(struct p9_client
*c
, struct p9_fcall
*tc
,
122 struct p9_fcall
**rc
)
124 return c
->trans
->rpc(c
->trans
, tc
, rc
);
127 struct p9_client
*p9_client_create(const char *dev_name
, char *options
)
130 struct p9_client
*clnt
;
131 struct p9_fcall
*tc
, *rc
;
132 struct p9_str
*version
;
137 clnt
= kmalloc(sizeof(struct p9_client
), GFP_KERNEL
);
139 return ERR_PTR(-ENOMEM
);
141 spin_lock_init(&clnt
->lock
);
142 INIT_LIST_HEAD(&clnt
->fidlist
);
143 clnt
->fidpool
= p9_idpool_create();
144 if (!clnt
->fidpool
) {
145 err
= PTR_ERR(clnt
->fidpool
);
146 clnt
->fidpool
= NULL
;
150 parse_opts(options
, clnt
);
151 if (clnt
->trans_mod
== NULL
) {
152 err
= -EPROTONOSUPPORT
;
153 P9_DPRINTK(P9_DEBUG_ERROR
,
154 "No transport defined or default transport\n");
158 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p trans %p msize %d dotu %d\n",
159 clnt
, clnt
->trans_mod
, clnt
->msize
, clnt
->dotu
);
162 clnt
->trans
= clnt
->trans_mod
->create(dev_name
, options
, clnt
->msize
,
164 if (IS_ERR(clnt
->trans
)) {
165 err
= PTR_ERR(clnt
->trans
);
170 if ((clnt
->msize
+P9_IOHDRSZ
) > clnt
->trans_mod
->maxsize
)
171 clnt
->msize
= clnt
->trans_mod
->maxsize
-P9_IOHDRSZ
;
173 tc
= p9_create_tversion(clnt
->msize
, clnt
->dotu
?"9P2000.u":"9P2000");
180 err
= p9_client_rpc(clnt
, tc
, &rc
);
184 version
= &rc
->params
.rversion
.version
;
185 if (version
->len
== 8 && !memcmp(version
->str
, "9P2000.u", 8))
187 else if (version
->len
== 6 && !memcmp(version
->str
, "9P2000", 6))
194 n
= rc
->params
.rversion
.msize
;
205 p9_client_destroy(clnt
);
208 EXPORT_SYMBOL(p9_client_create
);
210 void p9_client_destroy(struct p9_client
*clnt
)
212 struct p9_fid
*fid
, *fidptr
;
214 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
217 clnt
->trans
->close(clnt
->trans
);
222 list_for_each_entry_safe(fid
, fidptr
, &clnt
->fidlist
, flist
)
226 p9_idpool_destroy(clnt
->fidpool
);
230 EXPORT_SYMBOL(p9_client_destroy
);
232 void p9_client_disconnect(struct p9_client
*clnt
)
234 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
235 clnt
->trans
->status
= Disconnected
;
237 EXPORT_SYMBOL(p9_client_disconnect
);
239 struct p9_fid
*p9_client_attach(struct p9_client
*clnt
, struct p9_fid
*afid
,
240 char *uname
, u32 n_uname
, char *aname
)
243 struct p9_fcall
*tc
, *rc
;
246 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p afid %d uname %s aname %s\n",
247 clnt
, afid
?afid
->fid
:-1, uname
, aname
);
252 fid
= p9_fid_create(clnt
);
259 tc
= p9_create_tattach(fid
->fid
, afid
?afid
->fid
:P9_NOFID
, uname
, aname
,
260 n_uname
, clnt
->dotu
);
267 err
= p9_client_rpc(clnt
, tc
, &rc
);
271 memmove(&fid
->qid
, &rc
->params
.rattach
.qid
, sizeof(struct p9_qid
));
283 EXPORT_SYMBOL(p9_client_attach
);
285 struct p9_fid
*p9_client_auth(struct p9_client
*clnt
, char *uname
,
286 u32 n_uname
, char *aname
)
289 struct p9_fcall
*tc
, *rc
;
292 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p uname %s aname %s\n", clnt
, uname
,
298 fid
= p9_fid_create(clnt
);
305 tc
= p9_create_tauth(fid
->fid
, uname
, aname
, n_uname
, clnt
->dotu
);
312 err
= p9_client_rpc(clnt
, tc
, &rc
);
316 memmove(&fid
->qid
, &rc
->params
.rauth
.qid
, sizeof(struct p9_qid
));
328 EXPORT_SYMBOL(p9_client_auth
);
330 struct p9_fid
*p9_client_walk(struct p9_fid
*oldfid
, int nwname
, char **wnames
,
334 struct p9_fcall
*tc
, *rc
;
335 struct p9_client
*clnt
;
338 P9_DPRINTK(P9_DEBUG_9P
, "fid %d nwname %d wname[0] %s\n",
339 oldfid
->fid
, nwname
, wnames
?wnames
[0]:NULL
);
345 fid
= p9_fid_create(clnt
);
352 fid
->uid
= oldfid
->uid
;
356 tc
= p9_create_twalk(oldfid
->fid
, fid
->fid
, nwname
, wnames
);
363 err
= p9_client_rpc(clnt
, tc
, &rc
);
365 if (rc
&& rc
->id
== P9_RWALK
)
371 if (rc
->params
.rwalk
.nwqid
!= nwname
) {
378 &rc
->params
.rwalk
.wqids
[rc
->params
.rwalk
.nwqid
- 1],
379 sizeof(struct p9_qid
));
381 fid
->qid
= oldfid
->qid
;
391 tc
= p9_create_tclunk(fid
->fid
);
398 p9_client_rpc(clnt
, tc
, &rc
);
403 if (fid
&& (fid
!= oldfid
))
408 EXPORT_SYMBOL(p9_client_walk
);
410 int p9_client_open(struct p9_fid
*fid
, int mode
)
413 struct p9_fcall
*tc
, *rc
;
414 struct p9_client
*clnt
;
416 P9_DPRINTK(P9_DEBUG_9P
, "fid %d mode %d\n", fid
->fid
, mode
);
425 tc
= p9_create_topen(fid
->fid
, mode
);
432 err
= p9_client_rpc(clnt
, tc
, &rc
);
437 fid
->iounit
= rc
->params
.ropen
.iounit
;
444 EXPORT_SYMBOL(p9_client_open
);
446 int p9_client_fcreate(struct p9_fid
*fid
, char *name
, u32 perm
, int mode
,
450 struct p9_fcall
*tc
, *rc
;
451 struct p9_client
*clnt
;
453 P9_DPRINTK(P9_DEBUG_9P
, "fid %d name %s perm %d mode %d\n", fid
->fid
,
463 tc
= p9_create_tcreate(fid
->fid
, name
, perm
, mode
, extension
,
471 err
= p9_client_rpc(clnt
, tc
, &rc
);
476 fid
->iounit
= rc
->params
.ropen
.iounit
;
483 EXPORT_SYMBOL(p9_client_fcreate
);
485 int p9_client_clunk(struct p9_fid
*fid
)
488 struct p9_fcall
*tc
, *rc
;
489 struct p9_client
*clnt
;
491 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
497 tc
= p9_create_tclunk(fid
->fid
);
504 err
= p9_client_rpc(clnt
, tc
, &rc
);
515 EXPORT_SYMBOL(p9_client_clunk
);
517 int p9_client_remove(struct p9_fid
*fid
)
520 struct p9_fcall
*tc
, *rc
;
521 struct p9_client
*clnt
;
523 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
529 tc
= p9_create_tremove(fid
->fid
);
536 err
= p9_client_rpc(clnt
, tc
, &rc
);
547 EXPORT_SYMBOL(p9_client_remove
);
549 int p9_client_read(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
551 int err
, n
, rsize
, total
;
552 struct p9_fcall
*tc
, *rc
;
553 struct p9_client
*clnt
;
555 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu %d\n", fid
->fid
,
556 (long long unsigned) offset
, count
);
564 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
565 rsize
= clnt
->msize
- P9_IOHDRSZ
;
571 tc
= p9_create_tread(fid
->fid
, offset
, rsize
);
578 err
= p9_client_rpc(clnt
, tc
, &rc
);
582 n
= rc
->params
.rread
.count
;
586 memmove(data
, rc
->params
.rread
.data
, n
);
595 } while (count
> 0 && n
== rsize
);
604 EXPORT_SYMBOL(p9_client_read
);
606 int p9_client_write(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
608 int err
, n
, rsize
, total
;
609 struct p9_fcall
*tc
, *rc
;
610 struct p9_client
*clnt
;
612 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
613 (long long unsigned) offset
, count
);
621 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
622 rsize
= clnt
->msize
- P9_IOHDRSZ
;
628 tc
= p9_create_twrite(fid
->fid
, offset
, rsize
, data
);
635 err
= p9_client_rpc(clnt
, tc
, &rc
);
639 n
= rc
->params
.rread
.count
;
657 EXPORT_SYMBOL(p9_client_write
);
660 p9_client_uread(struct p9_fid
*fid
, char __user
*data
, u64 offset
, u32 count
)
662 int err
, n
, rsize
, total
;
663 struct p9_fcall
*tc
, *rc
;
664 struct p9_client
*clnt
;
666 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
667 (long long unsigned) offset
, count
);
675 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
676 rsize
= clnt
->msize
- P9_IOHDRSZ
;
682 tc
= p9_create_tread(fid
->fid
, offset
, rsize
);
689 err
= p9_client_rpc(clnt
, tc
, &rc
);
693 n
= rc
->params
.rread
.count
;
697 err
= copy_to_user(data
, rc
->params
.rread
.data
, n
);
711 } while (count
> 0 && n
== rsize
);
720 EXPORT_SYMBOL(p9_client_uread
);
723 p9_client_uwrite(struct p9_fid
*fid
, const char __user
*data
, u64 offset
,
726 int err
, n
, rsize
, total
;
727 struct p9_fcall
*tc
, *rc
;
728 struct p9_client
*clnt
;
730 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
731 (long long unsigned) offset
, count
);
739 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
740 rsize
= clnt
->msize
- P9_IOHDRSZ
;
746 tc
= p9_create_twrite_u(fid
->fid
, offset
, rsize
, data
);
753 err
= p9_client_rpc(clnt
, tc
, &rc
);
757 n
= rc
->params
.rread
.count
;
775 EXPORT_SYMBOL(p9_client_uwrite
);
777 int p9_client_readn(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
781 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
782 (long long unsigned) offset
, count
);
786 n
= p9_client_read(fid
, data
, offset
, count
);
801 EXPORT_SYMBOL(p9_client_readn
);
803 struct p9_stat
*p9_client_stat(struct p9_fid
*fid
)
806 struct p9_fcall
*tc
, *rc
;
807 struct p9_client
*clnt
;
810 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
817 tc
= p9_create_tstat(fid
->fid
);
824 err
= p9_client_rpc(clnt
, tc
, &rc
);
828 ret
= p9_clone_stat(&rc
->params
.rstat
.stat
, clnt
->dotu
);
845 EXPORT_SYMBOL(p9_client_stat
);
847 int p9_client_wstat(struct p9_fid
*fid
, struct p9_wstat
*wst
)
850 struct p9_fcall
*tc
, *rc
;
851 struct p9_client
*clnt
;
853 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
859 tc
= p9_create_twstat(fid
->fid
, wst
, clnt
->dotu
);
866 err
= p9_client_rpc(clnt
, tc
, &rc
);
873 EXPORT_SYMBOL(p9_client_wstat
);
875 struct p9_stat
*p9_client_dirread(struct p9_fid
*fid
, u64 offset
)
878 struct p9_fcall
*tc
, *rc
;
879 struct p9_client
*clnt
;
880 struct p9_stat st
, *ret
;
882 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu\n", fid
->fid
,
883 (long long unsigned) offset
);
890 /* if the offset is below or above the current response, free it */
891 if (offset
< fid
->rdir_fpos
|| (fid
->rdir_fcall
&&
892 offset
>= fid
->rdir_fpos
+fid
->rdir_fcall
->params
.rread
.count
)) {
895 fid
->rdir_fpos
+= fid
->rdir_fcall
->params
.rread
.count
;
897 kfree(fid
->rdir_fcall
);
898 fid
->rdir_fcall
= NULL
;
899 if (offset
< fid
->rdir_fpos
)
903 if (!fid
->rdir_fcall
) {
905 if (!n
|| n
> clnt
->msize
-P9_IOHDRSZ
)
906 n
= clnt
->msize
- P9_IOHDRSZ
;
909 if (fid
->rdir_fcall
) {
911 fid
->rdir_fcall
->params
.rread
.count
;
912 kfree(fid
->rdir_fcall
);
913 fid
->rdir_fcall
= NULL
;
916 tc
= p9_create_tread(fid
->fid
, fid
->rdir_fpos
, n
);
923 err
= p9_client_rpc(clnt
, tc
, &rc
);
927 n
= rc
->params
.rread
.count
;
931 fid
->rdir_fcall
= rc
;
933 if (offset
>= fid
->rdir_fpos
&&
934 offset
< fid
->rdir_fpos
+n
)
941 m
= offset
- fid
->rdir_fpos
;
945 n
= p9_deserialize_stat(fid
->rdir_fcall
->params
.rread
.data
+ m
,
946 fid
->rdir_fcall
->params
.rread
.count
- m
, &st
, clnt
->dotu
);
955 ret
= p9_clone_stat(&st
, clnt
->dotu
);
973 EXPORT_SYMBOL(p9_client_dirread
);
975 static struct p9_stat
*p9_clone_stat(struct p9_stat
*st
, int dotu
)
981 n
= sizeof(struct p9_stat
) + st
->name
.len
+ st
->uid
.len
+ st
->gid
.len
+
985 n
+= st
->extension
.len
;
987 ret
= kmalloc(n
, GFP_KERNEL
);
989 return ERR_PTR(-ENOMEM
);
991 memmove(ret
, st
, sizeof(struct p9_stat
));
992 p
= ((char *) ret
) + sizeof(struct p9_stat
);
993 memmove(p
, st
->name
.str
, st
->name
.len
);
996 memmove(p
, st
->uid
.str
, st
->uid
.len
);
999 memmove(p
, st
->gid
.str
, st
->gid
.len
);
1002 memmove(p
, st
->muid
.str
, st
->muid
.len
);
1007 memmove(p
, st
->extension
.str
, st
->extension
.len
);
1008 ret
->extension
.str
= p
;
1009 p
+= st
->extension
.len
;
1015 static struct p9_fid
*p9_fid_create(struct p9_client
*clnt
)
1020 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
1021 fid
= kmalloc(sizeof(struct p9_fid
), GFP_KERNEL
);
1023 return ERR_PTR(-ENOMEM
);
1025 fid
->fid
= p9_idpool_get(clnt
->fidpool
);
1031 memset(&fid
->qid
, 0, sizeof(struct p9_qid
));
1035 fid
->rdir_fcall
= NULL
;
1036 fid
->uid
= current
->fsuid
;
1040 spin_lock(&clnt
->lock
);
1041 list_add(&fid
->flist
, &clnt
->fidlist
);
1042 spin_unlock(&clnt
->lock
);
1048 return ERR_PTR(err
);
1051 static void p9_fid_destroy(struct p9_fid
*fid
)
1053 struct p9_client
*clnt
;
1055 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
1057 p9_idpool_put(fid
->fid
, clnt
->fidpool
);
1058 spin_lock(&clnt
->lock
);
1059 list_del(&fid
->flist
);
1060 spin_unlock(&clnt
->lock
);
1061 kfree(fid
->rdir_fcall
);