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
67 * Return 0 upon success, -ERRNO upon failure
70 static int parse_opts(char *opts
, struct p9_client
*clnt
)
74 substring_t args
[MAX_OPT_ARGS
];
78 clnt
->trans_mod
= v9fs_default_trans();
85 options
= kstrdup(opts
, GFP_KERNEL
);
87 P9_DPRINTK(P9_DEBUG_ERROR
,
88 "failed to allocate copy of option string\n");
92 while ((p
= strsep(&options
, ",")) != NULL
) {
96 token
= match_token(p
, tokens
, args
);
97 if (token
< Opt_trans
) {
98 int r
= match_int(&args
[0], &option
);
100 P9_DPRINTK(P9_DEBUG_ERROR
,
101 "integer field, but no integer?\n");
108 clnt
->msize
= option
;
111 clnt
->trans_mod
= v9fs_match_trans(&args
[0]);
126 * p9_client_rpc - sends 9P request and waits until a response is available.
127 * The function can be interrupted.
129 * @tc: request to be sent
130 * @rc: pointer where a pointer to the response is stored
133 p9_client_rpc(struct p9_client
*c
, struct p9_fcall
*tc
,
134 struct p9_fcall
**rc
)
136 return c
->trans
->rpc(c
->trans
, tc
, rc
);
139 struct p9_client
*p9_client_create(const char *dev_name
, char *options
)
142 struct p9_client
*clnt
;
143 struct p9_fcall
*tc
, *rc
;
144 struct p9_str
*version
;
149 clnt
= kmalloc(sizeof(struct p9_client
), GFP_KERNEL
);
151 return ERR_PTR(-ENOMEM
);
154 spin_lock_init(&clnt
->lock
);
155 INIT_LIST_HEAD(&clnt
->fidlist
);
156 clnt
->fidpool
= p9_idpool_create();
157 if (IS_ERR(clnt
->fidpool
)) {
158 err
= PTR_ERR(clnt
->fidpool
);
159 clnt
->fidpool
= NULL
;
163 err
= parse_opts(options
, clnt
);
167 if (clnt
->trans_mod
== NULL
) {
168 err
= -EPROTONOSUPPORT
;
169 P9_DPRINTK(P9_DEBUG_ERROR
,
170 "No transport defined or default transport\n");
174 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p trans %p msize %d dotu %d\n",
175 clnt
, clnt
->trans_mod
, clnt
->msize
, clnt
->dotu
);
178 clnt
->trans
= clnt
->trans_mod
->create(dev_name
, options
, clnt
->msize
,
180 if (IS_ERR(clnt
->trans
)) {
181 err
= PTR_ERR(clnt
->trans
);
186 if ((clnt
->msize
+P9_IOHDRSZ
) > clnt
->trans_mod
->maxsize
)
187 clnt
->msize
= clnt
->trans_mod
->maxsize
-P9_IOHDRSZ
;
189 tc
= p9_create_tversion(clnt
->msize
, clnt
->dotu
?"9P2000.u":"9P2000");
196 err
= p9_client_rpc(clnt
, tc
, &rc
);
200 version
= &rc
->params
.rversion
.version
;
201 if (version
->len
== 8 && !memcmp(version
->str
, "9P2000.u", 8))
203 else if (version
->len
== 6 && !memcmp(version
->str
, "9P2000", 6))
210 n
= rc
->params
.rversion
.msize
;
221 p9_client_destroy(clnt
);
224 EXPORT_SYMBOL(p9_client_create
);
226 void p9_client_destroy(struct p9_client
*clnt
)
228 struct p9_fid
*fid
, *fidptr
;
230 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
233 clnt
->trans
->close(clnt
->trans
);
238 list_for_each_entry_safe(fid
, fidptr
, &clnt
->fidlist
, flist
)
242 p9_idpool_destroy(clnt
->fidpool
);
246 EXPORT_SYMBOL(p9_client_destroy
);
248 void p9_client_disconnect(struct p9_client
*clnt
)
250 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
251 clnt
->trans
->status
= Disconnected
;
253 EXPORT_SYMBOL(p9_client_disconnect
);
255 struct p9_fid
*p9_client_attach(struct p9_client
*clnt
, struct p9_fid
*afid
,
256 char *uname
, u32 n_uname
, char *aname
)
259 struct p9_fcall
*tc
, *rc
;
262 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p afid %d uname %s aname %s\n",
263 clnt
, afid
?afid
->fid
:-1, uname
, aname
);
268 fid
= p9_fid_create(clnt
);
275 tc
= p9_create_tattach(fid
->fid
, afid
?afid
->fid
:P9_NOFID
, uname
, aname
,
276 n_uname
, clnt
->dotu
);
283 err
= p9_client_rpc(clnt
, tc
, &rc
);
287 memmove(&fid
->qid
, &rc
->params
.rattach
.qid
, sizeof(struct p9_qid
));
299 EXPORT_SYMBOL(p9_client_attach
);
301 struct p9_fid
*p9_client_auth(struct p9_client
*clnt
, char *uname
,
302 u32 n_uname
, char *aname
)
305 struct p9_fcall
*tc
, *rc
;
308 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p uname %s aname %s\n", clnt
, uname
,
314 fid
= p9_fid_create(clnt
);
321 tc
= p9_create_tauth(fid
->fid
, uname
, aname
, n_uname
, clnt
->dotu
);
328 err
= p9_client_rpc(clnt
, tc
, &rc
);
332 memmove(&fid
->qid
, &rc
->params
.rauth
.qid
, sizeof(struct p9_qid
));
344 EXPORT_SYMBOL(p9_client_auth
);
346 struct p9_fid
*p9_client_walk(struct p9_fid
*oldfid
, int nwname
, char **wnames
,
350 struct p9_fcall
*tc
, *rc
;
351 struct p9_client
*clnt
;
354 P9_DPRINTK(P9_DEBUG_9P
, "fid %d nwname %d wname[0] %s\n",
355 oldfid
->fid
, nwname
, wnames
?wnames
[0]:NULL
);
361 fid
= p9_fid_create(clnt
);
368 fid
->uid
= oldfid
->uid
;
372 tc
= p9_create_twalk(oldfid
->fid
, fid
->fid
, nwname
, wnames
);
379 err
= p9_client_rpc(clnt
, tc
, &rc
);
381 if (rc
&& rc
->id
== P9_RWALK
)
387 if (rc
->params
.rwalk
.nwqid
!= nwname
) {
394 &rc
->params
.rwalk
.wqids
[rc
->params
.rwalk
.nwqid
- 1],
395 sizeof(struct p9_qid
));
397 fid
->qid
= oldfid
->qid
;
407 tc
= p9_create_tclunk(fid
->fid
);
414 p9_client_rpc(clnt
, tc
, &rc
);
419 if (fid
&& (fid
!= oldfid
))
424 EXPORT_SYMBOL(p9_client_walk
);
426 int p9_client_open(struct p9_fid
*fid
, int mode
)
429 struct p9_fcall
*tc
, *rc
;
430 struct p9_client
*clnt
;
432 P9_DPRINTK(P9_DEBUG_9P
, "fid %d mode %d\n", fid
->fid
, mode
);
441 tc
= p9_create_topen(fid
->fid
, mode
);
448 err
= p9_client_rpc(clnt
, tc
, &rc
);
453 fid
->iounit
= rc
->params
.ropen
.iounit
;
460 EXPORT_SYMBOL(p9_client_open
);
462 int p9_client_fcreate(struct p9_fid
*fid
, char *name
, u32 perm
, int mode
,
466 struct p9_fcall
*tc
, *rc
;
467 struct p9_client
*clnt
;
469 P9_DPRINTK(P9_DEBUG_9P
, "fid %d name %s perm %d mode %d\n", fid
->fid
,
479 tc
= p9_create_tcreate(fid
->fid
, name
, perm
, mode
, extension
,
487 err
= p9_client_rpc(clnt
, tc
, &rc
);
492 fid
->iounit
= rc
->params
.ropen
.iounit
;
499 EXPORT_SYMBOL(p9_client_fcreate
);
501 int p9_client_clunk(struct p9_fid
*fid
)
504 struct p9_fcall
*tc
, *rc
;
505 struct p9_client
*clnt
;
507 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
513 tc
= p9_create_tclunk(fid
->fid
);
520 err
= p9_client_rpc(clnt
, tc
, &rc
);
531 EXPORT_SYMBOL(p9_client_clunk
);
533 int p9_client_remove(struct p9_fid
*fid
)
536 struct p9_fcall
*tc
, *rc
;
537 struct p9_client
*clnt
;
539 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
545 tc
= p9_create_tremove(fid
->fid
);
552 err
= p9_client_rpc(clnt
, tc
, &rc
);
563 EXPORT_SYMBOL(p9_client_remove
);
565 int p9_client_read(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
567 int err
, n
, rsize
, total
;
568 struct p9_fcall
*tc
, *rc
;
569 struct p9_client
*clnt
;
571 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu %d\n", fid
->fid
,
572 (long long unsigned) offset
, count
);
580 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
581 rsize
= clnt
->msize
- P9_IOHDRSZ
;
587 tc
= p9_create_tread(fid
->fid
, offset
, rsize
);
594 err
= p9_client_rpc(clnt
, tc
, &rc
);
598 n
= rc
->params
.rread
.count
;
602 memmove(data
, rc
->params
.rread
.data
, n
);
611 } while (count
> 0 && n
== rsize
);
620 EXPORT_SYMBOL(p9_client_read
);
622 int p9_client_write(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
624 int err
, n
, rsize
, total
;
625 struct p9_fcall
*tc
, *rc
;
626 struct p9_client
*clnt
;
628 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
629 (long long unsigned) offset
, count
);
637 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
638 rsize
= clnt
->msize
- P9_IOHDRSZ
;
644 tc
= p9_create_twrite(fid
->fid
, offset
, rsize
, data
);
651 err
= p9_client_rpc(clnt
, tc
, &rc
);
655 n
= rc
->params
.rread
.count
;
673 EXPORT_SYMBOL(p9_client_write
);
676 p9_client_uread(struct p9_fid
*fid
, char __user
*data
, u64 offset
, u32 count
)
678 int err
, n
, rsize
, total
;
679 struct p9_fcall
*tc
, *rc
;
680 struct p9_client
*clnt
;
682 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
683 (long long unsigned) offset
, count
);
691 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
692 rsize
= clnt
->msize
- P9_IOHDRSZ
;
698 tc
= p9_create_tread(fid
->fid
, offset
, rsize
);
705 err
= p9_client_rpc(clnt
, tc
, &rc
);
709 n
= rc
->params
.rread
.count
;
713 err
= copy_to_user(data
, rc
->params
.rread
.data
, n
);
727 } while (count
> 0 && n
== rsize
);
736 EXPORT_SYMBOL(p9_client_uread
);
739 p9_client_uwrite(struct p9_fid
*fid
, const char __user
*data
, u64 offset
,
742 int err
, n
, rsize
, total
;
743 struct p9_fcall
*tc
, *rc
;
744 struct p9_client
*clnt
;
746 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
747 (long long unsigned) offset
, count
);
755 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
756 rsize
= clnt
->msize
- P9_IOHDRSZ
;
762 tc
= p9_create_twrite_u(fid
->fid
, offset
, rsize
, data
);
769 err
= p9_client_rpc(clnt
, tc
, &rc
);
773 n
= rc
->params
.rread
.count
;
791 EXPORT_SYMBOL(p9_client_uwrite
);
793 int p9_client_readn(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
797 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
798 (long long unsigned) offset
, count
);
802 n
= p9_client_read(fid
, data
, offset
, count
);
817 EXPORT_SYMBOL(p9_client_readn
);
819 struct p9_stat
*p9_client_stat(struct p9_fid
*fid
)
822 struct p9_fcall
*tc
, *rc
;
823 struct p9_client
*clnt
;
826 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
833 tc
= p9_create_tstat(fid
->fid
);
840 err
= p9_client_rpc(clnt
, tc
, &rc
);
844 ret
= p9_clone_stat(&rc
->params
.rstat
.stat
, clnt
->dotu
);
861 EXPORT_SYMBOL(p9_client_stat
);
863 int p9_client_wstat(struct p9_fid
*fid
, struct p9_wstat
*wst
)
866 struct p9_fcall
*tc
, *rc
;
867 struct p9_client
*clnt
;
869 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
875 tc
= p9_create_twstat(fid
->fid
, wst
, clnt
->dotu
);
882 err
= p9_client_rpc(clnt
, tc
, &rc
);
889 EXPORT_SYMBOL(p9_client_wstat
);
891 struct p9_stat
*p9_client_dirread(struct p9_fid
*fid
, u64 offset
)
894 struct p9_fcall
*tc
, *rc
;
895 struct p9_client
*clnt
;
896 struct p9_stat st
, *ret
;
898 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu\n", fid
->fid
,
899 (long long unsigned) offset
);
906 /* if the offset is below or above the current response, free it */
907 if (offset
< fid
->rdir_fpos
|| (fid
->rdir_fcall
&&
908 offset
>= fid
->rdir_fpos
+fid
->rdir_fcall
->params
.rread
.count
)) {
911 fid
->rdir_fpos
+= fid
->rdir_fcall
->params
.rread
.count
;
913 kfree(fid
->rdir_fcall
);
914 fid
->rdir_fcall
= NULL
;
915 if (offset
< fid
->rdir_fpos
)
919 if (!fid
->rdir_fcall
) {
921 if (!n
|| n
> clnt
->msize
-P9_IOHDRSZ
)
922 n
= clnt
->msize
- P9_IOHDRSZ
;
925 if (fid
->rdir_fcall
) {
927 fid
->rdir_fcall
->params
.rread
.count
;
928 kfree(fid
->rdir_fcall
);
929 fid
->rdir_fcall
= NULL
;
932 tc
= p9_create_tread(fid
->fid
, fid
->rdir_fpos
, n
);
939 err
= p9_client_rpc(clnt
, tc
, &rc
);
943 n
= rc
->params
.rread
.count
;
947 fid
->rdir_fcall
= rc
;
949 if (offset
>= fid
->rdir_fpos
&&
950 offset
< fid
->rdir_fpos
+n
)
957 m
= offset
- fid
->rdir_fpos
;
961 n
= p9_deserialize_stat(fid
->rdir_fcall
->params
.rread
.data
+ m
,
962 fid
->rdir_fcall
->params
.rread
.count
- m
, &st
, clnt
->dotu
);
971 ret
= p9_clone_stat(&st
, clnt
->dotu
);
989 EXPORT_SYMBOL(p9_client_dirread
);
991 static struct p9_stat
*p9_clone_stat(struct p9_stat
*st
, int dotu
)
997 n
= sizeof(struct p9_stat
) + st
->name
.len
+ st
->uid
.len
+ st
->gid
.len
+
1001 n
+= st
->extension
.len
;
1003 ret
= kmalloc(n
, GFP_KERNEL
);
1005 return ERR_PTR(-ENOMEM
);
1007 memmove(ret
, st
, sizeof(struct p9_stat
));
1008 p
= ((char *) ret
) + sizeof(struct p9_stat
);
1009 memmove(p
, st
->name
.str
, st
->name
.len
);
1012 memmove(p
, st
->uid
.str
, st
->uid
.len
);
1015 memmove(p
, st
->gid
.str
, st
->gid
.len
);
1018 memmove(p
, st
->muid
.str
, st
->muid
.len
);
1023 memmove(p
, st
->extension
.str
, st
->extension
.len
);
1024 ret
->extension
.str
= p
;
1025 p
+= st
->extension
.len
;
1031 static struct p9_fid
*p9_fid_create(struct p9_client
*clnt
)
1036 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
1037 fid
= kmalloc(sizeof(struct p9_fid
), GFP_KERNEL
);
1039 return ERR_PTR(-ENOMEM
);
1041 fid
->fid
= p9_idpool_get(clnt
->fidpool
);
1047 memset(&fid
->qid
, 0, sizeof(struct p9_qid
));
1051 fid
->rdir_fcall
= NULL
;
1052 fid
->uid
= current
->fsuid
;
1056 spin_lock(&clnt
->lock
);
1057 list_add(&fid
->flist
, &clnt
->fidlist
);
1058 spin_unlock(&clnt
->lock
);
1064 return ERR_PTR(err
);
1067 static void p9_fid_destroy(struct p9_fid
*fid
)
1069 struct p9_client
*clnt
;
1071 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
1073 p9_idpool_put(fid
->fid
, clnt
->fidpool
);
1074 spin_lock(&clnt
->lock
);
1075 list_del(&fid
->flist
);
1076 spin_unlock(&clnt
->lock
);
1077 kfree(fid
->rdir_fcall
);