fuse update for 6.15

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQSQHSd0lITzzeNWNm3h3BK/laaZPAUCZ+vB5QAKCRDh3BK/laaZ
 PGA2AQCVsyLmZFinaNC10S+Bkmx+a7f9MLhX6u+ILbmio8nT1AD7BKCDFD9pucG0
 pilz+OaCXjXt/og6doyugM4SW/Q3tA0=
 =BhLT
 -----END PGP SIGNATURE-----

Merge tag 'fuse-update-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi:

 - Allow connection to server to time out (Joanne Koong)

 - If server doesn't support creating a hard link, return EPERM rather
   than ENOSYS (Matt Johnston)

 - Allow file names longer than 1024 chars (Bernd Schubert)

 - Fix a possible race if request on io_uring queue is interrupted
   (Bernd Schubert)

 - Misc fixes and cleanups

* tag 'fuse-update-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: remove unneeded atomic set in uring creation
  fuse: fix uring race condition for null dereference of fc
  fuse: Increase FUSE_NAME_MAX to PATH_MAX
  fuse: Allocate only namelen buf memory in fuse_notify_
  fuse: add default_request_timeout and max_request_timeout sysctls
  fuse: add kernel-enforced timeout option for requests
  fuse: optmize missing FUSE_LINK support
  fuse: Return EPERM rather than ENOSYS from link()
  fuse: removed unused function fuse_uring_create() from header
  fuse: {io-uring} Fix a possible req cancellation race
This commit is contained in:
Linus Torvalds 2025-04-02 16:36:59 -07:00
commit 5e17b5c717
10 changed files with 356 additions and 41 deletions

View File

@ -347,3 +347,28 @@ filesystems:
``/proc/sys/fs/fuse/max_pages_limit`` is a read/write file for
setting/getting the maximum number of pages that can be used for servicing
requests in FUSE.
``/proc/sys/fs/fuse/default_request_timeout`` is a read/write file for
setting/getting the default timeout (in seconds) for a fuse server to
reply to a kernel-issued request in the event where the server did not
specify a timeout at mount. If the server set a timeout,
then default_request_timeout will be ignored. The default
"default_request_timeout" is set to 0. 0 indicates no default timeout.
The maximum value that can be set is 65535.
``/proc/sys/fs/fuse/max_request_timeout`` is a read/write file for
setting/getting the maximum timeout (in seconds) for a fuse server to
reply to a kernel-issued request. A value greater than 0 automatically opts
the server into a timeout that will be set to at most "max_request_timeout",
even if the server did not specify a timeout and default_request_timeout is
set to 0. If max_request_timeout is greater than 0 and the server set a timeout
greater than max_request_timeout or default_request_timeout is set to a value
greater than max_request_timeout, the system will use max_request_timeout as the
timeout. 0 indicates no max request timeout. The maximum value that can be set
is 65535.
For timeouts, if the server does not respond to the request by the time
the set timeout elapses, then the connection to the fuse server will be aborted.
Please note that the timeouts are not 100% precise (eg you may set 60 seconds but
the timeout may kick in after 70 seconds). The upper margin of error for the
timeout is roughly FUSE_TIMEOUT_TIMER_FREQ seconds.

View File

