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

Configure Feed

Select the types of activity you want to include in your feed.

fuse: clean up device cloning

- fuse_mutex is not needed for device cloning, because fuse_dev_install()
uses cmpxcg() to set fud->fc, which prevents races between clone/mount
or clone/clone. This makes the logic simpler

- Drop fc->dev_count. This is only used to check in release if the device
is the last clone, but checking list_empty(&fc->devices) is equivalent
after removing the released device from the list. Removing the fuse_dev
before calling fuse_abort_conn() is okay, since the processing and io
lists are now empty for this device.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>

+15 -24
+15 -20
fs/fuse/dev.c
··· 2547 2547 struct fuse_pqueue *fpq = &fud->pq; 2548 2548 LIST_HEAD(to_end); 2549 2549 unsigned int i; 2550 + bool last; 2550 2551 2551 2552 spin_lock(&fpq->lock); 2552 2553 WARN_ON(!list_empty(&fpq->io)); ··· 2557 2556 2558 2557 fuse_dev_end_requests(&to_end); 2559 2558 2559 + spin_lock(&fc->lock); 2560 + list_del(&fud->entry); 2560 2561 /* Are we the last open device? */ 2561 - if (atomic_dec_and_test(&fc->dev_count)) { 2562 + last = list_empty(&fc->devices); 2563 + spin_unlock(&fc->lock); 2564 + 2565 + if (last) { 2562 2566 WARN_ON(fc->iq.fasync != NULL); 2563 2567 fuse_abort_conn(fc); 2564 2568 } 2565 - spin_lock(&fc->lock); 2566 - list_del(&fud->entry); 2567 - spin_unlock(&fc->lock); 2568 2569 fuse_conn_put(fc); 2569 2570 } 2570 2571 fuse_dev_put(fud); ··· 2585 2582 return fasync_helper(fd, file, on, &fud->fc->iq.fasync); 2586 2583 } 2587 2584 2588 - static int fuse_device_clone(struct fuse_conn *fc, struct file *new) 2589 - { 2590 - struct fuse_dev *new_fud = fuse_file_to_fud(new); 2591 - 2592 - if (fuse_dev_fc_get(new_fud)) 2593 - return -EINVAL; 2594 - 2595 - fuse_dev_install(new_fud, fc); 2596 - atomic_inc(&fc->dev_count); 2597 - 2598 - return 0; 2599 - } 2600 - 2601 2585 static long fuse_dev_ioctl_clone(struct file *file, __u32 __user *argp) 2602 2586 { 2603 2587 int oldfd; 2604 - struct fuse_dev *fud; 2588 + struct fuse_dev *fud, *new_fud; 2605 2589 2606 2590 if (get_user(oldfd, argp)) 2607 2591 return -EFAULT; ··· 2608 2618 if (IS_ERR(fud)) 2609 2619 return PTR_ERR(fud); 2610 2620 2611 - guard(mutex)(&fuse_mutex); 2612 - return fuse_device_clone(fud->fc, file); 2621 + new_fud = fuse_file_to_fud(file); 2622 + if (fuse_dev_fc_get(new_fud)) 2623 + return -EINVAL; 2624 + 2625 + fuse_dev_install(new_fud, fud->fc); 2626 + 2627 + return 0; 2613 2628 } 2614 2629 2615 2630 static long fuse_dev_ioctl_backing_open(struct file *file,
-3
fs/fuse/fuse_i.h
··· 650 650 /** Refcount */ 651 651 refcount_t count; 652 652 653 - /** Number of fuse_dev's */ 654 - atomic_t dev_count; 655 - 656 653 /** Current epoch for up-to-date dentries */ 657 654 atomic_t epoch; 658 655
-1
fs/fuse/inode.c
··· 1001 1001 spin_lock_init(&fc->bg_lock); 1002 1002 init_rwsem(&fc->killsb); 1003 1003 refcount_set(&fc->count, 1); 1004 - atomic_set(&fc->dev_count, 1); 1005 1004 atomic_set(&fc->epoch, 1); 1006 1005 INIT_WORK(&fc->epoch_work, fuse_epoch_work); 1007 1006 init_waitqueue_head(&fc->blocked_waitq);