[AIO] cleanup thread based aio fallback code Clean up the thread based aio fallback code by making use of ki_opcode to switch based on the iocb. Introduce a cancel method for thread based fallback that sends a SIGKILL to the thread performing the io. Signed-off-by: Benjamin LaHaise diff -purN --exclude=description 87_cancel_cleanup/fs/aio.c 88_thread_cleanup/fs/aio.c --- 87_cancel_cleanup/fs/aio.c 2005-08-17 12:40:07.000000000 -0400 +++ 88_thread_cleanup/fs/aio.c 2005-08-17 13:54:36.000000000 -0400 @@ -1506,85 +1506,67 @@ ssize_t aio_pwrite(struct kiocb *iocb) return ret; } -static int aio_thread_read_fn(void *arg) +static int aio_thread_cancel(struct kiocb *iocb, struct io_event *res) { - 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_recvmsg_fn(void *arg) -{ - struct kiocb *iocb = arg; - long ret; - - set_fs(USER_DS); - use_mm(iocb->ki_ctx->mm); - ret = vfs_recvmsg(iocb->ki_filp->private_data, - (void __user *)iocb->ki_buf, iocb->ki_pos); - unuse_mm(iocb->ki_ctx->mm); - aio_complete(iocb, ret, 0); - - return 0; + force_sig_specific(SIGKILL, iocb->private); + return -EAGAIN; } -static int aio_thread_sendmsg_fn(void *arg) +static int aio_thread_rw_v_fn(void *arg) { struct kiocb *iocb = arg; long ret; + current->exit_signal = -1; set_fs(USER_DS); - use_mm(iocb->ki_ctx->mm); - ret = vfs_sendmsg(iocb->ki_filp->private_data, - (void __user *)iocb->ki_buf, iocb->ki_pos); - unuse_mm(iocb->ki_ctx->mm); - aio_complete(iocb, ret, 0); - return 0; -} + /* setup cancellation */ + iocb->private = current; + iocb->ki_cancel = aio_thread_cancel; + unlock_kiocb(iocb); -static int aio_thread_rw_v_fn(void *arg) -{ - struct kiocb *iocb = arg; - long ret; - - set_fs(USER_DS); - use_mm(iocb->ki_ctx->mm); + ret = -EINTR; + if (kiocbIsCancelled(iocb)) + goto out; + /* We don't count against the aio usage count. */ + if (atomic_dec_and_test(&iocb->ki_ctx->mm->default_kioctx.users)) + goto out; - if (iocb->ki_opcode == IOCB_CMD_PREADV) + switch (iocb->ki_opcode) { + case IOCB_CMD_PREAD: + ret = iocb->ki_filp->f_op->read(iocb->ki_filp, iocb->ki_buf, + iocb->ki_left, &iocb->ki_pos); + break; + case IOCB_CMD_PREADV: ret = vfs_readv(iocb->ki_filp, &iocb->ki_iovec[iocb->ki_cur_seg], iocb->ki_nr_segs - iocb->ki_cur_seg, &iocb->ki_pos); - else + break; + case IOCB_CMD_PWRITE: + ret = iocb->ki_filp->f_op->write(iocb->ki_filp, iocb->ki_buf, + iocb->ki_left, &iocb->ki_pos); + break; + case IOCB_CMD_PWRITEV: ret = vfs_writev(iocb->ki_filp, &iocb->ki_iovec[iocb->ki_cur_seg], iocb->ki_nr_segs - iocb->ki_cur_seg, &iocb->ki_pos); - unuse_mm(iocb->ki_ctx->mm); + break; + case IOCB_CMD_SENDMSG: + ret = vfs_sendmsg(iocb->ki_filp, + (void __user *)iocb->ki_buf, iocb->ki_pos); + break; + case IOCB_CMD_RECVMSG: + ret = vfs_recvmsg(iocb->ki_filp, + (void __user *)iocb->ki_buf, iocb->ki_pos); + break; + default: + ret = -EINVAL; + break; + } +out: + current->aio_mm = NULL; /* prevent mmput from dec'ing aio_mm */ aio_complete(iocb, ret, 0); return 0; @@ -1617,31 +1599,21 @@ static int aio_thread_fdsync_fn(void *ar 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. + + /* Setting up cancellation depends on actions of the thread, so + * we need to prevent the submit path from unlocking the iocb + * until our cancel method is in place. */ - ret = kernel_thread(fn, iocb, CLONE_FS|CLONE_FILES); + kiocbSetDontUnlock(iocb); + + ret = kernel_thread(fn, iocb, CLONE_VM|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_preadv(struct kiocb *iocb) -{ - return aio_kernel_thread(iocb, aio_thread_rw_v_fn); -} - -static ssize_t aio_thread_pwrite(struct kiocb *iocb) -{ - return aio_kernel_thread(iocb, aio_thread_write_fn); + return -EIOCBQUEUED; } -static ssize_t aio_thread_pwritev(struct kiocb *iocb) +static ssize_t aio_thread_rw_v(struct kiocb *iocb) { return aio_kernel_thread(iocb, aio_thread_rw_v_fn); } @@ -1656,16 +1628,6 @@ static ssize_t aio_thread_fdsync(struct return aio_kernel_thread(iocb, aio_thread_fdsync_fn); } -static ssize_t aio_thread_sendmsg(struct kiocb *iocb) -{ - return aio_kernel_thread(iocb, aio_thread_sendmsg); -} - -static ssize_t aio_thread_recvmsg(struct kiocb *iocb) -{ - return aio_kernel_thread(iocb, aio_thread_recvmsg); -} - static ssize_t aio_fdsync(struct kiocb *iocb) { struct file *file = iocb->ki_filp; @@ -1730,7 +1692,7 @@ static ssize_t aio_setup_iocb(struct kio if (file->f_op->aio_read) kiocb->ki_retry = aio_pread; else if (file->f_op->read) - kiocb->ki_retry = aio_thread_pread; + kiocb->ki_retry = aio_thread_rw_v; break; case IOCB_CMD_PWRITE: ret = -EBADF; @@ -1744,7 +1706,7 @@ static ssize_t aio_setup_iocb(struct kio if (file->f_op->aio_write) kiocb->ki_retry = aio_pwrite; else if (file->f_op->write) - kiocb->ki_retry = aio_thread_pwrite; + kiocb->ki_retry = aio_thread_rw_v; break; case IOCB_CMD_PREADV: ret = -EBADF; @@ -1757,7 +1719,7 @@ static ssize_t aio_setup_iocb(struct kio if (file->f_op->aio_readv) kiocb->ki_retry = aio_rw_vect_retry; else if (file->f_op->readv || file->f_op->read) - kiocb->ki_retry = aio_thread_preadv; + kiocb->ki_retry = aio_thread_rw_v; break; case IOCB_CMD_PWRITEV: ret = -EBADF; @@ -1770,7 +1732,7 @@ static ssize_t aio_setup_iocb(struct kio if (file->f_op->aio_writev) kiocb->ki_retry = aio_rw_vect_retry; else if (file->f_op->writev || file->f_op->write) - kiocb->ki_retry = aio_thread_pwritev; + kiocb->ki_retry = aio_thread_rw_v; break; case IOCB_CMD_FDSYNC: ret = -EINVAL; @@ -1787,16 +1749,11 @@ static ssize_t aio_setup_iocb(struct kio kiocb->ki_retry = aio_thread_fsync; break; case IOCB_CMD_SENDMSG: - ret = -EINVAL; - if (kiocb->ki_nbytes != sizeof(struct msghdr)) - break; - kiocb->ki_retry = aio_thread_thread_sendmsg; - break; case IOCB_CMD_RECVMSG: ret = -EINVAL; if (kiocb->ki_nbytes != sizeof(struct msghdr)) break; - kiocb->ki_retry = aio_thread_thread_recvmsg; + kiocb->ki_retry = aio_thread_rw_v; break; default: dprintk("EINVAL: io_submit: no operation provided\n"); @@ -1983,17 +1940,15 @@ int fastcall io_submit_one(struct kioctx goto out_put_req; spin_lock_irq(&ctx->ctx_lock); - if (likely(list_empty(&ctx->run_list))) { - aio_run_iocb(req); - } else { - list_add_tail(&req->ki_run_list, &ctx->run_list); + aio_run_iocb(req); + if (!kiocbIsDontUnlock(req)) + unlock_kiocb(req); + if (!list_empty(&ctx->run_list)) { /* drain the run list */ while (__aio_run_iocbs(ctx)) ; } spin_unlock_irq(&ctx->ctx_lock); - if (!kiocbIsDontUnlock(req)) - unlock_kiocb(req); aio_put_req(req); /* drop extra ref to req */ return 0; diff -purN --exclude=description 87_cancel_cleanup/net/socket.c 88_thread_cleanup/net/socket.c --- 87_cancel_cleanup/net/socket.c 2005-08-17 14:14:03.000000000 -0400 +++ 88_thread_cleanup/net/socket.c 2005-08-17 14:26:24.000000000 -0400 @@ -421,7 +421,7 @@ out: return fd; } -static inline void file_to_sock(struct file *file) +static inline struct socket *file_to_socket(struct file *file) { if (file->f_op == &socket_file_ops) return file->private_data; @@ -453,7 +453,7 @@ struct socket *sockfd_lookup(int fd, int return NULL; } - sock - file_to_sock(file); + sock = file_to_socket(file); if (!IS_ERR(sock)) return sock; @@ -1738,7 +1738,7 @@ out: long vfs_sendmsg(struct file *file, struct msghdr __user *msg, unsigned flags) { struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; - struct socket *sock = file_to_sock(file); + struct socket *sock = file_to_socket(file); char address[MAX_SOCK_ADDR]; struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */ @@ -1842,7 +1842,7 @@ out: long vfs_recvmsg(struct file *file, struct msghdr __user *msg, unsigned int flags) { struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; - struct socket *sock = file_to_sock(file); + struct socket *sock = file_to_socket(file); struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov=iovstack; struct msghdr msg_sys;