*/
#include "fuse_i.h"
-#include "fuse_dev_i.h"
+#include "dev.h"
#include <linux/init.h>
#include <linux/module.h>
if (!fc)
return 0;
- value = atomic_read(&fc->chan->num_waiting);
+ value = fuse_chan_num_waiting(fc->chan);
file->private_data = (void *)value;
fuse_conn_put(fc);
}
if (!fc)
return 0;
- val = READ_ONCE(fc->chan->max_background);
+ val = fuse_chan_max_background(fc->chan);
fuse_conn_put(fc);
return fuse_conn_limit_read(file, buf, len, ppos, val);
if (ret > 0) {
struct fuse_conn *fc = fuse_ctl_file_conn_get(file);
if (fc) {
- spin_lock(&fc->chan->bg_lock);
- fc->chan->max_background = val;
- fc->chan->blocked = fc->chan->num_background >= fc->chan->max_background;
- if (!fc->chan->blocked)
- wake_up(&fc->chan->blocked_waitq);
- spin_unlock(&fc->chan->bg_lock);
+ fuse_chan_max_background_set(fc->chan, val);
fuse_conn_put(fc);
}
}
refcount_dec(&req->count);
}
-void fuse_set_initialized(struct fuse_conn *fc)
+void fuse_chan_set_initialized(struct fuse_chan *fch)
{
/* Make sure stores before this are seen on another CPU */
smp_wmb();
- fc->chan->initialized = 1;
+ fch->initialized = 1;
+ wake_up_all(&fch->blocked_waitq);
}
static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background)
(TASK_KILLABLE | TASK_FREEZABLE)))
goto out;
}
- /* Matches smp_wmb() in fuse_set_initialized() */
+ /* Matches smp_wmb() in fuse_chan_set_initialized() */
smp_rmb();
err = -ENOTCONN;
if (fiq->ops->release)
fiq->ops->release(fiq);
+
+ if (fch->timeout.req_timeout)
+ cancel_delayed_work_sync(&fch->timeout.work);
}
void fuse_chan_free(struct fuse_chan *fch)
}
EXPORT_SYMBOL_GPL(fuse_dev_chan_new);
+unsigned int fuse_chan_num_background(struct fuse_chan *fch)
+{
+ return fch->num_background;
+}
+
+unsigned int fuse_chan_max_background(struct fuse_chan *fch)
+{
+ return READ_ONCE(fch->max_background);
+}
+
+void fuse_chan_max_background_set(struct fuse_chan *fch, unsigned int val)
+{
+ spin_lock(&fch->bg_lock);
+ fch->max_background = val;
+ fch->blocked = fch->num_background >= fch->max_background;
+ if (!fch->blocked)
+ wake_up(&fch->blocked_waitq);
+ spin_unlock(&fch->bg_lock);
+}
+
+unsigned int fuse_chan_num_waiting(struct fuse_chan *fch)
+{
+ return atomic_read(&fch->num_waiting);
+}
+
+void fuse_chan_set_fc(struct fuse_chan *fch, struct fuse_conn *fc)
+{
+ fch->conn = fc;
+}
+
+void fuse_chan_io_uring_enable(struct fuse_chan *fch)
+{
+ fch->io_uring = 1;
+}
+
void fuse_pqueue_init(struct fuse_pqueue *fpq)
{
unsigned int i;
}
EXPORT_SYMBOL_GPL(fuse_dev_put);
+bool fuse_dev_is_installed(struct fuse_dev *fud)
+{
+ struct fuse_conn *fc = fuse_dev_fc_get(fud);
+
+ return fc != NULL && fc != FUSE_DEV_FC_DISCONNECTED;
+}
+
+/*
+ * Checks if @fc matches the one installed in @fud
+ */
+bool fuse_dev_verify(struct fuse_dev *fud, struct fuse_conn *fc)
+{
+ return fuse_dev_fc_get(fud) == fc;
+}
+
+bool fuse_dev_is_sync_init(struct fuse_dev *fud)
+{
+ return fud->sync_init;
+}
+
+struct fuse_dev *fuse_dev_grab(struct file *file)
+{
+ struct fuse_dev *fud = fuse_file_to_fud(file);
+
+ refcount_inc(&fud->ref);
+ return fud;
+}
+
static void fuse_send_one(struct fuse_iqueue *fiq, struct fuse_req *req)
{
req->in.h.len = sizeof(struct fuse_in_header) +
fc->chan->connected = 0;
spin_unlock(&fc->chan->bg_lock);
- fuse_set_initialized(fc);
+ fuse_chan_set_initialized(fc->chan);
list_for_each_entry(fud, &fc->chan->devices, entry) {
struct fuse_pqueue *fpq = &fud->pq;
{
/* matches implicit memory barrier in fuse_drop_waiting() */
smp_mb();
- wait_event(fc->chan->blocked_waitq, atomic_read(&fc->chan->num_waiting) == 0);
+ wait_event(fc->chan->blocked_waitq, fuse_chan_num_waiting(fc->chan) == 0);
fuse_uring_wait_stopped_queues(fc);
}
struct fuse_conn;
struct fuse_chan;
struct fuse_dev;
+struct file;
struct fuse_chan *fuse_chan_new(void);
struct fuse_chan *fuse_dev_chan_new(void);
void fuse_chan_release(struct fuse_chan *fch);
void fuse_chan_free(struct fuse_chan *fch);
+unsigned int fuse_chan_num_background(struct fuse_chan *fch);
+unsigned int fuse_chan_max_background(struct fuse_chan *fch);
+void fuse_chan_max_background_set(struct fuse_chan *fch, unsigned int val);
+unsigned int fuse_chan_num_waiting(struct fuse_chan *fch);
+void fuse_chan_set_fc(struct fuse_chan *fch, struct fuse_conn *fc);
+void fuse_chan_set_initialized(struct fuse_chan *fch);
+void fuse_chan_io_uring_enable(struct fuse_chan *fch);
+
DEFINE_FREE(fuse_chan_free, struct fuse_chan *, if (_T) fuse_chan_free(_T))
void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc);
+bool fuse_dev_verify(struct fuse_dev *fud, struct fuse_conn *fc);
void fuse_dev_put(struct fuse_dev *fud);
+bool fuse_dev_is_installed(struct fuse_dev *fud);
+bool fuse_dev_is_sync_init(struct fuse_dev *fud);
+struct fuse_dev *fuse_dev_grab(struct file *file);
void fuse_init_server_timeout(struct fuse_chan *fch, unsigned int timeout);
+#ifdef CONFIG_FUSE_IO_URING
+bool fuse_uring_enabled(void);
+void fuse_uring_destruct(struct fuse_chan *fch);
+#else /* CONFIG_FUSE_IO_URING */
+static inline bool fuse_uring_enabled(void)
+{
+ return false;
+}
+
+static inline void fuse_uring_destruct(struct fuse_chan *fch)
+{
+}
+#endif /* CONFIG_FUSE_IO_URING */
+
#endif /* _FS_FUSE_DEV_H */
* Copyright (c) 2023-2024 DataDirect Networks.
*/
+#include "dev.h"
#include "fuse_i.h"
#include "dev_uring_i.h"
#include "fuse_dev_i.h"
return false;
}
-void fuse_uring_destruct(struct fuse_conn *fc)
+void fuse_uring_destruct(struct fuse_chan *fch)
{
- struct fuse_ring *ring = fc->chan->ring;
+ struct fuse_ring *ring = fch->ring;
int qid;
if (!ring)
kfree(ring->queues);
kfree(ring);
- fc->chan->ring = NULL;
+ fch->ring = NULL;
}
/*
bool ready;
};
-bool fuse_uring_enabled(void);
-void fuse_uring_destruct(struct fuse_conn *fc);
void fuse_uring_stop_queues(struct fuse_ring *ring);
void fuse_uring_abort_end_requests(struct fuse_ring *ring);
int fuse_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags);
#else /* CONFIG_FUSE_IO_URING */
-static inline void fuse_uring_destruct(struct fuse_conn *fc)
-{
-}
-
-static inline bool fuse_uring_enabled(void)
-{
- return false;
-}
-
static inline void fuse_uring_abort(struct fuse_conn *fc)
{
}
*/
#include "fuse_i.h"
-#include "fuse_dev_i.h"
+#include "dev.h"
#include <linux/pagemap.h>
#include <linux/slab.h>
ia = NULL;
}
if (!ia) {
- if (fc->chan->num_background >= fc->congestion_threshold &&
+ if (fuse_chan_num_background(fc->chan) >= fc->congestion_threshold &&
rac->ra->async_size >= readahead_count(rac))
/*
* Congested and only async pages left, so skip the
return -EIO;
if (wbc->sync_mode == WB_SYNC_NONE &&
- fc->chan->num_background >= fc->congestion_threshold)
+ fuse_chan_num_background(fc->chan) >= fc->congestion_threshold)
return 0;
return iomap_writepages(&wpc);
int fuse_do_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr, struct file *file);
-void fuse_set_initialized(struct fuse_conn *fc);
-
void fuse_unlock_inode(struct inode *inode, bool locked);
bool fuse_lock_inode(struct inode *inode);
#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>
if (file->f_cred->user_ns != fsc->user_ns)
return invalfc(fsc, "wrong user namespace for fuse device");
- ctx->fud = file->private_data;
- refcount_inc(&ctx->fud->ref);
+ ctx->fud = fuse_dev_grab(file);
return 0;
}
INIT_LIST_HEAD(&fc->mounts);
list_add(&fm->fc_entry, &fc->mounts);
fm->fc = fc;
- fch->conn = fc;
+ fuse_chan_set_fc(fch, fc);
fc->chan = fch;
}
EXPORT_SYMBOL_GPL(fuse_conn_init);
{
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);
if (IS_ENABLED(CONFIG_FUSE_DAX))
fuse_dax_conn_free(fc);
- if (fc->chan->timeout.req_timeout)
- cancel_delayed_work_sync(&fc->chan->timeout.work);
cancel_work_sync(&fc->epoch_work);
fuse_chan_release(fc->chan);
put_pid_ns(fc->pid_ns);
sanitize_global_limit(&max_user_bgreq);
sanitize_global_limit(&max_user_congthresh);
- spin_lock(&fc->chan->bg_lock);
if (arg->max_background) {
- fc->chan->max_background = arg->max_background;
+ unsigned int max_background = arg->max_background;
- if (!cap_sys_admin && fc->chan->max_background > max_user_bgreq)
- fc->chan->max_background = max_user_bgreq;
+ if (!cap_sys_admin && max_background > max_user_bgreq)
+ max_background = max_user_bgreq;
+
+ fuse_chan_max_background_set(fc->chan, max_background);
}
if (arg->congestion_threshold) {
fc->congestion_threshold = arg->congestion_threshold;
fc->congestion_threshold > max_user_congthresh)
fc->congestion_threshold = max_user_congthresh;
}
- spin_unlock(&fc->chan->bg_lock);
}
struct fuse_init_args {
ok = false;
}
if (flags & FUSE_OVER_IO_URING && fuse_uring_enabled())
- fc->chan->io_uring = 1;
+ fuse_chan_io_uring_enable(fc->chan);
if (flags & FUSE_REQUEST_TIMEOUT)
timeout = arg->request_timeout;
fc->conn_error = 1;
}
- fuse_set_initialized(fc);
- wake_up_all(&fc->chan->blocked_waitq);
+ fuse_chan_set_initialized(fc->chan);
}
static struct fuse_init_args *fuse_new_init(struct fuse_mount *fm)
mutex_lock(&fuse_mutex);
err = -EINVAL;
if (fud) {
- if (fuse_dev_fc_get(fud))
+ if (fuse_dev_is_installed(fud))
goto err_unlock;
- if (fud->sync_init)
+ if (fuse_dev_is_sync_init(fud))
fc->sync_init = 1;
}
static int fuse_test_super(struct super_block *sb, struct fs_context *fsc)
{
- struct fuse_dev *fud = fsc->sget_key;
-
- return fuse_dev_fc_get(fud) == get_fuse_conn_super(sb);
+ return fuse_dev_verify(fsc->sget_key, get_fuse_conn_super(sb));
}
static int fuse_get_tree(struct fs_context *fsc)
* Allow creating a fuse mount with an already initialized fuse
* connection
*/
- if (fuse_dev_fc_get(ctx->fud)) {
+ 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);