aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/inode.c
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2006-06-25 08:48:51 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:01:19 -0400
commitbafa96541b250a7051e3fbc5de6e8369daf8ffec (patch)
tree9b758c424fcda2d263c71f25358bb65a0abc15d4 /fs/fuse/inode.c
parent51eb01e73599efb88c6c20b1c226d20309a75450 (diff)
[PATCH] fuse: add control filesystem
Add a control filesystem to fuse, replacing the attributes currently exported through sysfs. An empty directory '/sys/fs/fuse/connections' is still created in sysfs, and mounting the control filesystem here provides backward compatibility. Advantages of the control filesystem over the previous solution: - allows the object directory and the attributes to be owned by the filesystem owner, hence letting unpriviled users abort the filesystem connection - does not suffer from module unload race [akpm@osdl.org: fix this fs for recent dhowells depredations] [akpm@osdl.org: fix 64-bit printk warnings] 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.c141
1 files changed, 44 insertions, 97 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 0225729977c4..13a7e8ab7a78 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -22,13 +22,8 @@ MODULE_DESCRIPTION("Filesystem in Userspace");
22MODULE_LICENSE("GPL"); 22MODULE_LICENSE("GPL");
23 23
24static kmem_cache_t *fuse_inode_cachep; 24static kmem_cache_t *fuse_inode_cachep;
25static struct subsystem connections_subsys; 25struct list_head fuse_conn_list;
26 26DEFINE_MUTEX(fuse_mutex);
27struct fuse_conn_attr {
28 struct attribute attr;
29 ssize_t (*show)(struct fuse_conn *, char *);
30 ssize_t (*store)(struct fuse_conn *, const char *, size_t);
31};
32 27
33#define FUSE_SUPER_MAGIC 0x65735546 28#define FUSE_SUPER_MAGIC 0x65735546
34 29
@@ -211,8 +206,11 @@ static void fuse_put_super(struct super_block *sb)
211 kill_fasync(&fc->fasync, SIGIO, POLL_IN); 206 kill_fasync(&fc->fasync, SIGIO, POLL_IN);
212 wake_up_all(&fc->waitq); 207 wake_up_all(&fc->waitq);
213 wake_up_all(&fc->blocked_waitq); 208 wake_up_all(&fc->blocked_waitq);
214 kobject_del(&fc->kobj); 209 mutex_lock(&fuse_mutex);
215 kobject_put(&fc->kobj); 210 list_del(&fc->entry);
211 fuse_ctl_remove_conn(fc);
212 mutex_unlock(&fuse_mutex);
213 fuse_conn_put(fc);
216} 214}
217 215
218static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) 216static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr)
@@ -362,11 +360,6 @@ static int fuse_show_options(struct seq_file *m, struct vfsmount *mnt)
362 return 0; 360 return 0;
363} 361}
364 362
365static void fuse_conn_release(struct kobject *kobj)
366{
367 kfree(get_fuse_conn_kobj(kobj));
368}
369
370static struct fuse_conn *new_conn(void) 363static struct fuse_conn *new_conn(void)
371{ 364{
372 struct fuse_conn *fc; 365 struct fuse_conn *fc;
@@ -374,13 +367,12 @@ static struct fuse_conn *new_conn(void)
374 fc = kzalloc(sizeof(*fc), GFP_KERNEL); 367 fc = kzalloc(sizeof(*fc), GFP_KERNEL);
375 if (fc) { 368 if (fc) {
376 spin_lock_init(&fc->lock); 369 spin_lock_init(&fc->lock);
370 atomic_set(&fc->count, 1);
377 init_waitqueue_head(&fc->waitq); 371 init_waitqueue_head(&fc->waitq);
378 init_waitqueue_head(&fc->blocked_waitq); 372 init_waitqueue_head(&fc->blocked_waitq);
379 INIT_LIST_HEAD(&fc->pending); 373 INIT_LIST_HEAD(&fc->pending);
380 INIT_LIST_HEAD(&fc->processing); 374 INIT_LIST_HEAD(&fc->processing);
381 INIT_LIST_HEAD(&fc->io); 375 INIT_LIST_HEAD(&fc->io);
382 kobj_set_kset_s(fc, connections_subsys);
383 kobject_init(&fc->kobj);
384 atomic_set(&fc->num_waiting, 0); 376 atomic_set(&fc->num_waiting, 0);
385 fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; 377 fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
386 fc->bdi.unplug_io_fn = default_unplug_io_fn; 378 fc->bdi.unplug_io_fn = default_unplug_io_fn;
@@ -390,6 +382,18 @@ static struct fuse_conn *new_conn(void)
390 return fc; 382 return fc;
391} 383}
392 384
385void fuse_conn_put(struct fuse_conn *fc)
386{
387 if (atomic_dec_and_test(&fc->count))
388 kfree(fc);
389}
390
391struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
392{
393 atomic_inc(&fc->count);
394 return fc;
395}
396
393static struct inode *get_root_inode(struct super_block *sb, unsigned mode) 397static struct inode *get_root_inode(struct super_block *sb, unsigned mode)
394{ 398{
395 struct fuse_attr attr; 399 struct fuse_attr attr;
@@ -459,10 +463,9 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
459 request_send_background(fc, req); 463 request_send_background(fc, req);
460} 464}
461 465
462static unsigned long long conn_id(void) 466static u64 conn_id(void)
463{ 467{
464 /* BKL is held for ->get_sb() */ 468 static u64 ctr = 1;
465 static unsigned long long ctr = 1;
466 return ctr++; 469 return ctr++;
467} 470}
468 471
@@ -519,24 +522,21 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
519 if (!init_req) 522 if (!init_req)
520 goto err_put_root; 523 goto err_put_root;
521 524
522 err = kobject_set_name(&fc->kobj, "%llu", conn_id()); 525 mutex_lock(&fuse_mutex);
523 if (err)
524 goto err_free_req;
525
526 err = kobject_add(&fc->kobj);
527 if (err)
528 goto err_free_req;
529
530 /* Setting file->private_data can't race with other mount()
531 instances, since BKL is held for ->get_sb() */
532 err = -EINVAL; 526 err = -EINVAL;
533 if (file->private_data) 527 if (file->private_data)
534 goto err_kobject_del; 528 goto err_unlock;
535 529
530 fc->id = conn_id();
531 err = fuse_ctl_add_conn(fc);
532 if (err)
533 goto err_unlock;
534
535 list_add_tail(&fc->entry, &fuse_conn_list);
536 sb->s_root = root_dentry; 536 sb->s_root = root_dentry;
537 fc->connected = 1; 537 fc->connected = 1;
538 kobject_get(&fc->kobj); 538 file->private_data = fuse_conn_get(fc);
539 file->private_data = fc; 539 mutex_unlock(&fuse_mutex);
540 /* 540 /*
541 * atomic_dec_and_test() in fput() provides the necessary 541 * atomic_dec_and_test() in fput() provides the necessary
542 * memory barrier for file->private_data to be visible on all 542 * memory barrier for file->private_data to be visible on all
@@ -548,15 +548,14 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
548 548
549 return 0; 549 return 0;
550 550
551 err_kobject_del: 551 err_unlock:
552 kobject_del(&fc->kobj); 552 mutex_unlock(&fuse_mutex);
553 err_free_req:
554 fuse_request_free(init_req); 553 fuse_request_free(init_req);
555 err_put_root: 554 err_put_root:
556 dput(root_dentry); 555 dput(root_dentry);
557 err: 556 err:
558 fput(file); 557 fput(file);
559 kobject_put(&fc->kobj); 558 fuse_conn_put(fc);
560 return err; 559 return err;
561} 560}
562 561
@@ -574,68 +573,8 @@ static struct file_system_type fuse_fs_type = {
574 .kill_sb = kill_anon_super, 573 .kill_sb = kill_anon_super,
575}; 574};
576 575
577static ssize_t fuse_conn_waiting_show(struct fuse_conn *fc, char *page)
578{
579 return sprintf(page, "%i\n", atomic_read(&fc->num_waiting));
580}
581
582static ssize_t fuse_conn_abort_store(struct fuse_conn *fc, const char *page,
583 size_t count)
584{
585 fuse_abort_conn(fc);
586 return count;
587}
588
589static struct fuse_conn_attr fuse_conn_waiting =
590 __ATTR(waiting, 0400, fuse_conn_waiting_show, NULL);
591static struct fuse_conn_attr fuse_conn_abort =
592 __ATTR(abort, 0600, NULL, fuse_conn_abort_store);
593
594static struct attribute *fuse_conn_attrs[] = {
595 &fuse_conn_waiting.attr,
596 &fuse_conn_abort.attr,
597 NULL,
598};
599
600static ssize_t fuse_conn_attr_show(struct kobject *kobj,
601 struct attribute *attr,
602 char *page)
603{
604 struct fuse_conn_attr *fca =
605 container_of(attr, struct fuse_conn_attr, attr);
606
607 if (fca->show)
608 return fca->show(get_fuse_conn_kobj(kobj), page);
609 else
610 return -EACCES;
611}
612
613static ssize_t fuse_conn_attr_store(struct kobject *kobj,
614 struct attribute *attr,
615 const char *page, size_t count)
616{
617 struct fuse_conn_attr *fca =
618 container_of(attr, struct fuse_conn_attr, attr);
619
620 if (fca->store)
621 return fca->store(get_fuse_conn_kobj(kobj), page, count);
622 else
623 return -EACCES;
624}
625
626static struct sysfs_ops fuse_conn_sysfs_ops = {
627 .show = &fuse_conn_attr_show,
628 .store = &fuse_conn_attr_store,
629};
630
631static struct kobj_type ktype_fuse_conn = {
632 .release = fuse_conn_release,
633 .sysfs_ops = &fuse_conn_sysfs_ops,
634 .default_attrs = fuse_conn_attrs,
635};
636
637static decl_subsys(fuse, NULL, NULL); 576static decl_subsys(fuse, NULL, NULL);
638static decl_subsys(connections, &ktype_fuse_conn, NULL); 577static decl_subsys(connections, NULL, NULL);
639 578
640static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep, 579static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep,
641 unsigned long flags) 580 unsigned long flags)
@@ -709,6 +648,7 @@ static int __init fuse_init(void)
709 printk("fuse init (API version %i.%i)\n", 648 printk("fuse init (API version %i.%i)\n",
710 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); 649 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
711 650
651 INIT_LIST_HEAD(&fuse_conn_list);
712 res = fuse_fs_init(); 652 res = fuse_fs_init();
713 if (res) 653 if (res)
714 goto err; 654 goto err;
@@ -721,8 +661,14 @@ static int __init fuse_init(void)
721 if (res) 661 if (res)
722 goto err_dev_cleanup; 662 goto err_dev_cleanup;
723 663
664 res = fuse_ctl_init();
665 if (res)
666 goto err_sysfs_cleanup;
667
724 return 0; 668 return 0;
725 669
670 err_sysfs_cleanup:
671 fuse_sysfs_cleanup();
726 err_dev_cleanup: 672 err_dev_cleanup:
727 fuse_dev_cleanup(); 673 fuse_dev_cleanup();
728 err_fs_cleanup: 674 err_fs_cleanup:
@@ -735,6 +681,7 @@ static void __exit fuse_exit(void)
735{ 681{
736 printk(KERN_DEBUG "fuse exit\n"); 682 printk(KERN_DEBUG "fuse exit\n");
737 683
684 fuse_ctl_cleanup();
738 fuse_sysfs_cleanup(); 685 fuse_sysfs_cleanup();
739 fuse_fs_cleanup(); 686 fuse_fs_cleanup();
740 fuse_dev_cleanup(); 687 fuse_dev_cleanup();