Applications that require a unified event loop occasionally have a need to interface with libraries or other code that require notification on a file descriptor becoming ready for read or write via poll. Add support for the aio poll operation to enable these use-cases by way of the thread based aio helpers. Signed-off-by: Benjamin LaHaise <ben.lahaise@xxxxxxxxxxxxxxxxx> Signed-off-by: Benjamin LaHaise <bcrl@xxxxxxxxx> --- fs/aio.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/aio_abi.h | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/fs/aio.c b/fs/aio.c index 576b780..4384df4 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -200,6 +200,7 @@ struct aio_kiocb { struct task_struct *ki_submit_task; #if IS_ENABLED(CONFIG_AIO_THREAD) struct task_struct *ki_cancel_task; + unsigned long ki_data; unsigned long ki_rlimit_fsize; aio_thread_work_fn_t ki_work_fn; struct work_struct ki_work; @@ -225,6 +226,7 @@ static const struct address_space_operations aio_ctx_aops; static void aio_complete(struct kiocb *kiocb, long res, long res2); ssize_t aio_fsync(struct kiocb *iocb, int datasync); +long aio_poll(struct aio_kiocb *iocb); static __always_inline bool aio_may_use_threads(void) { @@ -1675,6 +1677,45 @@ ssize_t aio_fsync(struct kiocb *iocb, int datasync) return aio_thread_queue_iocb(req, datasync ? aio_thread_op_fdatasync : aio_thread_op_fsync, 0); } + +static long aio_thread_op_poll(struct aio_kiocb *iocb) +{ + struct file *file = iocb->common.ki_filp; + short events = iocb->ki_data; + struct poll_wqueues table; + unsigned int mask; + ssize_t ret = 0; + + poll_initwait(&table); + events |= POLLERR | POLLHUP; + + for (;;) { + mask = DEFAULT_POLLMASK; + if (file->f_op && file->f_op->poll) { + table.pt._key = events; + mask = file->f_op->poll(file, &table.pt); + } + /* Mask out unneeded events. */ + mask &= events; + ret = mask; + if (mask) + break; + + ret = -EINTR; + if (signal_pending(current)) + break; + + poll_schedule_timeout(&table, TASK_INTERRUPTIBLE, NULL, 0); + } + + poll_freewait(&table); + return ret; +} + +long aio_poll(struct aio_kiocb *req) +{ + return aio_thread_queue_iocb(req, aio_thread_op_poll, 0); +} #endif /* IS_ENABLED(CONFIG_AIO_THREAD) */ /* @@ -1764,6 +1805,11 @@ rw_common: ret = aio_fsync(&req->common, 0); break; + case IOCB_CMD_POLL: + if (aio_may_use_threads()) + ret = aio_poll(req); + break; + default: pr_debug("EINVAL: no operation provided\n"); return -EINVAL; diff --git a/include/uapi/linux/aio_abi.h b/include/uapi/linux/aio_abi.h index bb2554f..7639fb1 100644 --- a/include/uapi/linux/aio_abi.h +++ b/include/uapi/linux/aio_abi.h @@ -39,8 +39,8 @@ enum { IOCB_CMD_FDSYNC = 3, /* These two are experimental. * IOCB_CMD_PREADX = 4, - * IOCB_CMD_POLL = 5, */ + IOCB_CMD_POLL = 5, IOCB_CMD_NOOP = 6, IOCB_CMD_PREADV = 7, IOCB_CMD_PWRITEV = 8, -- 2.5.0 -- "Thought is the essence of where you are now." -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html