From: Miklos Szeredi Date: Wed, 1 Jul 2015 14:26:08 +0000 (+0200) Subject: fuse: device fd clone X-Git-Tag: v4.2-rc1~37^2~3 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=00c570f4ba43ae73b41fa0a2269c3b0ac20386ef;p=karo-tx-linux.git fuse: device fd clone Allow an open fuse device to be "cloned". Userspace can create a clone by: newfd = open("/dev/fuse", O_RDWR) ioctl(newfd, FUSE_DEV_IOC_CLONE, &oldfd); At this point newfd will refer to the same fuse connection as oldfd. Signed-off-by: Miklos Szeredi Reviewed-by: Ashish Samant --- diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 51f4221657bf..611c52267d24 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -321,6 +321,7 @@ Code Seq#(hex) Include File Comments 0xDB 00-0F drivers/char/mwave/mwavepub.h 0xDD 00-3F ZFCP device driver see drivers/s390/scsi/ +0xE5 00-3F linux/fuse.h 0xEC 00-01 drivers/platform/chrome/cros_ec_dev.h ChromeOS EC driver 0xF3 00-3F drivers/usb/misc/sisusbvga/sisusb.h sisfb (in development) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index dcfc87172a47..d405c1fa4618 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2197,6 +2197,44 @@ static int fuse_dev_fasync(int fd, struct file *file, int on) return fasync_helper(fd, file, on, &fc->iq.fasync); } +static int fuse_device_clone(struct fuse_conn *fc, struct file *new) +{ + if (new->private_data) + return -EINVAL; + + new->private_data = fuse_conn_get(fc); + + return 0; +} + +static long fuse_dev_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int err = -ENOTTY; + + if (cmd == FUSE_DEV_IOC_CLONE) { + int oldfd; + + err = -EFAULT; + if (!get_user(oldfd, (__u32 __user *) arg)) { + struct file *old = fget(oldfd); + + err = -EINVAL; + if (old) { + struct fuse_conn *fc = fuse_get_conn(old); + + if (fc) { + mutex_lock(&fuse_mutex); + err = fuse_device_clone(fc, file); + mutex_unlock(&fuse_mutex); + } + fput(old); + } + } + } + return err; +} + const struct file_operations fuse_dev_operations = { .owner = THIS_MODULE, .open = fuse_dev_open, @@ -2208,6 +2246,8 @@ const struct file_operations fuse_dev_operations = { .poll = fuse_dev_poll, .release = fuse_dev_release, .fasync = fuse_dev_fasync, + .unlocked_ioctl = fuse_dev_ioctl, + .compat_ioctl = fuse_dev_ioctl, }; EXPORT_SYMBOL_GPL(fuse_dev_operations); diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 25084a052a1e..c9aca042e61d 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -755,4 +755,7 @@ struct fuse_notify_retrieve_in { uint64_t dummy4; }; +/* Device ioctls: */ +#define FUSE_DEV_IOC_CLONE _IOR(229, 0, uint32_t) + #endif /* _LINUX_FUSE_H */