From: Stanislav Kinsburskiy <skinsbur...@virtuozzo.com> This adds ioctl, which allows to set ring buffer tail and to wait till aio requests are finished.
v2: Add pseudosuper check https://jira.sw.ru/browse/PSBM-42488 Signed-off-by: Kirill Tkhai <ktk...@virtuozzo.com> Reviewed-by: Cyrill Gorcunov <gorcu...@openvz.org> khorenko@: we don't support migration of incomplete aio requests https://jira.sw.ru/browse/PSBM-41425 so using added instruments we wait till all AIO requests are completed and migrate the results (AIO req contexts with status). ====================================== ve/aio: Enumerate ioctl numbers right Do not use common used numbers, use custom. Also, make error codes different. https://jira.sw.ru/browse/PSBM-42488 Signed-off-by: Kirill Tkhai <ktk...@virtuozzo.com> Acked-by: Cyrill Gorcunov <gorcu...@openvz.org> ====================================== ve/aio: Kill ve_aio_set_tail() Since tail is restored using submitting requests to write in /dev/null, we do not need this interface anymore. https://jira.sw.ru/browse/PSBM-42488 Signed-off-by: Kirill Tkhai <ktk...@virtuozzo.com> Acked-by: Cyrill Gorcunov <gorcu...@openvz.org> ====================================== ve/aio: Wait for all inflight AIO reqs of a task Make it wait all task's AIO contexts instead of a single AIO request. This minimizes the number of syscall we do to dump aios. https://jira.sw.ru/browse/PSBM-42488 Signed-off-by: Kirill Tkhai <ktk...@virtuozzo.com> Acked-by: Cyrill Gorcunov <gorcu...@openvz.org> ====================================== Ported with respect to ms commits: 34e83fc ("aio: reqs_active -> reqs_available") 723be6e ("aio: percpu ioctx refcount") db446a0 ("aio: convert the ioctx list to table lookup v3") https://jira.sw.ru/browse/PSBM-123159 Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalit...@virtuozzo.com> --- fs/aio.c | 98 +++++++++++++++++++++++++++++++++++++++++++++ fs/proc/base.c | 27 +++++++++++++ include/linux/aio.h | 13 ++++++ 3 files changed, 138 insertions(+) diff --git a/fs/aio.c b/fs/aio.c index 492f1a8b7661..1afdf3dcd335 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -20,6 +20,7 @@ #include <linux/backing-dev.h> #include <linux/uio.h> +#include <linux/sched/mm.h> #include <linux/sched/signal.h> #include <linux/fs.h> #include <linux/file.h> @@ -1892,6 +1893,103 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id, return ret; } +#ifdef CONFIG_VE +static bool has_reqs_active(struct kioctx *ctx) +{ + unsigned long flags; + unsigned nr; + + spin_lock_irqsave(&ctx->completion_lock, flags); + nr = (ctx->nr_events - 1) - atomic_read(&ctx->reqs_available); + nr -= ctx->completed_events; + spin_unlock_irqrestore(&ctx->completion_lock, flags); + + return !!nr; +} + +static int ve_aio_wait_inflight_reqs(struct task_struct *p) +{ + struct mm_struct *mm; + struct kioctx_table *table; + int ret, i; + + if (p->flags & PF_KTHREAD) + return -EINVAL; + + task_lock(p); + mm = p->mm; + if (mm) + atomic_inc(&mm->mm_count); + task_unlock(p); + if (!mm) + return -ESRCH; + +again: + spin_lock_irq(&mm->ioctx_lock); +#if 0 + hlist_for_each_entry_rcu(ctx, &mm->ioctx_list, list) { + if (!has_reqs_active(ctx)) + continue; + + atomic_inc(&ctx->users); + spin_unlock_irq(&mm->ioctx_lock); + + ret = wait_event_interruptible(ctx->wait, !has_reqs_active(ctx)); + put_ioctx(ctx); + + if (ret) + goto mmdrop; + goto again; + } +#endif + rcu_read_lock(); + table = rcu_dereference(mm->ioctx_table); + for (i = 0; i < table->nr; i++) { + struct kioctx *ctx; + + ctx = rcu_dereference(table->table[i]); + if (!ctx) + continue; + + if (!has_reqs_active(ctx)) + continue; + + percpu_ref_get(&ctx->users); + rcu_read_unlock(); + spin_unlock_irq(&mm->ioctx_lock); + + ret = wait_event_interruptible(ctx->wait, !has_reqs_active(ctx)); + percpu_ref_put(&ctx->users); + + if (ret) + goto mmdrop; + goto again; + } + + rcu_read_unlock(); + spin_unlock_irq(&mm->ioctx_lock); + ret = 0; +mmdrop: + mmdrop(mm); + return ret; +} + +int ve_aio_ioctl(struct task_struct *task, unsigned int cmd, unsigned long arg) +{ + int ret; + + switch (cmd) { + case VE_AIO_IOC_WAIT_ACTIVE: + ret = ve_aio_wait_inflight_reqs(task); + break; + default: + ret = -EINVAL; + } + + return ret; +} +#endif + struct __aio_sigset { const sigset_t __user *sigmask; size_t sigsetsize; diff --git a/fs/proc/base.c b/fs/proc/base.c index 85fee7396e90..0c6dabda99cd 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -94,6 +94,7 @@ #include <linux/sched/stat.h> #include <linux/flex_array.h> #include <linux/posix-timers.h> +#include <linux/aio.h> #include <trace/events/oom.h> #include "internal.h" #include "fd.h" @@ -2422,6 +2423,29 @@ static const struct file_operations proc_pid_set_timerslack_ns_operations = { .release = single_release, }; +#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 dentry *dentry, struct task_struct *task, const void *ptr) { @@ -3000,6 +3024,9 @@ static const struct pid_entry tgid_base_stuff[] = { REG("timers", S_IRUGO, proc_timers_operations), #endif REG("timerslack_ns", S_IRUGO|S_IWUGO, proc_pid_set_timerslack_ns_operations), +#ifdef CONFIG_CHECKPOINT_RESTORE + REG("aio", S_IRUGO|S_IWUSR, proc_aio_operations), +#endif #ifdef CONFIG_LIVEPATCH ONE("patch_state", S_IRUSR, proc_pid_patch_state), #endif diff --git a/include/linux/aio.h b/include/linux/aio.h index 4b7a331156ff..ccaaae0db31d 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -12,14 +12,27 @@ typedef int (kiocb_cancel_fn)(struct kiocb *); #define AIO_MAX_NR_DEFAULT 0x10000 +struct ve_ioc_arg +{ + aio_context_t ctx_id; + unsigned val; +}; + +#define VE_AIO_IOC_WAIT_ACTIVE _IOW('a', 1, struct ve_ioc_arg) + /* prototypes */ #ifdef CONFIG_AIO extern void exit_aio(struct mm_struct *mm); void kiocb_set_cancel_fn(struct kiocb *req, kiocb_cancel_fn *cancel); +#ifdef CONFIG_VE +int ve_aio_ioctl(struct task_struct *, unsigned int, unsigned long); +#endif #else static inline void exit_aio(struct mm_struct *mm) { } 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 */ #endif /* __LINUX__AIO_H */ -- 2.27.0 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel