diff options
author | Miklos Szeredi <miklos@szeredi.hu> | 2006-04-11 01:54:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-04-11 09:18:49 -0400 |
commit | ce1d5a491f0ee50560416a73faa5e4ddbab074bd (patch) | |
tree | 21f91d983b467ad05df0213f54fe00aad84e5761 /fs/fuse/inode.c | |
parent | a87046d822f2d982d25b24c4a644d34f22d4888a (diff) |
[PATCH] fuse: clean up request accounting
FUSE allocated most requests from a fixed size pool filled at mount time.
However in some cases (release/forget) non-pool requests were used. File
locking operations aren't well served by the request pool, since they may
block indefinetly thus exhausting the pool.
This patch removes the request pool and always allocates requests on demand.
Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 54 |
1 files changed, 15 insertions, 39 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index cc58debeabd4..824ebbc428ed 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -243,9 +243,9 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf) | |||
243 | struct fuse_statfs_out outarg; | 243 | struct fuse_statfs_out outarg; |
244 | int err; | 244 | int err; |
245 | 245 | ||
246 | req = fuse_get_request(fc); | 246 | req = fuse_get_req(fc); |
247 | if (!req) | 247 | if (IS_ERR(req)) |
248 | return -EINTR; | 248 | return PTR_ERR(req); |
249 | 249 | ||
250 | memset(&outarg, 0, sizeof(outarg)); | 250 | memset(&outarg, 0, sizeof(outarg)); |
251 | req->in.numargs = 0; | 251 | req->in.numargs = 0; |
@@ -370,15 +370,7 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
370 | 370 | ||
371 | static void fuse_conn_release(struct kobject *kobj) | 371 | static void fuse_conn_release(struct kobject *kobj) |
372 | { | 372 | { |
373 | struct fuse_conn *fc = get_fuse_conn_kobj(kobj); | 373 | kfree(get_fuse_conn_kobj(kobj)); |
374 | |||
375 | while (!list_empty(&fc->unused_list)) { | ||
376 | struct fuse_req *req; | ||
377 | req = list_entry(fc->unused_list.next, struct fuse_req, list); | ||
378 | list_del(&req->list); | ||
379 | fuse_request_free(req); | ||
380 | } | ||
381 | kfree(fc); | ||
382 | } | 374 | } |
383 | 375 | ||
384 | static struct fuse_conn *new_conn(void) | 376 | static struct fuse_conn *new_conn(void) |
@@ -387,27 +379,16 @@ static struct fuse_conn *new_conn(void) | |||
387 | 379 | ||
388 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); | 380 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); |
389 | if (fc) { | 381 | if (fc) { |
390 | int i; | ||
391 | spin_lock_init(&fc->lock); | 382 | spin_lock_init(&fc->lock); |
392 | init_waitqueue_head(&fc->waitq); | 383 | init_waitqueue_head(&fc->waitq); |
393 | INIT_LIST_HEAD(&fc->pending); | 384 | INIT_LIST_HEAD(&fc->pending); |
394 | INIT_LIST_HEAD(&fc->processing); | 385 | INIT_LIST_HEAD(&fc->processing); |
395 | INIT_LIST_HEAD(&fc->io); | 386 | INIT_LIST_HEAD(&fc->io); |
396 | INIT_LIST_HEAD(&fc->unused_list); | ||
397 | INIT_LIST_HEAD(&fc->background); | 387 | INIT_LIST_HEAD(&fc->background); |
398 | sema_init(&fc->outstanding_sem, 1); /* One for INIT */ | ||
399 | init_rwsem(&fc->sbput_sem); | 388 | init_rwsem(&fc->sbput_sem); |
400 | kobj_set_kset_s(fc, connections_subsys); | 389 | kobj_set_kset_s(fc, connections_subsys); |
401 | kobject_init(&fc->kobj); | 390 | kobject_init(&fc->kobj); |
402 | atomic_set(&fc->num_waiting, 0); | 391 | atomic_set(&fc->num_waiting, 0); |
403 | for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { | ||
404 | struct fuse_req *req = fuse_request_alloc(); | ||
405 | if (!req) { | ||
406 | kobject_put(&fc->kobj); | ||
407 | return NULL; | ||
408 | } | ||
409 | list_add(&req->list, &fc->unused_list); | ||
410 | } | ||
411 | fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; | 392 | fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; |
412 | fc->bdi.unplug_io_fn = default_unplug_io_fn; | 393 | fc->bdi.unplug_io_fn = default_unplug_io_fn; |
413 | fc->reqctr = 0; | 394 | fc->reqctr = 0; |
@@ -438,7 +419,6 @@ static struct super_operations fuse_super_operations = { | |||
438 | 419 | ||
439 | static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | 420 | static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) |
440 | { | 421 | { |
441 | int i; | ||
442 | struct fuse_init_out *arg = &req->misc.init_out; | 422 | struct fuse_init_out *arg = &req->misc.init_out; |
443 | 423 | ||
444 | if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION) | 424 | if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION) |
@@ -457,22 +437,11 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
457 | fc->minor = arg->minor; | 437 | fc->minor = arg->minor; |
458 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; | 438 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; |
459 | } | 439 | } |
460 | |||
461 | /* After INIT reply is received other requests can go | ||
462 | out. So do (FUSE_MAX_OUTSTANDING - 1) number of | ||
463 | up()s on outstanding_sem. The last up() is done in | ||
464 | fuse_putback_request() */ | ||
465 | for (i = 1; i < FUSE_MAX_OUTSTANDING; i++) | ||
466 | up(&fc->outstanding_sem); | ||
467 | |||
468 | fuse_put_request(fc, req); | 440 | fuse_put_request(fc, req); |
469 | } | 441 | } |
470 | 442 | ||
471 | static void fuse_send_init(struct fuse_conn *fc) | 443 | static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) |
472 | { | 444 | { |
473 | /* This is called from fuse_read_super() so there's guaranteed | ||
474 | to be exactly one request available */ | ||
475 | struct fuse_req *req = fuse_get_request(fc); | ||
476 | struct fuse_init_in *arg = &req->misc.init_in; | 445 | struct fuse_init_in *arg = &req->misc.init_in; |
477 | 446 | ||
478 | arg->major = FUSE_KERNEL_VERSION; | 447 | arg->major = FUSE_KERNEL_VERSION; |
@@ -508,6 +477,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
508 | struct fuse_mount_data d; | 477 | struct fuse_mount_data d; |
509 | struct file *file; | 478 | struct file *file; |
510 | struct dentry *root_dentry; | 479 | struct dentry *root_dentry; |
480 | struct fuse_req *init_req; | ||
511 | int err; | 481 | int err; |
512 | 482 | ||
513 | if (!parse_fuse_opt((char *) data, &d)) | 483 | if (!parse_fuse_opt((char *) data, &d)) |
@@ -554,13 +524,17 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
554 | goto err; | 524 | goto err; |
555 | } | 525 | } |
556 | 526 | ||
527 | init_req = fuse_request_alloc(); | ||
528 | if (!init_req) | ||
529 | goto err_put_root; | ||
530 | |||
557 | err = kobject_set_name(&fc->kobj, "%llu", conn_id()); | 531 | err = kobject_set_name(&fc->kobj, "%llu", conn_id()); |
558 | if (err) | 532 | if (err) |
559 | goto err_put_root; | 533 | goto err_free_req; |
560 | 534 | ||
561 | err = kobject_add(&fc->kobj); | 535 | err = kobject_add(&fc->kobj); |
562 | if (err) | 536 | if (err) |
563 | goto err_put_root; | 537 | goto err_free_req; |
564 | 538 | ||
565 | sb->s_root = root_dentry; | 539 | sb->s_root = root_dentry; |
566 | fc->mounted = 1; | 540 | fc->mounted = 1; |
@@ -574,10 +548,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
574 | */ | 548 | */ |
575 | fput(file); | 549 | fput(file); |
576 | 550 | ||
577 | fuse_send_init(fc); | 551 | fuse_send_init(fc, init_req); |
578 | 552 | ||
579 | return 0; | 553 | return 0; |
580 | 554 | ||
555 | err_free_req: | ||
556 | fuse_request_free(init_req); | ||
581 | err_put_root: | 557 | err_put_root: |
582 | dput(root_dentry); | 558 | dput(root_dentry); |
583 | err: | 559 | err: |