@ -32,6 +32,100 @@ MODULE_ALIAS("devname:fuse");
static struct kmem_cache *fuse_req_cachep;
const unsigned long fuse_timeout_timer_freq =
secs_to_jiffies(FUSE_TIMEOUT_TIMER_FREQ);
bool fuse_request_expired(struct fuse_conn *fc, struct list_head *list)
{
struct fuse_req *req;
req = list_first_entry_or_null(list, struct fuse_req, list);
if (!req)
return false;
return time_is_before_jiffies(req->create_time + fc->timeout.req_timeout);
}
bool fuse_fpq_processing_expired(struct fuse_conn *fc, struct list_head *processing)
{
int i;
for (i = 0; i < FUSE_PQ_HASH_SIZE; i++)
if (fuse_request_expired(fc, &processing[i]))
return true;
return false;
}
/*
* Check if any requests aren't being completed by the time the request timeout
* elapses. To do so, we:
* - check the fiq pending list
* - check the bg queue
* - check the fpq io and processing lists
*
* To make this fast, we only check against the head request on each list since
* these are generally queued in order of creation time (eg newer requests get
* queued to the tail). We might miss a few edge cases (eg requests transitioning
* between lists, re-sent requests at the head of the pending list having a
* later creation time than other requests on that list, etc.) but that is fine
* since if the request never gets fulfilled, it will eventually be caught.
*/
void fuse_check_timeout(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct fuse_conn *fc = container_of(dwork, struct fuse_conn,
timeout.work);
struct fuse_iqueue *fiq = &fc->iq;
struct fuse_dev *fud;
struct fuse_pqueue *fpq;
bool expired = false;
if (!atomic_read(&fc->num_waiting))
goto out;
spin_lock(&fiq->lock);
expired = fuse_request_expired(fc, &fiq->pending);
spin_unlock(&fiq->lock);
if (expired)
goto abort_conn;
spin_lock(&fc->bg_lock);
expired = fuse_request_expired(fc, &fc->bg_queue);
spin_unlock(&fc->bg_lock);
if (expired)
goto abort_conn;
spin_lock(&fc->lock);
if (!fc->connected) {
spin_unlock(&fc->lock);
return;
}
list_for_each_entry(fud, &fc->devices, entry) {
fpq = &fud->pq;
spin_lock(&fpq->lock);
if (fuse_request_expired(fc, &fpq->io) ||
fuse_fpq_processing_expired(fc, fpq->processing)) {
spin_unlock(&fpq->lock);
spin_unlock(&fc->lock);
goto abort_conn;
}
spin_unlock(&fpq->lock);
}
spin_unlock(&fc->lock);
if (fuse_uring_request_expired(fc))
goto abort_conn;
out:
queue_delayed_work(system_wq, &fc->timeout.work,
fuse_timeout_timer_freq);
return;
abort_conn:
fuse_abort_conn(fc);
}
static void fuse_request_init(struct fuse_mount *fm, struct fuse_req *req)
{
INIT_LIST_HEAD(&req->list);
@ -40,6 +134,7 @@ static void fuse_request_init(struct fuse_mount *fm, struct fuse_req *req)
refcount_set(&req->count, 1);
__set_bit(FR_PENDING, &req->flags);
req->fm = fm;
req->create_time = jiffies;
}
static struct fuse_req *fuse_request_alloc(struct fuse_mount *fm, gfp_t flags)
@ -407,6 +502,24 @@ static int queue_interrupt(struct fuse_req *req)
return 0;
}
bool fuse_remove_pending_req(struct fuse_req *req, spinlock_t *lock)
{
spin_lock(lock);
if (test_bit(FR_PENDING, &req->flags)) {
/*
* FR_PENDING does not get cleared as the request will end
* up in destruction anyway.
*/
list_del(&req->list);
spin_unlock(lock);
__fuse_put_request(req);
req->out.h.error = -EINTR;
return true;
}
spin_unlock(lock);
return false;
}
static void request_wait_answer(struct fuse_req *req)
{
struct fuse_conn *fc = req->fm->fc;
@ -428,22 +541,20 @@ static void request_wait_answer(struct fuse_req *req)
}
if (!test_bit(FR_FORCE, &req->flags)) {
bool removed;
/* Only fatal signals may interrupt this */
err = wait_event_killable(req->waitq,
test_bit(FR_FINISHED, &req->flags));
if (!err)
return;
spin_lock(&fiq->lock);
/* Request is not yet in userspace, bail out */
if (test_bit(FR_PENDING, &req->flags)) {
list_del(&req->list);
spin_unlock(&fiq->lock);
__fuse_put_request(req);
req->out.h.error = -EINTR;
if (test_bit(FR_URING, &req->flags))
removed = fuse_uring_remove_pending_req(req);
else
removed = fuse_remove_pending_req(req, &fiq->lock);
if (removed)
return;
}
spin_unlock(&fiq->lock);
}
/*
@ -1533,14 +1644,10 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
struct fuse_copy_state *cs)
{
struct fuse_notify_inval_entry_out outarg;
int err = -ENOMEM;
char *buf;
int err;
char *buf = NULL;
struct qstr name;
buf = kzalloc(FUSE_NAME_MAX + 1, GFP_KERNEL);
if (!buf)
goto err;
err = -EINVAL;
if (size < sizeof(outarg))
goto err;
@ -1550,13 +1657,18 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
goto err;
err = -ENAMETOOLONG;
if (outarg.namelen > FUSE_NAME_MAX)
if (outarg.namelen > fc->name_max)
goto err;
err = -EINVAL;
if (size != sizeof(outarg) + outarg.namelen + 1)
goto err;
err = -ENOMEM;
buf = kzalloc(outarg.namelen + 1, GFP_KERNEL);
if (!buf)
goto err;
name.name = buf;
name.len = outarg.namelen;
err = fuse_copy_one(cs, buf, outarg.namelen + 1);
@ -1581,14 +1693,10 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
struct fuse_copy_state *cs)
{
struct fuse_notify_delete_out outarg;
int err = -ENOMEM;
char *buf;
int err;
char *buf = NULL;
struct qstr name;
buf = kzalloc(FUSE_NAME_MAX + 1, GFP_KERNEL);
if (!buf)
goto err;
err = -EINVAL;
if (size < sizeof(outarg))
goto err;
@ -1598,13 +1706,18 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
goto err;
err = -ENAMETOOLONG;
if (outarg.namelen > FUSE_NAME_MAX)
if (outarg.namelen > fc->name_max)
goto err;
err = -EINVAL;
if (size != sizeof(outarg) + outarg.namelen + 1)
goto err;
err = -ENOMEM;
buf = kzalloc(outarg.namelen + 1, GFP_KERNEL);
if (!buf)
goto err;
name.name = buf;
name.len = outarg.namelen;
err = fuse_copy_one(cs, buf, outarg.namelen + 1);
@ -2275,6 +2388,9 @@ void fuse_abort_conn(struct fuse_conn *fc)
LIST_HEAD(to_end);
unsigned int i;
if (fc->timeout.req_timeout)
cancel_delayed_work(&fc->timeout.work);
/* Background queuing checks fc->connected under bg_lock */
spin_lock(&fc->bg_lock);
fc->connected = 0;

