diff options
-rw-r--r-- | fs/aio.c | 65 | ||||
-rw-r--r-- | fs/compat.c | 2 | ||||
-rw-r--r-- | include/linux/aio.h | 5 |
3 files changed, 47 insertions, 25 deletions
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/blkdev.h> | 36 | #include <linux/blkdev.h> |
37 | #include <linux/mempool.h> | 37 | #include <linux/mempool.h> |
38 | #include <linux/hash.h> | 38 | #include <linux/hash.h> |
39 | #include <linux/compat.h> | ||
39 | 40 | ||
40 | #include <asm/kmap_types.h> | 41 | #include <asm/kmap_types.h> |
41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
@@ -1384,13 +1385,22 @@ static ssize_t aio_fsync(struct kiocb *iocb) | |||
1384 | return ret; | 1385 | return ret; |
1385 | } | 1386 | } |
1386 | 1387 | ||
1387 | static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb) | 1388 | static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb, bool compat) |
1388 | { | 1389 | { |
1389 | ssize_t ret; | 1390 | ssize_t ret; |
1390 | 1391 | ||
1391 | ret = rw_copy_check_uvector(type, (struct iovec __user *)kiocb->ki_buf, | 1392 | #ifdef CONFIG_COMPAT |
1392 | kiocb->ki_nbytes, 1, | 1393 | if (compat) |
1393 | &kiocb->ki_inline_vec, &kiocb->ki_iovec); | 1394 | ret = compat_rw_copy_check_uvector(type, |
1395 | (struct compat_iovec __user *)kiocb->ki_buf, | ||
1396 | kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec, | ||
1397 | &kiocb->ki_iovec); | ||
1398 | else | ||
1399 | #endif | ||
1400 | ret = rw_copy_check_uvector(type, | ||
1401 | (struct iovec __user *)kiocb->ki_buf, | ||
1402 | kiocb->ki_nbytes, 1, &kiocb->ki_inline_vec, | ||
1403 | &kiocb->ki_iovec); | ||
1394 | if (ret < 0) | 1404 | if (ret < 0) |
1395 | goto out; | 1405 | goto out; |
1396 | 1406 | ||
@@ -1420,7 +1430,7 @@ static ssize_t aio_setup_single_vector(struct kiocb *kiocb) | |||
1420 | * Performs the initial checks and aio retry method | 1430 | * Performs the initial checks and aio retry method |
1421 | * setup for the kiocb at the time of io submission. | 1431 | * setup for the kiocb at the time of io submission. |
1422 | */ | 1432 | */ |
1423 | static ssize_t aio_setup_iocb(struct kiocb *kiocb) | 1433 | static ssize_t aio_setup_iocb(struct kiocb *kiocb, bool compat) |
1424 | { | 1434 | { |
1425 | struct file *file = kiocb->ki_filp; | 1435 | struct file *file = kiocb->ki_filp; |
1426 | ssize_t ret = 0; | 1436 | ssize_t ret = 0; |
@@ -1469,7 +1479,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb) | |||
1469 | ret = security_file_permission(file, MAY_READ); | 1479 | ret = security_file_permission(file, MAY_READ); |
1470 | if (unlikely(ret)) | 1480 | if (unlikely(ret)) |
1471 | break; | 1481 | break; |
1472 | ret = aio_setup_vectored_rw(READ, kiocb); | 1482 | ret = aio_setup_vectored_rw(READ, kiocb, compat); |
1473 | if (ret) | 1483 | if (ret) |
1474 | break; | 1484 | break; |
1475 | ret = -EINVAL; | 1485 | ret = -EINVAL; |
@@ -1483,7 +1493,7 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb) | |||
1483 | ret = security_file_permission(file, MAY_WRITE); | 1493 | ret = security_file_permission(file, MAY_WRITE); |
1484 | if (unlikely(ret)) | 1494 | if (unlikely(ret)) |
1485 | break; | 1495 | break; |
1486 | ret = aio_setup_vectored_rw(WRITE, kiocb); | 1496 | ret = aio_setup_vectored_rw(WRITE, kiocb, compat); |
1487 | if (ret) | 1497 | if (ret) |
1488 | break; | 1498 | break; |
1489 | ret = -EINVAL; | 1499 | ret = -EINVAL; |
@@ -1548,7 +1558,8 @@ static void aio_batch_free(struct hlist_head *batch_hash) | |||
1548 | } | 1558 | } |
1549 | 1559 | ||
1550 | static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | 1560 | static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, |
1551 | struct iocb *iocb, struct hlist_head *batch_hash) | 1561 | struct iocb *iocb, struct hlist_head *batch_hash, |
1562 | bool compat) | ||
1552 | { | 1563 | { |
1553 | struct kiocb *req; | 1564 | struct kiocb *req; |
1554 | struct file *file; | 1565 | struct file *file; |
@@ -1609,7 +1620,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1609 | req->ki_left = req->ki_nbytes = iocb->aio_nbytes; | 1620 | req->ki_left = req->ki_nbytes = iocb->aio_nbytes; |
1610 | req->ki_opcode = iocb->aio_lio_opcode; | 1621 | req->ki_opcode = iocb->aio_lio_opcode; |
1611 | 1622 | ||
1612 | ret = aio_setup_iocb(req); | 1623 | ret = aio_setup_iocb(req, compat); |
1613 | 1624 | ||
1614 | if (ret) | 1625 | if (ret) |
1615 | goto out_put_req; | 1626 | goto out_put_req; |
@@ -1637,20 +1648,8 @@ out_put_req: | |||
1637 | return ret; | 1648 | return ret; |
1638 | } | 1649 | } |
1639 | 1650 | ||
1640 | /* sys_io_submit: | 1651 | long do_io_submit(aio_context_t ctx_id, long nr, |
1641 | * Queue the nr iocbs pointed to by iocbpp for processing. Returns | 1652 | struct iocb __user *__user *iocbpp, bool compat) |
1642 | * the number of iocbs queued. May return -EINVAL if the aio_context | ||
1643 | * specified by ctx_id is invalid, if nr is < 0, if the iocb at | ||
1644 | * *iocbpp[0] is not properly initialized, if the operation specified | ||
1645 | * is invalid for the file descriptor in the iocb. May fail with | ||
1646 | * -EFAULT if any of the data structures point to invalid data. May | ||
1647 | * fail with -EBADF if the file descriptor specified in the first | ||
1648 | * iocb is invalid. May fail with -EAGAIN if insufficient resources | ||
1649 | * are available to queue any iocbs. Will return 0 if nr is 0. Will | ||
1650 | * fail with -ENOSYS if not implemented. | ||
1651 | */ | ||
1652 | SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr, | ||
1653 | struct iocb __user * __user *, iocbpp) | ||
1654 | { | 1653 | { |
1655 | struct kioctx *ctx; | 1654 | struct kioctx *ctx; |
1656 | long ret = 0; | 1655 | long ret = 0; |
@@ -1687,7 +1686,7 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr, | |||
1687 | break; | 1686 | break; |
1688 | } | 1687 | } |
1689 | 1688 | ||
1690 | ret = io_submit_one(ctx, user_iocb, &tmp, batch_hash); | 1689 | ret = io_submit_one(ctx, user_iocb, &tmp, batch_hash, compat); |
1691 | if (ret) | 1690 | if (ret) |
1692 | break; | 1691 | break; |
1693 | } | 1692 | } |
@@ -1697,6 +1696,24 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr, | |||
1697 | return i ? i : ret; | 1696 | return i ? i : ret; |
1698 | } | 1697 | } |
1699 | 1698 | ||
1699 | /* sys_io_submit: | ||
1700 | * Queue the nr iocbs pointed to by iocbpp for processing. Returns | ||
1701 | * the number of iocbs queued. May return -EINVAL if the aio_context | ||
1702 | * specified by ctx_id is invalid, if nr is < 0, if the iocb at | ||
1703 | * *iocbpp[0] is not properly initialized, if the operation specified | ||
1704 | * is invalid for the file descriptor in the iocb. May fail with | ||
1705 | * -EFAULT if any of the data structures point to invalid data. May | ||
1706 | * fail with -EBADF if the file descriptor specified in the first | ||
1707 | * iocb is invalid. May fail with -EAGAIN if insufficient resources | ||
1708 | * are available to queue any iocbs. Will return 0 if nr is 0. Will | ||
1709 | * fail with -ENOSYS if not implemented. | ||
1710 | */ | ||
1711 | SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr, | ||
1712 | struct iocb __user * __user *, iocbpp) | ||
1713 | { | ||
1714 | return do_io_submit(ctx_id, nr, iocbpp, 0); | ||
1715 | } | ||
1716 | |||
1700 | /* lookup_kiocb | 1717 | /* lookup_kiocb |
1701 | * Finds a given iocb for cancellation. | 1718 | * Finds a given iocb for cancellation. |
1702 | */ | 1719 | */ |
diff --git a/fs/compat.c b/fs/compat.c index 7b4aabb3bb36..f0b391c50552 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -673,7 +673,7 @@ compat_sys_io_submit(aio_context_t ctx_id, int nr, u32 __user *iocb) | |||
673 | iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64)); | 673 | iocb64 = compat_alloc_user_space(nr * sizeof(*iocb64)); |
674 | ret = copy_iocb(nr, iocb, iocb64); | 674 | ret = copy_iocb(nr, iocb, iocb64); |
675 | if (!ret) | 675 | if (!ret) |
676 | ret = sys_io_submit(ctx_id, nr, iocb64); | 676 | ret = do_io_submit(ctx_id, nr, iocb64, 1); |
677 | return ret; | 677 | return ret; |
678 | } | 678 | } |
679 | 679 | ||
diff --git a/include/linux/aio.h b/include/linux/aio.h index 811dbb369379..7a8db4155281 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h | |||
@@ -212,6 +212,8 @@ extern void kick_iocb(struct kiocb *iocb); | |||
212 | extern int aio_complete(struct kiocb *iocb, long res, long res2); | 212 | extern int aio_complete(struct kiocb *iocb, long res, long res2); |
213 | struct mm_struct; | 213 | struct mm_struct; |
214 | extern void exit_aio(struct mm_struct *mm); | 214 | extern void exit_aio(struct mm_struct *mm); |
215 | extern long do_io_submit(aio_context_t ctx_id, long nr, | ||
216 | struct iocb __user *__user *iocbpp, bool compat); | ||
215 | #else | 217 | #else |
216 | static inline ssize_t wait_on_sync_kiocb(struct kiocb *iocb) { return 0; } | 218 | static inline ssize_t wait_on_sync_kiocb(struct kiocb *iocb) { return 0; } |
217 | static inline int aio_put_req(struct kiocb *iocb) { return 0; } | 219 | static inline int aio_put_req(struct kiocb *iocb) { return 0; } |
@@ -219,6 +221,9 @@ static inline void kick_iocb(struct kiocb *iocb) { } | |||
219 | static inline int aio_complete(struct kiocb *iocb, long res, long res2) { return 0; } | 221 | static inline int aio_complete(struct kiocb *iocb, long res, long res2) { return 0; } |
220 | struct mm_struct; | 222 | struct mm_struct; |
221 | static inline void exit_aio(struct mm_struct *mm) { } | 223 | static inline void exit_aio(struct mm_struct *mm) { } |
224 | static inline long do_io_submit(aio_context_t ctx_id, long nr, | ||
225 | struct iocb __user * __user *iocbpp, | ||
226 | bool compat) { return 0; } | ||
222 | #endif /* CONFIG_AIO */ | 227 | #endif /* CONFIG_AIO */ |
223 | 228 | ||
224 | static inline struct kiocb *list_kiocb(struct list_head *h) | 229 | static inline struct kiocb *list_kiocb(struct list_head *h) |