Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Miklos Szeredi and committed by
Linus Torvalds
bafa9654 51eb01e7

+331 -115
+21 -9
Documentation/filesystems/fuse.txt
··· 18 18 user. NOTE: this is not the same as mounts allowed with the "user" 19 19 option in /etc/fstab, which is not discussed here. 20 20 21 + Filesystem connection: 22 + 23 + A connection between the filesystem daemon and the kernel. The 24 + connection exists until either the daemon dies, or the filesystem is 25 + umounted. Note that detaching (or lazy umounting) the filesystem 26 + does _not_ break the connection, in this case it will exist until 27 + the last reference to the filesystem is released. 28 + 21 29 Mount owner: 22 30 23 31 The user who does the mounting. ··· 94 86 The default is infinite. Note that the size of read requests is 95 87 limited anyway to 32 pages (which is 128kbyte on i386). 96 88 97 - Sysfs 98 - ~~~~~ 89 + Control filesystem 90 + ~~~~~~~~~~~~~~~~~~ 99 91 100 - FUSE sets up the following hierarchy in sysfs: 92 + There's a control filesystem for FUSE, which can be mounted by: 101 93 102 - /sys/fs/fuse/connections/N/ 94 + mount -t fusectl none /sys/fs/fuse/connections 103 95 104 - where N is an increasing number allocated to each new connection. 96 + Mounting it under the '/sys/fs/fuse/connections' directory makes it 97 + backwards compatible with earlier versions. 105 98 106 - For each connection the following attributes are defined: 99 + Under the fuse control filesystem each connection has a directory 100 + named by a unique number. 101 + 102 + For each connection the following files exist within this directory: 107 103 108 104 'waiting' 109 105 ··· 122 110 connection. This means that all waiting requests will be aborted an 123 111 error returned for all aborted and new requests. 124 112 125 - Only a privileged user may read or write these attributes. 113 + Only the owner of the mount may read or write these files. 126 114 127 115 Aborting a filesystem connection 128 116 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ··· 151 139 - Use forced umount (umount -f). Works in all cases but only if 152 140 filesystem is still attached (it hasn't been lazy unmounted) 153 141 154 - - Abort filesystem through the sysfs interface. Most powerful 155 - method, always works. 142 + - Abort filesystem through the FUSE control filesystem. Most 143 + powerful method, always works. 156 144 157 145 How do non-privileged mounts work? 158 146 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+1 -1
fs/fuse/Makefile
··· 4 4 5 5 obj-$(CONFIG_FUSE_FS) += fuse.o 6 6 7 - fuse-objs := dev.o dir.o file.o inode.o 7 + fuse-objs := dev.o dir.o file.o inode.o control.o
+218
fs/fuse/control.c
··· 1 + /* 2 + FUSE: Filesystem in Userspace 3 + Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> 4 + 5 + This program can be distributed under the terms of the GNU GPL. 6 + See the file COPYING. 7 + */ 8 + 9 + #include "fuse_i.h" 10 + 11 + #include <linux/init.h> 12 + #include <linux/module.h> 13 + 14 + #define FUSE_CTL_SUPER_MAGIC 0x65735543 15 + 16 + /* 17 + * This is non-NULL when the single instance of the control filesystem 18 + * exists. Protected by fuse_mutex 19 + */ 20 + static struct super_block *fuse_control_sb; 21 + 22 + static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file) 23 + { 24 + struct fuse_conn *fc; 25 + mutex_lock(&fuse_mutex); 26 + fc = file->f_dentry->d_inode->u.generic_ip; 27 + if (fc) 28 + fc = fuse_conn_get(fc); 29 + mutex_unlock(&fuse_mutex); 30 + return fc; 31 + } 32 + 33 + static ssize_t fuse_conn_abort_write(struct file *file, const char __user *buf, 34 + size_t count, loff_t *ppos) 35 + { 36 + struct fuse_conn *fc = fuse_ctl_file_conn_get(file); 37 + if (fc) { 38 + fuse_abort_conn(fc); 39 + fuse_conn_put(fc); 40 + } 41 + return count; 42 + } 43 + 44 + static ssize_t fuse_conn_waiting_read(struct file *file, char __user *buf, 45 + size_t len, loff_t *ppos) 46 + { 47 + char tmp[32]; 48 + size_t size; 49 + 50 + if (!*ppos) { 51 + struct fuse_conn *fc = fuse_ctl_file_conn_get(file); 52 + if (!fc) 53 + return 0; 54 + 55 + file->private_data=(void *)(long)atomic_read(&fc->num_waiting); 56 + fuse_conn_put(fc); 57 + } 58 + size = sprintf(tmp, "%ld\n", (long)file->private_data); 59 + return simple_read_from_buffer(buf, len, ppos, tmp, size); 60 + } 61 + 62 + static const struct file_operations fuse_ctl_abort_ops = { 63 + .open = nonseekable_open, 64 + .write = fuse_conn_abort_write, 65 + }; 66 + 67 + static const struct file_operations fuse_ctl_waiting_ops = { 68 + .open = nonseekable_open, 69 + .read = fuse_conn_waiting_read, 70 + }; 71 + 72 + static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, 73 + struct fuse_conn *fc, 74 + const char *name, 75 + int mode, int nlink, 76 + struct inode_operations *iop, 77 + const struct file_operations *fop) 78 + { 79 + struct dentry *dentry; 80 + struct inode *inode; 81 + 82 + BUG_ON(fc->ctl_ndents >= FUSE_CTL_NUM_DENTRIES); 83 + dentry = d_alloc_name(parent, name); 84 + if (!dentry) 85 + return NULL; 86 + 87 + fc->ctl_dentry[fc->ctl_ndents++] = dentry; 88 + inode = new_inode(fuse_control_sb); 89 + if (!inode) 90 + return NULL; 91 + 92 + inode->i_mode = mode; 93 + inode->i_uid = fc->user_id; 94 + inode->i_gid = fc->group_id; 95 + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 96 + /* setting ->i_op to NULL is not allowed */ 97 + if (iop) 98 + inode->i_op = iop; 99 + inode->i_fop = fop; 100 + inode->i_nlink = nlink; 101 + inode->u.generic_ip = fc; 102 + d_add(dentry, inode); 103 + return dentry; 104 + } 105 + 106 + /* 107 + * Add a connection to the control filesystem (if it exists). Caller 108 + * must host fuse_mutex 109 + */ 110 + int fuse_ctl_add_conn(struct fuse_conn *fc) 111 + { 112 + struct dentry *parent; 113 + char name[32]; 114 + 115 + if (!fuse_control_sb) 116 + return 0; 117 + 118 + parent = fuse_control_sb->s_root; 119 + parent->d_inode->i_nlink++; 120 + sprintf(name, "%llu", (unsigned long long) fc->id); 121 + parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2, 122 + &simple_dir_inode_operations, 123 + &simple_dir_operations); 124 + if (!parent) 125 + goto err; 126 + 127 + if (!fuse_ctl_add_dentry(parent, fc, "waiting", S_IFREG | 0400, 1, 128 + NULL, &fuse_ctl_waiting_ops) || 129 + !fuse_ctl_add_dentry(parent, fc, "abort", S_IFREG | 0200, 1, 130 + NULL, &fuse_ctl_abort_ops)) 131 + goto err; 132 + 133 + return 0; 134 + 135 + err: 136 + fuse_ctl_remove_conn(fc); 137 + return -ENOMEM; 138 + } 139 + 140 + /* 141 + * Remove a connection from the control filesystem (if it exists). 142 + * Caller must host fuse_mutex 143 + */ 144 + void fuse_ctl_remove_conn(struct fuse_conn *fc) 145 + { 146 + int i; 147 + 148 + if (!fuse_control_sb) 149 + return; 150 + 151 + for (i = fc->ctl_ndents - 1; i >= 0; i--) { 152 + struct dentry *dentry = fc->ctl_dentry[i]; 153 + dentry->d_inode->u.generic_ip = NULL; 154 + d_drop(dentry); 155 + dput(dentry); 156 + } 157 + fuse_control_sb->s_root->d_inode->i_nlink--; 158 + } 159 + 160 + static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent) 161 + { 162 + struct tree_descr empty_descr = {""}; 163 + struct fuse_conn *fc; 164 + int err; 165 + 166 + err = simple_fill_super(sb, FUSE_CTL_SUPER_MAGIC, &empty_descr); 167 + if (err) 168 + return err; 169 + 170 + mutex_lock(&fuse_mutex); 171 + BUG_ON(fuse_control_sb); 172 + fuse_control_sb = sb; 173 + list_for_each_entry(fc, &fuse_conn_list, entry) { 174 + err = fuse_ctl_add_conn(fc); 175 + if (err) { 176 + fuse_control_sb = NULL; 177 + mutex_unlock(&fuse_mutex); 178 + return err; 179 + } 180 + } 181 + mutex_unlock(&fuse_mutex); 182 + 183 + return 0; 184 + } 185 + 186 + static int fuse_ctl_get_sb(struct file_system_type *fs_type, int flags, 187 + const char *dev_name, void *raw_data, 188 + struct vfsmount *mnt) 189 + { 190 + return get_sb_single(fs_type, flags, raw_data, 191 + fuse_ctl_fill_super, mnt); 192 + } 193 + 194 + static void fuse_ctl_kill_sb(struct super_block *sb) 195 + { 196 + mutex_lock(&fuse_mutex); 197 + fuse_control_sb = NULL; 198 + mutex_unlock(&fuse_mutex); 199 + 200 + kill_litter_super(sb); 201 + } 202 + 203 + static struct file_system_type fuse_ctl_fs_type = { 204 + .owner = THIS_MODULE, 205 + .name = "fusectl", 206 + .get_sb = fuse_ctl_get_sb, 207 + .kill_sb = fuse_ctl_kill_sb, 208 + }; 209 + 210 + int __init fuse_ctl_init(void) 211 + { 212 + return register_filesystem(&fuse_ctl_fs_type); 213 + } 214 + 215 + void fuse_ctl_cleanup(void) 216 + { 217 + unregister_filesystem(&fuse_ctl_fs_type); 218 + }
+1 -1
fs/fuse/dev.c
··· 833 833 end_requests(fc, &fc->processing); 834 834 spin_unlock(&fc->lock); 835 835 fasync_helper(-1, file, 0, &fc->fasync); 836 - kobject_put(&fc->kobj); 836 + fuse_conn_put(fc); 837 837 } 838 838 839 839 return 0;
+46 -7
fs/fuse/fuse_i.h
··· 14 14 #include <linux/spinlock.h> 15 15 #include <linux/mm.h> 16 16 #include <linux/backing-dev.h> 17 + #include <linux/mutex.h> 17 18 18 19 /** Max number of pages that can be used in a single read request */ 19 20 #define FUSE_MAX_PAGES_PER_REQ 32 ··· 25 24 /** It could be as large as PATH_MAX, but would that have any uses? */ 26 25 #define FUSE_NAME_MAX 1024 27 26 27 + /** Number of dentries for each connection in the control filesystem */ 28 + #define FUSE_CTL_NUM_DENTRIES 3 29 + 28 30 /** If the FUSE_DEFAULT_PERMISSIONS flag is given, the filesystem 29 31 module will check permissions based on the file mode. Otherwise no 30 32 permission checking is done in the kernel */ ··· 37 33 doing the mount will be allowed to access the filesystem */ 38 34 #define FUSE_ALLOW_OTHER (1 << 1) 39 35 36 + /** List of active connections */ 37 + extern struct list_head fuse_conn_list; 38 + 39 + /** Global mutex protecting fuse_conn_list and the control filesystem */ 40 + extern struct mutex fuse_mutex; 40 41 41 42 /** FUSE inode */ 42 43 struct fuse_inode { ··· 225 216 /** Lock protecting accessess to members of this structure */ 226 217 spinlock_t lock; 227 218 219 + /** Refcount */ 220 + atomic_t count; 221 + 228 222 /** The user id for this mount */ 229 223 uid_t user_id; 230 224 ··· 322 310 /** Backing dev info */ 323 311 struct backing_dev_info bdi; 324 312 325 - /** kobject */ 326 - struct kobject kobj; 313 + /** Entry on the fuse_conn_list */ 314 + struct list_head entry; 315 + 316 + /** Unique ID */ 317 + u64 id; 318 + 319 + /** Dentries in the control filesystem */ 320 + struct dentry *ctl_dentry[FUSE_CTL_NUM_DENTRIES]; 321 + 322 + /** number of dentries used in the above array */ 323 + int ctl_ndents; 327 324 328 325 /** O_ASYNC requests */ 329 326 struct fasync_struct *fasync; ··· 346 325 static inline struct fuse_conn *get_fuse_conn(struct inode *inode) 347 326 { 348 327 return get_fuse_conn_super(inode->i_sb); 349 - } 350 - 351 - static inline struct fuse_conn *get_fuse_conn_kobj(struct kobject *obj) 352 - { 353 - return container_of(obj, struct fuse_conn, kobj); 354 328 } 355 329 356 330 static inline struct fuse_inode *get_fuse_inode(struct inode *inode) ··· 438 422 */ 439 423 void fuse_dev_cleanup(void); 440 424 425 + int fuse_ctl_init(void); 426 + void fuse_ctl_cleanup(void); 427 + 441 428 /** 442 429 * Allocate a request 443 430 */ ··· 489 470 * Invalidate inode attributes 490 471 */ 491 472 void fuse_invalidate_attr(struct inode *inode); 473 + 474 + /** 475 + * Acquire reference to fuse_conn 476 + */ 477 + struct fuse_conn *fuse_conn_get(struct fuse_conn *fc); 478 + 479 + /** 480 + * Release reference to fuse_conn 481 + */ 482 + void fuse_conn_put(struct fuse_conn *fc); 483 + 484 + /** 485 + * Add connection to control filesystem 486 + */ 487 + int fuse_ctl_add_conn(struct fuse_conn *fc); 488 + 489 + /** 490 + * Remove connection from control filesystem 491 + */ 492 + void fuse_ctl_remove_conn(struct fuse_conn *fc);
+44 -97
fs/fuse/inode.c
··· 22 22 MODULE_LICENSE("GPL"); 23 23 24 24 static kmem_cache_t *fuse_inode_cachep; 25 - static struct subsystem connections_subsys; 26 - 27 - struct 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 - }; 25 + struct list_head fuse_conn_list; 26 + DEFINE_MUTEX(fuse_mutex); 32 27 33 28 #define FUSE_SUPER_MAGIC 0x65735546 34 29 ··· 206 211 kill_fasync(&fc->fasync, SIGIO, POLL_IN); 207 212 wake_up_all(&fc->waitq); 208 213 wake_up_all(&fc->blocked_waitq); 209 - kobject_del(&fc->kobj); 210 - kobject_put(&fc->kobj); 214 + mutex_lock(&fuse_mutex); 215 + list_del(&fc->entry); 216 + fuse_ctl_remove_conn(fc); 217 + mutex_unlock(&fuse_mutex); 218 + fuse_conn_put(fc); 211 219 } 212 220 213 221 static void convert_fuse_statfs(struct kstatfs *stbuf, struct fuse_kstatfs *attr) ··· 360 362 return 0; 361 363 } 362 364 363 - static void fuse_conn_release(struct kobject *kobj) 364 - { 365 - kfree(get_fuse_conn_kobj(kobj)); 366 - } 367 - 368 365 static struct fuse_conn *new_conn(void) 369 366 { 370 367 struct fuse_conn *fc; ··· 367 374 fc = kzalloc(sizeof(*fc), GFP_KERNEL); 368 375 if (fc) { 369 376 spin_lock_init(&fc->lock); 377 + atomic_set(&fc->count, 1); 370 378 init_waitqueue_head(&fc->waitq); 371 379 init_waitqueue_head(&fc->blocked_waitq); 372 380 INIT_LIST_HEAD(&fc->pending); 373 381 INIT_LIST_HEAD(&fc->processing); 374 382 INIT_LIST_HEAD(&fc->io); 375 - kobj_set_kset_s(fc, connections_subsys); 376 - kobject_init(&fc->kobj); 377 383 atomic_set(&fc->num_waiting, 0); 378 384 fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; 379 385 fc->bdi.unplug_io_fn = default_unplug_io_fn; 380 386 fc->reqctr = 0; 381 387 fc->blocked = 1; 382 388 } 389 + return fc; 390 + } 391 + 392 + void fuse_conn_put(struct fuse_conn *fc) 393 + { 394 + if (atomic_dec_and_test(&fc->count)) 395 + kfree(fc); 396 + } 397 + 398 + struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) 399 + { 400 + atomic_inc(&fc->count); 383 401 return fc; 384 402 } 385 403 ··· 463 459 request_send_background(fc, req); 464 460 } 465 461 466 - static unsigned long long conn_id(void) 462 + static u64 conn_id(void) 467 463 { 468 - /* BKL is held for ->get_sb() */ 469 - static unsigned long long ctr = 1; 464 + static u64 ctr = 1; 470 465 return ctr++; 471 466 } 472 467 ··· 522 519 if (!init_req) 523 520 goto err_put_root; 524 521 525 - err = kobject_set_name(&fc->kobj, "%llu", conn_id()); 526 - if (err) 527 - goto err_free_req; 528 - 529 - err = kobject_add(&fc->kobj); 530 - if (err) 531 - goto err_free_req; 532 - 533 - /* Setting file->private_data can't race with other mount() 534 - instances, since BKL is held for ->get_sb() */ 522 + mutex_lock(&fuse_mutex); 535 523 err = -EINVAL; 536 524 if (file->private_data) 537 - goto err_kobject_del; 525 + goto err_unlock; 538 526 527 + fc->id = conn_id(); 528 + err = fuse_ctl_add_conn(fc); 529 + if (err) 530 + goto err_unlock; 531 + 532 + list_add_tail(&fc->entry, &fuse_conn_list); 539 533 sb->s_root = root_dentry; 540 534 fc->connected = 1; 541 - kobject_get(&fc->kobj); 542 - file->private_data = fc; 535 + file->private_data = fuse_conn_get(fc); 536 + mutex_unlock(&fuse_mutex); 543 537 /* 544 538 * atomic_dec_and_test() in fput() provides the necessary 545 539 * memory barrier for file->private_data to be visible on all ··· 548 548 549 549 return 0; 550 550 551 - err_kobject_del: 552 - kobject_del(&fc->kobj); 553 - err_free_req: 551 + err_unlock: 552 + mutex_unlock(&fuse_mutex); 554 553 fuse_request_free(init_req); 555 554 err_put_root: 556 555 dput(root_dentry); 557 556 err: 558 557 fput(file); 559 - kobject_put(&fc->kobj); 558 + fuse_conn_put(fc); 560 559 return err; 561 560 } 562 561 ··· 573 574 .kill_sb = kill_anon_super, 574 575 }; 575 576 576 - static ssize_t fuse_conn_waiting_show(struct fuse_conn *fc, char *page) 577 - { 578 - return sprintf(page, "%i\n", atomic_read(&fc->num_waiting)); 579 - } 580 - 581 - static ssize_t fuse_conn_abort_store(struct fuse_conn *fc, const char *page, 582 - size_t count) 583 - { 584 - fuse_abort_conn(fc); 585 - return count; 586 - } 587 - 588 - static struct fuse_conn_attr fuse_conn_waiting = 589 - __ATTR(waiting, 0400, fuse_conn_waiting_show, NULL); 590 - static struct fuse_conn_attr fuse_conn_abort = 591 - __ATTR(abort, 0600, NULL, fuse_conn_abort_store); 592 - 593 - static struct attribute *fuse_conn_attrs[] = { 594 - &fuse_conn_waiting.attr, 595 - &fuse_conn_abort.attr, 596 - NULL, 597 - }; 598 - 599 - static ssize_t fuse_conn_attr_show(struct kobject *kobj, 600 - struct attribute *attr, 601 - char *page) 602 - { 603 - struct fuse_conn_attr *fca = 604 - container_of(attr, struct fuse_conn_attr, attr); 605 - 606 - if (fca->show) 607 - return fca->show(get_fuse_conn_kobj(kobj), page); 608 - else 609 - return -EACCES; 610 - } 611 - 612 - static ssize_t fuse_conn_attr_store(struct kobject *kobj, 613 - struct attribute *attr, 614 - const char *page, size_t count) 615 - { 616 - struct fuse_conn_attr *fca = 617 - container_of(attr, struct fuse_conn_attr, attr); 618 - 619 - if (fca->store) 620 - return fca->store(get_fuse_conn_kobj(kobj), page, count); 621 - else 622 - return -EACCES; 623 - } 624 - 625 - static struct sysfs_ops fuse_conn_sysfs_ops = { 626 - .show = &fuse_conn_attr_show, 627 - .store = &fuse_conn_attr_store, 628 - }; 629 - 630 - static struct kobj_type ktype_fuse_conn = { 631 - .release = fuse_conn_release, 632 - .sysfs_ops = &fuse_conn_sysfs_ops, 633 - .default_attrs = fuse_conn_attrs, 634 - }; 635 - 636 577 static decl_subsys(fuse, NULL, NULL); 637 - static decl_subsys(connections, &ktype_fuse_conn, NULL); 578 + static decl_subsys(connections, NULL, NULL); 638 579 639 580 static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep, 640 581 unsigned long flags) ··· 648 709 printk("fuse init (API version %i.%i)\n", 649 710 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); 650 711 712 + INIT_LIST_HEAD(&fuse_conn_list); 651 713 res = fuse_fs_init(); 652 714 if (res) 653 715 goto err; ··· 661 721 if (res) 662 722 goto err_dev_cleanup; 663 723 724 + res = fuse_ctl_init(); 725 + if (res) 726 + goto err_sysfs_cleanup; 727 + 664 728 return 0; 665 729 730 + err_sysfs_cleanup: 731 + fuse_sysfs_cleanup(); 666 732 err_dev_cleanup: 667 733 fuse_dev_cleanup(); 668 734 err_fs_cleanup: ··· 681 735 { 682 736 printk(KERN_DEBUG "fuse exit\n"); 683 737 738 + fuse_ctl_cleanup(); 684 739 fuse_sysfs_cleanup(); 685 740 fuse_fs_cleanup(); 686 741 fuse_dev_cleanup();