This adds ioctl, which allows to set ring buffer tail and to wait till aio requests are finished.
v2: Add pseudosuper check Signed-off-by: Kirill Tkhai <[email protected]> --- fs/aio.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/proc/base.c | 27 +++++++++++++++++ include/linux/aio.h | 15 ++++++++++ 3 files changed, 121 insertions(+) diff --git a/fs/aio.c b/fs/aio.c index 8ec32e2..7c8158f 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -1847,3 +1847,82 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id, } return ret; } + +#ifdef CONFIG_VE +static int ve_aio_set_tail(struct kioctx *ctx, unsigned tail) +{ + struct aio_ring *ring; + int ret; + + if (!get_exec_env()->is_pseudosuper) + return -EACCES; + + mutex_lock(&ctx->ring_lock); + spin_lock_irq(&ctx->completion_lock); + + ret = -EINVAL; + if (tail >= ctx->nr_events) + goto out; + + ctx->tail = tail; + + ring = kmap_atomic(ctx->ring_pages[0]); + ring->tail = tail; + kunmap_atomic(ring); + ret = 0; +out: + spin_unlock_irq(&ctx->completion_lock); + mutex_unlock(&ctx->ring_lock); + return ret; +} + +static bool has_reqs_active(struct kioctx *ctx) +{ + unsigned long flags; + unsigned nr; + + spin_lock_irqsave(&ctx->completion_lock, flags); + nr = atomic_read(&ctx->reqs_active); + nr -= ctx->completed_events; + spin_unlock_irqrestore(&ctx->completion_lock, flags); + + return !!nr; +} + +static int ve_aio_wait_inflight_reqs(struct kioctx *ioctx) +{ + return wait_event_interruptible(ioctx->wait, !has_reqs_active(ioctx)); +} + +int ve_aio_ioctl(struct task_struct *task, unsigned int cmd, unsigned long arg) +{ + struct ve_ioc_arg karg; + struct kioctx *ioctx; + int ret; + + if (task != current) + return -EINVAL; + + if (copy_from_user(&karg, (void *)arg, sizeof(karg))) + return -EFAULT; + + ioctx = lookup_ioctx(karg.ctx_id); + if (!ioctx) + return -EINVAL;; + + switch (cmd) { + case VE_AIO_IOC_SET_TAIL: + ret = ve_aio_set_tail(ioctx, karg.val); + break; + case VE_AIO_IOC_WAIT_ACTIVE: + ret = ve_aio_wait_inflight_reqs(ioctx); + break; + default: + ret = -EINVAL; + } + + put_ioctx(ioctx); + + return ret; +} +#endif diff --git a/fs/proc/base.c b/fs/proc/base.c index 6d2faa0..ae546aa 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -87,6 +87,7 @@ #include <linux/slab.h> #include <linux/flex_array.h> #include <linux/posix-timers.h> +#include <linux/aio.h> #ifdef CONFIG_HARDWALL #include <asm/hardwall.h> #endif @@ -2351,8 +2352,33 @@ static const struct file_operations proc_timers_operations = { .llseek = seq_lseek, .release = seq_release_private, }; + + #endif /* CONFIG_CHECKPOINT_RESTORE */ +#ifdef CONFIG_VE +static long proc_aio_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct inode *inode = file_inode(file); + struct task_struct *task; + int ret; + + task = get_proc_task(inode); + if (!task) + return -ESRCH; + + ret = ve_aio_ioctl(task, cmd, arg); + + put_task_struct(task); + + return ret; +} + +static const struct file_operations proc_aio_operations = { + .unlocked_ioctl = proc_aio_ioctl, +}; +#endif /* CONFIG_VE */ + static struct dentry *proc_pident_instantiate(struct inode *dir, struct dentry *dentry, struct task_struct *task, const void *ptr) { @@ -2975,6 +3001,7 @@ static const struct pid_entry tgid_base_stuff[] = { #endif #ifdef CONFIG_CHECKPOINT_RESTORE REG("timers", S_IRUGO, proc_timers_operations), + REG("aio", S_IRUGO|S_IWUSR, proc_aio_operations), #endif }; diff --git a/include/linux/aio.h b/include/linux/aio.h index 0aa7dd3..f40a32b 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -16,6 +16,15 @@ struct kiocb; #define AIO_MAX_NR_DEFAULT 0x10000 +#define VE_AIO_IOC_SET_TAIL 1 +#define VE_AIO_IOC_WAIT_ACTIVE 2 + +struct ve_ioc_arg +{ + aio_context_t ctx_id; + unsigned val; +}; + /* * We use ki_cancel == KIOCB_CANCELLED to indicate that a kiocb has been either * cancelled or completed (this makes a certain amount of sense because @@ -108,6 +117,10 @@ void aio_kernel_init_callback(struct kiocb *iocb, void (*complete)(u64 user_data, long res), u64 user_data); int aio_kernel_submit(struct kiocb *iocb); +#ifdef CONFIG_VE +int ve_aio_ioctl(struct task_struct *, unsigned int, unsigned long); +#endif + #else static inline ssize_t wait_on_sync_kiocb(struct kiocb *iocb) { return 0; } static inline void aio_put_req(struct kiocb *iocb) { } @@ -119,6 +132,8 @@ static inline long do_io_submit(aio_context_t ctx_id, long nr, bool compat) { return 0; } static inline void kiocb_set_cancel_fn(struct kiocb *req, kiocb_cancel_fn *cancel) { } +static int ve_aio_ioctl(struct task_struct *task, unsigned int cmd, + unsigned long arg) { return 0; } #endif /* CONFIG_AIO */ static inline struct kiocb *list_kiocb(struct list_head *h) _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
