Contributors: 9
Author Tokens Token Proportion Commits Commit Proportion
Miklos Szeredi 572 59.40% 48 63.16%
Bernd Schubert 262 27.21% 11 14.47%
Stefan Hajnoczi 37 3.84% 4 5.26%
Joanne Koong 36 3.74% 7 9.21%
Randy Dunlap 31 3.22% 1 1.32%
Kirill V Tkhai 17 1.77% 2 2.63%
Maxim Patlasov 4 0.42% 1 1.32%
Csaba Henk 3 0.31% 1 1.32%
Max Reitz 1 0.10% 1 1.32%
Total 963 76


/* SPDX-License-Identifier: GPL-2.0
 *
 * FUSE: Filesystem in Userspace
 * Copyright (C) 2001-2008  Miklos Szeredi <miklos@szeredi.hu>
 */
#ifndef _FS_FUSE_DEV_I_H
#define _FS_FUSE_DEV_I_H

#include <linux/fuse.h>
#include <linux/types.h>
#include <linux/refcount.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/fs.h>

/* Ordinary requests have even IDs, while interrupts IDs are odd */
#define FUSE_INT_REQ_BIT (1ULL << 0)
#define FUSE_REQ_ID_STEP (1ULL << 1)

struct fuse_arg;
struct fuse_args;
struct fuse_pqueue;
struct fuse_iqueue;

/**
 * enum fuse_req_flag - Request flags
 *
 * @FR_ISREPLY:		set if the request has reply
 * @FR_FORCE:		force sending of the request even if interrupted
 * @FR_BACKGROUND:	request is sent in the background
 * @FR_WAITING:		request is counted as "waiting"
 * @FR_ABORTED:		the request was aborted
 * @FR_INTERRUPTED:	the request has been interrupted
 * @FR_LOCKED:		data is being copied to/from the request
 * @FR_PENDING:		request is not yet in userspace
 * @FR_SENT:		request is in userspace, waiting for an answer
 * @FR_FINISHED:	request is finished
 * @FR_PRIVATE:		request is on private list
 * @FR_ASYNC:		request is asynchronous
 * @FR_URING:		request is handled through fuse-io-uring
 */
enum fuse_req_flag {
	FR_ISREPLY,
	FR_FORCE,
	FR_BACKGROUND,
	FR_WAITING,
	FR_ABORTED,
	FR_INTERRUPTED,
	FR_LOCKED,
	FR_PENDING,
	FR_SENT,
	FR_FINISHED,
	FR_PRIVATE,
	FR_ASYNC,
	FR_URING,
};

/**
 * struct fuse_req - A request to the client
 *
 * .waitq.lock protects the following fields:
 *   - FR_ABORTED
 *   - FR_LOCKED (may also be modified under fpq->lock, tested under both)
 */
struct fuse_req {
	/**
	 * @list: This can be on either pending processing or io lists in
	 * fuse_conn
	 */
	struct list_head list;

	/** @intr_entry: Entry on the interrupts list  */
	struct list_head intr_entry;

	/** @args: Input/output arguments */
	struct fuse_args *args;

	/** @count: refcount */
	refcount_t count;

	/** @flags: Request flags, updated with test/set/clear_bit() */
	unsigned long flags;

	/** @in: The request input header */
	struct {
		/** @in.h: The request input header */
		struct fuse_in_header h;
	} in;

	/** @out: The request output header */
	struct {
		/** @out.h: The request output header */
		struct fuse_out_header h;
	} out;

	/** @waitq: Used to wake up the task waiting for completion of request */
	wait_queue_head_t waitq;

#if IS_ENABLED(CONFIG_VIRTIO_FS)
	/**
	 * @argbuf: virtio-fs's physically contiguous buffer for in and out
	 * args
	 */
	void *argbuf;
#endif

	/** @chan: fuse_chan this request belongs to */
	struct fuse_chan *chan;

#ifdef CONFIG_FUSE_IO_URING
	void *ring_entry;
	void *ring_queue;
#endif
	/** @create_time: When (in jiffies) the request was created */
	unsigned long create_time;
};

/* One forget request */
struct fuse_forget_link {
	struct fuse_forget_one forget_one;
	struct fuse_forget_link *next;
};

