Commit | Line | Data |
---|---|---|
9e82cf6a EVH |
1 | /* |
2 | * linux/fs/9p/v9fs.c | |
3 | * | |
4 | * This file contains functions assisting in mapping VFS to 9P2000 | |
5 | * | |
6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | |
7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
42e8c509 EVH |
10 | * it under the terms of the GNU General Public License version 2 |
11 | * as published by the Free Software Foundation. | |
9e82cf6a EVH |
12 | * |
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. | |
17 | * | |
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 | |
23 | * | |
24 | */ | |
25 | ||
9e82cf6a EVH |
26 | #include <linux/module.h> |
27 | #include <linux/errno.h> | |
28 | #include <linux/fs.h> | |
914e2637 | 29 | #include <linux/sched.h> |
9e82cf6a EVH |
30 | #include <linux/parser.h> |
31 | #include <linux/idr.h> | |
bd238fb4 LI |
32 | #include <net/9p/9p.h> |
33 | #include <net/9p/transport.h> | |
34 | #include <net/9p/conn.h> | |
35 | #include <net/9p/client.h> | |
9e82cf6a | 36 | #include "v9fs.h" |
9e82cf6a | 37 | #include "v9fs_vfs.h" |
9e82cf6a EVH |
38 | |
39 | /* | |
40 | * Option Parsing (code inspired by NFS code) | |
41 | * | |
42 | */ | |
43 | ||
44 | enum { | |
45 | /* Options that take integer arguments */ | |
9e2f6688 | 46 | Opt_debug, Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, |
9e82cf6a EVH |
47 | Opt_rfdno, Opt_wfdno, |
48 | /* String options */ | |
67543e50 | 49 | Opt_uname, Opt_remotename, |
9e82cf6a | 50 | /* Options that take no arguments */ |
bd238fb4 | 51 | Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, Opt_pci, |
e03abc0c EVH |
52 | /* Cache options */ |
53 | Opt_cache_loose, | |
9e82cf6a EVH |
54 | /* Error token */ |
55 | Opt_err | |
56 | }; | |
57 | ||
58 | static match_table_t tokens = { | |
9e2f6688 | 59 | {Opt_debug, "debug=%x"}, |
9e82cf6a EVH |
60 | {Opt_port, "port=%u"}, |
61 | {Opt_msize, "msize=%u"}, | |
62 | {Opt_uid, "uid=%u"}, | |
63 | {Opt_gid, "gid=%u"}, | |
64 | {Opt_afid, "afid=%u"}, | |
65 | {Opt_rfdno, "rfdno=%u"}, | |
66 | {Opt_wfdno, "wfdno=%u"}, | |
67543e50 | 67 | {Opt_uname, "uname=%s"}, |
9e82cf6a EVH |
68 | {Opt_remotename, "aname=%s"}, |
69 | {Opt_unix, "proto=unix"}, | |
70 | {Opt_tcp, "proto=tcp"}, | |
71 | {Opt_fd, "proto=fd"}, | |
bd238fb4 LI |
72 | #ifdef CONFIG_PCI_9P |
73 | {Opt_pci, "proto=pci"}, | |
74 | #endif | |
9e82cf6a EVH |
75 | {Opt_tcp, "tcp"}, |
76 | {Opt_unix, "unix"}, | |
77 | {Opt_fd, "fd"}, | |
78 | {Opt_legacy, "noextend"}, | |
79 | {Opt_nodevmap, "nodevmap"}, | |
e03abc0c EVH |
80 | {Opt_cache_loose, "cache=loose"}, |
81 | {Opt_cache_loose, "loose"}, | |
9e82cf6a EVH |
82 | {Opt_err, NULL} |
83 | }; | |
84 | ||
bd238fb4 LI |
85 | extern struct p9_transport *p9pci_trans_create(void); |
86 | ||
9e82cf6a EVH |
87 | /* |
88 | * Parse option string. | |
89 | */ | |
90 | ||
91 | /** | |
92 | * v9fs_parse_options - parse mount options into session structure | |
93 | * @options: options string passed from mount | |
94 | * @v9ses: existing v9fs session information | |
95 | * | |
96 | */ | |
97 | ||
98 | static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) | |
99 | { | |
100 | char *p; | |
101 | substring_t args[MAX_OPT_ARGS]; | |
102 | int option; | |
103 | int ret; | |
104 | ||
105 | /* setup defaults */ | |
106 | v9ses->port = V9FS_PORT; | |
107 | v9ses->maxdata = 9000; | |
108 | v9ses->proto = PROTO_TCP; | |
109 | v9ses->extended = 1; | |
110 | v9ses->afid = ~0; | |
111 | v9ses->debug = 0; | |
112 | v9ses->rfdno = ~0; | |
113 | v9ses->wfdno = ~0; | |
e03abc0c | 114 | v9ses->cache = 0; |
9e82cf6a EVH |
115 | |
116 | if (!options) | |
117 | return; | |
118 | ||
119 | while ((p = strsep(&options, ",")) != NULL) { | |
120 | int token; | |
121 | if (!*p) | |
122 | continue; | |
123 | token = match_token(p, tokens, args); | |
67543e50 | 124 | if (token < Opt_uname) { |
9e82cf6a | 125 | if ((ret = match_int(&args[0], &option)) < 0) { |
bd238fb4 | 126 | P9_DPRINTK(P9_DEBUG_ERROR, |
9e82cf6a EVH |
127 | "integer field, but no integer?\n"); |
128 | continue; | |
129 | } | |
9e82cf6a EVH |
130 | } |
131 | switch (token) { | |
9e2f6688 EVH |
132 | case Opt_debug: |
133 | v9ses->debug = option; | |
10fa16e7 | 134 | #ifdef CONFIG_NET_9P_DEBUG |
9e2f6688 | 135 | p9_debug_level = option; |
10fa16e7 | 136 | #endif |
9e2f6688 | 137 | break; |
9e82cf6a EVH |
138 | case Opt_port: |
139 | v9ses->port = option; | |
140 | break; | |
141 | case Opt_msize: | |
142 | v9ses->maxdata = option; | |
143 | break; | |
144 | case Opt_uid: | |
145 | v9ses->uid = option; | |
146 | break; | |
147 | case Opt_gid: | |
148 | v9ses->gid = option; | |
149 | break; | |
150 | case Opt_afid: | |
151 | v9ses->afid = option; | |
152 | break; | |
153 | case Opt_rfdno: | |
154 | v9ses->rfdno = option; | |
155 | break; | |
156 | case Opt_wfdno: | |
157 | v9ses->wfdno = option; | |
158 | break; | |
9e82cf6a EVH |
159 | case Opt_tcp: |
160 | v9ses->proto = PROTO_TCP; | |
161 | break; | |
162 | case Opt_unix: | |
163 | v9ses->proto = PROTO_UNIX; | |
164 | break; | |
bd238fb4 LI |
165 | case Opt_pci: |
166 | v9ses->proto = PROTO_PCI; | |
167 | break; | |
9e82cf6a EVH |
168 | case Opt_fd: |
169 | v9ses->proto = PROTO_FD; | |
170 | break; | |
67543e50 | 171 | case Opt_uname: |
9e82cf6a EVH |
172 | match_strcpy(v9ses->name, &args[0]); |
173 | break; | |
174 | case Opt_remotename: | |
175 | match_strcpy(v9ses->remotename, &args[0]); | |
176 | break; | |
177 | case Opt_legacy: | |
178 | v9ses->extended = 0; | |
179 | break; | |
180 | case Opt_nodevmap: | |
181 | v9ses->nodev = 1; | |
182 | break; | |
e03abc0c EVH |
183 | case Opt_cache_loose: |
184 | v9ses->cache = CACHE_LOOSE; | |
185 | break; | |
9e82cf6a EVH |
186 | default: |
187 | continue; | |
188 | } | |
189 | } | |
190 | } | |
191 | ||
9e82cf6a EVH |
192 | /** |
193 | * v9fs_session_init - initialize session | |
194 | * @v9ses: session information structure | |
195 | * @dev_name: device being mounted | |
196 | * @data: options | |
197 | * | |
198 | */ | |
199 | ||
bd238fb4 | 200 | struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, |
9e82cf6a EVH |
201 | const char *dev_name, char *data) |
202 | { | |
9e82cf6a | 203 | int retval = -EINVAL; |
bd238fb4 LI |
204 | struct p9_transport *trans; |
205 | struct p9_fid *fid; | |
9e82cf6a EVH |
206 | |
207 | v9ses->name = __getname(); | |
208 | if (!v9ses->name) | |
bd238fb4 | 209 | return ERR_PTR(-ENOMEM); |
9e82cf6a EVH |
210 | |
211 | v9ses->remotename = __getname(); | |
212 | if (!v9ses->remotename) { | |
ce44eeb6 | 213 | __putname(v9ses->name); |
bd238fb4 | 214 | return ERR_PTR(-ENOMEM); |
9e82cf6a EVH |
215 | } |
216 | ||
217 | strcpy(v9ses->name, V9FS_DEFUSER); | |
218 | strcpy(v9ses->remotename, V9FS_DEFANAME); | |
219 | ||
220 | v9fs_parse_options(data, v9ses); | |
221 | ||
9e82cf6a EVH |
222 | switch (v9ses->proto) { |
223 | case PROTO_TCP: | |
bd238fb4 | 224 | trans = p9_trans_create_tcp(dev_name, v9ses->port); |
9e82cf6a EVH |
225 | break; |
226 | case PROTO_UNIX: | |
bd238fb4 | 227 | trans = p9_trans_create_unix(dev_name); |
9e82cf6a EVH |
228 | *v9ses->remotename = 0; |
229 | break; | |
230 | case PROTO_FD: | |
bd238fb4 LI |
231 | trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno); |
232 | *v9ses->remotename = 0; | |
233 | break; | |
234 | #ifdef CONFIG_PCI_9P | |
235 | case PROTO_PCI: | |
236 | trans = p9pci_trans_create(); | |
9e82cf6a | 237 | *v9ses->remotename = 0; |
9e82cf6a | 238 | break; |
bd238fb4 | 239 | #endif |
9e82cf6a EVH |
240 | default: |
241 | printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); | |
242 | retval = -ENOPROTOOPT; | |
bd238fb4 | 243 | goto error; |
9e82cf6a EVH |
244 | }; |
245 | ||
bd238fb4 LI |
246 | if (IS_ERR(trans)) { |
247 | retval = PTR_ERR(trans); | |
248 | trans = NULL; | |
249 | goto error; | |
a8e63bff LI |
250 | } |
251 | ||
bd238fb4 LI |
252 | v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ, |
253 | v9ses->extended); | |
9e82cf6a | 254 | |
bd238fb4 LI |
255 | if (IS_ERR(v9ses->clnt)) { |
256 | retval = PTR_ERR(v9ses->clnt); | |
257 | v9ses->clnt = NULL; | |
258 | P9_DPRINTK(P9_DEBUG_ERROR, "problem initializing 9p client\n"); | |
259 | goto error; | |
9e82cf6a EVH |
260 | } |
261 | ||
bd238fb4 LI |
262 | fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name, |
263 | v9ses->remotename); | |
264 | if (IS_ERR(fid)) { | |
265 | retval = PTR_ERR(fid); | |
266 | fid = NULL; | |
267 | P9_DPRINTK(P9_DEBUG_ERROR, "cannot attach\n"); | |
268 | goto error; | |
9e82cf6a EVH |
269 | } |
270 | ||
bd238fb4 | 271 | return fid; |
9e82cf6a | 272 | |
bd238fb4 | 273 | error: |
9e82cf6a | 274 | v9fs_session_close(v9ses); |
bd238fb4 | 275 | return ERR_PTR(retval); |
9e82cf6a EVH |
276 | } |
277 | ||
278 | /** | |
279 | * v9fs_session_close - shutdown a session | |
280 | * @v9ses: session information structure | |
281 | * | |
282 | */ | |
283 | ||
284 | void v9fs_session_close(struct v9fs_session_info *v9ses) | |
285 | { | |
bd238fb4 LI |
286 | if (v9ses->clnt) { |
287 | p9_client_destroy(v9ses->clnt); | |
288 | v9ses->clnt = NULL; | |
3cf6429a | 289 | } |
9e82cf6a | 290 | |
ce44eeb6 DA |
291 | __putname(v9ses->name); |
292 | __putname(v9ses->remotename); | |
9e82cf6a EVH |
293 | } |
294 | ||
322b329a EVH |
295 | /** |
296 | * v9fs_session_cancel - mark transport as disconnected | |
297 | * and cancel all pending requests. | |
298 | */ | |
299 | void v9fs_session_cancel(struct v9fs_session_info *v9ses) { | |
bd238fb4 LI |
300 | P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses); |
301 | p9_client_disconnect(v9ses->clnt); | |
322b329a EVH |
302 | } |
303 | ||
9e82cf6a EVH |
304 | extern int v9fs_error_init(void); |
305 | ||
306 | /** | |
307 | * v9fs_init - Initialize module | |
308 | * | |
309 | */ | |
310 | ||
311 | static int __init init_v9fs(void) | |
312 | { | |
f94b3470 | 313 | printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); |
9e82cf6a | 314 | |
bd238fb4 | 315 | return register_filesystem(&v9fs_fs_type); |
9e82cf6a EVH |
316 | } |
317 | ||
318 | /** | |
319 | * v9fs_init - shutdown module | |
320 | * | |
321 | */ | |
322 | ||
323 | static void __exit exit_v9fs(void) | |
324 | { | |
325 | unregister_filesystem(&v9fs_fs_type); | |
326 | } | |
327 | ||
328 | module_init(init_v9fs) | |
329 | module_exit(exit_v9fs) | |
330 | ||
bd238fb4 | 331 | MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>"); |
9e82cf6a EVH |
332 | MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>"); |
333 | MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>"); | |
334 | MODULE_LICENSE("GPL"); |