[AIO] fix sync iocb use of retry mechanism When the sync infrastructure is used to run a retry using read/write, we need to correctly use the buffer offset and byte counts from the iocb on subsequent calls to the aio method. Signed-off-by: Benjamin LaHaise diff -purN --exclude=description 55_iocb_intr/fs/read_write.c 57_intr_cancel/fs/read_write.c --- 55_iocb_intr/fs/read_write.c 2005-08-08 17:15:42.000000000 -0400 +++ 57_intr_cancel/fs/read_write.c 2005-08-08 17:15:45.000000000 -0400 @@ -203,16 +203,33 @@ Einval: return -EINVAL; } -static void wait_on_retry_sync_kiocb(struct kiocb *iocb) +static long wait_on_retry_sync_kiocb(struct kiocb *iocb) { + long (*cancel)(struct kiocb *, struct io_event *); + long ret = 0; set_current_state(kiocbIsIntr(iocb) ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); if (!kiocbIsKicked(iocb)) schedule(); else kiocbClearKicked(iocb); + + /* If we were interrupted by a signal, issue a cancel to allow the + * operation to clean up. + */ + cancel = iocb->ki_cancel; + if (kiocbIsIntr(iocb) && signal_pending(current) && cancel) { + struct io_event dummy_event; + dummy_event.res = 0; + if (!cancel(iocb, &dummy_event)) { + ret = dummy_event.res; + if (!ret) + printk(KERN_DEBUG "wait_on_retry_sync_kiocb: ki_cancel method %p is buggy\n", cancel); + } + } kiocbClearIntr(iocb); __set_current_state(TASK_RUNNING); + return ret; } ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) @@ -222,12 +239,16 @@ ssize_t do_sync_read(struct file *filp, init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; - while (-EIOCBRETRY == - (ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos))) - wait_on_retry_sync_kiocb(&kiocb); + while (-EIOCBRETRY == + (ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos))) { + ret = wait_on_retry_sync_kiocb(&kiocb); + if (ret) + break; + } if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); + BUG_ON(!list_empty(&kiocb.ki_wait.task_list)); *ppos = kiocb.ki_pos; return ret; } @@ -273,12 +294,16 @@ ssize_t do_sync_write(struct file *filp, init_sync_kiocb(&kiocb, filp); kiocb.ki_pos = *ppos; - while (-EIOCBRETRY == - (ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos))) - wait_on_retry_sync_kiocb(&kiocb); + while (-EIOCBRETRY == + (ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos))) { + ret = wait_on_retry_sync_kiocb(&kiocb); + if (ret) + break; + } if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&kiocb); + BUG_ON(!list_empty(&kiocb.ki_wait.task_list)); *ppos = kiocb.ki_pos; return ret; }