/**
 * struct fuse_iqueue_ops - Input queue callbacks
 *
 * Input queue signalling is device-specific.  For example, the /dev/fuse file
 * uses fiq->waitq and fasync to wake processes that are waiting on queue
 * readiness.  These callbacks allow other device types to respond to input
 * queue activity.
 */
struct fuse_iqueue_ops {
	/**
	 * @send_forget: Send one forget
	 */
	void (*send_forget)(struct fuse_iqueue *fiq, struct fuse_forget_link *link);

	/**
	 * @send_interrupt: Send interrupt for request
	 */
	void (*send_interrupt)(struct fuse_iqueue *fiq, struct fuse_req *req);

	/**
	 * @send_req: Send one request
	 */
	void (*send_req)(struct fuse_iqueue *fiq, struct fuse_req *req);

	/**
	 * @release: Clean up when fuse_iqueue is destroyed
	 */
	void (*release)(struct fuse_iqueue *fiq);
};

struct fuse_iqueue {
	/** Connection established */
	unsigned connected;

	/** Lock protecting accesses to members of this structure */
	spinlock_t lock;

	/** Readers of the connection are waiting on this */
	wait_queue_head_t waitq;

	/** The next unique request id */
	u64 reqctr;

	/** The list of pending requests */
	struct list_head pending;

	/** Pending interrupts */
	struct list_head interrupts;

	/** Queue of pending forgets */
	struct fuse_forget_link forget_list_head;
	struct fuse_forget_link *forget_list_tail;

	/** Batching of FORGET requests (positive indicates FORGET batch) */
	int forget_batch;

	/** O_ASYNC requests */
	struct fasync_struct *fasync;

	/** Device-specific callbacks */
	const struct fuse_iqueue_ops *ops;

	/** Device-specific state */
	void *priv;
};

struct fuse_chan {
	/** Lock protecting:
	    - devices
	    - connected
	    - ring
	    - ring->queues[qid]
	 */
	spinlock_t lock;

	/* back pointer: fc->chan->conn == fc */
	struct fuse_conn *conn;

	/** Input queue */
	struct fuse_iqueue iq;

	/** List of device instances belonging to this connection */
	struct list_head devices;

	/** Maximum number of outstanding background requests */
	unsigned max_background;

	/** Number of requests currently in the background */
	unsigned num_background;

	/** Number of background requests currently queued for userspace */
	unsigned active_background;

	/** The list of background requests set aside for later queuing */
	struct list_head bg_queue;

	/** Protects: max_background, num_background, active_background, bg_queue, blocked */
	spinlock_t bg_lock;

	/** Flag indicating that INIT reply has been received. Allocating
	 * any fuse request will be suspended until the flag is set */
	int initialized;

	/** Flag indicating if connection is blocked.  This will be
	    the case before the INIT reply is received, and if there
	    are too many outstading backgrounds requests */
	int blocked;

	/** waitq for blocked connection */
	wait_queue_head_t blocked_waitq;

	/** Connection established, cleared on umount, connection
	    abort and device release */
	unsigned connected;

	/** The number of requests waiting for completion */
	atomic_t num_waiting;

	/** Is interrupt not implemented by fs? */
	bool no_interrupt;

	/* Use io_uring for communication */
	unsigned int io_uring;

	/* Negotiated minor version */
	unsigned int minor;

	/* Maximum write size */
	unsigned int max_write;

	/* Maximum number of pages that can be used in a single request */
	unsigned int max_pages;

	/* Before being installed into fud, contains the preallocated pq array*/
	struct list_head *pq_prealloc;

	/** Connection aborted via sysfs, respond with ECONNABORTED on device I/O */
	bool abort_with_err;

#ifdef CONFIG_FUSE_IO_URING
	/**  uring connection information*/
	struct fuse_ring *ring;
#endif

	/** Only used if the connection opts into request timeouts */
	struct {
		/* Worker for checking if any requests have timed out */
		struct delayed_work work;

		/* Request timeout (in jiffies). 0 = no timeout */
		unsigned int req_timeout;
	} timeout;
};

#define FUSE_PQ_HASH_BITS 8
#define FUSE_PQ_HASH_SIZE (1 << FUSE_PQ_HASH_BITS)

struct fuse_pqueue {
	/** Connection established */
	unsigned connected;

	/** Lock protecting accessess to  members of this structure */
	spinlock_t lock;

