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/client.h>
37 #include <net/9p/transport.h>
40 * Client Option Parsing (code inspired by NFS code)
41 * - a little lazy - parse all client options
51 static const match_table_t tokens
= {
52 {Opt_msize
, "msize=%u"},
53 {Opt_legacy
, "noextend"},
54 {Opt_trans
, "trans=%s"},
59 * v9fs_parse_options - parse mount options into session structure
60 * @options: options string passed from mount
61 * @v9ses: existing v9fs session information
63 * Return 0 upon success, -ERRNO upon failure
66 static int parse_opts(char *opts
, struct p9_client
*clnt
)
70 substring_t args
[MAX_OPT_ARGS
];
80 options
= kstrdup(opts
, GFP_KERNEL
);
82 P9_DPRINTK(P9_DEBUG_ERROR
,
83 "failed to allocate copy of option string\n");
87 while ((p
= strsep(&options
, ",")) != NULL
) {
91 token
= match_token(p
, tokens
, args
);
92 if (token
< Opt_trans
) {
93 int r
= match_int(&args
[0], &option
);
95 P9_DPRINTK(P9_DEBUG_ERROR
,
96 "integer field, but no integer?\n");
103 clnt
->msize
= option
;
106 clnt
->trans_mod
= v9fs_get_trans_by_name(&args
[0]);
116 if (!clnt
->trans_mod
)
117 clnt
->trans_mod
= v9fs_get_default_trans();
123 static struct p9_fid
*p9_fid_create(struct p9_client
*clnt
)
128 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
129 fid
= kmalloc(sizeof(struct p9_fid
), GFP_KERNEL
);
131 return ERR_PTR(-ENOMEM
);
133 fid
->fid
= p9_idpool_get(clnt
->fidpool
);
139 memset(&fid
->qid
, 0, sizeof(struct p9_qid
));
143 fid
->rdir_fcall
= NULL
;
144 fid
->uid
= current
->fsuid
;
148 spin_lock(&clnt
->lock
);
149 list_add(&fid
->flist
, &clnt
->fidlist
);
150 spin_unlock(&clnt
->lock
);
159 static void p9_fid_destroy(struct p9_fid
*fid
)
161 struct p9_client
*clnt
;
163 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
165 p9_idpool_put(fid
->fid
, clnt
->fidpool
);
166 spin_lock(&clnt
->lock
);
167 list_del(&fid
->flist
);
168 spin_unlock(&clnt
->lock
);
169 kfree(fid
->rdir_fcall
);
174 * p9_client_rpc - sends 9P request and waits until a response is available.
175 * The function can be interrupted.
177 * @tc: request to be sent
178 * @rc: pointer where a pointer to the response is stored
181 p9_client_rpc(struct p9_client
*c
, struct p9_fcall
*tc
,
182 struct p9_fcall
**rc
)
184 return c
->trans_mod
->rpc(c
, tc
, rc
);
187 struct p9_client
*p9_client_create(const char *dev_name
, char *options
)
190 struct p9_client
*clnt
;
191 struct p9_fcall
*tc
, *rc
;
192 struct p9_str
*version
;
197 clnt
= kmalloc(sizeof(struct p9_client
), GFP_KERNEL
);
199 return ERR_PTR(-ENOMEM
);
201 clnt
->trans_mod
= NULL
;
203 spin_lock_init(&clnt
->lock
);
204 INIT_LIST_HEAD(&clnt
->fidlist
);
205 clnt
->fidpool
= p9_idpool_create();
206 if (IS_ERR(clnt
->fidpool
)) {
207 err
= PTR_ERR(clnt
->fidpool
);
208 clnt
->fidpool
= NULL
;
212 err
= parse_opts(options
, clnt
);
216 if (clnt
->trans_mod
== NULL
) {
217 err
= -EPROTONOSUPPORT
;
218 P9_DPRINTK(P9_DEBUG_ERROR
,
219 "No transport defined or default transport\n");
223 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p trans %p msize %d dotu %d\n",
224 clnt
, clnt
->trans_mod
, clnt
->msize
, clnt
->dotu
);
227 err
= clnt
->trans_mod
->create(clnt
, dev_name
, options
);
231 if ((clnt
->msize
+P9_IOHDRSZ
) > clnt
->trans_mod
->maxsize
)
232 clnt
->msize
= clnt
->trans_mod
->maxsize
-P9_IOHDRSZ
;
234 tc
= p9_create_tversion(clnt
->msize
, clnt
->dotu
?"9P2000.u":"9P2000");
241 err
= p9_client_rpc(clnt
, tc
, &rc
);
245 version
= &rc
->params
.rversion
.version
;
246 if (version
->len
== 8 && !memcmp(version
->str
, "9P2000.u", 8))
248 else if (version
->len
== 6 && !memcmp(version
->str
, "9P2000", 6))
255 n
= rc
->params
.rversion
.msize
;
266 p9_client_destroy(clnt
);
269 EXPORT_SYMBOL(p9_client_create
);
271 void p9_client_destroy(struct p9_client
*clnt
)
273 struct p9_fid
*fid
, *fidptr
;
275 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
278 clnt
->trans_mod
->close(clnt
);
280 v9fs_put_trans(clnt
->trans_mod
);
282 list_for_each_entry_safe(fid
, fidptr
, &clnt
->fidlist
, flist
)
286 p9_idpool_destroy(clnt
->fidpool
);
290 EXPORT_SYMBOL(p9_client_destroy
);
292 void p9_client_disconnect(struct p9_client
*clnt
)
294 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
295 clnt
->status
= Disconnected
;
297 EXPORT_SYMBOL(p9_client_disconnect
);
299 struct p9_fid
*p9_client_attach(struct p9_client
*clnt
, struct p9_fid
*afid
,
300 char *uname
, u32 n_uname
, char *aname
)
303 struct p9_fcall
*tc
, *rc
;
306 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p afid %d uname %s aname %s\n",
307 clnt
, afid
?afid
->fid
:-1, uname
, aname
);
312 fid
= p9_fid_create(clnt
);
319 tc
= p9_create_tattach(fid
->fid
, afid
?afid
->fid
:P9_NOFID
, uname
, aname
,
320 n_uname
, clnt
->dotu
);
327 err
= p9_client_rpc(clnt
, tc
, &rc
);
331 memmove(&fid
->qid
, &rc
->params
.rattach
.qid
, sizeof(struct p9_qid
));
343 EXPORT_SYMBOL(p9_client_attach
);
345 struct p9_fid
*p9_client_auth(struct p9_client
*clnt
, char *uname
,
346 u32 n_uname
, char *aname
)
349 struct p9_fcall
*tc
, *rc
;
352 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p uname %s aname %s\n", clnt
, uname
,
358 fid
= p9_fid_create(clnt
);
365 tc
= p9_create_tauth(fid
->fid
, uname
, aname
, n_uname
, clnt
->dotu
);
372 err
= p9_client_rpc(clnt
, tc
, &rc
);
376 memmove(&fid
->qid
, &rc
->params
.rauth
.qid
, sizeof(struct p9_qid
));
388 EXPORT_SYMBOL(p9_client_auth
);
390 struct p9_fid
*p9_client_walk(struct p9_fid
*oldfid
, int nwname
, char **wnames
,
394 struct p9_fcall
*tc
, *rc
;
395 struct p9_client
*clnt
;
398 P9_DPRINTK(P9_DEBUG_9P
, "fid %d nwname %d wname[0] %s\n",
399 oldfid
->fid
, nwname
, wnames
?wnames
[0]:NULL
);
405 fid
= p9_fid_create(clnt
);
412 fid
->uid
= oldfid
->uid
;
416 tc
= p9_create_twalk(oldfid
->fid
, fid
->fid
, nwname
, wnames
);
423 err
= p9_client_rpc(clnt
, tc
, &rc
);
425 if (rc
&& rc
->id
== P9_RWALK
)
431 if (rc
->params
.rwalk
.nwqid
!= nwname
) {
438 &rc
->params
.rwalk
.wqids
[rc
->params
.rwalk
.nwqid
- 1],
439 sizeof(struct p9_qid
));
441 fid
->qid
= oldfid
->qid
;
451 tc
= p9_create_tclunk(fid
->fid
);
458 p9_client_rpc(clnt
, tc
, &rc
);
463 if (fid
&& (fid
!= oldfid
))
468 EXPORT_SYMBOL(p9_client_walk
);
470 int p9_client_open(struct p9_fid
*fid
, int mode
)
473 struct p9_fcall
*tc
, *rc
;
474 struct p9_client
*clnt
;
476 P9_DPRINTK(P9_DEBUG_9P
, "fid %d mode %d\n", fid
->fid
, mode
);
485 tc
= p9_create_topen(fid
->fid
, mode
);
492 err
= p9_client_rpc(clnt
, tc
, &rc
);
497 fid
->iounit
= rc
->params
.ropen
.iounit
;
504 EXPORT_SYMBOL(p9_client_open
);
506 int p9_client_fcreate(struct p9_fid
*fid
, char *name
, u32 perm
, int mode
,
510 struct p9_fcall
*tc
, *rc
;
511 struct p9_client
*clnt
;
513 P9_DPRINTK(P9_DEBUG_9P
, "fid %d name %s perm %d mode %d\n", fid
->fid
,
523 tc
= p9_create_tcreate(fid
->fid
, name
, perm
, mode
, extension
,
531 err
= p9_client_rpc(clnt
, tc
, &rc
);
536 fid
->iounit
= rc
->params
.ropen
.iounit
;
543 EXPORT_SYMBOL(p9_client_fcreate
);
545 int p9_client_clunk(struct p9_fid
*fid
)
548 struct p9_fcall
*tc
, *rc
;
549 struct p9_client
*clnt
;
551 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
557 tc
= p9_create_tclunk(fid
->fid
);
564 err
= p9_client_rpc(clnt
, tc
, &rc
);
575 EXPORT_SYMBOL(p9_client_clunk
);
577 int p9_client_remove(struct p9_fid
*fid
)
580 struct p9_fcall
*tc
, *rc
;
581 struct p9_client
*clnt
;
583 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
589 tc
= p9_create_tremove(fid
->fid
);
596 err
= p9_client_rpc(clnt
, tc
, &rc
);
607 EXPORT_SYMBOL(p9_client_remove
);
609 int p9_client_read(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
611 int err
, n
, rsize
, total
;
612 struct p9_fcall
*tc
, *rc
;
613 struct p9_client
*clnt
;
615 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu %d\n", fid
->fid
,
616 (long long unsigned) offset
, count
);
624 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
625 rsize
= clnt
->msize
- P9_IOHDRSZ
;
631 tc
= p9_create_tread(fid
->fid
, offset
, rsize
);
638 err
= p9_client_rpc(clnt
, tc
, &rc
);
642 n
= rc
->params
.rread
.count
;
646 memmove(data
, rc
->params
.rread
.data
, n
);
655 } while (count
> 0 && n
== rsize
);
664 EXPORT_SYMBOL(p9_client_read
);
666 int p9_client_write(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
668 int err
, n
, rsize
, total
;
669 struct p9_fcall
*tc
, *rc
;
670 struct p9_client
*clnt
;
672 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
673 (long long unsigned) offset
, count
);
681 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
682 rsize
= clnt
->msize
- P9_IOHDRSZ
;
688 tc
= p9_create_twrite(fid
->fid
, offset
, rsize
, data
);
695 err
= p9_client_rpc(clnt
, tc
, &rc
);
699 n
= rc
->params
.rread
.count
;
717 EXPORT_SYMBOL(p9_client_write
);
720 p9_client_uread(struct p9_fid
*fid
, char __user
*data
, u64 offset
, u32 count
)
722 int err
, n
, rsize
, total
;
723 struct p9_fcall
*tc
, *rc
;
724 struct p9_client
*clnt
;
726 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
727 (long long unsigned) offset
, count
);
735 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
736 rsize
= clnt
->msize
- P9_IOHDRSZ
;
742 tc
= p9_create_tread(fid
->fid
, offset
, rsize
);
749 err
= p9_client_rpc(clnt
, tc
, &rc
);
753 n
= rc
->params
.rread
.count
;
757 err
= copy_to_user(data
, rc
->params
.rread
.data
, n
);
771 } while (count
> 0 && n
== rsize
);
780 EXPORT_SYMBOL(p9_client_uread
);
783 p9_client_uwrite(struct p9_fid
*fid
, const char __user
*data
, u64 offset
,
786 int err
, n
, rsize
, total
;
787 struct p9_fcall
*tc
, *rc
;
788 struct p9_client
*clnt
;
790 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
791 (long long unsigned) offset
, count
);
799 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
800 rsize
= clnt
->msize
- P9_IOHDRSZ
;
806 tc
= p9_create_twrite_u(fid
->fid
, offset
, rsize
, data
);
813 err
= p9_client_rpc(clnt
, tc
, &rc
);
817 n
= rc
->params
.rread
.count
;
835 EXPORT_SYMBOL(p9_client_uwrite
);
837 int p9_client_readn(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
841 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
842 (long long unsigned) offset
, count
);
846 n
= p9_client_read(fid
, data
, offset
, count
);
861 EXPORT_SYMBOL(p9_client_readn
);
863 static struct p9_stat
*p9_clone_stat(struct p9_stat
*st
, int dotu
)
869 n
= sizeof(struct p9_stat
) + st
->name
.len
+ st
->uid
.len
+ st
->gid
.len
+
873 n
+= st
->extension
.len
;
875 ret
= kmalloc(n
, GFP_KERNEL
);
877 return ERR_PTR(-ENOMEM
);
879 memmove(ret
, st
, sizeof(struct p9_stat
));
880 p
= ((char *) ret
) + sizeof(struct p9_stat
);
881 memmove(p
, st
->name
.str
, st
->name
.len
);
884 memmove(p
, st
->uid
.str
, st
->uid
.len
);
887 memmove(p
, st
->gid
.str
, st
->gid
.len
);
890 memmove(p
, st
->muid
.str
, st
->muid
.len
);
895 memmove(p
, st
->extension
.str
, st
->extension
.len
);
896 ret
->extension
.str
= p
;
897 p
+= st
->extension
.len
;
903 struct p9_stat
*p9_client_stat(struct p9_fid
*fid
)
906 struct p9_fcall
*tc
, *rc
;
907 struct p9_client
*clnt
;
910 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
917 tc
= p9_create_tstat(fid
->fid
);
924 err
= p9_client_rpc(clnt
, tc
, &rc
);
928 ret
= p9_clone_stat(&rc
->params
.rstat
.stat
, clnt
->dotu
);
945 EXPORT_SYMBOL(p9_client_stat
);
947 int p9_client_wstat(struct p9_fid
*fid
, struct p9_wstat
*wst
)
950 struct p9_fcall
*tc
, *rc
;
951 struct p9_client
*clnt
;
953 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
959 tc
= p9_create_twstat(fid
->fid
, wst
, clnt
->dotu
);
966 err
= p9_client_rpc(clnt
, tc
, &rc
);
973 EXPORT_SYMBOL(p9_client_wstat
);
975 struct p9_stat
*p9_client_dirread(struct p9_fid
*fid
, u64 offset
)
978 struct p9_fcall
*tc
, *rc
;
979 struct p9_client
*clnt
;
980 struct p9_stat st
, *ret
;
982 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu\n", fid
->fid
,
983 (long long unsigned) offset
);
990 /* if the offset is below or above the current response, free it */
991 if (offset
< fid
->rdir_fpos
|| (fid
->rdir_fcall
&&
992 offset
>= fid
->rdir_fpos
+fid
->rdir_fcall
->params
.rread
.count
)) {
995 fid
->rdir_fpos
+= fid
->rdir_fcall
->params
.rread
.count
;
997 kfree(fid
->rdir_fcall
);
998 fid
->rdir_fcall
= NULL
;
999 if (offset
< fid
->rdir_fpos
)
1003 if (!fid
->rdir_fcall
) {
1005 if (!n
|| n
> clnt
->msize
-P9_IOHDRSZ
)
1006 n
= clnt
->msize
- P9_IOHDRSZ
;
1009 if (fid
->rdir_fcall
) {
1011 fid
->rdir_fcall
->params
.rread
.count
;
1012 kfree(fid
->rdir_fcall
);
1013 fid
->rdir_fcall
= NULL
;
1016 tc
= p9_create_tread(fid
->fid
, fid
->rdir_fpos
, n
);
1023 err
= p9_client_rpc(clnt
, tc
, &rc
);
1027 n
= rc
->params
.rread
.count
;
1031 fid
->rdir_fcall
= rc
;
1033 if (offset
>= fid
->rdir_fpos
&&
1034 offset
< fid
->rdir_fpos
+n
)
1041 m
= offset
- fid
->rdir_fpos
;
1045 n
= p9_deserialize_stat(fid
->rdir_fcall
->params
.rread
.data
+ m
,
1046 fid
->rdir_fcall
->params
.rread
.count
- m
, &st
, clnt
->dotu
);
1055 ret
= p9_clone_stat(&st
, clnt
->dotu
);
1071 return ERR_PTR(err
);
1073 EXPORT_SYMBOL(p9_client_dirread
);