diff options
Diffstat (limited to 'fs/9p/v9fs.c')
-rw-r--r-- | fs/9p/v9fs.c | 288 |
1 files changed, 58 insertions, 230 deletions
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 6ad6f192b6e4..4feb5ae63ecf 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c | |||
@@ -29,16 +29,12 @@ | |||
29 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
30 | #include <linux/parser.h> | 30 | #include <linux/parser.h> |
31 | #include <linux/idr.h> | 31 | #include <linux/idr.h> |
32 | 32 | #include <net/9p/9p.h> | |
33 | #include "debug.h" | 33 | #include <net/9p/transport.h> |
34 | #include <net/9p/conn.h> | ||
35 | #include <net/9p/client.h> | ||
34 | #include "v9fs.h" | 36 | #include "v9fs.h" |
35 | #include "9p.h" | ||
36 | #include "v9fs_vfs.h" | 37 | #include "v9fs_vfs.h" |
37 | #include "transport.h" | ||
38 | #include "mux.h" | ||
39 | |||
40 | /* TODO: sysfs or debugfs interface */ | ||
41 | int v9fs_debug_level = 0; /* feature-rific global debug level */ | ||
42 | 38 | ||
43 | /* | 39 | /* |
44 | * Option Parsing (code inspired by NFS code) | 40 | * Option Parsing (code inspired by NFS code) |
@@ -47,12 +43,12 @@ int v9fs_debug_level = 0; /* feature-rific global debug level */ | |||
47 | 43 | ||
48 | enum { | 44 | enum { |
49 | /* Options that take integer arguments */ | 45 | /* Options that take integer arguments */ |
50 | Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, Opt_debug, | 46 | Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, |
51 | Opt_rfdno, Opt_wfdno, | 47 | Opt_rfdno, Opt_wfdno, |
52 | /* String options */ | 48 | /* String options */ |
53 | Opt_uname, Opt_remotename, | 49 | Opt_uname, Opt_remotename, |
54 | /* Options that take no arguments */ | 50 | /* Options that take no arguments */ |
55 | Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, | 51 | Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, Opt_pci, |
56 | /* Cache options */ | 52 | /* Cache options */ |
57 | Opt_cache_loose, | 53 | Opt_cache_loose, |
58 | /* Error token */ | 54 | /* Error token */ |
@@ -67,12 +63,14 @@ static match_table_t tokens = { | |||
67 | {Opt_afid, "afid=%u"}, | 63 | {Opt_afid, "afid=%u"}, |
68 | {Opt_rfdno, "rfdno=%u"}, | 64 | {Opt_rfdno, "rfdno=%u"}, |
69 | {Opt_wfdno, "wfdno=%u"}, | 65 | {Opt_wfdno, "wfdno=%u"}, |
70 | {Opt_debug, "debug=%x"}, | ||
71 | {Opt_uname, "uname=%s"}, | 66 | {Opt_uname, "uname=%s"}, |
72 | {Opt_remotename, "aname=%s"}, | 67 | {Opt_remotename, "aname=%s"}, |
73 | {Opt_unix, "proto=unix"}, | 68 | {Opt_unix, "proto=unix"}, |
74 | {Opt_tcp, "proto=tcp"}, | 69 | {Opt_tcp, "proto=tcp"}, |
75 | {Opt_fd, "proto=fd"}, | 70 | {Opt_fd, "proto=fd"}, |
71 | #ifdef CONFIG_PCI_9P | ||
72 | {Opt_pci, "proto=pci"}, | ||
73 | #endif | ||
76 | {Opt_tcp, "tcp"}, | 74 | {Opt_tcp, "tcp"}, |
77 | {Opt_unix, "unix"}, | 75 | {Opt_unix, "unix"}, |
78 | {Opt_fd, "fd"}, | 76 | {Opt_fd, "fd"}, |
@@ -83,6 +81,8 @@ static match_table_t tokens = { | |||
83 | {Opt_err, NULL} | 81 | {Opt_err, NULL} |
84 | }; | 82 | }; |
85 | 83 | ||
84 | extern struct p9_transport *p9pci_trans_create(void); | ||
85 | |||
86 | /* | 86 | /* |
87 | * Parse option string. | 87 | * Parse option string. |
88 | */ | 88 | */ |
@@ -122,7 +122,7 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) | |||
122 | token = match_token(p, tokens, args); | 122 | token = match_token(p, tokens, args); |
123 | if (token < Opt_uname) { | 123 | if (token < Opt_uname) { |
124 | if ((ret = match_int(&args[0], &option)) < 0) { | 124 | if ((ret = match_int(&args[0], &option)) < 0) { |
125 | dprintk(DEBUG_ERROR, | 125 | P9_DPRINTK(P9_DEBUG_ERROR, |
126 | "integer field, but no integer?\n"); | 126 | "integer field, but no integer?\n"); |
127 | continue; | 127 | continue; |
128 | } | 128 | } |
@@ -149,15 +149,15 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) | |||
149 | case Opt_wfdno: | 149 | case Opt_wfdno: |
150 | v9ses->wfdno = option; | 150 | v9ses->wfdno = option; |
151 | break; | 151 | break; |
152 | case Opt_debug: | ||
153 | v9ses->debug = option; | ||
154 | break; | ||
155 | case Opt_tcp: | 152 | case Opt_tcp: |
156 | v9ses->proto = PROTO_TCP; | 153 | v9ses->proto = PROTO_TCP; |
157 | break; | 154 | break; |
158 | case Opt_unix: | 155 | case Opt_unix: |
159 | v9ses->proto = PROTO_UNIX; | 156 | v9ses->proto = PROTO_UNIX; |
160 | break; | 157 | break; |
158 | case Opt_pci: | ||
159 | v9ses->proto = PROTO_PCI; | ||
160 | break; | ||
161 | case Opt_fd: | 161 | case Opt_fd: |
162 | v9ses->proto = PROTO_FD; | 162 | v9ses->proto = PROTO_FD; |
163 | break; | 163 | break; |
@@ -183,82 +183,6 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses) | |||
183 | } | 183 | } |
184 | 184 | ||
185 | /** | 185 | /** |
186 | * v9fs_inode2v9ses - safely extract v9fs session info from super block | ||
187 | * @inode: inode to extract information from | ||
188 | * | ||
189 | * Paranoid function to extract v9ses information from superblock, | ||
190 | * if anything is missing it will report an error. | ||
191 | * | ||
192 | */ | ||
193 | |||
194 | struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode) | ||
195 | { | ||
196 | return (inode->i_sb->s_fs_info); | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * v9fs_get_idpool - allocate numeric id from pool | ||
201 | * @p - pool to allocate from | ||
202 | * | ||
203 | * XXX - This seems to be an awful generic function, should it be in idr.c with | ||
204 | * the lock included in struct idr? | ||
205 | */ | ||
206 | |||
207 | int v9fs_get_idpool(struct v9fs_idpool *p) | ||
208 | { | ||
209 | int i = 0; | ||
210 | int error; | ||
211 | |||
212 | retry: | ||
213 | if (idr_pre_get(&p->pool, GFP_KERNEL) == 0) | ||
214 | return 0; | ||
215 | |||
216 | if (down_interruptible(&p->lock) == -EINTR) { | ||
217 | eprintk(KERN_WARNING, "Interrupted while locking\n"); | ||
218 | return -1; | ||
219 | } | ||
220 | |||
221 | /* no need to store exactly p, we just need something non-null */ | ||
222 | error = idr_get_new(&p->pool, p, &i); | ||
223 | up(&p->lock); | ||
224 | |||
225 | if (error == -EAGAIN) | ||
226 | goto retry; | ||
227 | else if (error) | ||
228 | return -1; | ||
229 | |||
230 | return i; | ||
231 | } | ||
232 | |||
233 | /** | ||
234 | * v9fs_put_idpool - release numeric id from pool | ||
235 | * @p - pool to allocate from | ||
236 | * | ||
237 | * XXX - This seems to be an awful generic function, should it be in idr.c with | ||
238 | * the lock included in struct idr? | ||
239 | */ | ||
240 | |||
241 | void v9fs_put_idpool(int id, struct v9fs_idpool *p) | ||
242 | { | ||
243 | if (down_interruptible(&p->lock) == -EINTR) { | ||
244 | eprintk(KERN_WARNING, "Interrupted while locking\n"); | ||
245 | return; | ||
246 | } | ||
247 | idr_remove(&p->pool, id); | ||
248 | up(&p->lock); | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * v9fs_check_idpool - check if the specified id is available | ||
253 | * @id - id to check | ||
254 | * @p - pool | ||
255 | */ | ||
256 | int v9fs_check_idpool(int id, struct v9fs_idpool *p) | ||
257 | { | ||
258 | return idr_find(&p->pool, id) != NULL; | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * v9fs_session_init - initialize session | 186 | * v9fs_session_init - initialize session |
263 | * @v9ses: session information structure | 187 | * @v9ses: session information structure |
264 | * @dev_name: device being mounted | 188 | * @dev_name: device being mounted |
@@ -266,25 +190,21 @@ int v9fs_check_idpool(int id, struct v9fs_idpool *p) | |||
266 | * | 190 | * |
267 | */ | 191 | */ |
268 | 192 | ||
269 | int | 193 | struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, |
270 | v9fs_session_init(struct v9fs_session_info *v9ses, | ||
271 | const char *dev_name, char *data) | 194 | const char *dev_name, char *data) |
272 | { | 195 | { |
273 | struct v9fs_fcall *fcall = NULL; | ||
274 | struct v9fs_transport *trans_proto; | ||
275 | int n = 0; | ||
276 | int newfid = -1; | ||
277 | int retval = -EINVAL; | 196 | int retval = -EINVAL; |
278 | struct v9fs_str *version; | 197 | struct p9_transport *trans; |
198 | struct p9_fid *fid; | ||
279 | 199 | ||
280 | v9ses->name = __getname(); | 200 | v9ses->name = __getname(); |
281 | if (!v9ses->name) | 201 | if (!v9ses->name) |
282 | return -ENOMEM; | 202 | return ERR_PTR(-ENOMEM); |
283 | 203 | ||
284 | v9ses->remotename = __getname(); | 204 | v9ses->remotename = __getname(); |
285 | if (!v9ses->remotename) { | 205 | if (!v9ses->remotename) { |
286 | __putname(v9ses->name); | 206 | __putname(v9ses->name); |
287 | return -ENOMEM; | 207 | return ERR_PTR(-ENOMEM); |
288 | } | 208 | } |
289 | 209 | ||
290 | strcpy(v9ses->name, V9FS_DEFUSER); | 210 | strcpy(v9ses->name, V9FS_DEFUSER); |
@@ -292,130 +212,60 @@ v9fs_session_init(struct v9fs_session_info *v9ses, | |||
292 | 212 | ||
293 | v9fs_parse_options(data, v9ses); | 213 | v9fs_parse_options(data, v9ses); |
294 | 214 | ||
295 | /* set global debug level */ | ||
296 | v9fs_debug_level = v9ses->debug; | ||
297 | |||
298 | /* id pools that are session-dependent: fids and tags */ | ||
299 | idr_init(&v9ses->fidpool.pool); | ||
300 | init_MUTEX(&v9ses->fidpool.lock); | ||
301 | |||
302 | switch (v9ses->proto) { | 215 | switch (v9ses->proto) { |
303 | case PROTO_TCP: | 216 | case PROTO_TCP: |
304 | trans_proto = &v9fs_trans_tcp; | 217 | trans = p9_trans_create_tcp(dev_name, v9ses->port); |
305 | break; | 218 | break; |
306 | case PROTO_UNIX: | 219 | case PROTO_UNIX: |
307 | trans_proto = &v9fs_trans_unix; | 220 | trans = p9_trans_create_unix(dev_name); |
308 | *v9ses->remotename = 0; | 221 | *v9ses->remotename = 0; |
309 | break; | 222 | break; |
310 | case PROTO_FD: | 223 | case PROTO_FD: |
311 | trans_proto = &v9fs_trans_fd; | 224 | trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno); |
225 | *v9ses->remotename = 0; | ||
226 | break; | ||
227 | #ifdef CONFIG_PCI_9P | ||
228 | case PROTO_PCI: | ||
229 | trans = p9pci_trans_create(); | ||
312 | *v9ses->remotename = 0; | 230 | *v9ses->remotename = 0; |
313 | break; | 231 | break; |
232 | #endif | ||
314 | default: | 233 | default: |
315 | printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); | 234 | printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto); |
316 | retval = -ENOPROTOOPT; | 235 | retval = -ENOPROTOOPT; |
317 | goto SessCleanUp; | 236 | goto error; |
318 | }; | 237 | }; |
319 | 238 | ||
320 | v9ses->transport = kmalloc(sizeof(*v9ses->transport), GFP_KERNEL); | 239 | if (IS_ERR(trans)) { |
321 | if (!v9ses->transport) { | 240 | retval = PTR_ERR(trans); |
322 | retval = -ENOMEM; | 241 | trans = NULL; |
323 | goto SessCleanUp; | 242 | goto error; |
324 | } | 243 | } |
325 | 244 | ||
326 | memmove(v9ses->transport, trans_proto, sizeof(*v9ses->transport)); | 245 | v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ, |
246 | v9ses->extended); | ||
327 | 247 | ||
328 | if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) { | 248 | if (IS_ERR(v9ses->clnt)) { |
329 | eprintk(KERN_ERR, "problem initializing transport\n"); | 249 | retval = PTR_ERR(v9ses->clnt); |
330 | goto SessCleanUp; | 250 | v9ses->clnt = NULL; |
251 | P9_DPRINTK(P9_DEBUG_ERROR, "problem initializing 9p client\n"); | ||
252 | goto error; | ||
331 | } | 253 | } |
332 | 254 | ||
333 | v9ses->inprogress = 0; | 255 | fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name, |
334 | v9ses->shutdown = 0; | 256 | v9ses->remotename); |
335 | v9ses->session_hung = 0; | 257 | if (IS_ERR(fid)) { |
336 | 258 | retval = PTR_ERR(fid); | |
337 | v9ses->mux = v9fs_mux_init(v9ses->transport, v9ses->maxdata + V9FS_IOHDRSZ, | 259 | fid = NULL; |
338 | &v9ses->extended); | 260 | P9_DPRINTK(P9_DEBUG_ERROR, "cannot attach\n"); |
339 | 261 | goto error; | |
340 | if (IS_ERR(v9ses->mux)) { | ||
341 | retval = PTR_ERR(v9ses->mux); | ||
342 | v9ses->mux = NULL; | ||
343 | dprintk(DEBUG_ERROR, "problem initializing mux\n"); | ||
344 | goto SessCleanUp; | ||
345 | } | 262 | } |
346 | 263 | ||
347 | if (v9ses->afid == ~0) { | 264 | return fid; |
348 | if (v9ses->extended) | ||
349 | retval = | ||
350 | v9fs_t_version(v9ses, v9ses->maxdata, "9P2000.u", | ||
351 | &fcall); | ||
352 | else | ||
353 | retval = v9fs_t_version(v9ses, v9ses->maxdata, "9P2000", | ||
354 | &fcall); | ||
355 | |||
356 | if (retval < 0) { | ||
357 | dprintk(DEBUG_ERROR, "v9fs_t_version failed\n"); | ||
358 | goto FreeFcall; | ||
359 | } | ||
360 | |||
361 | version = &fcall->params.rversion.version; | ||
362 | if (version->len==8 && !memcmp(version->str, "9P2000.u", 8)) { | ||
363 | dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n"); | ||
364 | v9ses->extended = 1; | ||
365 | } else if (version->len==6 && !memcmp(version->str, "9P2000", 6)) { | ||
366 | dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n"); | ||
367 | v9ses->extended = 0; | ||
368 | } else { | ||
369 | retval = -EREMOTEIO; | ||
370 | goto FreeFcall; | ||
371 | } | ||
372 | 265 | ||
373 | n = fcall->params.rversion.msize; | 266 | error: |
374 | kfree(fcall); | ||
375 | |||
376 | if (n < v9ses->maxdata) | ||
377 | v9ses->maxdata = n; | ||
378 | } | ||
379 | |||
380 | newfid = v9fs_get_idpool(&v9ses->fidpool); | ||
381 | if (newfid < 0) { | ||
382 | eprintk(KERN_WARNING, "couldn't allocate FID\n"); | ||
383 | retval = -ENOMEM; | ||
384 | goto SessCleanUp; | ||
385 | } | ||
386 | /* it is a little bit ugly, but we have to prevent newfid */ | ||
387 | /* being the same as afid, so if it is, get a new fid */ | ||
388 | if (v9ses->afid != ~0 && newfid == v9ses->afid) { | ||
389 | newfid = v9fs_get_idpool(&v9ses->fidpool); | ||
390 | if (newfid < 0) { | ||
391 | eprintk(KERN_WARNING, "couldn't allocate FID\n"); | ||
392 | retval = -ENOMEM; | ||
393 | goto SessCleanUp; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | if ((retval = | ||
398 | v9fs_t_attach(v9ses, v9ses->name, v9ses->remotename, newfid, | ||
399 | v9ses->afid, NULL)) | ||
400 | < 0) { | ||
401 | dprintk(DEBUG_ERROR, "cannot attach\n"); | ||
402 | goto SessCleanUp; | ||
403 | } | ||
404 | |||
405 | if (v9ses->afid != ~0) { | ||
406 | dprintk(DEBUG_ERROR, "afid not equal to ~0\n"); | ||
407 | if (v9fs_t_clunk(v9ses, v9ses->afid)) | ||
408 | dprintk(DEBUG_ERROR, "clunk failed\n"); | ||
409 | } | ||
410 | |||
411 | return newfid; | ||
412 | |||
413 | FreeFcall: | ||
414 | kfree(fcall); | ||
415 | |||
416 | SessCleanUp: | ||
417 | v9fs_session_close(v9ses); | 267 | v9fs_session_close(v9ses); |
418 | return retval; | 268 | return ERR_PTR(retval); |
419 | } | 269 | } |
420 | 270 | ||
421 | /** | 271 | /** |
@@ -426,15 +276,9 @@ v9fs_session_init(struct v9fs_session_info *v9ses, | |||
426 | 276 | ||
427 | void v9fs_session_close(struct v9fs_session_info *v9ses) | 277 | void v9fs_session_close(struct v9fs_session_info *v9ses) |
428 | { | 278 | { |
429 | if (v9ses->mux) { | 279 | if (v9ses->clnt) { |
430 | v9fs_mux_destroy(v9ses->mux); | 280 | p9_client_destroy(v9ses->clnt); |
431 | v9ses->mux = NULL; | 281 | v9ses->clnt = NULL; |
432 | } | ||
433 | |||
434 | if (v9ses->transport) { | ||
435 | v9ses->transport->close(v9ses->transport); | ||
436 | kfree(v9ses->transport); | ||
437 | v9ses->transport = NULL; | ||
438 | } | 282 | } |
439 | 283 | ||
440 | __putname(v9ses->name); | 284 | __putname(v9ses->name); |
@@ -446,9 +290,8 @@ void v9fs_session_close(struct v9fs_session_info *v9ses) | |||
446 | * and cancel all pending requests. | 290 | * and cancel all pending requests. |
447 | */ | 291 | */ |
448 | void v9fs_session_cancel(struct v9fs_session_info *v9ses) { | 292 | void v9fs_session_cancel(struct v9fs_session_info *v9ses) { |
449 | dprintk(DEBUG_ERROR, "cancel session %p\n", v9ses); | 293 | P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses); |
450 | v9ses->transport->status = Disconnected; | 294 | p9_client_disconnect(v9ses->clnt); |
451 | v9fs_mux_cancel(v9ses->mux, -EIO); | ||
452 | } | 295 | } |
453 | 296 | ||
454 | extern int v9fs_error_init(void); | 297 | extern int v9fs_error_init(void); |
@@ -460,24 +303,9 @@ extern int v9fs_error_init(void); | |||
460 | 303 | ||
461 | static int __init init_v9fs(void) | 304 | static int __init init_v9fs(void) |
462 | { | 305 | { |
463 | int ret; | ||
464 | |||
465 | v9fs_error_init(); | ||
466 | |||
467 | printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); | 306 | printk(KERN_INFO "Installing v9fs 9p2000 file system support\n"); |
468 | 307 | ||
469 | ret = v9fs_mux_global_init(); | 308 | return register_filesystem(&v9fs_fs_type); |
470 | if (ret) { | ||
471 | printk(KERN_WARNING "v9fs: starting mux failed\n"); | ||
472 | return ret; | ||
473 | } | ||
474 | ret = register_filesystem(&v9fs_fs_type); | ||
475 | if (ret) { | ||
476 | printk(KERN_WARNING "v9fs: registering file system failed\n"); | ||
477 | v9fs_mux_global_exit(); | ||
478 | } | ||
479 | |||
480 | return ret; | ||
481 | } | 309 | } |
482 | 310 | ||
483 | /** | 311 | /** |
@@ -487,13 +315,13 @@ static int __init init_v9fs(void) | |||
487 | 315 | ||
488 | static void __exit exit_v9fs(void) | 316 | static void __exit exit_v9fs(void) |
489 | { | 317 | { |
490 | v9fs_mux_global_exit(); | ||
491 | unregister_filesystem(&v9fs_fs_type); | 318 | unregister_filesystem(&v9fs_fs_type); |
492 | } | 319 | } |
493 | 320 | ||
494 | module_init(init_v9fs) | 321 | module_init(init_v9fs) |
495 | module_exit(exit_v9fs) | 322 | module_exit(exit_v9fs) |
496 | 323 | ||
324 | MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>"); | ||
497 | MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>"); | 325 | MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>"); |
498 | MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>"); | 326 | MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>"); |
499 | MODULE_LICENSE("GPL"); | 327 | MODULE_LICENSE("GPL"); |