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
];
84 options
= kstrdup(opts
, GFP_KERNEL
);
86 P9_DPRINTK(P9_DEBUG_ERROR
,
87 "failed to allocate copy of option string\n");
91 while ((p
= strsep(&options
, ",")) != NULL
) {
95 token
= match_token(p
, tokens
, args
);
96 if (token
< Opt_trans
) {
97 int r
= match_int(&args
[0], &option
);
99 P9_DPRINTK(P9_DEBUG_ERROR
,
100 "integer field, but no integer?\n");
107 clnt
->msize
= option
;
110 clnt
->trans_mod
= v9fs_get_trans_by_name(&args
[0]);
120 if (!clnt
->trans_mod
)
121 clnt
->trans_mod
= v9fs_get_default_trans();
129 * p9_client_rpc - sends 9P request and waits until a response is available.
130 * The function can be interrupted.
132 * @tc: request to be sent
133 * @rc: pointer where a pointer to the response is stored
136 p9_client_rpc(struct p9_client
*c
, struct p9_fcall
*tc
,
137 struct p9_fcall
**rc
)
139 return c
->trans
->rpc(c
->trans
, tc
, rc
);
142 struct p9_client
*p9_client_create(const char *dev_name
, char *options
)
145 struct p9_client
*clnt
;
146 struct p9_fcall
*tc
, *rc
;
147 struct p9_str
*version
;
152 clnt
= kmalloc(sizeof(struct p9_client
), GFP_KERNEL
);
154 return ERR_PTR(-ENOMEM
);
156 clnt
->trans_mod
= NULL
;
158 spin_lock_init(&clnt
->lock
);
159 INIT_LIST_HEAD(&clnt
->fidlist
);
160 clnt
->fidpool
= p9_idpool_create();
161 if (IS_ERR(clnt
->fidpool
)) {
162 err
= PTR_ERR(clnt
->fidpool
);
163 clnt
->fidpool
= NULL
;
167 err
= parse_opts(options
, clnt
);
171 if (clnt
->trans_mod
== NULL
) {
172 err
= -EPROTONOSUPPORT
;
173 P9_DPRINTK(P9_DEBUG_ERROR
,
174 "No transport defined or default transport\n");
178 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p trans %p msize %d dotu %d\n",
179 clnt
, clnt
->trans_mod
, clnt
->msize
, clnt
->dotu
);
182 clnt
->trans
= clnt
->trans_mod
->create(dev_name
, options
, clnt
->msize
,
184 if (IS_ERR(clnt
->trans
)) {
185 err
= PTR_ERR(clnt
->trans
);
190 if ((clnt
->msize
+P9_IOHDRSZ
) > clnt
->trans_mod
->maxsize
)
191 clnt
->msize
= clnt
->trans_mod
->maxsize
-P9_IOHDRSZ
;
193 tc
= p9_create_tversion(clnt
->msize
, clnt
->dotu
?"9P2000.u":"9P2000");
200 err
= p9_client_rpc(clnt
, tc
, &rc
);
204 version
= &rc
->params
.rversion
.version
;
205 if (version
->len
== 8 && !memcmp(version
->str
, "9P2000.u", 8))
207 else if (version
->len
== 6 && !memcmp(version
->str
, "9P2000", 6))
214 n
= rc
->params
.rversion
.msize
;
225 p9_client_destroy(clnt
);
228 EXPORT_SYMBOL(p9_client_create
);
230 void p9_client_destroy(struct p9_client
*clnt
)
232 struct p9_fid
*fid
, *fidptr
;
234 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
237 clnt
->trans
->close(clnt
->trans
);
242 v9fs_put_trans(clnt
->trans_mod
);
244 list_for_each_entry_safe(fid
, fidptr
, &clnt
->fidlist
, flist
)
248 p9_idpool_destroy(clnt
->fidpool
);
252 EXPORT_SYMBOL(p9_client_destroy
);
254 void p9_client_disconnect(struct p9_client
*clnt
)
256 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
257 clnt
->trans
->status
= Disconnected
;
259 EXPORT_SYMBOL(p9_client_disconnect
);
261 struct p9_fid
*p9_client_attach(struct p9_client
*clnt
, struct p9_fid
*afid
,
262 char *uname
, u32 n_uname
, char *aname
)
265 struct p9_fcall
*tc
, *rc
;
268 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p afid %d uname %s aname %s\n",
269 clnt
, afid
?afid
->fid
:-1, uname
, aname
);
274 fid
= p9_fid_create(clnt
);
281 tc
= p9_create_tattach(fid
->fid
, afid
?afid
->fid
:P9_NOFID
, uname
, aname
,
282 n_uname
, clnt
->dotu
);
289 err
= p9_client_rpc(clnt
, tc
, &rc
);
293 memmove(&fid
->qid
, &rc
->params
.rattach
.qid
, sizeof(struct p9_qid
));
305 EXPORT_SYMBOL(p9_client_attach
);
307 struct p9_fid
*p9_client_auth(struct p9_client
*clnt
, char *uname
,
308 u32 n_uname
, char *aname
)
311 struct p9_fcall
*tc
, *rc
;
314 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p uname %s aname %s\n", clnt
, uname
,
320 fid
= p9_fid_create(clnt
);
327 tc
= p9_create_tauth(fid
->fid
, uname
, aname
, n_uname
, clnt
->dotu
);
334 err
= p9_client_rpc(clnt
, tc
, &rc
);
338 memmove(&fid
->qid
, &rc
->params
.rauth
.qid
, sizeof(struct p9_qid
));
350 EXPORT_SYMBOL(p9_client_auth
);
352 struct p9_fid
*p9_client_walk(struct p9_fid
*oldfid
, int nwname
, char **wnames
,
356 struct p9_fcall
*tc
, *rc
;
357 struct p9_client
*clnt
;
360 P9_DPRINTK(P9_DEBUG_9P
, "fid %d nwname %d wname[0] %s\n",
361 oldfid
->fid
, nwname
, wnames
?wnames
[0]:NULL
);
367 fid
= p9_fid_create(clnt
);
374 fid
->uid
= oldfid
->uid
;
378 tc
= p9_create_twalk(oldfid
->fid
, fid
->fid
, nwname
, wnames
);
385 err
= p9_client_rpc(clnt
, tc
, &rc
);
387 if (rc
&& rc
->id
== P9_RWALK
)
393 if (rc
->params
.rwalk
.nwqid
!= nwname
) {
400 &rc
->params
.rwalk
.wqids
[rc
->params
.rwalk
.nwqid
- 1],
401 sizeof(struct p9_qid
));
403 fid
->qid
= oldfid
->qid
;
413 tc
= p9_create_tclunk(fid
->fid
);
420 p9_client_rpc(clnt
, tc
, &rc
);
425 if (fid
&& (fid
!= oldfid
))
430 EXPORT_SYMBOL(p9_client_walk
);
432 int p9_client_open(struct p9_fid
*fid
, int mode
)
435 struct p9_fcall
*tc
, *rc
;
436 struct p9_client
*clnt
;
438 P9_DPRINTK(P9_DEBUG_9P
, "fid %d mode %d\n", fid
->fid
, mode
);
447 tc
= p9_create_topen(fid
->fid
, mode
);
454 err
= p9_client_rpc(clnt
, tc
, &rc
);
459 fid
->iounit
= rc
->params
.ropen
.iounit
;
466 EXPORT_SYMBOL(p9_client_open
);
468 int p9_client_fcreate(struct p9_fid
*fid
, char *name
, u32 perm
, int mode
,
472 struct p9_fcall
*tc
, *rc
;
473 struct p9_client
*clnt
;
475 P9_DPRINTK(P9_DEBUG_9P
, "fid %d name %s perm %d mode %d\n", fid
->fid
,
485 tc
= p9_create_tcreate(fid
->fid
, name
, perm
, mode
, extension
,
493 err
= p9_client_rpc(clnt
, tc
, &rc
);
498 fid
->iounit
= rc
->params
.ropen
.iounit
;
505 EXPORT_SYMBOL(p9_client_fcreate
);
507 int p9_client_clunk(struct p9_fid
*fid
)
510 struct p9_fcall
*tc
, *rc
;
511 struct p9_client
*clnt
;
513 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
519 tc
= p9_create_tclunk(fid
->fid
);
526 err
= p9_client_rpc(clnt
, tc
, &rc
);
537 EXPORT_SYMBOL(p9_client_clunk
);
539 int p9_client_remove(struct p9_fid
*fid
)
542 struct p9_fcall
*tc
, *rc
;
543 struct p9_client
*clnt
;
545 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
551 tc
= p9_create_tremove(fid
->fid
);
558 err
= p9_client_rpc(clnt
, tc
, &rc
);
569 EXPORT_SYMBOL(p9_client_remove
);
571 int p9_client_read(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
573 int err
, n
, rsize
, total
;
574 struct p9_fcall
*tc
, *rc
;
575 struct p9_client
*clnt
;
577 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu %d\n", fid
->fid
,
578 (long long unsigned) offset
, count
);
586 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
587 rsize
= clnt
->msize
- P9_IOHDRSZ
;
593 tc
= p9_create_tread(fid
->fid
, offset
, rsize
);
600 err
= p9_client_rpc(clnt
, tc
, &rc
);
604 n
= rc
->params
.rread
.count
;
608 memmove(data
, rc
->params
.rread
.data
, n
);
617 } while (count
> 0 && n
== rsize
);
626 EXPORT_SYMBOL(p9_client_read
);
628 int p9_client_write(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
630 int err
, n
, rsize
, total
;
631 struct p9_fcall
*tc
, *rc
;
632 struct p9_client
*clnt
;
634 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
635 (long long unsigned) offset
, count
);
643 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
644 rsize
= clnt
->msize
- P9_IOHDRSZ
;
650 tc
= p9_create_twrite(fid
->fid
, offset
, rsize
, data
);
657 err
= p9_client_rpc(clnt
, tc
, &rc
);
661 n
= rc
->params
.rread
.count
;
679 EXPORT_SYMBOL(p9_client_write
);
682 p9_client_uread(struct p9_fid
*fid
, char __user
*data
, u64 offset
, u32 count
)
684 int err
, n
, rsize
, total
;
685 struct p9_fcall
*tc
, *rc
;
686 struct p9_client
*clnt
;
688 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
689 (long long unsigned) offset
, count
);
697 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
698 rsize
= clnt
->msize
- P9_IOHDRSZ
;
704 tc
= p9_create_tread(fid
->fid
, offset
, rsize
);
711 err
= p9_client_rpc(clnt
, tc
, &rc
);
715 n
= rc
->params
.rread
.count
;
719 err
= copy_to_user(data
, rc
->params
.rread
.data
, n
);
733 } while (count
> 0 && n
== rsize
);
742 EXPORT_SYMBOL(p9_client_uread
);
745 p9_client_uwrite(struct p9_fid
*fid
, const char __user
*data
, u64 offset
,
748 int err
, n
, rsize
, total
;
749 struct p9_fcall
*tc
, *rc
;
750 struct p9_client
*clnt
;
752 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
753 (long long unsigned) offset
, count
);
761 if (!rsize
|| rsize
> clnt
->msize
-P9_IOHDRSZ
)
762 rsize
= clnt
->msize
- P9_IOHDRSZ
;
768 tc
= p9_create_twrite_u(fid
->fid
, offset
, rsize
, data
);
775 err
= p9_client_rpc(clnt
, tc
, &rc
);
779 n
= rc
->params
.rread
.count
;
797 EXPORT_SYMBOL(p9_client_uwrite
);
799 int p9_client_readn(struct p9_fid
*fid
, char *data
, u64 offset
, u32 count
)
803 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu count %d\n", fid
->fid
,
804 (long long unsigned) offset
, count
);
808 n
= p9_client_read(fid
, data
, offset
, count
);
823 EXPORT_SYMBOL(p9_client_readn
);
825 struct p9_stat
*p9_client_stat(struct p9_fid
*fid
)
828 struct p9_fcall
*tc
, *rc
;
829 struct p9_client
*clnt
;
832 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
839 tc
= p9_create_tstat(fid
->fid
);
846 err
= p9_client_rpc(clnt
, tc
, &rc
);
850 ret
= p9_clone_stat(&rc
->params
.rstat
.stat
, clnt
->dotu
);
867 EXPORT_SYMBOL(p9_client_stat
);
869 int p9_client_wstat(struct p9_fid
*fid
, struct p9_wstat
*wst
)
872 struct p9_fcall
*tc
, *rc
;
873 struct p9_client
*clnt
;
875 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
881 tc
= p9_create_twstat(fid
->fid
, wst
, clnt
->dotu
);
888 err
= p9_client_rpc(clnt
, tc
, &rc
);
895 EXPORT_SYMBOL(p9_client_wstat
);
897 struct p9_stat
*p9_client_dirread(struct p9_fid
*fid
, u64 offset
)
900 struct p9_fcall
*tc
, *rc
;
901 struct p9_client
*clnt
;
902 struct p9_stat st
, *ret
;
904 P9_DPRINTK(P9_DEBUG_9P
, "fid %d offset %llu\n", fid
->fid
,
905 (long long unsigned) offset
);
912 /* if the offset is below or above the current response, free it */
913 if (offset
< fid
->rdir_fpos
|| (fid
->rdir_fcall
&&
914 offset
>= fid
->rdir_fpos
+fid
->rdir_fcall
->params
.rread
.count
)) {
917 fid
->rdir_fpos
+= fid
->rdir_fcall
->params
.rread
.count
;
919 kfree(fid
->rdir_fcall
);
920 fid
->rdir_fcall
= NULL
;
921 if (offset
< fid
->rdir_fpos
)
925 if (!fid
->rdir_fcall
) {
927 if (!n
|| n
> clnt
->msize
-P9_IOHDRSZ
)
928 n
= clnt
->msize
- P9_IOHDRSZ
;
931 if (fid
->rdir_fcall
) {
933 fid
->rdir_fcall
->params
.rread
.count
;
934 kfree(fid
->rdir_fcall
);
935 fid
->rdir_fcall
= NULL
;
938 tc
= p9_create_tread(fid
->fid
, fid
->rdir_fpos
, n
);
945 err
= p9_client_rpc(clnt
, tc
, &rc
);
949 n
= rc
->params
.rread
.count
;
953 fid
->rdir_fcall
= rc
;
955 if (offset
>= fid
->rdir_fpos
&&
956 offset
< fid
->rdir_fpos
+n
)
963 m
= offset
- fid
->rdir_fpos
;
967 n
= p9_deserialize_stat(fid
->rdir_fcall
->params
.rread
.data
+ m
,
968 fid
->rdir_fcall
->params
.rread
.count
- m
, &st
, clnt
->dotu
);
977 ret
= p9_clone_stat(&st
, clnt
->dotu
);
995 EXPORT_SYMBOL(p9_client_dirread
);
997 static struct p9_stat
*p9_clone_stat(struct p9_stat
*st
, int dotu
)
1001 struct p9_stat
*ret
;
1003 n
= sizeof(struct p9_stat
) + st
->name
.len
+ st
->uid
.len
+ st
->gid
.len
+
1007 n
+= st
->extension
.len
;
1009 ret
= kmalloc(n
, GFP_KERNEL
);
1011 return ERR_PTR(-ENOMEM
);
1013 memmove(ret
, st
, sizeof(struct p9_stat
));
1014 p
= ((char *) ret
) + sizeof(struct p9_stat
);
1015 memmove(p
, st
->name
.str
, st
->name
.len
);
1018 memmove(p
, st
->uid
.str
, st
->uid
.len
);
1021 memmove(p
, st
->gid
.str
, st
->gid
.len
);
1024 memmove(p
, st
->muid
.str
, st
->muid
.len
);
1029 memmove(p
, st
->extension
.str
, st
->extension
.len
);
1030 ret
->extension
.str
= p
;
1031 p
+= st
->extension
.len
;
1037 static struct p9_fid
*p9_fid_create(struct p9_client
*clnt
)
1042 P9_DPRINTK(P9_DEBUG_9P
, "clnt %p\n", clnt
);
1043 fid
= kmalloc(sizeof(struct p9_fid
), GFP_KERNEL
);
1045 return ERR_PTR(-ENOMEM
);
1047 fid
->fid
= p9_idpool_get(clnt
->fidpool
);
1053 memset(&fid
->qid
, 0, sizeof(struct p9_qid
));
1057 fid
->rdir_fcall
= NULL
;
1058 fid
->uid
= current
->fsuid
;
1062 spin_lock(&clnt
->lock
);
1063 list_add(&fid
->flist
, &clnt
->fidlist
);
1064 spin_unlock(&clnt
->lock
);
1070 return ERR_PTR(err
);
1073 static void p9_fid_destroy(struct p9_fid
*fid
)
1075 struct p9_client
*clnt
;
1077 P9_DPRINTK(P9_DEBUG_9P
, "fid %d\n", fid
->fid
);
1079 p9_idpool_put(fid
->fid
, clnt
->fidpool
);
1080 spin_lock(&clnt
->lock
);
1081 list_del(&fid
->flist
);
1082 spin_unlock(&clnt
->lock
);
1083 kfree(fid
->rdir_fcall
);