diff options
Diffstat (limited to 'fs/fuse/inode.c')
| -rw-r--r-- | fs/fuse/inode.c | 282 | 
1 files changed, 235 insertions, 47 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index e69a546844d0..c755a0440a66 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c  | |||
| @@ -24,6 +24,13 @@ MODULE_LICENSE("GPL"); | |||
| 24 | 24 | ||
| 25 | spinlock_t fuse_lock; | 25 | spinlock_t fuse_lock; | 
| 26 | static kmem_cache_t *fuse_inode_cachep; | 26 | static kmem_cache_t *fuse_inode_cachep; | 
| 27 | static struct subsystem connections_subsys; | ||
| 28 | |||
| 29 | struct fuse_conn_attr { | ||
| 30 | struct attribute attr; | ||
| 31 | ssize_t (*show)(struct fuse_conn *, char *); | ||
| 32 | ssize_t (*store)(struct fuse_conn *, const char *, size_t); | ||
| 33 | }; | ||
| 27 | 34 | ||
| 28 | #define FUSE_SUPER_MAGIC 0x65735546 | 35 | #define FUSE_SUPER_MAGIC 0x65735546 | 
| 29 | 36 | ||
| @@ -135,12 +142,8 @@ static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) | |||
| 135 | fuse_init_common(inode); | 142 | fuse_init_common(inode); | 
| 136 | init_special_inode(inode, inode->i_mode, | 143 | init_special_inode(inode, inode->i_mode, | 
| 137 | new_decode_dev(attr->rdev)); | 144 | new_decode_dev(attr->rdev)); | 
| 138 | } else { | 145 | } else | 
| 139 | /* Don't let user create weird files */ | 146 | BUG(); | 
| 140 | inode->i_mode = S_IFREG; | ||
| 141 | fuse_init_common(inode); | ||
| 142 | fuse_init_file_inode(inode); | ||
| 143 | } | ||
| 144 | } | 147 | } | 
| 145 | 148 | ||
| 146 | static int fuse_inode_eq(struct inode *inode, void *_nodeidp) | 149 | static int fuse_inode_eq(struct inode *inode, void *_nodeidp) | 
| @@ -193,6 +196,11 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | |||
| 193 | return inode; | 196 | return inode; | 
| 194 | } | 197 | } | 
| 195 | 198 | ||
| 199 | static void fuse_umount_begin(struct super_block *sb) | ||
| 200 | { | ||
| 201 | fuse_abort_conn(get_fuse_conn_super(sb)); | ||
| 202 | } | ||
| 203 | |||
| 196 | static void fuse_put_super(struct super_block *sb) | 204 | static void fuse_put_super(struct super_block *sb) | 
| 197 | { | 205 | { | 
| 198 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 206 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 
| @@ -204,20 +212,20 @@ static void fuse_put_super(struct super_block *sb) | |||
| 204 | 212 | ||
| 205 | spin_lock(&fuse_lock); | 213 | spin_lock(&fuse_lock); | 
| 206 | fc->mounted = 0; | 214 | fc->mounted = 0; | 
| 207 | fc->user_id = 0; | 215 | fc->connected = 0; | 
| 208 | fc->group_id = 0; | 216 | spin_unlock(&fuse_lock); | 
| 209 | fc->flags = 0; | 217 | up_write(&fc->sbput_sem); | 
| 210 | /* Flush all readers on this fs */ | 218 | /* Flush all readers on this fs */ | 
| 211 | wake_up_all(&fc->waitq); | 219 | wake_up_all(&fc->waitq); | 
| 212 | up_write(&fc->sbput_sem); | 220 | kobject_del(&fc->kobj); | 
| 213 | fuse_release_conn(fc); | 221 | kobject_put(&fc->kobj); | 
| 214 | spin_unlock(&fuse_lock); | ||
| 215 | } | 222 | } | 
| 216 | 223 | ||
| 217 | static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) | 224 | static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) | 
| 218 | { | 225 | { | 
| 219 | stbuf->f_type = FUSE_SUPER_MAGIC; | 226 | stbuf->f_type = FUSE_SUPER_MAGIC; | 
| 220 | stbuf->f_bsize = attr->bsize; | 227 | stbuf->f_bsize = attr->bsize; | 
| 228 | stbuf->f_frsize = attr->frsize; | ||
| 221 | stbuf->f_blocks = attr->blocks; | 229 | stbuf->f_blocks = attr->blocks; | 
| 222 | stbuf->f_bfree = attr->bfree; | 230 | stbuf->f_bfree = attr->bfree; | 
| 223 | stbuf->f_bavail = attr->bavail; | 231 | stbuf->f_bavail = attr->bavail; | 
| @@ -238,10 +246,12 @@ static int fuse_statfs(struct super_block *sb, struct kstatfs *buf) | |||
| 238 | if (!req) | 246 | if (!req) | 
| 239 | return -EINTR; | 247 | return -EINTR; | 
| 240 | 248 | ||
| 249 | memset(&outarg, 0, sizeof(outarg)); | ||
| 241 | req->in.numargs = 0; | 250 | req->in.numargs = 0; | 
| 242 | req->in.h.opcode = FUSE_STATFS; | 251 | req->in.h.opcode = FUSE_STATFS; | 
| 243 | req->out.numargs = 1; | 252 | req->out.numargs = 1; | 
| 244 | req->out.args[0].size = sizeof(outarg); | 253 | req->out.args[0].size = | 
| 254 | fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg); | ||
| 245 | req->out.args[0].value = &outarg; | 255 | req->out.args[0].value = &outarg; | 
| 246 | request_send(fc, req); | 256 | request_send(fc, req); | 
| 247 | err = req->out.h.error; | 257 | err = req->out.h.error; | 
| @@ -357,8 +367,10 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
| 357 | return 0; | 367 | return 0; | 
| 358 | } | 368 | } | 
| 359 | 369 | ||
| 360 | static void free_conn(struct fuse_conn *fc) | 370 | static void fuse_conn_release(struct kobject *kobj) | 
| 361 | { | 371 | { | 
| 372 | struct fuse_conn *fc = get_fuse_conn_kobj(kobj); | ||
| 373 | |||
| 362 | while (!list_empty(&fc->unused_list)) { | 374 | while (!list_empty(&fc->unused_list)) { | 
| 363 | struct fuse_req *req; | 375 | struct fuse_req *req; | 
| 364 | req = list_entry(fc->unused_list.next, struct fuse_req, list); | 376 | req = list_entry(fc->unused_list.next, struct fuse_req, list); | 
| @@ -368,33 +380,28 @@ static void free_conn(struct fuse_conn *fc) | |||
| 368 | kfree(fc); | 380 | kfree(fc); | 
| 369 | } | 381 | } | 
| 370 | 382 | ||
| 371 | /* Must be called with the fuse lock held */ | ||
| 372 | void fuse_release_conn(struct fuse_conn *fc) | ||
| 373 | { | ||
| 374 | fc->count--; | ||
| 375 | if (!fc->count) | ||
| 376 | free_conn(fc); | ||
| 377 | } | ||
| 378 | |||
| 379 | static struct fuse_conn *new_conn(void) | 383 | static struct fuse_conn *new_conn(void) | 
| 380 | { | 384 | { | 
| 381 | struct fuse_conn *fc; | 385 | struct fuse_conn *fc; | 
| 382 | 386 | ||
| 383 | fc = kmalloc(sizeof(*fc), GFP_KERNEL); | 387 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); | 
| 384 | if (fc != NULL) { | 388 | if (fc) { | 
| 385 | int i; | 389 | int i; | 
| 386 | memset(fc, 0, sizeof(*fc)); | ||
| 387 | init_waitqueue_head(&fc->waitq); | 390 | init_waitqueue_head(&fc->waitq); | 
| 388 | INIT_LIST_HEAD(&fc->pending); | 391 | INIT_LIST_HEAD(&fc->pending); | 
| 389 | INIT_LIST_HEAD(&fc->processing); | 392 | INIT_LIST_HEAD(&fc->processing); | 
| 393 | INIT_LIST_HEAD(&fc->io); | ||
| 390 | INIT_LIST_HEAD(&fc->unused_list); | 394 | INIT_LIST_HEAD(&fc->unused_list); | 
| 391 | INIT_LIST_HEAD(&fc->background); | 395 | INIT_LIST_HEAD(&fc->background); | 
| 392 | sema_init(&fc->outstanding_sem, 0); | 396 | sema_init(&fc->outstanding_sem, 1); /* One for INIT */ | 
| 393 | init_rwsem(&fc->sbput_sem); | 397 | init_rwsem(&fc->sbput_sem); | 
| 398 | kobj_set_kset_s(fc, connections_subsys); | ||
| 399 | kobject_init(&fc->kobj); | ||
| 400 | atomic_set(&fc->num_waiting, 0); | ||
| 394 | for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { | 401 | for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { | 
| 395 | struct fuse_req *req = fuse_request_alloc(); | 402 | struct fuse_req *req = fuse_request_alloc(); | 
| 396 | if (!req) { | 403 | if (!req) { | 
| 397 | free_conn(fc); | 404 | kobject_put(&fc->kobj); | 
| 398 | return NULL; | 405 | return NULL; | 
| 399 | } | 406 | } | 
| 400 | list_add(&req->list, &fc->unused_list); | 407 | list_add(&req->list, &fc->unused_list); | 
| @@ -409,25 +416,32 @@ static struct fuse_conn *new_conn(void) | |||
| 409 | static struct fuse_conn *get_conn(struct file *file, struct super_block *sb) | 416 | static struct fuse_conn *get_conn(struct file *file, struct super_block *sb) | 
| 410 | { | 417 | { | 
| 411 | struct fuse_conn *fc; | 418 | struct fuse_conn *fc; | 
| 419 | int err; | ||
| 412 | 420 | ||
| 421 | err = -EINVAL; | ||
| 413 | if (file->f_op != &fuse_dev_operations) | 422 | if (file->f_op != &fuse_dev_operations) | 
| 414 | return ERR_PTR(-EINVAL); | 423 | goto out_err; | 
| 424 | |||
| 425 | err = -ENOMEM; | ||
| 415 | fc = new_conn(); | 426 | fc = new_conn(); | 
| 416 | if (fc == NULL) | 427 | if (!fc) | 
| 417 | return ERR_PTR(-ENOMEM); | 428 | goto out_err; | 
| 429 | |||
| 418 | spin_lock(&fuse_lock); | 430 | spin_lock(&fuse_lock); | 
| 419 | if (file->private_data) { | 431 | err = -EINVAL; | 
| 420 | free_conn(fc); | 432 | if (file->private_data) | 
| 421 | fc = ERR_PTR(-EINVAL); | 433 | goto out_unlock; | 
| 422 | } else { | 434 | |
| 423 | file->private_data = fc; | 435 | kobject_get(&fc->kobj); | 
| 424 | *get_fuse_conn_super_p(sb) = fc; | 436 | file->private_data = fc; | 
| 425 | fc->mounted = 1; | ||
| 426 | fc->connected = 1; | ||
| 427 | fc->count = 2; | ||
| 428 | } | ||
| 429 | spin_unlock(&fuse_lock); | 437 | spin_unlock(&fuse_lock); | 
| 430 | return fc; | 438 | return fc; | 
| 439 | |||
| 440 | out_unlock: | ||
| 441 | spin_unlock(&fuse_lock); | ||
| 442 | kobject_put(&fc->kobj); | ||
| 443 | out_err: | ||
| 444 | return ERR_PTR(err); | ||
| 431 | } | 445 | } | 
| 432 | 446 | ||
| 433 | static struct inode *get_root_inode(struct super_block *sb, unsigned mode) | 447 | static struct inode *get_root_inode(struct super_block *sb, unsigned mode) | 
| @@ -446,16 +460,74 @@ static struct super_operations fuse_super_operations = { | |||
| 446 | .read_inode = fuse_read_inode, | 460 | .read_inode = fuse_read_inode, | 
| 447 | .clear_inode = fuse_clear_inode, | 461 | .clear_inode = fuse_clear_inode, | 
| 448 | .put_super = fuse_put_super, | 462 | .put_super = fuse_put_super, | 
| 463 | .umount_begin = fuse_umount_begin, | ||
| 449 | .statfs = fuse_statfs, | 464 | .statfs = fuse_statfs, | 
| 450 | .show_options = fuse_show_options, | 465 | .show_options = fuse_show_options, | 
| 451 | }; | 466 | }; | 
| 452 | 467 | ||
| 468 | static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | ||
| 469 | { | ||
| 470 | int i; | ||
| 471 | struct fuse_init_out *arg = &req->misc.init_out; | ||
| 472 | |||
| 473 | if (req->out.h.error || arg->major != FUSE_KERNEL_VERSION) | ||
| 474 | fc->conn_error = 1; | ||
| 475 | else { | ||
| 476 | fc->minor = arg->minor; | ||
| 477 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; | ||
| 478 | } | ||
| 479 | |||
| 480 | /* After INIT reply is received other requests can go | ||
| 481 | out. So do (FUSE_MAX_OUTSTANDING - 1) number of | ||
| 482 | up()s on outstanding_sem. The last up() is done in | ||
| 483 | fuse_putback_request() */ | ||
| 484 | for (i = 1; i < FUSE_MAX_OUTSTANDING; i++) | ||
| 485 | up(&fc->outstanding_sem); | ||
| 486 | |||
| 487 | fuse_put_request(fc, req); | ||
| 488 | } | ||
| 489 | |||
| 490 | static void fuse_send_init(struct fuse_conn *fc) | ||
| 491 | { | ||
| 492 | /* This is called from fuse_read_super() so there's guaranteed | ||
| 493 | to be exactly one request available */ | ||
| 494 | struct fuse_req *req = fuse_get_request(fc); | ||
| 495 | struct fuse_init_in *arg = &req->misc.init_in; | ||
| 496 | |||
| 497 | arg->major = FUSE_KERNEL_VERSION; | ||
| 498 | arg->minor = FUSE_KERNEL_MINOR_VERSION; | ||
| 499 | req->in.h.opcode = FUSE_INIT; | ||
| 500 | req->in.numargs = 1; | ||
| 501 | req->in.args[0].size = sizeof(*arg); | ||
| 502 | req->in.args[0].value = arg; | ||
| 503 | req->out.numargs = 1; | ||
| 504 | /* Variable length arguement used for backward compatibility | ||
| 505 | with interface version < 7.5. Rest of init_out is zeroed | ||
| 506 | by do_get_request(), so a short reply is not a problem */ | ||
| 507 | req->out.argvar = 1; | ||
| 508 | req->out.args[0].size = sizeof(struct fuse_init_out); | ||
| 509 | req->out.args[0].value = &req->misc.init_out; | ||
| 510 | req->end = process_init_reply; | ||
| 511 | request_send_background(fc, req); | ||
| 512 | } | ||
| 513 | |||
| 514 | static unsigned long long conn_id(void) | ||
| 515 | { | ||
| 516 | static unsigned long long ctr = 1; | ||
| 517 | unsigned long long val; | ||
| 518 | spin_lock(&fuse_lock); | ||
| 519 | val = ctr++; | ||
| 520 | spin_unlock(&fuse_lock); | ||
| 521 | return val; | ||
| 522 | } | ||
| 523 | |||
| 453 | static int fuse_fill_super(struct super_block *sb, void *data, int silent) | 524 | static int fuse_fill_super(struct super_block *sb, void *data, int silent) | 
| 454 | { | 525 | { | 
| 455 | struct fuse_conn *fc; | 526 | struct fuse_conn *fc; | 
| 456 | struct inode *root; | 527 | struct inode *root; | 
| 457 | struct fuse_mount_data d; | 528 | struct fuse_mount_data d; | 
| 458 | struct file *file; | 529 | struct file *file; | 
| 530 | struct dentry *root_dentry; | ||
| 459 | int err; | 531 | int err; | 
| 460 | 532 | ||
| 461 | if (!parse_fuse_opt((char *) data, &d)) | 533 | if (!parse_fuse_opt((char *) data, &d)) | 
| @@ -482,25 +554,43 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
| 482 | fc->max_read = d.max_read; | 554 | fc->max_read = d.max_read; | 
| 483 | if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) | 555 | if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) | 
| 484 | fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; | 556 | fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; | 
| 485 | fc->max_write = FUSE_MAX_IN / 2; | 557 | |
| 558 | /* Used by get_root_inode() */ | ||
| 559 | sb->s_fs_info = fc; | ||
| 486 | 560 | ||
| 487 | err = -ENOMEM; | 561 | err = -ENOMEM; | 
| 488 | root = get_root_inode(sb, d.rootmode); | 562 | root = get_root_inode(sb, d.rootmode); | 
| 489 | if (root == NULL) | 563 | if (!root) | 
| 490 | goto err; | 564 | goto err; | 
| 491 | 565 | ||
| 492 | sb->s_root = d_alloc_root(root); | 566 | root_dentry = d_alloc_root(root); | 
| 493 | if (!sb->s_root) { | 567 | if (!root_dentry) { | 
| 494 | iput(root); | 568 | iput(root); | 
| 495 | goto err; | 569 | goto err; | 
| 496 | } | 570 | } | 
| 571 | |||
| 572 | err = kobject_set_name(&fc->kobj, "%llu", conn_id()); | ||
| 573 | if (err) | ||
| 574 | goto err_put_root; | ||
| 575 | |||
| 576 | err = kobject_add(&fc->kobj); | ||
| 577 | if (err) | ||
| 578 | goto err_put_root; | ||
| 579 | |||
| 580 | sb->s_root = root_dentry; | ||
| 581 | spin_lock(&fuse_lock); | ||
| 582 | fc->mounted = 1; | ||
| 583 | fc->connected = 1; | ||
| 584 | spin_unlock(&fuse_lock); | ||
| 585 | |||
| 497 | fuse_send_init(fc); | 586 | fuse_send_init(fc); | 
| 587 | |||
| 498 | return 0; | 588 | return 0; | 
| 499 | 589 | ||
| 590 | err_put_root: | ||
| 591 | dput(root_dentry); | ||
| 500 | err: | 592 | err: | 
| 501 | spin_lock(&fuse_lock); | 593 | kobject_put(&fc->kobj); | 
| 502 | fuse_release_conn(fc); | ||
| 503 | spin_unlock(&fuse_lock); | ||
| 504 | return err; | 594 | return err; | 
| 505 | } | 595 | } | 
| 506 | 596 | ||
| @@ -518,6 +608,69 @@ static struct file_system_type fuse_fs_type = { | |||
| 518 | .kill_sb = kill_anon_super, | 608 | .kill_sb = kill_anon_super, | 
| 519 | }; | 609 | }; | 
| 520 | 610 | ||
| 611 | static ssize_t fuse_conn_waiting_show(struct fuse_conn *fc, char *page) | ||
| 612 | { | ||
| 613 | return sprintf(page, "%i\n", atomic_read(&fc->num_waiting)); | ||
| 614 | } | ||
| 615 | |||
| 616 | static ssize_t fuse_conn_abort_store(struct fuse_conn *fc, const char *page, | ||
| 617 | size_t count) | ||
| 618 | { | ||
| 619 | fuse_abort_conn(fc); | ||
| 620 | return count; | ||
| 621 | } | ||
| 622 | |||
| 623 | static struct fuse_conn_attr fuse_conn_waiting = | ||
| 624 | __ATTR(waiting, 0400, fuse_conn_waiting_show, NULL); | ||
| 625 | static struct fuse_conn_attr fuse_conn_abort = | ||
| 626 | __ATTR(abort, 0600, NULL, fuse_conn_abort_store); | ||
| 627 | |||
| 628 | static struct attribute *fuse_conn_attrs[] = { | ||
| 629 | &fuse_conn_waiting.attr, | ||
| 630 | &fuse_conn_abort.attr, | ||
| 631 | NULL, | ||
| 632 | }; | ||
| 633 | |||
| 634 | static ssize_t fuse_conn_attr_show(struct kobject *kobj, | ||
| 635 | struct attribute *attr, | ||
| 636 | char *page) | ||
| 637 | { | ||
| 638 | struct fuse_conn_attr *fca = | ||
| 639 | container_of(attr, struct fuse_conn_attr, attr); | ||
| 640 | |||
| 641 | if (fca->show) | ||
| 642 | return fca->show(get_fuse_conn_kobj(kobj), page); | ||
| 643 | else | ||
| 644 | return -EACCES; | ||
| 645 | } | ||
| 646 | |||
| 647 | static ssize_t fuse_conn_attr_store(struct kobject *kobj, | ||
| 648 | struct attribute *attr, | ||
| 649 | const char *page, size_t count) | ||
| 650 | { | ||
| 651 | struct fuse_conn_attr *fca = | ||
| 652 | container_of(attr, struct fuse_conn_attr, attr); | ||
| 653 | |||
| 654 | if (fca->store) | ||
| 655 | return fca->store(get_fuse_conn_kobj(kobj), page, count); | ||
| 656 | else | ||
| 657 | return -EACCES; | ||
| 658 | } | ||
| 659 | |||
| 660 | static struct sysfs_ops fuse_conn_sysfs_ops = { | ||
| 661 | .show = &fuse_conn_attr_show, | ||
| 662 | .store = &fuse_conn_attr_store, | ||
| 663 | }; | ||
| 664 | |||
| 665 | static struct kobj_type ktype_fuse_conn = { | ||
| 666 | .release = fuse_conn_release, | ||
| 667 | .sysfs_ops = &fuse_conn_sysfs_ops, | ||
| 668 | .default_attrs = fuse_conn_attrs, | ||
| 669 | }; | ||
| 670 | |||
| 671 | static decl_subsys(fuse, NULL, NULL); | ||
| 672 | static decl_subsys(connections, &ktype_fuse_conn, NULL); | ||
| 673 | |||
| 521 | static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep, | 674 | static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep, | 
| 522 | unsigned long flags) | 675 | unsigned long flags) | 
| 523 | { | 676 | { | 
| @@ -555,6 +708,34 @@ static void fuse_fs_cleanup(void) | |||
| 555 | kmem_cache_destroy(fuse_inode_cachep); | 708 | kmem_cache_destroy(fuse_inode_cachep); | 
| 556 | } | 709 | } | 
| 557 | 710 | ||
| 711 | static int fuse_sysfs_init(void) | ||
| 712 | { | ||
| 713 | int err; | ||
| 714 | |||
| 715 | kset_set_kset_s(&fuse_subsys, fs_subsys); | ||
| 716 | err = subsystem_register(&fuse_subsys); | ||
| 717 | if (err) | ||
| 718 | goto out_err; | ||
| 719 | |||
| 720 | kset_set_kset_s(&connections_subsys, fuse_subsys); | ||
| 721 | err = subsystem_register(&connections_subsys); | ||
| 722 | if (err) | ||
| 723 | goto out_fuse_unregister; | ||
| 724 | |||
| 725 | return 0; | ||
| 726 | |||
| 727 | out_fuse_unregister: | ||
| 728 | subsystem_unregister(&fuse_subsys); | ||
| 729 | out_err: | ||
| 730 | return err; | ||
| 731 | } | ||
| 732 | |||
| 733 | static void fuse_sysfs_cleanup(void) | ||
| 734 | { | ||
| 735 | subsystem_unregister(&connections_subsys); | ||
| 736 | subsystem_unregister(&fuse_subsys); | ||
| 737 | } | ||
| 738 | |||
| 558 | static int __init fuse_init(void) | 739 | static int __init fuse_init(void) | 
| 559 | { | 740 | { | 
| 560 | int res; | 741 | int res; | 
| @@ -571,8 +752,14 @@ static int __init fuse_init(void) | |||
| 571 | if (res) | 752 | if (res) | 
| 572 | goto err_fs_cleanup; | 753 | goto err_fs_cleanup; | 
| 573 | 754 | ||
| 755 | res = fuse_sysfs_init(); | ||
| 756 | if (res) | ||
| 757 | goto err_dev_cleanup; | ||
| 758 | |||
| 574 | return 0; | 759 | return 0; | 
| 575 | 760 | ||
| 761 | err_dev_cleanup: | ||
| 762 | fuse_dev_cleanup(); | ||
| 576 | err_fs_cleanup: | 763 | err_fs_cleanup: | 
| 577 | fuse_fs_cleanup(); | 764 | fuse_fs_cleanup(); | 
| 578 | err: | 765 | err: | 
| @@ -583,6 +770,7 @@ static void __exit fuse_exit(void) | |||
| 583 | { | 770 | { | 
| 584 | printk(KERN_DEBUG "fuse exit\n"); | 771 | printk(KERN_DEBUG "fuse exit\n"); | 
| 585 | 772 | ||
| 773 | fuse_sysfs_cleanup(); | ||
| 586 | fuse_fs_cleanup(); | 774 | fuse_fs_cleanup(); | 
| 587 | fuse_dev_cleanup(); | 775 | fuse_dev_cleanup(); | 
| 588 | } | 776 | } | 
