@@ -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,87 @@ 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);
+ 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;
@@ -95,6 +95,7 @@
#include <linux/flex_array.h>
#include <linux/posix-timers.h>
#include <linux/resctrl.h>
+#include <linux/aio.h>
#include <trace/events/oom.h>
#include "internal.h"
#include "fd.h"
@@ -2429,6 +2430,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)
{
@@ -3010,6 +3034,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
@@ -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 */