105 lines
3.3 KiB
Diff
105 lines
3.3 KiB
Diff
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
|
|
--- a/fs/fuse/dev.c
|
|
+++ b/fs/fuse/dev.c
|
|
@@ -213,10 +213,13 @@ EXPORT_SYMBOL_GPL(fuse_req_hash);
|
|
/*
|
|
* A new request is available, wake fiq->waitq
|
|
*/
|
|
-static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq)
|
|
+static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq, bool sync)
|
|
__releases(fiq->lock)
|
|
{
|
|
- wake_up(&fiq->waitq);
|
|
+ if (sync)
|
|
+ wake_up_sync(&fiq->waitq);
|
|
+ else
|
|
+ wake_up(&fiq->waitq);
|
|
kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
|
|
spin_unlock(&fiq->lock);
|
|
}
|
|
@@ -233,7 +236,7 @@ void fuse_dev_queue_forget(struct fuse_iqueue *fiq,
|
|
if (fiq->connected) {
|
|
fiq->forget_list_tail->next = forget;
|
|
fiq->forget_list_tail = forget;
|
|
- fuse_dev_wake_and_unlock(fiq);
|
|
+ fuse_dev_wake_and_unlock(fiq, false);
|
|
} else {
|
|
kfree(forget);
|
|
spin_unlock(&fiq->lock);
|
|
@@ -255,7 +258,7 @@ void fuse_dev_queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
|
|
list_del_init(&req->intr_entry);
|
|
spin_unlock(&fiq->lock);
|
|
} else {
|
|
- fuse_dev_wake_and_unlock(fiq);
|
|
+ fuse_dev_wake_and_unlock(fiq, false);
|
|
}
|
|
} else {
|
|
spin_unlock(&fiq->lock);
|
|
@@ -285,11 +288,13 @@ EXPORT_SYMBOL_GPL(fuse_request_assign_unique);
|
|
|
|
static void fuse_dev_queue_req(struct fuse_iqueue *fiq, struct fuse_req *req)
|
|
{
|
|
+ bool sync = test_and_clear_bit(FR_SYNC_WAKEUP, &req->flags);
|
|
+
|
|
spin_lock(&fiq->lock);
|
|
if (fiq->connected) {
|
|
fuse_request_assign_unique_locked(fiq, req);
|
|
list_add_tail(&req->list, &fiq->pending);
|
|
- fuse_dev_wake_and_unlock(fiq);
|
|
+ fuse_dev_wake_and_unlock(fiq, sync);
|
|
} else {
|
|
spin_unlock(&fiq->lock);
|
|
req->out.h.error = -ENOTCONN;
|
|
@@ -752,6 +757,11 @@ static void __fuse_request_send(struct fuse_req *req)
|
|
/* acquire extra reference, since request is still needed after
|
|
fuse_request_end() */
|
|
__fuse_get_request(req);
|
|
+ /*
|
|
+ * This is a synchronous request: the caller will block waiting for
|
|
+ * the answer. Hint the scheduler via wake_up_sync().
|
|
+ */
|
|
+ set_bit(FR_SYNC_WAKEUP, &req->flags);
|
|
fuse_send_one(fiq, req);
|
|
|
|
request_wait_answer(req);
|
|
@@ -1806,7 +1816,7 @@ void fuse_chan_resend(struct fuse_chan *fch)
|
|
}
|
|
/* iq and pq requests are both oldest to newest */
|
|
list_splice(&to_queue, &fiq->pending);
|
|
- fuse_dev_wake_and_unlock(fiq);
|
|
+ fuse_dev_wake_and_unlock(fiq, false);
|
|
}
|
|
|
|
/* Look up request on processing list by unique ID */
|
|
diff --git a/fs/fuse/fuse_dev_i.h b/fs/fuse/fuse_dev_i.h
|
|
--- a/fs/fuse/fuse_dev_i.h
|
|
+++ b/fs/fuse/fuse_dev_i.h
|
|
@@ -38,6 +38,8 @@ struct fuse_iqueue;
|
|
* @FR_PRIVATE: request is on private list
|
|
* @FR_ASYNC: request is asynchronous
|
|
* @FR_URING: request is handled through fuse-io-uring
|
|
+ * @FR_SYNC_WAKEUP: use synchronous wakeup when queueing this request to
|
|
+ * give the scheduler a hint about the waker task
|
|
*/
|
|
enum fuse_req_flag {
|
|
FR_ISREPLY,
|
|
@@ -53,6 +55,7 @@ enum fuse_req_flag {
|
|
FR_PRIVATE,
|
|
FR_ASYNC,
|
|
FR_URING,
|
|
+ FR_SYNC_WAKEUP,
|
|
};
|
|
|
|
/**
|
|
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
|
|
--- a/fs/fuse/inode.c
|
|
+++ b/fs/fuse/inode.c
|
|
@@ -1420,6 +1420,7 @@ static void process_init_reply(struct fuse_args *args, int error)
|
|
|
|
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);
|