[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 80_no_net_aio/fs/aio.c 82_aio_threads/fs/aio.c --- 80_no_net_aio/fs/aio.c 2005-08-08 17:16:06.000000000 -0400 +++ 82_aio_threads/fs/aio.c 2005-08-08 23:28:52.000000000 -0400 @@ -1381,6 +1381,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 -ENOMEM; + 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; @@ -1423,6 +1509,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; @@ -1435,16 +1523,22 @@ 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_FDSYNC: 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");