	/** Hash table of requests being processed */
	struct list_head *processing;

	/** The list of requests under I/O */
	struct list_head io;
};

/**
 * struct fuse_dev - Fuse device instance
 */
struct fuse_dev {
	/** @ref: Reference count of this object */
	refcount_t ref;

	/** @sync_init: Issue FUSE_INIT synchronously */
	bool sync_init;

	/** @chan: Fuse channel for this device */
	struct fuse_chan *chan;

	/** @pq: Processing queue */
	struct fuse_pqueue pq;

	/** @entry: list entry on fch->devices */
	struct list_head entry;
};

struct fuse_copy_state {
	struct fuse_req *req;
	struct iov_iter *iter;
	struct pipe_buffer *pipebufs;
	struct pipe_buffer *currbuf;
	struct pipe_inode_info *pipe;
	unsigned long nr_segs;
	struct page *pg;
	unsigned int len;
	unsigned int offset;
	bool write:1;
	bool move_folios:1;
	bool is_uring:1;
	struct {
		unsigned int copied_sz; /* copied size into the user buffer */
	} ring;
};

/* fud->chan gets assigned to this value when /dev/fuse is closed */
#define FUSE_DEV_CHAN_DISCONNECTED ((struct fuse_chan *) 1)

/*
 * Lockless access is OK, because fud->chan is set once during mount and is valid
 * until the file is released.
 *
 * fud->chan is set to FUSE_DEV_CHAN_DISCONNECTED only after the containing file is
 * released, so result is safe to dereference in most cases.  Exceptions are:
 * fuse_dev_put() and fuse_fill_super_common().
 */
static inline struct fuse_chan *fuse_dev_chan_get(struct fuse_dev *fud)
{
	/* Pairs with xchg() in fuse_dev_install() */
	return smp_load_acquire(&fud->chan);
}

static inline struct fuse_dev *fuse_file_to_fud(struct file *file)
{
	return file->private_data;
}

static inline struct fuse_dev *__fuse_get_dev(struct file *file)
{
	struct fuse_dev *fud = fuse_file_to_fud(file);

	if (!fuse_dev_chan_get(fud))
		return NULL;

	return fud;
}

void fuse_iqueue_init(struct fuse_iqueue *fiq, const struct fuse_iqueue_ops *ops, void *priv);

struct fuse_dev *fuse_get_dev(struct file *file);

unsigned int fuse_req_hash(u64 unique);
struct fuse_req *fuse_request_find(struct fuse_pqueue *fpq, u64 unique);

void fuse_dev_end_requests(struct list_head *head);
void fuse_request_bg_finish(struct fuse_chan *fch, struct fuse_req *req);

void fuse_copy_init(struct fuse_copy_state *cs, bool write,
			   struct iov_iter *iter);
/*
 * Return the number of bytes in an arguments list
 */
unsigned int fuse_len_args(unsigned int numargs, struct fuse_arg *args);

int fuse_copy_args(struct fuse_copy_state *cs, unsigned int numargs,
		   unsigned int argpages, struct fuse_arg *args,
		   int zeroing);
int fuse_copy_out_args(struct fuse_copy_state *cs, struct fuse_args *args,
		       unsigned int nbytes);
void fuse_dev_queue_forget(struct fuse_iqueue *fiq,
			   struct fuse_forget_link *forget);
void fuse_dev_queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req);
bool fuse_remove_pending_req(struct fuse_req *req, spinlock_t *lock);

bool fuse_request_expired(struct fuse_chan *fch, struct list_head *list);

/*
 * Assign a unique id to a fuse request
 */
void fuse_request_assign_unique(struct fuse_iqueue *fiq, struct fuse_req *req);

/*
 * Get the next unique ID for a request
 */
u64 fuse_get_unique(struct fuse_iqueue *fiq);

struct fuse_dev *fuse_dev_alloc_install(struct fuse_chan *fch);
struct fuse_dev *fuse_dev_alloc(void);

int fuse_dev_release(struct inode *inode, struct file *file);

struct list_head *fuse_pqueue_alloc(void);

/*
 * Initialize the fuse processing queue
 */
void fuse_pqueue_init(struct fuse_pqueue *fpq);

/*
 * End a finished request
 */
void fuse_request_end(struct fuse_req *req);

#endif