mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 14:12:06 +00:00
b76da70fc3
When we find new work to process within the work handler, we queue the linked timeout before we have issued the new work. This can be problematic for very short timeouts, as we have a window where the new work isn't visible. Allow the work handler to store a callback function for this in the work item, and flag it with IO_WQ_WORK_CB if the caller has done so. If that is set, then io-wq will call the callback when it has setup the new work item. Reported-by: Pavel Begunkov <asml.silence@gmail.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
79 lines
2.0 KiB
C
79 lines
2.0 KiB
C
#ifndef INTERNAL_IO_WQ_H
|
|
#define INTERNAL_IO_WQ_H
|
|
|
|
struct io_wq;
|
|
|
|
enum {
|
|
IO_WQ_WORK_CANCEL = 1,
|
|
IO_WQ_WORK_HAS_MM = 2,
|
|
IO_WQ_WORK_HASHED = 4,
|
|
IO_WQ_WORK_NEEDS_USER = 8,
|
|
IO_WQ_WORK_NEEDS_FILES = 16,
|
|
IO_WQ_WORK_UNBOUND = 32,
|
|
IO_WQ_WORK_INTERNAL = 64,
|
|
IO_WQ_WORK_CB = 128,
|
|
|
|
IO_WQ_HASH_SHIFT = 24, /* upper 8 bits are used for hash key */
|
|
};
|
|
|
|
enum io_wq_cancel {
|
|
IO_WQ_CANCEL_OK, /* cancelled before started */
|
|
IO_WQ_CANCEL_RUNNING, /* found, running, and attempted cancelled */
|
|
IO_WQ_CANCEL_NOTFOUND, /* work not found */
|
|
};
|
|
|
|
struct io_wq_work {
|
|
union {
|
|
struct list_head list;
|
|
void *data;
|
|
};
|
|
void (*func)(struct io_wq_work **);
|
|
unsigned flags;
|
|
struct files_struct *files;
|
|
};
|
|
|
|
#define INIT_IO_WORK(work, _func) \
|
|
do { \
|
|
(work)->func = _func; \
|
|
(work)->flags = 0; \
|
|
(work)->files = NULL; \
|
|
} while (0) \
|
|
|
|
typedef void (get_work_fn)(struct io_wq_work *);
|
|
typedef void (put_work_fn)(struct io_wq_work *);
|
|
|
|
struct io_wq *io_wq_create(unsigned bounded, struct mm_struct *mm,
|
|
struct user_struct *user,
|
|
get_work_fn *get_work, put_work_fn *put_work);
|
|
void io_wq_destroy(struct io_wq *wq);
|
|
|
|
void io_wq_enqueue(struct io_wq *wq, struct io_wq_work *work);
|
|
void io_wq_enqueue_hashed(struct io_wq *wq, struct io_wq_work *work, void *val);
|
|
void io_wq_flush(struct io_wq *wq);
|
|
|
|
void io_wq_cancel_all(struct io_wq *wq);
|
|
enum io_wq_cancel io_wq_cancel_work(struct io_wq *wq, struct io_wq_work *cwork);
|
|
|
|
typedef bool (work_cancel_fn)(struct io_wq_work *, void *);
|
|
|
|
enum io_wq_cancel io_wq_cancel_cb(struct io_wq *wq, work_cancel_fn *cancel,
|
|
void *data);
|
|
|
|
#if defined(CONFIG_IO_WQ)
|
|
extern void io_wq_worker_sleeping(struct task_struct *);
|
|
extern void io_wq_worker_running(struct task_struct *);
|
|
#else
|
|
static inline void io_wq_worker_sleeping(struct task_struct *tsk)
|
|
{
|
|
}
|
|
static inline void io_wq_worker_running(struct task_struct *tsk)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
static inline bool io_wq_current_is_worker(void)
|
|
{
|
|
return in_task() && (current->flags & PF_IO_WORKER);
|
|
}
|
|
#endif
|