View File

@ -140,6 +140,33 @@ void fuse_uring_abort_end_requests(struct fuse_ring *ring)
}
}
bool fuse_uring_request_expired(struct fuse_conn *fc)
{
struct fuse_ring *ring = fc->ring;
struct fuse_ring_queue *queue;
int qid;
if (!ring)
return false;
for (qid = 0; qid < ring->nr_queues; qid++) {
queue = READ_ONCE(ring->queues[qid]);
if (!queue)
continue;
spin_lock(&queue->lock);
if (fuse_request_expired(fc, &queue->fuse_req_queue) ||
fuse_request_expired(fc, &queue->fuse_req_bg_queue) ||
fuse_fpq_processing_expired(fc, queue->fpq.processing)) {
spin_unlock(&queue->lock);
return true;
}
spin_unlock(&queue->lock);
}
return false;
}
void fuse_uring_destruct(struct fuse_conn *fc)
{
struct fuse_ring *ring = fc->ring;
@ -211,7 +238,6 @@ static struct fuse_ring *fuse_uring_create(struct fuse_conn *fc)
ring->nr_queues = nr_queues;
ring->fc = fc;
ring->max_payload_sz = max_payload_size;
atomic_set(&ring->queue_refs, 0);
smp_store_release(&fc->ring, ring);
spin_unlock(&fc->lock);
@ -726,8 +752,6 @@ static void fuse_uring_add_req_to_ring_ent(struct fuse_ring_ent *ent,
struct fuse_req *req)
{
struct fuse_ring_queue *queue = ent->queue;
struct fuse_conn *fc = req->fm->fc;
struct fuse_iqueue *fiq = &fc->iq;
lockdep_assert_held(&queue->lock);
@ -737,9 +761,7 @@ static void fuse_uring_add_req_to_ring_ent(struct fuse_ring_ent *ent,
ent->state);
}
spin_lock(&fiq->lock);
clear_bit(FR_PENDING, &req->flags);
spin_unlock(&fiq->lock);
ent->fuse_req = req;
ent->state = FRRS_FUSE_REQ;
list_move(&ent->list, &queue->ent_w_req_queue);
@ -1238,6 +1260,8 @@ void fuse_uring_queue_fuse_req(struct fuse_iqueue *fiq, struct fuse_req *req)
if (unlikely(queue->stopped))
goto err_unlock;
set_bit(FR_URING, &req->flags);
req->ring_queue = queue;
ent = list_first_entry_or_null(&queue->ent_avail_queue,
struct fuse_ring_ent, list);
if (ent)
@ -1276,6 +1300,8 @@ bool fuse_uring_queue_bq_req(struct fuse_req *req)
return false;
}
set_bit(FR_URING, &req->flags);
req->ring_queue = queue;
list_add_tail(&req->list, &queue->fuse_req_bg_queue);
ent = list_first_entry_or_null(&queue->ent_avail_queue,
@ -1306,6 +1332,13 @@ bool fuse_uring_queue_bq_req(struct fuse_req *req)
return true;
}
bool fuse_uring_remove_pending_req(struct fuse_req *req)
{
struct fuse_ring_queue *queue = req->ring_queue;
return fuse_remove_pending_req(req, &queue->lock);
}
static const struct fuse_iqueue_ops fuse_io_uring_ops = {
/* should be send over io-uring as enhancement */
.send_forget = fuse_dev_queue_forget,

View File

@ -142,6 +142,8 @@ void fuse_uring_abort_end_requests(struct fuse_ring *ring);
int fuse_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags);
void fuse_uring_queue_fuse_req(struct fuse_iqueue *fiq, struct fuse_req *req);
bool fuse_uring_queue_bq_req(struct fuse_req *req);
bool fuse_uring_remove_pending_req(struct fuse_req *req);
bool fuse_uring_request_expired(struct fuse_conn *fc);
static inline void fuse_uring_abort(struct fuse_conn *fc)
{
@ -172,12 +174,6 @@ static inline bool fuse_uring_ready(struct fuse_conn *fc)
#else /* CONFIG_FUSE_IO_URING */
struct fuse_ring;
static inline void fuse_uring_create(struct fuse_conn *fc)
{
}
static inline void fuse_uring_destruct(struct fuse_conn *fc)
{
}
@ -200,6 +196,16 @@ static inline bool fuse_uring_ready(struct fuse_conn *fc)
return false;
}
static inline bool fuse_uring_remove_pending_req(struct fuse_req *req)
{
return false;
}
static inline bool fuse_uring_request_expired(struct fuse_conn *fc)
{
return false;
}
#endif /* CONFIG_FUSE_IO_URING */
#endif /* _FS_FUSE_DEV_URING_I_H */

