diff options
-rw-r--r-- | fs/fuse/dev.c | 4 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 17 | ||||
-rw-r--r-- | fs/fuse/inode.c | 186 |
3 files changed, 164 insertions, 43 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 5cd43bf917a4..de4a0a0bda8a 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -852,9 +852,11 @@ static int fuse_dev_release(struct inode *inode, struct file *file) | |||
852 | fc->connected = 0; | 852 | fc->connected = 0; |
853 | end_requests(fc, &fc->pending); | 853 | end_requests(fc, &fc->pending); |
854 | end_requests(fc, &fc->processing); | 854 | end_requests(fc, &fc->processing); |
855 | fuse_release_conn(fc); | ||
856 | } | 855 | } |
857 | spin_unlock(&fuse_lock); | 856 | spin_unlock(&fuse_lock); |
857 | if (fc) | ||
858 | kobject_put(&fc->kobj); | ||
859 | |||
858 | return 0; | 860 | return 0; |
859 | } | 861 | } |
860 | 862 | ||
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index e824a09d3151..6ef1e5f5873b 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -196,9 +196,6 @@ struct fuse_req { | |||
196 | * unmounted. | 196 | * unmounted. |
197 | */ | 197 | */ |
198 | struct fuse_conn { | 198 | struct fuse_conn { |
199 | /** Reference count */ | ||
200 | int count; | ||
201 | |||
202 | /** The user id for this mount */ | 199 | /** The user id for this mount */ |
203 | uid_t user_id; | 200 | uid_t user_id; |
204 | 201 | ||
@@ -288,6 +285,9 @@ struct fuse_conn { | |||
288 | 285 | ||
289 | /** Backing dev info */ | 286 | /** Backing dev info */ |
290 | struct backing_dev_info bdi; | 287 | struct backing_dev_info bdi; |
288 | |||
289 | /** kobject */ | ||
290 | struct kobject kobj; | ||
291 | }; | 291 | }; |
292 | 292 | ||
293 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) | 293 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) |
@@ -300,6 +300,11 @@ static inline struct fuse_conn *get_fuse_conn(struct inode *inode) | |||
300 | return get_fuse_conn_super(inode->i_sb); | 300 | return get_fuse_conn_super(inode->i_sb); |
301 | } | 301 | } |
302 | 302 | ||
303 | static inline struct fuse_conn *get_fuse_conn_kobj(struct kobject *obj) | ||
304 | { | ||
305 | return container_of(obj, struct fuse_conn, kobj); | ||
306 | } | ||
307 | |||
303 | static inline struct fuse_inode *get_fuse_inode(struct inode *inode) | 308 | static inline struct fuse_inode *get_fuse_inode(struct inode *inode) |
304 | { | 309 | { |
305 | return container_of(inode, struct fuse_inode, inode); | 310 | return container_of(inode, struct fuse_inode, inode); |
@@ -400,12 +405,6 @@ void fuse_init_symlink(struct inode *inode); | |||
400 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr); | 405 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr); |
401 | 406 | ||
402 | /** | 407 | /** |
403 | * Check if the connection can be released, and if yes, then free the | ||
404 | * connection structure | ||
405 | */ | ||
406 | void fuse_release_conn(struct fuse_conn *fc); | ||
407 | |||
408 | /** | ||
409 | * Initialize the client device | 408 | * Initialize the client device |
410 | */ | 409 | */ |
411 | int fuse_dev_init(void); | 410 | int fuse_dev_init(void); |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index d6a09fdaa941..514b700c863d 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 | ||
@@ -201,11 +208,12 @@ static void fuse_put_super(struct super_block *sb) | |||
201 | spin_lock(&fuse_lock); | 208 | spin_lock(&fuse_lock); |
202 | fc->mounted = 0; | 209 | fc->mounted = 0; |
203 | fc->connected = 0; | 210 | fc->connected = 0; |
211 | spin_unlock(&fuse_lock); | ||
212 | up_write(&fc->sbput_sem); | ||
204 | /* Flush all readers on this fs */ | 213 | /* Flush all readers on this fs */ |
205 | wake_up_all(&fc->waitq); | 214 | wake_up_all(&fc->waitq); |
206 | up_write(&fc->sbput_sem); | 215 | kobject_del(&fc->kobj); |
207 | fuse_release_conn(fc); | 216 | kobject_put(&fc->kobj); |
208 | spin_unlock(&fuse_lock); | ||
209 | } | 217 | } |
210 | 218 | ||
211 | static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) | 219 | static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) |
@@ -354,8 +362,10 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
354 | return 0; | 362 | return 0; |
355 | } | 363 | } |
356 | 364 | ||
357 | static void free_conn(struct fuse_conn *fc) | 365 | static void fuse_conn_release(struct kobject *kobj) |
358 | { | 366 | { |
367 | struct fuse_conn *fc = get_fuse_conn_kobj(kobj); | ||
368 | |||
359 | while (!list_empty(&fc->unused_list)) { | 369 | while (!list_empty(&fc->unused_list)) { |
360 | struct fuse_req *req; | 370 | struct fuse_req *req; |
361 | req = list_entry(fc->unused_list.next, struct fuse_req, list); | 371 | req = list_entry(fc->unused_list.next, struct fuse_req, list); |
@@ -365,20 +375,12 @@ static void free_conn(struct fuse_conn *fc) | |||
365 | kfree(fc); | 375 | kfree(fc); |
366 | } | 376 | } |
367 | 377 | ||
368 | /* Must be called with the fuse lock held */ | ||
369 | void fuse_release_conn(struct fuse_conn *fc) | ||
370 | { | ||
371 | fc->count--; | ||
372 | if (!fc->count) | ||
373 | free_conn(fc); | ||
374 | } | ||
375 | |||
376 | static struct fuse_conn *new_conn(void) | 378 | static struct fuse_conn *new_conn(void) |
377 | { | 379 | { |
378 | struct fuse_conn *fc; | 380 | struct fuse_conn *fc; |
379 | 381 | ||
380 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); | 382 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); |
381 | if (fc != NULL) { | 383 | if (fc) { |
382 | int i; | 384 | int i; |
383 | init_waitqueue_head(&fc->waitq); | 385 | init_waitqueue_head(&fc->waitq); |
384 | INIT_LIST_HEAD(&fc->pending); | 386 | INIT_LIST_HEAD(&fc->pending); |
@@ -388,10 +390,12 @@ static struct fuse_conn *new_conn(void) | |||
388 | INIT_LIST_HEAD(&fc->background); | 390 | INIT_LIST_HEAD(&fc->background); |
389 | sema_init(&fc->outstanding_sem, 1); /* One for INIT */ | 391 | sema_init(&fc->outstanding_sem, 1); /* One for INIT */ |
390 | init_rwsem(&fc->sbput_sem); | 392 | init_rwsem(&fc->sbput_sem); |
393 | kobj_set_kset_s(fc, connections_subsys); | ||
394 | kobject_init(&fc->kobj); | ||
391 | for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { | 395 | for (i = 0; i < FUSE_MAX_OUTSTANDING; i++) { |
392 | struct fuse_req *req = fuse_request_alloc(); | 396 | struct fuse_req *req = fuse_request_alloc(); |
393 | if (!req) { | 397 | if (!req) { |
394 | free_conn(fc); | 398 | kobject_put(&fc->kobj); |
395 | return NULL; | 399 | return NULL; |
396 | } | 400 | } |
397 | list_add(&req->list, &fc->unused_list); | 401 | list_add(&req->list, &fc->unused_list); |
@@ -406,25 +410,32 @@ static struct fuse_conn *new_conn(void) | |||
406 | static struct fuse_conn *get_conn(struct file *file, struct super_block *sb) | 410 | static struct fuse_conn *get_conn(struct file *file, struct super_block *sb) |
407 | { | 411 | { |
408 | struct fuse_conn *fc; | 412 | struct fuse_conn *fc; |
413 | int err; | ||
409 | 414 | ||
415 | err = -EINVAL; | ||
410 | if (file->f_op != &fuse_dev_operations) | 416 | if (file->f_op != &fuse_dev_operations) |
411 | return ERR_PTR(-EINVAL); | 417 | goto out_err; |
418 | |||
419 | err = -ENOMEM; | ||
412 | fc = new_conn(); | 420 | fc = new_conn(); |
413 | if (fc == NULL) | 421 | if (!fc) |
414 | return ERR_PTR(-ENOMEM); | 422 | goto out_err; |
423 | |||
415 | spin_lock(&fuse_lock); | 424 | spin_lock(&fuse_lock); |
416 | if (file->private_data) { | 425 | err = -EINVAL; |
417 | free_conn(fc); | 426 | if (file->private_data) |
418 | fc = ERR_PTR(-EINVAL); | 427 | goto out_unlock; |
419 | } else { | 428 | |
420 | file->private_data = fc; | 429 | kobject_get(&fc->kobj); |
421 | sb->s_fs_info = fc; | 430 | file->private_data = fc; |
422 | fc->mounted = 1; | ||
423 | fc->connected = 1; | ||
424 | fc->count = 2; | ||
425 | } | ||
426 | spin_unlock(&fuse_lock); | 431 | spin_unlock(&fuse_lock); |
427 | return fc; | 432 | return fc; |
433 | |||
434 | out_unlock: | ||
435 | spin_unlock(&fuse_lock); | ||
436 | kobject_put(&fc->kobj); | ||
437 | out_err: | ||
438 | return ERR_PTR(err); | ||
428 | } | 439 | } |
429 | 440 | ||
430 | static struct inode *get_root_inode(struct super_block *sb, unsigned mode) | 441 | static struct inode *get_root_inode(struct super_block *sb, unsigned mode) |
@@ -447,12 +458,23 @@ static struct super_operations fuse_super_operations = { | |||
447 | .show_options = fuse_show_options, | 458 | .show_options = fuse_show_options, |
448 | }; | 459 | }; |
449 | 460 | ||
461 | static unsigned long long conn_id(void) | ||
462 | { | ||
463 | static unsigned long long ctr = 1; | ||
464 | unsigned long long val; | ||
465 | spin_lock(&fuse_lock); | ||
466 | val = ctr++; | ||
467 | spin_unlock(&fuse_lock); | ||
468 | return val; | ||
469 | } | ||
470 | |||
450 | static int fuse_fill_super(struct super_block *sb, void *data, int silent) | 471 | static int fuse_fill_super(struct super_block *sb, void *data, int silent) |
451 | { | 472 | { |
452 | struct fuse_conn *fc; | 473 | struct fuse_conn *fc; |
453 | struct inode *root; | 474 | struct inode *root; |
454 | struct fuse_mount_data d; | 475 | struct fuse_mount_data d; |
455 | struct file *file; | 476 | struct file *file; |
477 | struct dentry *root_dentry; | ||
456 | int err; | 478 | int err; |
457 | 479 | ||
458 | if (!parse_fuse_opt((char *) data, &d)) | 480 | if (!parse_fuse_opt((char *) data, &d)) |
@@ -480,23 +502,42 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
480 | if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) | 502 | if (fc->max_read / PAGE_CACHE_SIZE < fc->bdi.ra_pages) |
481 | fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; | 503 | fc->bdi.ra_pages = fc->max_read / PAGE_CACHE_SIZE; |
482 | 504 | ||
505 | /* Used by get_root_inode() */ | ||
506 | sb->s_fs_info = fc; | ||
507 | |||
483 | err = -ENOMEM; | 508 | err = -ENOMEM; |
484 | root = get_root_inode(sb, d.rootmode); | 509 | root = get_root_inode(sb, d.rootmode); |
485 | if (root == NULL) | 510 | if (!root) |
486 | goto err; | 511 | goto err; |
487 | 512 | ||
488 | sb->s_root = d_alloc_root(root); | 513 | root_dentry = d_alloc_root(root); |
489 | if (!sb->s_root) { | 514 | if (!root_dentry) { |
490 | iput(root); | 515 | iput(root); |
491 | goto err; | 516 | goto err; |
492 | } | 517 | } |
518 | |||
519 | err = kobject_set_name(&fc->kobj, "%llu", conn_id()); | ||
520 | if (err) | ||
521 | goto err_put_root; | ||
522 | |||
523 | err = kobject_add(&fc->kobj); | ||
524 | if (err) | ||
525 | goto err_put_root; | ||
526 | |||
527 | sb->s_root = root_dentry; | ||
528 | spin_lock(&fuse_lock); | ||
529 | fc->mounted = 1; | ||
530 | fc->connected = 1; | ||
531 | spin_unlock(&fuse_lock); | ||
532 | |||
493 | fuse_send_init(fc); | 533 | fuse_send_init(fc); |
534 | |||
494 | return 0; | 535 | return 0; |
495 | 536 | ||
537 | err_put_root: | ||
538 | dput(root_dentry); | ||
496 | err: | 539 | err: |
497 | spin_lock(&fuse_lock); | 540 | kobject_put(&fc->kobj); |
498 | fuse_release_conn(fc); | ||
499 | spin_unlock(&fuse_lock); | ||
500 | return err; | 541 | return err; |
501 | } | 542 | } |
502 | 543 | ||
@@ -514,6 +555,50 @@ static struct file_system_type fuse_fs_type = { | |||
514 | .kill_sb = kill_anon_super, | 555 | .kill_sb = kill_anon_super, |
515 | }; | 556 | }; |
516 | 557 | ||
558 | static struct attribute *fuse_conn_attrs[] = { | ||
559 | NULL, | ||
560 | }; | ||
561 | |||
562 | static ssize_t fuse_conn_attr_show(struct kobject *kobj, | ||
563 | struct attribute *attr, | ||
564 | char *page) | ||
565 | { | ||
566 | struct fuse_conn_attr *fca = | ||
567 | container_of(attr, struct fuse_conn_attr, attr); | ||
568 | |||
569 | if (fca->show) | ||
570 | return fca->show(get_fuse_conn_kobj(kobj), page); | ||
571 | else | ||
572 | return -EACCES; | ||
573 | } | ||
574 | |||
575 | static ssize_t fuse_conn_attr_store(struct kobject *kobj, | ||
576 | struct attribute *attr, | ||
577 | const char *page, size_t count) | ||
578 | { | ||
579 | struct fuse_conn_attr *fca = | ||
580 | container_of(attr, struct fuse_conn_attr, attr); | ||
581 | |||
582 | if (fca->store) | ||
583 | return fca->store(get_fuse_conn_kobj(kobj), page, count); | ||
584 | else | ||
585 | return -EACCES; | ||
586 | } | ||
587 | |||
588 | static struct sysfs_ops fuse_conn_sysfs_ops = { | ||
589 | .show = &fuse_conn_attr_show, | ||
590 | .store = &fuse_conn_attr_store, | ||
591 | }; | ||
592 | |||
593 | static struct kobj_type ktype_fuse_conn = { | ||
594 | .release = fuse_conn_release, | ||
595 | .sysfs_ops = &fuse_conn_sysfs_ops, | ||
596 | .default_attrs = fuse_conn_attrs, | ||
597 | }; | ||
598 | |||
599 | static decl_subsys(fuse, NULL, NULL); | ||
600 | static decl_subsys(connections, &ktype_fuse_conn, NULL); | ||
601 | |||
517 | static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep, | 602 | static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep, |
518 | unsigned long flags) | 603 | unsigned long flags) |
519 | { | 604 | { |
@@ -551,6 +636,34 @@ static void fuse_fs_cleanup(void) | |||
551 | kmem_cache_destroy(fuse_inode_cachep); | 636 | kmem_cache_destroy(fuse_inode_cachep); |
552 | } | 637 | } |
553 | 638 | ||
639 | static int fuse_sysfs_init(void) | ||
640 | { | ||
641 | int err; | ||
642 | |||
643 | kset_set_kset_s(&fuse_subsys, fs_subsys); | ||
644 | err = subsystem_register(&fuse_subsys); | ||
645 | if (err) | ||
646 | goto out_err; | ||
647 | |||
648 | kset_set_kset_s(&connections_subsys, fuse_subsys); | ||
649 | err = subsystem_register(&connections_subsys); | ||
650 | if (err) | ||
651 | goto out_fuse_unregister; | ||
652 | |||
653 | return 0; | ||
654 | |||
655 | out_fuse_unregister: | ||
656 | subsystem_unregister(&fuse_subsys); | ||
657 | out_err: | ||
658 | return err; | ||
659 | } | ||
660 | |||
661 | static void fuse_sysfs_cleanup(void) | ||
662 | { | ||
663 | subsystem_unregister(&connections_subsys); | ||
664 | subsystem_unregister(&fuse_subsys); | ||
665 | } | ||
666 | |||
554 | static int __init fuse_init(void) | 667 | static int __init fuse_init(void) |
555 | { | 668 | { |
556 | int res; | 669 | int res; |
@@ -567,8 +680,14 @@ static int __init fuse_init(void) | |||
567 | if (res) | 680 | if (res) |
568 | goto err_fs_cleanup; | 681 | goto err_fs_cleanup; |
569 | 682 | ||
683 | res = fuse_sysfs_init(); | ||
684 | if (res) | ||
685 | goto err_dev_cleanup; | ||
686 | |||
570 | return 0; | 687 | return 0; |
571 | 688 | ||
689 | err_dev_cleanup: | ||
690 | fuse_dev_cleanup(); | ||
572 | err_fs_cleanup: | 691 | err_fs_cleanup: |
573 | fuse_fs_cleanup(); | 692 | fuse_fs_cleanup(); |
574 | err: | 693 | err: |
@@ -579,6 +698,7 @@ static void __exit fuse_exit(void) | |||
579 | { | 698 | { |
580 | printk(KERN_DEBUG "fuse exit\n"); | 699 | printk(KERN_DEBUG "fuse exit\n"); |
581 | 700 | ||
701 | fuse_sysfs_cleanup(); | ||
582 | fuse_fs_cleanup(); | 702 | fuse_fs_cleanup(); |
583 | fuse_dev_cleanup(); | 703 | fuse_dev_cleanup(); |
584 | } | 704 | } |