summaryrefslogtreecommitdiff
path: root/fs/fuse/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r--fs/fuse/inode.c345
1 files changed, 110 insertions, 235 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index e57b8af06be9..e9552be3637b 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1,14 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
-
- This program can be distributed under the terms of the GNU GPL.
- See the file COPYING.
*/
+#include "dev.h"
#include "fuse_i.h"
-#include "fuse_dev_i.h"
-#include "dev_uring_i.h"
#include <linux/dax.h>
#include <linux/pagemap.h>
@@ -35,14 +32,11 @@ MODULE_LICENSE("GPL");
static struct kmem_cache *fuse_inode_cachep;
struct list_head fuse_conn_list;
DEFINE_MUTEX(fuse_mutex);
-DECLARE_WAIT_QUEUE_HEAD(fuse_dev_waitq);
static int set_global_limit(const char *val, const struct kernel_param *kp);
unsigned int fuse_max_pages_limit = 256;
/* default is no timeout */
-unsigned int fuse_default_req_timeout;
-unsigned int fuse_max_req_timeout;
unsigned int max_user_bgreq;
module_param_call(max_user_bgreq, set_global_limit, param_get_uint,
@@ -62,9 +56,6 @@ MODULE_PARM_DESC(max_user_congthresh,
#define FUSE_DEFAULT_BLKSIZE 512
-/** Maximum number of outstanding background requests */
-#define FUSE_DEFAULT_MAX_BACKGROUND 12
-
/** Congestion starts at 75% of maximum */
#define FUSE_DEFAULT_CONGESTION_THRESHOLD (FUSE_DEFAULT_MAX_BACKGROUND * 3 / 4)
@@ -72,11 +63,6 @@ MODULE_PARM_DESC(max_user_congthresh,
static struct file_system_type fuseblk_fs_type;
#endif
-struct fuse_forget_link *fuse_alloc_forget(void)
-{
- return kzalloc_obj(struct fuse_forget_link, GFP_KERNEL_ACCOUNT);
-}
-
static struct fuse_submount_lookup *fuse_alloc_submount_lookup(void)
{
struct fuse_submount_lookup *sl;
@@ -150,7 +136,7 @@ static void fuse_cleanup_submount_lookup(struct fuse_conn *fc,
if (!refcount_dec_and_test(&sl->count))
return;
- fuse_queue_forget(fc, sl->forget, sl->nodeid, 1);
+ fuse_chan_queue_forget(fc->chan, sl->forget, sl->nodeid, 1);
sl->forget = NULL;
kfree(sl);
}
@@ -173,8 +159,8 @@ static void fuse_evict_inode(struct inode *inode)
if (FUSE_IS_DAX(inode))
fuse_dax_inode_cleanup(inode);
if (fi->nlookup) {
- fuse_queue_forget(fc, fi->forget, fi->nodeid,
- fi->nlookup);
+ fuse_chan_queue_forget(fc->chan, fi->forget, fi->nodeid,
+ fi->nlookup);
fi->forget = NULL;
}
@@ -470,6 +456,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
struct inode *inode;
struct fuse_inode *fi;
struct fuse_conn *fc = get_fuse_conn_super(sb);
+ bool is_new_inode = false;
/*
* Auto mount points get their node id from the submount root, which is
@@ -505,13 +492,13 @@ retry:
if (!inode)
return NULL;
- if ((inode_state_read_once(inode) & I_NEW)) {
+ is_new_inode = inode_state_read_once(inode) & I_NEW;
+ if (is_new_inode) {
inode->i_flags |= S_NOATIME;
if (!fc->writeback_cache || !S_ISREG(attr->mode))
inode->i_flags |= S_NOCMTIME;
inode->i_generation = generation;
fuse_init_inode(inode, attr, fc);
- unlock_new_inode(inode);
} else if (fuse_stale_inode(inode, generation, attr)) {
/* nodeid was reused, any I/O on the old inode should fail */
fuse_make_bad(inode);
@@ -528,6 +515,8 @@ retry:
done:
fuse_change_attributes_i(inode, attr, NULL, attr_valid, attr_version,
evict_ctr);
+ if (is_new_inode)
+ unlock_new_inode(inode);
return inode;
}
@@ -621,7 +610,7 @@ static void fuse_umount_begin(struct super_block *sb)
if (fc->no_force_umount)
return;
- fuse_abort_conn(fc);
+ fuse_chan_abort(fc->chan, false);
// Only retire block-device-based superblocks.
if (sb->s_bdev != NULL)
@@ -685,11 +674,9 @@ static struct fuse_sync_bucket *fuse_sync_bucket_alloc(void)
struct fuse_sync_bucket *bucket;
bucket = kzalloc_obj(*bucket, GFP_KERNEL | __GFP_NOFAIL);
- if (bucket) {
- init_waitqueue_head(&bucket->waitq);
- /* Initial active count */
- atomic_set(&bucket->count, 1);
- }
+ init_waitqueue_head(&bucket->waitq);
+ /* Initial active count */
+ atomic_set(&bucket->count, 1);
return bucket;
}
@@ -788,7 +775,7 @@ enum {
static const struct fs_parameter_spec fuse_fs_parameters[] = {
fsparam_string ("source", OPT_SOURCE),
- fsparam_u32 ("fd", OPT_FD),
+ fsparam_fd ("fd", OPT_FD),
fsparam_u32oct ("rootmode", OPT_ROOTMODE),
fsparam_uid ("user_id", OPT_USER_ID),
fsparam_gid ("group_id", OPT_GROUP_ID),
@@ -800,6 +787,27 @@ static const struct fs_parameter_spec fuse_fs_parameters[] = {
{}
};
+static int fuse_opt_fd(struct fs_context *fsc, struct file *file)
+{
+ struct fuse_fs_context *ctx = fsc->fs_private;
+
+ if (ctx->fud)
+ return invalfc(fsc, "Multiple fd specified");
+
+ if (file->f_op != &fuse_dev_operations)
+ return invalfc(fsc, "fd is not a fuse device");
+ /*
+ * Require mount to happen from the same user namespace which
+ * opened /dev/fuse to prevent potential attacks.
+ */
+ if (file->f_cred->user_ns != fsc->user_ns)
+ return invalfc(fsc, "wrong user namespace for fuse device");
+
+ ctx->fud = fuse_dev_grab(file);
+
+ return 0;
+}
+
static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param)
{
struct fs_parse_result result;
@@ -839,9 +847,15 @@ static int fuse_parse_param(struct fs_context *fsc, struct fs_parameter *param)
return 0;
case OPT_FD:
- ctx->fd = result.uint_32;
- ctx->fd_present = true;
- break;
+ if (param->type == fs_value_is_file) {
+ return fuse_opt_fd(fsc, param->file);
+ } else {
+ struct file *file __free(fput) = fget(result.uint_32);
+ if (!file)
+ return -EBADF;
+
+ return fuse_opt_fd(fsc, file);
+ }
case OPT_ROOTMODE:
if (!fuse_valid_type(result.uint_32))
@@ -904,6 +918,8 @@ static void fuse_free_fsc(struct fs_context *fsc)
struct fuse_fs_context *ctx = fsc->fs_private;
if (ctx) {
+ if (ctx->fud)
+ fuse_dev_put(ctx->fud);
kfree(ctx->subtype);
kfree(ctx);
}
@@ -940,57 +956,19 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root)
return 0;
}
-static void fuse_iqueue_init(struct fuse_iqueue *fiq,
- const struct fuse_iqueue_ops *ops,
- void *priv)
-{
- memset(fiq, 0, sizeof(struct fuse_iqueue));
- spin_lock_init(&fiq->lock);
- init_waitqueue_head(&fiq->waitq);
- INIT_LIST_HEAD(&fiq->pending);
- INIT_LIST_HEAD(&fiq->interrupts);
- fiq->forget_list_tail = &fiq->forget_list_head;
- fiq->connected = 1;
- fiq->ops = ops;
- fiq->priv = priv;
-}
-
-void fuse_pqueue_init(struct fuse_pqueue *fpq)
-{
- unsigned int i;
-
- spin_lock_init(&fpq->lock);
- for (i = 0; i < FUSE_PQ_HASH_SIZE; i++)
- INIT_LIST_HEAD(&fpq->processing[i]);
- INIT_LIST_HEAD(&fpq->io);
- fpq->connected = 1;
-}
-
void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
- struct user_namespace *user_ns,
- const struct fuse_iqueue_ops *fiq_ops, void *fiq_priv)
+ struct user_namespace *user_ns, struct fuse_chan *fch)
{
memset(fc, 0, sizeof(*fc));
spin_lock_init(&fc->lock);
- spin_lock_init(&fc->bg_lock);
init_rwsem(&fc->killsb);
refcount_set(&fc->count, 1);
- atomic_set(&fc->dev_count, 1);
atomic_set(&fc->epoch, 1);
INIT_WORK(&fc->epoch_work, fuse_epoch_work);
- init_waitqueue_head(&fc->blocked_waitq);
- fuse_iqueue_init(&fc->iq, fiq_ops, fiq_priv);
- INIT_LIST_HEAD(&fc->bg_queue);
INIT_LIST_HEAD(&fc->entry);
- INIT_LIST_HEAD(&fc->devices);
- atomic_set(&fc->num_waiting, 0);
- fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND;
fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD;
atomic64_set(&fc->khctr, 0);
fc->polled_files = RB_ROOT;
- fc->blocked = 0;
- fc->initialized = 0;
- fc->connected = 1;
atomic64_set(&fc->attr_version, 1);
atomic64_set(&fc->evict_ctr, 1);
get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
@@ -999,7 +977,6 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
fc->max_pages = FUSE_DEFAULT_MAX_PAGES_PER_REQ;
fc->max_pages_limit = fuse_max_pages_limit;
fc->name_max = FUSE_NAME_LOW_MAX;
- fc->timeout.req_timeout = 0;
if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
fuse_backing_files_init(fc);
@@ -1007,6 +984,8 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
INIT_LIST_HEAD(&fc->mounts);
list_add(&fm->fc_entry, &fc->mounts);
fm->fc = fc;
+ fuse_chan_set_fc(fch, fc);
+ fc->chan = fch;
}
EXPORT_SYMBOL_GPL(fuse_conn_init);
@@ -1014,7 +993,8 @@ static void delayed_release(struct rcu_head *p)
{
struct fuse_conn *fc = container_of(p, struct fuse_conn, rcu);
- fuse_uring_destruct(fc);
+ fuse_uring_destruct(fc->chan);
+ fuse_chan_free(fc->chan);
put_user_ns(fc->user_ns);
fc->release(fc);
@@ -1022,7 +1002,6 @@ static void delayed_release(struct rcu_head *p)
void fuse_conn_put(struct fuse_conn *fc)
{
- struct fuse_iqueue *fiq = &fc->iq;
struct fuse_sync_bucket *bucket;
if (!refcount_dec_and_test(&fc->count))
@@ -1030,11 +1009,8 @@ void fuse_conn_put(struct fuse_conn *fc)
if (IS_ENABLED(CONFIG_FUSE_DAX))
fuse_dax_conn_free(fc);
- if (fc->timeout.req_timeout)
- cancel_delayed_work_sync(&fc->timeout.work);
cancel_work_sync(&fc->epoch_work);
- if (fiq->ops->release)
- fiq->ops->release(fiq);
+ fuse_chan_release(fc->chan);
put_pid_ns(fc->pid_ns);
bucket = rcu_dereference_protected(fc->curr_bucket, 1);
if (bucket) {
@@ -1054,6 +1030,11 @@ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
}
EXPORT_SYMBOL_GPL(fuse_conn_get);
+dev_t fuse_conn_get_id(struct fuse_conn *fc)
+{
+ return fc->dev;
+}
+
static struct inode *fuse_get_root_inode(struct super_block *sb, unsigned int mode)
{
struct fuse_attr attr;
@@ -1084,12 +1065,11 @@ static struct dentry *fuse_get_dentry(struct super_block *sb,
inode = ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid);
if (!inode) {
struct fuse_entry_out outarg;
- const struct qstr name = QSTR_INIT(".", 1);
if (!fc->export_support)
goto out_err;
- err = fuse_lookup_name(sb, handle->nodeid, &name, &outarg,
+ err = fuse_lookup_name(sb, handle->nodeid, &QSTR("."), &outarg,
&inode);
if (err && err != -ENOENT)
goto out_err;
@@ -1265,12 +1245,13 @@ static void process_init_limits(struct fuse_conn *fc, struct fuse_init_out *arg)
sanitize_global_limit(&max_user_bgreq);
sanitize_global_limit(&max_user_congthresh);
- spin_lock(&fc->bg_lock);
if (arg->max_background) {
- fc->max_background = arg->max_background;
+ unsigned int max_background = arg->max_background;
+
+ if (!cap_sys_admin && max_background > max_user_bgreq)
+ max_background = max_user_bgreq;
- if (!cap_sys_admin && fc->max_background > max_user_bgreq)
- fc->max_background = max_user_bgreq;
+ fuse_chan_max_background_set(fc->chan, max_background);
}
if (arg->congestion_threshold) {
fc->congestion_threshold = arg->congestion_threshold;
@@ -1279,49 +1260,22 @@ static void process_init_limits(struct fuse_conn *fc, struct fuse_init_out *arg)
fc->congestion_threshold > max_user_congthresh)
fc->congestion_threshold = max_user_congthresh;
}
- spin_unlock(&fc->bg_lock);
-}
-
-static void set_request_timeout(struct fuse_conn *fc, unsigned int timeout)
-{
- fc->timeout.req_timeout = secs_to_jiffies(timeout);
- INIT_DELAYED_WORK(&fc->timeout.work, fuse_check_timeout);
- queue_delayed_work(system_percpu_wq, &fc->timeout.work,
- fuse_timeout_timer_freq);
-}
-
-static void init_server_timeout(struct fuse_conn *fc, unsigned int timeout)
-{
- if (!timeout && !fuse_max_req_timeout && !fuse_default_req_timeout)
- return;
-
- if (!timeout)
- timeout = fuse_default_req_timeout;
-
- if (fuse_max_req_timeout) {
- if (timeout)
- timeout = min(fuse_max_req_timeout, timeout);
- else
- timeout = fuse_max_req_timeout;
- }
-
- timeout = max(FUSE_TIMEOUT_TIMER_FREQ, timeout);
-
- set_request_timeout(fc, timeout);
}
struct fuse_init_args {
struct fuse_args args;
struct fuse_init_in in;
struct fuse_init_out out;
+ struct fuse_mount *fm;
};
-static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
- int error)
+static void process_init_reply(struct fuse_args *args, int error)
{
- struct fuse_conn *fc = fm->fc;
struct fuse_init_args *ia = container_of(args, typeof(*ia), args);
+ struct fuse_mount *fm = ia->fm;
+ struct fuse_conn *fc = fm->fc;
struct fuse_init_out *arg = &ia->out;
+ bool io_uring_enabled = false;
bool ok = true;
if (error || arg->major != FUSE_KERNEL_VERSION)
@@ -1452,7 +1406,7 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
ok = false;
}
if (flags & FUSE_OVER_IO_URING && fuse_uring_enabled())
- fc->io_uring = 1;
+ io_uring_enabled = true;
if (flags & FUSE_REQUEST_TIMEOUT)
timeout = arg->request_timeout;
@@ -1462,10 +1416,11 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
fc->no_flock = 1;
}
- init_server_timeout(fc, timeout);
+ fuse_init_server_timeout(fc->chan, timeout);
fm->sb->s_bdi->ra_pages =
min(fm->sb->s_bdi->ra_pages, ra_pages);
+ fm->sb->s_bdi->io_pages = fc->max_pages;
fc->minor = arg->minor;
fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
fc->max_write = max_t(unsigned, 4096, fc->max_write);
@@ -1476,10 +1431,16 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
if (!ok) {
fc->conn_init = 0;
fc->conn_error = 1;
+ fuse_chan_set_initialized(fc->chan, NULL);
+ } else {
+ struct fuse_chan_param cp = {
+ .minor = fc->minor,
+ .max_write = fc->max_write,
+ .max_pages = fc->max_pages,
+ .io_uring_enabled = io_uring_enabled,
+ };
+ fuse_chan_set_initialized(fc->chan, &cp);
}
-
- fuse_set_initialized(fc);
- wake_up_all(&fc->blocked_waitq);
}
static struct fuse_init_args *fuse_new_init(struct fuse_mount *fm)
@@ -1489,6 +1450,7 @@ static struct fuse_init_args *fuse_new_init(struct fuse_mount *fm)
ia = kzalloc_obj(*ia, GFP_KERNEL | __GFP_NOFAIL);
+ ia->fm = fm;
ia->in.major = FUSE_KERNEL_VERSION;
ia->in.minor = FUSE_KERNEL_MINOR_VERSION;
ia->in.max_readahead = fm->sb->s_bdi->ra_pages * PAGE_SIZE;
@@ -1518,12 +1480,8 @@ static struct fuse_init_args *fuse_new_init(struct fuse_mount *fm)
if (IS_ENABLED(CONFIG_FUSE_PASSTHROUGH))
flags |= FUSE_PASSTHROUGH;
- /*
- * This is just an information flag for fuse server. No need to check
- * the reply - server is either sending IORING_OP_URING_CMD or not.
- */
if (fuse_uring_enabled())
- flags |= FUSE_OVER_IO_URING;
+ flags |= FUSE_OVER_IO_URING | FUSE_HAS_IO_URING_BUFPOOL;
ia->in.flags = flags;
ia->in.flags2 = flags >> 32;
@@ -1551,6 +1509,7 @@ int fuse_send_init(struct fuse_mount *fm)
int err;
if (fm->fc->sync_init) {
+ ia->args.abort_on_kill = true;
err = fuse_simple_request(fm, &ia->args);
/* Ignore size of init reply */
if (err > 0)
@@ -1561,7 +1520,7 @@ int fuse_send_init(struct fuse_mount *fm)
if (!err)
return 0;
}
- process_init_reply(fm, &ia->args, err);
+ process_init_reply(&ia->args, err);
if (fm->fc->conn_error)
return -ENOTCONN;
return 0;
@@ -1570,7 +1529,6 @@ EXPORT_SYMBOL_GPL(fuse_send_init);
void fuse_free_conn(struct fuse_conn *fc)
{
- WARN_ON(!list_empty(&fc->devices));
kfree(fc);
}
EXPORT_SYMBOL_GPL(fuse_free_conn);
@@ -1613,66 +1571,6 @@ static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
return 0;
}
-struct fuse_dev *fuse_dev_alloc(void)
-{
- struct fuse_dev *fud;
- struct list_head *pq;
-
- fud = kzalloc_obj(struct fuse_dev);
- if (!fud)
- return NULL;
-
- pq = kzalloc_objs(struct list_head, FUSE_PQ_HASH_SIZE);
- if (!pq) {
- kfree(fud);
- return NULL;
- }
-
- fud->pq.processing = pq;
- fuse_pqueue_init(&fud->pq);
-
- return fud;
-}
-EXPORT_SYMBOL_GPL(fuse_dev_alloc);
-
-void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc)
-{
- fud->fc = fuse_conn_get(fc);
- spin_lock(&fc->lock);
- list_add_tail(&fud->entry, &fc->devices);
- spin_unlock(&fc->lock);
-}
-EXPORT_SYMBOL_GPL(fuse_dev_install);
-
-struct fuse_dev *fuse_dev_alloc_install(struct fuse_conn *fc)
-{
- struct fuse_dev *fud;
-
- fud = fuse_dev_alloc();
- if (!fud)
- return NULL;
-
- fuse_dev_install(fud, fc);
- return fud;
-}
-EXPORT_SYMBOL_GPL(fuse_dev_alloc_install);
-
-void fuse_dev_free(struct fuse_dev *fud)
-{
- struct fuse_conn *fc = fud->fc;
-
- if (fc) {
- spin_lock(&fc->lock);
- list_del(&fud->entry);
- spin_unlock(&fc->lock);
-
- fuse_conn_put(fc);
- }
- kfree(fud->pq.processing);
- kfree(fud);
-}
-EXPORT_SYMBOL_GPL(fuse_dev_free);
-
static void fuse_fill_attr_from_inode(struct fuse_attr *attr,
const struct fuse_inode *fi)
{
@@ -1709,6 +1607,7 @@ static void fuse_sb_defaults(struct super_block *sb)
sb->s_export_op = &fuse_export_operations;
sb->s_iflags |= SB_I_IMA_UNVERIFIABLE_SIGNATURE;
sb->s_iflags |= SB_I_NOIDMAP;
+ sb->s_iflags |= SB_I_NO_DATA_INTEGRITY;
if (sb->s_user_ns != &init_user_ns)
sb->s_iflags |= SB_I_UNTRUSTED_MOUNTER;
sb->s_flags &= ~(SB_NOSEC | SB_I_VERSION);
@@ -1742,6 +1641,8 @@ static int fuse_fill_super_submount(struct super_block *sb,
fuse_fill_attr_from_inode(&root_attr, parent_fi);
root = fuse_iget(sb, parent_fi->nodeid, 0, &root_attr, 0, 0,
fuse_get_evict_ctr(fm->fc));
+ if (!root)
+ return -ENOMEM;
/*
* This inode is just a duplicate, so it is not looked up and
* its nlookup should not be incremented. fuse_iget() does
@@ -1822,7 +1723,7 @@ EXPORT_SYMBOL_GPL(fuse_init_fs_context_submount);
int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
{
- struct fuse_dev *fud = NULL;
+ struct fuse_dev *fud = ctx->fud;
struct fuse_mount *fm = get_fuse_mount_super(sb);
struct fuse_conn *fc = fm->fc;
struct inode *root;
@@ -1856,18 +1757,11 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
goto err;
}
- if (ctx->fudptr) {
- err = -ENOMEM;
- fud = fuse_dev_alloc_install(fc);
- if (!fud)
- goto err_free_dax;
- }
-
fc->dev = sb->s_dev;
fm->sb = sb;
err = fuse_bdi_init(fc, sb);
if (err)
- goto err_dev_free;
+ goto err_free_dax;
/* Handle umasking inside the fuse code */
if (sb->s_flags & SB_POSIXACL)
@@ -1889,15 +1783,15 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
set_default_d_op(sb, &fuse_dentry_operations);
root_dentry = d_make_root(root);
if (!root_dentry)
- goto err_dev_free;
+ goto err_free_dax;
mutex_lock(&fuse_mutex);
err = -EINVAL;
- if (ctx->fudptr && *ctx->fudptr) {
- if (*ctx->fudptr == FUSE_DEV_SYNC_INIT)
- fc->sync_init = 1;
- else
+ if (fud) {
+ if (fuse_dev_is_installed(fud))
goto err_unlock;
+ if (fuse_dev_is_sync_init(fud))
+ fc->sync_init = 1;
}
err = fuse_ctl_add_conn(fc);
@@ -1906,19 +1800,15 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx)
list_add_tail(&fc->entry, &fuse_conn_list);
sb->s_root = root_dentry;
- if (ctx->fudptr) {
- *ctx->fudptr = fud;
- wake_up_all(&fuse_dev_waitq);
- }
+ if (fud)
+ fuse_dev_install(fud, fc->chan);
+
mutex_unlock(&fuse_mutex);
return 0;
err_unlock:
mutex_unlock(&fuse_mutex);
dput(root_dentry);
- err_dev_free:
- if (fud)
- fuse_dev_free(fud);
err_free_dax:
if (IS_ENABLED(CONFIG_FUSE_DAX))
fuse_dax_conn_free(fc);
@@ -1933,24 +1823,13 @@ static int fuse_fill_super(struct super_block *sb, struct fs_context *fsc)
struct fuse_mount *fm;
int err;
- if (!ctx->file || !ctx->rootmode_present ||
+ if (!ctx->fud || !ctx->rootmode_present ||
!ctx->user_id_present || !ctx->group_id_present)
return -EINVAL;
- /*
- * Require mount to happen from the same user namespace which
- * opened /dev/fuse to prevent potential attacks.
- */
- if ((ctx->file->f_op != &fuse_dev_operations) ||
- (ctx->file->f_cred->user_ns != sb->s_user_ns))
- return -EINVAL;
- ctx->fudptr = &ctx->file->private_data;
-
err = fuse_fill_super_common(sb, ctx);
if (err)
return err;
- /* file->private_data shall be visible on all CPUs after this */
- smp_mb();
fm = get_fuse_mount_super(sb);
@@ -1968,19 +1847,21 @@ static int fuse_set_no_super(struct super_block *sb, struct fs_context *fsc)
static int fuse_test_super(struct super_block *sb, struct fs_context *fsc)
{
-
- return fsc->sget_key == get_fuse_conn_super(sb);
+ return fuse_dev_verify(fsc->sget_key, get_fuse_conn_super(sb)->chan);
}
static int fuse_get_tree(struct fs_context *fsc)
{
struct fuse_fs_context *ctx = fsc->fs_private;
- struct fuse_dev *fud;
struct fuse_conn *fc;
struct fuse_mount *fm;
struct super_block *sb;
+ struct fuse_chan *fch __free(fuse_chan_free) = fuse_dev_chan_new();
int err;
+ if (!fch)
+ return -ENOMEM;
+
fc = kmalloc_obj(*fc);
if (!fc)
return -ENOMEM;
@@ -1991,14 +1872,11 @@ static int fuse_get_tree(struct fs_context *fsc)
return -ENOMEM;
}
- fuse_conn_init(fc, fm, fsc->user_ns, &fuse_dev_fiq_ops, NULL);
+ fuse_conn_init(fc, fm, fsc->user_ns, no_free_ptr(fch));
fc->release = fuse_free_conn;
fsc->s_fs_info = fm;
- if (ctx->fd_present)
- ctx->file = fget(ctx->fd);
-
if (IS_ENABLED(CONFIG_BLOCK) && ctx->is_bdev) {
err = get_tree_bdev(fsc, fuse_fill_super);
goto out;
@@ -2008,16 +1886,15 @@ static int fuse_get_tree(struct fs_context *fsc)
* (found by device name), normal fuse mounts can't
*/
err = -EINVAL;
- if (!ctx->file)
+ if (!ctx->fud)
goto out;
/*
* Allow creating a fuse mount with an already initialized fuse
* connection
*/
- fud = __fuse_get_dev(ctx->file);
- if (ctx->file->f_op == &fuse_dev_operations && fud) {
- fsc->sget_key = fud->fc;
+ if (fuse_dev_is_installed(ctx->fud)) {
+ fsc->sget_key = ctx->fud;
sb = sget_fc(fsc, fuse_test_super, fuse_set_no_super);
err = PTR_ERR_OR_ZERO(sb);
if (!IS_ERR(sb))
@@ -2028,8 +1905,6 @@ static int fuse_get_tree(struct fs_context *fsc)
out:
if (fsc->s_fs_info)
fuse_mount_destroy(fm);
- if (ctx->file)
- fput(ctx->file);
return err;
}
@@ -2089,8 +1964,8 @@ void fuse_conn_destroy(struct fuse_mount *fm)
if (fc->destroy)
fuse_send_destroy(fm);
- fuse_abort_conn(fc);
- fuse_wait_aborted(fc);
+ fuse_chan_abort(fc->chan, false);
+ fuse_chan_wait_aborted(fc->chan);
if (!list_empty(&fc->entry)) {
mutex_lock(&fuse_mutex);