View File

@ -370,7 +370,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
*inode = NULL;
err = -ENAMETOOLONG;
if (name->len > FUSE_NAME_MAX)
if (name->len > fm->fc->name_max)
goto out;
@ -1137,6 +1137,9 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
struct fuse_mount *fm = get_fuse_mount(inode);
FUSE_ARGS(args);
if (fm->fc->no_link)
goto out;
memset(&inarg, 0, sizeof(inarg));
inarg.oldnodeid = get_node_id(inode);
args.opcode = FUSE_LINK;
@ -1151,6 +1154,12 @@ static int fuse_link(struct dentry *entry, struct inode *newdir,
else if (err == -EINTR)
fuse_invalidate_attr(inode);
if (err == -ENOSYS)
fm->fc->no_link = 1;
out:
if (fm->fc->no_link)
return -EPERM;
return err;
}

View File

@ -61,6 +61,10 @@ int fuse_copy_out_args(struct fuse_copy_state *cs, struct fuse_args *args,
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_conn *fc, struct list_head *list);
bool fuse_fpq_processing_expired(struct fuse_conn *fc, struct list_head *processing);
#endif

View File

@ -38,14 +38,34 @@
/** Bias for fi->writectr, meaning new writepages must not be sent */
#define FUSE_NOWRITE INT_MIN
/** It could be as large as PATH_MAX, but would that have any uses? */
#define FUSE_NAME_MAX 1024
/** Maximum length of a filename, not including terminating null */
/* maximum, small enough for FUSE_MIN_READ_BUFFER*/
#define FUSE_NAME_LOW_MAX 1024
/* maximum, but needs a request buffer > FUSE_MIN_READ_BUFFER */
#define FUSE_NAME_MAX (PATH_MAX - 1)
/** Number of dentries for each connection in the control filesystem */
#define FUSE_CTL_NUM_DENTRIES 5
/* Frequency (in seconds) of request timeout checks, if opted into */
#define FUSE_TIMEOUT_TIMER_FREQ 15
/** Frequency (in jiffies) of request timeout checks, if opted into */
extern const unsigned long fuse_timeout_timer_freq;
/** Maximum of max_pages received in init_out */
extern unsigned int fuse_max_pages_limit;
/*
* Default timeout (in seconds) for the server to reply to a request
* before the connection is aborted, if no timeout was specified on mount.
*/
extern unsigned int fuse_default_req_timeout;
/*
* Max timeout (in seconds) for the server to reply to a request before
* the connection is aborted.
*/
extern unsigned int fuse_max_req_timeout;
/** List of active connections */
extern struct list_head fuse_conn_list;
@ -378,6 +398,7 @@ struct fuse_io_priv {
* 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,
@ -392,6 +413,7 @@ enum fuse_req_flag {
FR_FINISHED,
FR_PRIVATE,
FR_ASYNC,
FR_URING,
};
/**
@ -441,7 +463,10 @@ struct fuse_req {
#ifdef CONFIG_FUSE_IO_URING
void *ring_entry;
void *ring_queue;
#endif
/** When (in jiffies) the request was created */
unsigned long create_time;
};
struct fuse_iqueue;
@ -867,6 +892,9 @@ struct fuse_conn {
/* Use pages instead of pointer for kernel I/O */
unsigned int use_pages_for_kvec_io:1;
/* Is link not implemented by fs? */
unsigned int no_link:1;
/* Use io_uring for communication */
unsigned int io_uring;
@ -900,6 +928,9 @@ struct fuse_conn {
/** Version counter for evict inode */
atomic64_t evict_ctr;
/* maximum file name length */
u32 name_max;
/** Called on final put */
void (*release)(struct fuse_conn *);
@ -935,6 +966,15 @@ struct fuse_conn {
/** 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;
};
/*
@ -1216,6 +1256,9 @@ void fuse_request_end(struct fuse_req *req);
void fuse_abort_conn(struct fuse_conn *fc);
void fuse_wait_aborted(struct fuse_conn *fc);
/* Check if any requests timed out */
void fuse_check_timeout(struct work_struct *work);
/**
* Invalidate inode attributes
*/

View File

@ -37,6 +37,9 @@ DEFINE_MUTEX(fuse_mutex);
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 max_user_bgreq;
module_param_call(max_user_bgreq, set_global_limit, param_get_uint,
@ -979,6 +982,8 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
fc->user_ns = get_user_ns(user_ns);
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 +1012,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);
if (fiq->ops->release)
fiq->ops->release(fiq);
put_pid_ns(fc->pid_ns);
@ -1257,6 +1264,34 @@ static void process_init_limits(struct fuse_conn *fc, struct fuse_init_out *arg)
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_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;
@ -1275,6 +1310,7 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
ok = false;
else {
unsigned long ra_pages;
unsigned int timeout = 0;
process_init_limits(fc, arg);
@ -1338,6 +1374,13 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
fc->max_pages =
min_t(unsigned int, fc->max_pages_limit,
max_t(unsigned int, arg->max_pages, 1));
/*
* PATH_MAX file names might need two pages for
* ops like rename
*/
if (fc->max_pages > 1)
fc->name_max = FUSE_NAME_MAX;
}
if (IS_ENABLED(CONFIG_FUSE_DAX)) {
if (flags & FUSE_MAP_ALIGNMENT &&
@ -1392,12 +1435,17 @@ static void process_init_reply(struct fuse_mount *fm, struct fuse_args *args,
}
if (flags & FUSE_OVER_IO_URING && fuse_uring_enabled())
fc->io_uring = 1;
if (flags & FUSE_REQUEST_TIMEOUT)
timeout = arg->request_timeout;
} else {
ra_pages = fc->max_read / PAGE_SIZE;
fc->no_lock = 1;
fc->no_flock = 1;
}
init_server_timeout(fc, timeout);
fm->sb->s_bdi->ra_pages =
min(fm->sb->s_bdi->ra_pages, ra_pages);
fc->minor = arg->minor;
@ -1439,7 +1487,8 @@ void fuse_send_init(struct fuse_mount *fm)
FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT |
FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP |
FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP |
FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND | FUSE_ALLOW_IDMAP;
FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND | FUSE_ALLOW_IDMAP |
FUSE_REQUEST_TIMEOUT;
#ifdef CONFIG_FUSE_DAX
if (fm->fc->dax)
flags |= FUSE_MAP_ALIGNMENT;

View File

@ -13,6 +13,12 @@ static struct ctl_table_header *fuse_table_header;
/* Bound by fuse_init_out max_pages, which is a u16 */
static unsigned int sysctl_fuse_max_pages_limit = 65535;
/*
* fuse_init_out request timeouts are u16.
* This goes up to ~18 hours, which is plenty for a timeout.
*/
static unsigned int sysctl_fuse_req_timeout_limit = 65535;
static const struct ctl_table fuse_sysctl_table[] = {
{
.procname = "max_pages_limit",
@ -23,6 +29,24 @@ static const struct ctl_table fuse_sysctl_table[] = {
.extra1 = SYSCTL_ONE,
.extra2 = &sysctl_fuse_max_pages_limit,
},
{
.procname = "default_request_timeout",
.data = &fuse_default_req_timeout,
.maxlen = sizeof(fuse_default_req_timeout),
.mode = 0644,
.proc_handler = proc_douintvec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = &sysctl_fuse_req_timeout_limit,
},
{
.procname = "max_request_timeout",
.data = &fuse_max_req_timeout,
.maxlen = sizeof(fuse_max_req_timeout),
.mode = 0644,
.proc_handler = proc_douintvec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = &sysctl_fuse_req_timeout_limit,
},
};
int fuse_sysctl_register(void)

View File

@ -229,6 +229,9 @@
* - FUSE_URING_IN_OUT_HEADER_SZ
* - FUSE_URING_OP_IN_OUT_SZ
* - enum fuse_uring_cmd
*
* 7.43
* - add FUSE_REQUEST_TIMEOUT
*/
#ifndef _LINUX_FUSE_H
@ -264,7 +267,7 @@
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 42
#define FUSE_KERNEL_MINOR_VERSION 43
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@ -435,6 +438,8 @@ struct fuse_file_lock {
* of the request ID indicates resend requests
* FUSE_ALLOW_IDMAP: allow creation of idmapped mounts
* FUSE_OVER_IO_URING: Indicate that client supports io-uring
* FUSE_REQUEST_TIMEOUT: kernel supports timing out requests.
* init_out.request_timeout contains the timeout (in secs)
*/
#define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1)
@ -477,11 +482,11 @@ struct fuse_file_lock {
#define FUSE_PASSTHROUGH (1ULL << 37)
#define FUSE_NO_EXPORT_SUPPORT (1ULL << 38)
#define FUSE_HAS_RESEND (1ULL << 39)
/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */
#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP
#define FUSE_ALLOW_IDMAP (1ULL << 40)
#define FUSE_OVER_IO_URING (1ULL << 41)
#define FUSE_REQUEST_TIMEOUT (1ULL << 42)
/**
* CUSE INIT request/reply flags
@ -909,7 +914,8 @@ struct fuse_init_out {
uint16_t map_alignment;
uint32_t flags2;
uint32_t max_stack_depth;
uint32_t unused[6];
uint16_t request_timeout;
uint16_t unused[11];
};
#define CUSE_INIT_INFO_MAX 4096