mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
fuse: allow synchronous FUSE_INIT
FUSE_INIT has always been asynchronous with mount. That means that the server processed this request after the mount syscall returned. This means that FUSE_INIT can't supply the root inode's ID, hence it currently has a hardcoded value. There are other limitations such as not being able to perform getxattr during mount, which is needed by selinux. To remove these limitations allow server to process FUSE_INIT while initializing the in-core super block for the fuse filesystem. This can only be done if the server is prepared to handle this, so add FUSE_DEV_IOC_SYNC_INIT ioctl, which a) lets the server know whether this feature is supported, returning ENOTTY othewrwise. b) lets the kernel know to perform a synchronous initialization The implementation is slightly tricky, since fuse_dev/fuse_conn are set up only during super block creation. This is solved by setting the private data of the fuse device file to a special value ((struct fuse_dev *) 1) and waiting for this to be turned into a proper fuse_dev before commecing with operations on the device file. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
3ca1b31118
commit
dfb84c3307
|
|
@ -52,6 +52,7 @@
|
||||||
#include <linux/user_namespace.h>
|
#include <linux/user_namespace.h>
|
||||||
|
|
||||||
#include "fuse_i.h"
|
#include "fuse_i.h"
|
||||||
|
#include "fuse_dev_i.h"
|
||||||
|
|
||||||
#define CUSE_CONNTBL_LEN 64
|
#define CUSE_CONNTBL_LEN 64
|
||||||
|
|
||||||
|
|
@ -547,7 +548,7 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
|
||||||
*/
|
*/
|
||||||
static int cuse_channel_release(struct inode *inode, struct file *file)
|
static int cuse_channel_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct fuse_dev *fud = file->private_data;
|
struct fuse_dev *fud = __fuse_get_dev(file);
|
||||||
struct cuse_conn *cc = fc_to_cc(fud->fc);
|
struct cuse_conn *cc = fc_to_cc(fud->fc);
|
||||||
|
|
||||||
/* remove from the conntbl, no more access from this point on */
|
/* remove from the conntbl, no more access from this point on */
|
||||||
|
|
|
||||||
|
|
@ -1530,14 +1530,34 @@ static int fuse_dev_open(struct inode *inode, struct file *file)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct fuse_dev *fuse_get_dev(struct file *file)
|
||||||
|
{
|
||||||
|
struct fuse_dev *fud = __fuse_get_dev(file);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (likely(fud))
|
||||||
|
return fud;
|
||||||
|
|
||||||
|
err = wait_event_interruptible(fuse_dev_waitq,
|
||||||
|
READ_ONCE(file->private_data) != FUSE_DEV_SYNC_INIT);
|
||||||
|
if (err)
|
||||||
|
return ERR_PTR(err);
|
||||||
|
|
||||||
|
fud = __fuse_get_dev(file);
|
||||||
|
if (!fud)
|
||||||
|
return ERR_PTR(-EPERM);
|
||||||
|
|
||||||
|
return fud;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t fuse_dev_read(struct kiocb *iocb, struct iov_iter *to)
|
static ssize_t fuse_dev_read(struct kiocb *iocb, struct iov_iter *to)
|
||||||
{
|
{
|
||||||
struct fuse_copy_state cs;
|
struct fuse_copy_state cs;
|
||||||
struct file *file = iocb->ki_filp;
|
struct file *file = iocb->ki_filp;
|
||||||
struct fuse_dev *fud = fuse_get_dev(file);
|
struct fuse_dev *fud = fuse_get_dev(file);
|
||||||
|
|
||||||
if (!fud)
|
if (IS_ERR(fud))
|
||||||
return -EPERM;
|
return PTR_ERR(fud);
|
||||||
|
|
||||||
if (!user_backed_iter(to))
|
if (!user_backed_iter(to))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
@ -1557,8 +1577,8 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
|
||||||
struct fuse_copy_state cs;
|
struct fuse_copy_state cs;
|
||||||
struct fuse_dev *fud = fuse_get_dev(in);
|
struct fuse_dev *fud = fuse_get_dev(in);
|
||||||
|
|
||||||
if (!fud)
|
if (IS_ERR(fud))
|
||||||
return -EPERM;
|
return PTR_ERR(fud);
|
||||||
|
|
||||||
bufs = kvmalloc_array(pipe->max_usage, sizeof(struct pipe_buffer),
|
bufs = kvmalloc_array(pipe->max_usage, sizeof(struct pipe_buffer),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
|
|
@ -2231,7 +2251,7 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud,
|
||||||
static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from)
|
static ssize_t fuse_dev_write(struct kiocb *iocb, struct iov_iter *from)
|
||||||
{
|
{
|
||||||
struct fuse_copy_state cs;
|
struct fuse_copy_state cs;
|
||||||
struct fuse_dev *fud = fuse_get_dev(iocb->ki_filp);
|
struct fuse_dev *fud = __fuse_get_dev(iocb->ki_filp);
|
||||||
|
|
||||||
if (!fud)
|
if (!fud)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
@ -2253,11 +2273,10 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
|
||||||
unsigned idx;
|
unsigned idx;
|
||||||
struct pipe_buffer *bufs;
|
struct pipe_buffer *bufs;
|
||||||
struct fuse_copy_state cs;
|
struct fuse_copy_state cs;
|
||||||
struct fuse_dev *fud;
|
struct fuse_dev *fud = __fuse_get_dev(out);
|
||||||
size_t rem;
|
size_t rem;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
fud = fuse_get_dev(out);
|
|
||||||
if (!fud)
|
if (!fud)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
|
@ -2343,7 +2362,7 @@ static __poll_t fuse_dev_poll(struct file *file, poll_table *wait)
|
||||||
struct fuse_iqueue *fiq;
|
struct fuse_iqueue *fiq;
|
||||||
struct fuse_dev *fud = fuse_get_dev(file);
|
struct fuse_dev *fud = fuse_get_dev(file);
|
||||||
|
|
||||||
if (!fud)
|
if (IS_ERR(fud))
|
||||||
return EPOLLERR;
|
return EPOLLERR;
|
||||||
|
|
||||||
fiq = &fud->fc->iq;
|
fiq = &fud->fc->iq;
|
||||||
|
|
@ -2490,7 +2509,7 @@ void fuse_wait_aborted(struct fuse_conn *fc)
|
||||||
|
|
||||||
int fuse_dev_release(struct inode *inode, struct file *file)
|
int fuse_dev_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct fuse_dev *fud = fuse_get_dev(file);
|
struct fuse_dev *fud = __fuse_get_dev(file);
|
||||||
|
|
||||||
if (fud) {
|
if (fud) {
|
||||||
struct fuse_conn *fc = fud->fc;
|
struct fuse_conn *fc = fud->fc;
|
||||||
|
|
@ -2521,8 +2540,8 @@ static int fuse_dev_fasync(int fd, struct file *file, int on)
|
||||||
{
|
{
|
||||||
struct fuse_dev *fud = fuse_get_dev(file);
|
struct fuse_dev *fud = fuse_get_dev(file);
|
||||||
|
|
||||||
if (!fud)
|
if (IS_ERR(fud))
|
||||||
return -EPERM;
|
return PTR_ERR(fud);
|
||||||
|
|
||||||
/* No locking - fasync_helper does its own locking */
|
/* No locking - fasync_helper does its own locking */
|
||||||
return fasync_helper(fd, file, on, &fud->fc->iq.fasync);
|
return fasync_helper(fd, file, on, &fud->fc->iq.fasync);
|
||||||
|
|
@ -2532,7 +2551,7 @@ static int fuse_device_clone(struct fuse_conn *fc, struct file *new)
|
||||||
{
|
{
|
||||||
struct fuse_dev *fud;
|
struct fuse_dev *fud;
|
||||||
|
|
||||||
if (new->private_data)
|
if (__fuse_get_dev(new))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
fud = fuse_dev_alloc_install(fc);
|
fud = fuse_dev_alloc_install(fc);
|
||||||
|
|
@ -2563,7 +2582,7 @@ static long fuse_dev_ioctl_clone(struct file *file, __u32 __user *argp)
|
||||||
* uses the same ioctl handler.
|
* uses the same ioctl handler.
|
||||||
*/
|
*/
|
||||||
if (fd_file(f)->f_op == file->f_op)
|
if (fd_file(f)->f_op == file->f_op)
|
||||||
fud = fuse_get_dev(fd_file(f));
|
fud = __fuse_get_dev(fd_file(f));
|
||||||
|
|
||||||
res = -EINVAL;
|
res = -EINVAL;
|
||||||
if (fud) {
|
if (fud) {
|
||||||
|
|
@ -2581,8 +2600,8 @@ static long fuse_dev_ioctl_backing_open(struct file *file,
|
||||||
struct fuse_dev *fud = fuse_get_dev(file);
|
struct fuse_dev *fud = fuse_get_dev(file);
|
||||||
struct fuse_backing_map map;
|
struct fuse_backing_map map;
|
||||||
|
|
||||||
if (!fud)
|
if (IS_ERR(fud))
|
||||||
return -EPERM;
|
return PTR_ERR(fud);
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
|
if (!IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
@ -2598,8 +2617,8 @@ static long fuse_dev_ioctl_backing_close(struct file *file, __u32 __user *argp)
|
||||||
struct fuse_dev *fud = fuse_get_dev(file);
|
struct fuse_dev *fud = fuse_get_dev(file);
|
||||||
int backing_id;
|
int backing_id;
|
||||||
|
|
||||||
if (!fud)
|
if (IS_ERR(fud))
|
||||||
return -EPERM;
|
return PTR_ERR(fud);
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
|
if (!IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
@ -2610,6 +2629,19 @@ static long fuse_dev_ioctl_backing_close(struct file *file, __u32 __user *argp)
|
||||||
return fuse_backing_close(fud->fc, backing_id);
|
return fuse_backing_close(fud->fc, backing_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long fuse_dev_ioctl_sync_init(struct file *file)
|
||||||
|
{
|
||||||
|
int err = -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&fuse_mutex);
|
||||||
|
if (!__fuse_get_dev(file)) {
|
||||||
|
WRITE_ONCE(file->private_data, FUSE_DEV_SYNC_INIT);
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
mutex_unlock(&fuse_mutex);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
|
static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
|
||||||
unsigned long arg)
|
unsigned long arg)
|
||||||
{
|
{
|
||||||
|
|
@ -2625,6 +2657,9 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
|
||||||
case FUSE_DEV_IOC_BACKING_CLOSE:
|
case FUSE_DEV_IOC_BACKING_CLOSE:
|
||||||
return fuse_dev_ioctl_backing_close(file, argp);
|
return fuse_dev_ioctl_backing_close(file, argp);
|
||||||
|
|
||||||
|
case FUSE_DEV_IOC_SYNC_INIT:
|
||||||
|
return fuse_dev_ioctl_sync_init(file);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
|
@ -2633,7 +2668,7 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
static void fuse_dev_show_fdinfo(struct seq_file *seq, struct file *file)
|
static void fuse_dev_show_fdinfo(struct seq_file *seq, struct file *file)
|
||||||
{
|
{
|
||||||
struct fuse_dev *fud = fuse_get_dev(file);
|
struct fuse_dev *fud = __fuse_get_dev(file);
|
||||||
if (!fud)
|
if (!fud)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1139,9 +1139,9 @@ int fuse_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
fud = fuse_get_dev(cmd->file);
|
fud = fuse_get_dev(cmd->file);
|
||||||
if (!fud) {
|
if (IS_ERR(fud)) {
|
||||||
pr_info_ratelimited("No fuse device found\n");
|
pr_info_ratelimited("No fuse device found\n");
|
||||||
return -ENOTCONN;
|
return PTR_ERR(fud);
|
||||||
}
|
}
|
||||||
fc = fud->fc;
|
fc = fud->fc;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
#define FUSE_INT_REQ_BIT (1ULL << 0)
|
#define FUSE_INT_REQ_BIT (1ULL << 0)
|
||||||
#define FUSE_REQ_ID_STEP (1ULL << 1)
|
#define FUSE_REQ_ID_STEP (1ULL << 1)
|
||||||
|
|
||||||
|
extern struct wait_queue_head fuse_dev_waitq;
|
||||||
|
|
||||||
struct fuse_arg;
|
struct fuse_arg;
|
||||||
struct fuse_args;
|
struct fuse_args;
|
||||||
struct fuse_pqueue;
|
struct fuse_pqueue;
|
||||||
|
|
@ -37,15 +39,22 @@ struct fuse_copy_state {
|
||||||
} ring;
|
} ring;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct fuse_dev *fuse_get_dev(struct file *file)
|
#define FUSE_DEV_SYNC_INIT ((struct fuse_dev *) 1)
|
||||||
|
#define FUSE_DEV_PTR_MASK (~1UL)
|
||||||
|
|
||||||
|
static inline struct fuse_dev *__fuse_get_dev(struct file *file)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Lockless access is OK, because file->private data is set
|
* Lockless access is OK, because file->private data is set
|
||||||
* once during mount and is valid until the file is released.
|
* once during mount and is valid until the file is released.
|
||||||
*/
|
*/
|
||||||
return READ_ONCE(file->private_data);
|
struct fuse_dev *fud = READ_ONCE(file->private_data);
|
||||||
|
|
||||||
|
return (typeof(fud)) ((unsigned long) fud & FUSE_DEV_PTR_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct fuse_dev *fuse_get_dev(struct file *file);
|
||||||
|
|
||||||
unsigned int fuse_req_hash(u64 unique);
|
unsigned int fuse_req_hash(u64 unique);
|
||||||
struct fuse_req *fuse_request_find(struct fuse_pqueue *fpq, u64 unique);
|
struct fuse_req *fuse_request_find(struct fuse_pqueue *fpq, u64 unique);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -904,6 +904,9 @@ struct fuse_conn {
|
||||||
/* Is link not implemented by fs? */
|
/* Is link not implemented by fs? */
|
||||||
unsigned int no_link:1;
|
unsigned int no_link:1;
|
||||||
|
|
||||||
|
/* Is synchronous FUSE_INIT allowed? */
|
||||||
|
unsigned int sync_init:1;
|
||||||
|
|
||||||
/* Use io_uring for communication */
|
/* Use io_uring for communication */
|
||||||
unsigned int io_uring;
|
unsigned int io_uring;
|
||||||
|
|
||||||
|
|
@ -1318,7 +1321,7 @@ struct fuse_dev *fuse_dev_alloc_install(struct fuse_conn *fc);
|
||||||
struct fuse_dev *fuse_dev_alloc(void);
|
struct fuse_dev *fuse_dev_alloc(void);
|
||||||
void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc);
|
void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc);
|
||||||
void fuse_dev_free(struct fuse_dev *fud);
|
void fuse_dev_free(struct fuse_dev *fud);
|
||||||
void fuse_send_init(struct fuse_mount *fm);
|
int fuse_send_init(struct fuse_mount *fm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill in superblock and initialize fuse connection
|
* Fill in superblock and initialize fuse connection
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fuse_i.h"
|
#include "fuse_i.h"
|
||||||
|
#include "fuse_dev_i.h"
|
||||||
#include "dev_uring_i.h"
|
#include "dev_uring_i.h"
|
||||||
|
|
||||||
#include <linux/dax.h>
|
#include <linux/dax.h>
|
||||||
|
|
@ -34,6 +35,7 @@ MODULE_LICENSE("GPL");
|
||||||
static struct kmem_cache *fuse_inode_cachep;
|
static struct kmem_cache *fuse_inode_cachep;
|
||||||
struct list_head fuse_conn_list;
|
struct list_head fuse_conn_list;
|
||||||
DEFINE_MUTEX(fuse_mutex);
|
DEFINE_MUTEX(fuse_mutex);
|
||||||
|
DECLARE_WAIT_QUEUE_HEAD(fuse_dev_waitq);
|
||||||
|
|
||||||
static int set_global_limit(const char *val, const struct kernel_param *kp);
|
static int set_global_limit(const char *val, const struct kernel_param *kp);
|
||||||
|
|
||||||
|
|
@ -1466,7 +1468,7 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
|
||||||
wake_up_all(&fc->blocked_waitq);
|
wake_up_all(&fc->blocked_waitq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fuse_send_init(struct fuse_mount *fm)
|
static struct fuse_init_args *fuse_new_init(struct fuse_mount *fm)
|
||||||
{
|
{
|
||||||
struct fuse_init_args *ia;
|
struct fuse_init_args *ia;
|
||||||
u64 flags;
|
u64 flags;
|
||||||
|
|
@ -1525,10 +1527,30 @@ void fuse_send_init(struct fuse_mount *fm)
|
||||||
ia->args.out_args[0].value = &ia->out;
|
ia->args.out_args[0].value = &ia->out;
|
||||||
ia->args.force = true;
|
ia->args.force = true;
|
||||||
ia->args.nocreds = true;
|
ia->args.nocreds = true;
|
||||||
ia->args.end = process_init_reply;
|
|
||||||
|
|
||||||
if (fuse_simple_background(fm, &ia->args, GFP_KERNEL) != 0)
|
return ia;
|
||||||
process_init_reply(fm, &ia->args, -ENOTCONN);
|
}
|
||||||
|
|
||||||
|
int fuse_send_init(struct fuse_mount *fm)
|
||||||
|
{
|
||||||
|
struct fuse_init_args *ia = fuse_new_init(fm);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (fm->fc->sync_init) {
|
||||||
|
err = fuse_simple_request(fm, &ia->args);
|
||||||
|
/* Ignore size of init reply */
|
||||||
|
if (err > 0)
|
||||||
|
err = 0;
|
||||||
|
} else {
|
||||||
|
ia->args.end = process_init_reply;
|
||||||
|
err = fuse_simple_background(fm, &ia->args, GFP_KERNEL);
|
||||||
|
if (!err)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
process_init_reply(fm, &ia->args, err);
|
||||||
|
if (fm->fc->conn_error)
|
||||||
|
return -ENOTCONN;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fuse_send_init);
|
EXPORT_SYMBOL_GPL(fuse_send_init);
|
||||||
|
|
||||||
|
|
@ -1867,8 +1889,12 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
|
||||||
|
|
||||||
mutex_lock(&fuse_mutex);
|
mutex_lock(&fuse_mutex);
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
if (ctx->fudptr && *ctx->fudptr)
|
if (ctx->fudptr && *ctx->fudptr) {
|
||||||
goto err_unlock;
|
if (*ctx->fudptr == FUSE_DEV_SYNC_INIT)
|
||||||
|
fc->sync_init = 1;
|
||||||
|
else
|
||||||
|
goto err_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
err = fuse_ctl_add_conn(fc);
|
err = fuse_ctl_add_conn(fc);
|
||||||
if (err)
|
if (err)
|
||||||
|
|
@ -1876,8 +1902,10 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
|
||||||
|
|
||||||
list_add_tail(&fc->entry, &fuse_conn_list);
|
list_add_tail(&fc->entry, &fuse_conn_list);
|
||||||
sb->s_root = root_dentry;
|
sb->s_root = root_dentry;
|
||||||
if (ctx->fudptr)
|
if (ctx->fudptr) {
|
||||||
*ctx->fudptr = fud;
|
*ctx->fudptr = fud;
|
||||||
|
wake_up_all(&fuse_dev_waitq);
|
||||||
|
}
|
||||||
mutex_unlock(&fuse_mutex);
|
mutex_unlock(&fuse_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
@ -1898,6 +1926,7 @@ EXPORT_SYMBOL_GPL(fuse_fill_super_common);
|
||||||
static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc)
|
static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc)
|
||||||
{
|
{
|
||||||
struct fuse_fs_context *ctx = fsc->fs_private;
|
struct fuse_fs_context *ctx = fsc->fs_private;
|
||||||
|
struct fuse_mount *fm;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!ctx->file || !ctx->rootmode_present ||
|
if (!ctx->file || !ctx->rootmode_present ||
|
||||||
|
|
@ -1918,8 +1947,10 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc)
|
||||||
return err;
|
return err;
|
||||||
/* file->private_data shall be visible on all CPUs after this */
|
/* file->private_data shall be visible on all CPUs after this */
|
||||||
smp_mb();
|
smp_mb();
|
||||||
fuse_send_init(get_fuse_mount_super(sb));
|
|
||||||
return 0;
|
fm = get_fuse_mount_super(sb);
|
||||||
|
|
||||||
|
return fuse_send_init(fm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1980,7 +2011,7 @@ static int fuse_get_tree(struct fs_context *fsc)
|
||||||
* Allow creating a fuse mount with an already initialized fuse
|
* Allow creating a fuse mount with an already initialized fuse
|
||||||
* connection
|
* connection
|
||||||
*/
|
*/
|
||||||
fud = READ_ONCE(ctx->file->private_data);
|
fud = __fuse_get_dev(ctx->file);
|
||||||
if (ctx->file->f_op == &fuse_dev_operations && fud) {
|
if (ctx->file->f_op == &fuse_dev_operations && fud) {
|
||||||
fsc->sget_key = fud->fc;
|
fsc->sget_key = fud->fc;
|
||||||
sb = sget_fc(fsc, fuse_test_super, fuse_set_no_super);
|
sb = sget_fc(fsc, fuse_test_super, fuse_set_no_super);
|
||||||
|
|
|
||||||
|
|
@ -1131,6 +1131,7 @@ struct fuse_backing_map {
|
||||||
#define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \
|
#define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \
|
||||||
struct fuse_backing_map)
|
struct fuse_backing_map)
|
||||||
#define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t)
|
#define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t)
|
||||||
|
#define FUSE_DEV_IOC_SYNC_INIT _IO(FUSE_DEV_IOC_MAGIC, 3)
|
||||||
|
|
||||||
struct fuse_lseek_in {
|
struct fuse_lseek_in {
|
||||||
uint64_t fh;
|
uint64_t fh;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user