|
@@ -723,8 +723,6 @@ static void kiocb_free(struct kiocb *req)
|
|
|
eventfd_ctx_put(req->ki_eventfd);
|
|
|
if (req->ki_dtor)
|
|
|
req->ki_dtor(req);
|
|
|
- if (req->ki_iovec != &req->ki_inline_vec)
|
|
|
- kfree(req->ki_iovec);
|
|
|
kmem_cache_free(kiocb_cachep, req);
|
|
|
}
|
|
|
|
|
@@ -1054,24 +1052,26 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx)
|
|
|
typedef ssize_t (aio_rw_op)(struct kiocb *, const struct iovec *,
|
|
|
unsigned long, loff_t);
|
|
|
|
|
|
-static ssize_t aio_setup_vectored_rw(int rw, struct kiocb *kiocb, bool compat)
|
|
|
+static ssize_t aio_setup_vectored_rw(struct kiocb *kiocb,
|
|
|
+ int rw, char __user *buf,
|
|
|
+ unsigned long *nr_segs,
|
|
|
+ struct iovec **iovec,
|
|
|
+ bool compat)
|
|
|
{
|
|
|
ssize_t ret;
|
|
|
|
|
|
- kiocb->ki_nr_segs = kiocb->ki_nbytes;
|
|
|
+ *nr_segs = kiocb->ki_nbytes;
|
|
|
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
if (compat)
|
|
|
ret = compat_rw_copy_check_uvector(rw,
|
|
|
- (struct compat_iovec __user *)kiocb->ki_buf,
|
|
|
- kiocb->ki_nr_segs, 1, &kiocb->ki_inline_vec,
|
|
|
- &kiocb->ki_iovec);
|
|
|
+ (struct compat_iovec __user *)buf,
|
|
|
+ *nr_segs, 1, *iovec, iovec);
|
|
|
else
|
|
|
#endif
|
|
|
ret = rw_copy_check_uvector(rw,
|
|
|
- (struct iovec __user *)kiocb->ki_buf,
|
|
|
- kiocb->ki_nr_segs, 1, &kiocb->ki_inline_vec,
|
|
|
- &kiocb->ki_iovec);
|
|
|
+ (struct iovec __user *)buf,
|
|
|
+ *nr_segs, 1, *iovec, iovec);
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
|
|
@@ -1080,15 +1080,17 @@ static ssize_t aio_setup_vectored_rw(int rw, struct kiocb *kiocb, bool compat)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static ssize_t aio_setup_single_vector(int rw, struct kiocb *kiocb)
|
|
|
+static ssize_t aio_setup_single_vector(struct kiocb *kiocb,
|
|
|
+ int rw, char __user *buf,
|
|
|
+ unsigned long *nr_segs,
|
|
|
+ struct iovec *iovec)
|
|
|
{
|
|
|
- if (unlikely(!access_ok(!rw, kiocb->ki_buf, kiocb->ki_nbytes)))
|
|
|
+ if (unlikely(!access_ok(!rw, buf, kiocb->ki_nbytes)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
- kiocb->ki_iovec = &kiocb->ki_inline_vec;
|
|
|
- kiocb->ki_iovec->iov_base = kiocb->ki_buf;
|
|
|
- kiocb->ki_iovec->iov_len = kiocb->ki_nbytes;
|
|
|
- kiocb->ki_nr_segs = 1;
|
|
|
+ iovec->iov_base = buf;
|
|
|
+ iovec->iov_len = kiocb->ki_nbytes;
|
|
|
+ *nr_segs = 1;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1097,15 +1099,18 @@ static ssize_t aio_setup_single_vector(int rw, struct kiocb *kiocb)
|
|
|
* Performs the initial checks and aio retry method
|
|
|
* setup for the kiocb at the time of io submission.
|
|
|
*/
|
|
|
-static ssize_t aio_run_iocb(struct kiocb *req, bool compat)
|
|
|
+static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
|
|
|
+ char __user *buf, bool compat)
|
|
|
{
|
|
|
struct file *file = req->ki_filp;
|
|
|
ssize_t ret;
|
|
|
+ unsigned long nr_segs;
|
|
|
int rw;
|
|
|
fmode_t mode;
|
|
|
aio_rw_op *rw_op;
|
|
|
+ struct iovec inline_vec, *iovec = &inline_vec;
|
|
|
|
|
|
- switch (req->ki_opcode) {
|
|
|
+ switch (opcode) {
|
|
|
case IOCB_CMD_PREAD:
|
|
|
case IOCB_CMD_PREADV:
|
|
|
mode = FMODE_READ;
|
|
@@ -1126,16 +1131,21 @@ rw_common:
|
|
|
if (!rw_op)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- ret = (req->ki_opcode == IOCB_CMD_PREADV ||
|
|
|
- req->ki_opcode == IOCB_CMD_PWRITEV)
|
|
|
- ? aio_setup_vectored_rw(rw, req, compat)
|
|
|
- : aio_setup_single_vector(rw, req);
|
|
|
+ ret = (opcode == IOCB_CMD_PREADV ||
|
|
|
+ opcode == IOCB_CMD_PWRITEV)
|
|
|
+ ? aio_setup_vectored_rw(req, rw, buf, &nr_segs,
|
|
|
+ &iovec, compat)
|
|
|
+ : aio_setup_single_vector(req, rw, buf, &nr_segs,
|
|
|
+ iovec);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
|
ret = rw_verify_area(rw, file, &req->ki_pos, req->ki_nbytes);
|
|
|
- if (ret < 0)
|
|
|
+ if (ret < 0) {
|
|
|
+ if (iovec != &inline_vec)
|
|
|
+ kfree(iovec);
|
|
|
return ret;
|
|
|
+ }
|
|
|
|
|
|
req->ki_nbytes = ret;
|
|
|
|
|
@@ -1149,8 +1159,7 @@ rw_common:
|
|
|
if (rw == WRITE)
|
|
|
file_start_write(file);
|
|
|
|
|
|
- ret = rw_op(req, req->ki_iovec,
|
|
|
- req->ki_nr_segs, req->ki_pos);
|
|
|
+ ret = rw_op(req, iovec, nr_segs, req->ki_pos);
|
|
|
|
|
|
if (rw == WRITE)
|
|
|
file_end_write(file);
|
|
@@ -1175,6 +1184,9 @@ rw_common:
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ if (iovec != &inline_vec)
|
|
|
+ kfree(iovec);
|
|
|
+
|
|
|
if (ret != -EIOCBQUEUED) {
|
|
|
/*
|
|
|
* There's no easy way to restart the syscall since other AIO's
|
|
@@ -1246,12 +1258,11 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
|
|
|
req->ki_obj.user = user_iocb;
|
|
|
req->ki_user_data = iocb->aio_data;
|
|
|
req->ki_pos = iocb->aio_offset;
|
|
|
-
|
|
|
- req->ki_buf = (char __user *)(unsigned long)iocb->aio_buf;
|
|
|
req->ki_nbytes = iocb->aio_nbytes;
|
|
|
- req->ki_opcode = iocb->aio_lio_opcode;
|
|
|
|
|
|
- ret = aio_run_iocb(req, compat);
|
|
|
+ ret = aio_run_iocb(req, iocb->aio_lio_opcode,
|
|
|
+ (char __user *)(unsigned long)iocb->aio_buf,
|
|
|
+ compat);
|
|
|
if (ret)
|
|
|
goto out_put_req;
|
|
|
|