[AIO] implement threads based aio fallback path In order to make AIO more generally useful to userland applications, provide a thread based fallback for AIO operations that do not implement the AIO versions of file_operations. Signed-off-by: Benjamin LaHaise diff -purN --exclude=description 818_aio_vectored/fs/aio.c 82_aio_threads/fs/aio.c --- 818_aio_vectored/fs/aio.c 2005-08-17 13:46:51.000000000 -0400 +++ 82_aio_threads/fs/aio.c 2005-08-17 13:46:54.000000000 -0400 @@ -1507,6 +1507,92 @@ ssize_t aio_pwrite(struct kiocb *iocb) return ret; } +static int aio_thread_read_fn(void *arg) +{ + struct kiocb *iocb = arg; + long ret; + + set_fs(USER_DS); + use_mm(iocb->ki_ctx->mm); + ret = iocb->ki_filp->f_op->read(iocb->ki_filp, iocb->ki_buf, + iocb->ki_left, &iocb->ki_pos); + unuse_mm(iocb->ki_ctx->mm); + aio_complete(iocb, ret, 0); + + return 0; +} + +static int aio_thread_write_fn(void *arg) +{ + struct kiocb *iocb = arg; + long ret; + + set_fs(USER_DS); + use_mm(iocb->ki_ctx->mm); + ret = iocb->ki_filp->f_op->write(iocb->ki_filp, iocb->ki_buf, + iocb->ki_left, &iocb->ki_pos); + unuse_mm(iocb->ki_ctx->mm); + aio_complete(iocb, ret, 0); + + return 0; +} + +static int aio_thread_fsync_fn(void *arg) +{ + struct kiocb *iocb = arg; + long ret; + + ret = iocb->ki_filp->f_op->fsync(iocb->ki_filp, + iocb->ki_filp->f_dentry, 0); + aio_complete(iocb, ret, 0); + + return 0; +} + +static int aio_thread_fdsync_fn(void *arg) +{ + struct kiocb *iocb = arg; + long ret; + + ret = iocb->ki_filp->f_op->fsync(iocb->ki_filp, + iocb->ki_filp->f_dentry, 1); + aio_complete(iocb, ret, 0); + + return 0; +} + +static ssize_t aio_kernel_thread(struct kiocb *iocb, int (*fn)(void *)) +{ + long ret; + /* We don't use CLONE_VM as doing so means exit_aio() will not get + * called when the aio user exits. + */ + ret = kernel_thread(fn, iocb, CLONE_FS|CLONE_FILES); + if (ret < 0) + return ret; + return -EIOCBQUEUED; +} + +static ssize_t aio_thread_pread(struct kiocb *iocb) +{ + return aio_kernel_thread(iocb, aio_thread_read_fn); +} + +static ssize_t aio_thread_pwrite(struct kiocb *iocb) +{ + return aio_kernel_thread(iocb, aio_thread_write_fn); +} + +static ssize_t aio_thread_fsync(struct kiocb *iocb) +{ + return aio_kernel_thread(iocb, aio_thread_fsync_fn); +} + +static ssize_t aio_thread_fdsync(struct kiocb *iocb) +{ + return aio_kernel_thread(iocb, aio_thread_fdsync_fn); +} + static ssize_t aio_fdsync(struct kiocb *iocb) { struct file *file = iocb->ki_filp; @@ -1570,6 +1656,8 @@ static ssize_t aio_setup_iocb(struct kio ret = -EINVAL; if (file->f_op->aio_read) kiocb->ki_retry = aio_pread; + else if (file->f_op->read) + kiocb->ki_retry = aio_thread_pread; break; case IOCB_CMD_PWRITE: ret = -EBADF; @@ -1582,6 +1670,8 @@ static ssize_t aio_setup_iocb(struct kio ret = -EINVAL; if (file->f_op->aio_write) kiocb->ki_retry = aio_pwrite; + else if (file->f_op->write) + kiocb->ki_retry = aio_thread_pwrite; break; case IOCB_CMD_PREADV: ret = -EBADF; @@ -1609,11 +1699,15 @@ static ssize_t aio_setup_iocb(struct kio ret = -EINVAL; if (file->f_op->aio_fsync) kiocb->ki_retry = aio_fdsync; + else if (file->f_op->fsync) + kiocb->ki_retry = aio_thread_fdsync; break; case IOCB_CMD_FSYNC: ret = -EINVAL; if (file->f_op->aio_fsync) kiocb->ki_retry = aio_fsync; + else if (file->f_op->fsync) + kiocb->ki_retry = aio_thread_fsync; break; default: dprintk("EINVAL: io_submit: no operation provided\n");