aboutsummaryrefslogtreecommitdiffstats
path: root/fs/aio.c
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2016-10-30 12:42:03 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2016-10-30 13:09:42 -0400
commit89319d31d2d097da8e27fb0e0ae9d532f4f16827 (patch)
tree157f0809709c4dd88818e5f76d84ef4aad196146 /fs/aio.c
parent723c038475b78edc9327eb952f95f9881cc9d79d (diff)
fs: remove aio_run_iocb
Pass the ABI iocb structure to aio_setup_rw and let it handle the non-vectored I/O case as well. With that and a new helper for the AIO return value handling we can now define new aio_read and aio_write helpers that implement reads and writes in a self-contained way without duplicating too much code. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/aio.c')
-rw-r--r--fs/aio.c182
1 files changed, 94 insertions, 88 deletions
diff --git a/fs/aio.c b/fs/aio.c
index 2a6030af6ba5..c19755187ca5 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1392,110 +1392,100 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx)
1392 return -EINVAL; 1392 return -EINVAL;
1393} 1393}
1394 1394
1395typedef ssize_t (rw_iter_op)(struct kiocb *, struct iov_iter *); 1395static int aio_setup_rw(int rw, struct iocb *iocb, struct iovec **iovec,
1396 1396 bool vectored, bool compat, struct iov_iter *iter)
1397static int aio_setup_vectored_rw(int rw, char __user *buf, size_t len,
1398 struct iovec **iovec,
1399 bool compat,
1400 struct iov_iter *iter)
1401{ 1397{
1398 void __user *buf = (void __user *)(uintptr_t)iocb->aio_buf;
1399 size_t len = iocb->aio_nbytes;
1400
1401 if (!vectored) {
1402 ssize_t ret = import_single_range(rw, buf, len, *iovec, iter);
1403 *iovec = NULL;
1404 return ret;
1405 }
1402#ifdef CONFIG_COMPAT 1406#ifdef CONFIG_COMPAT
1403 if (compat) 1407 if (compat)
1404 return compat_import_iovec(rw, 1408 return compat_import_iovec(rw, buf, len, UIO_FASTIOV, iovec,
1405 (struct compat_iovec __user *)buf, 1409 iter);
1406 len, UIO_FASTIOV, iovec, iter);
1407#endif 1410#endif
1408 return import_iovec(rw, (struct iovec __user *)buf, 1411 return import_iovec(rw, buf, len, UIO_FASTIOV, iovec, iter);
1409 len, UIO_FASTIOV, iovec, iter);
1410} 1412}
1411 1413
1412/* 1414static inline ssize_t aio_ret(struct kiocb *req, ssize_t ret)
1413 * aio_run_iocb: 1415{
1414 * Performs the initial checks and io submission. 1416 switch (ret) {
1415 */ 1417 case -EIOCBQUEUED:
1416static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode, 1418 return ret;
1417 char __user *buf, size_t len, bool compat) 1419 case -ERESTARTSYS:
1420 case -ERESTARTNOINTR:
1421 case -ERESTARTNOHAND:
1422 case -ERESTART_RESTARTBLOCK:
1423 /*
1424 * There's no easy way to restart the syscall since other AIO's
1425 * may be already running. Just fail this IO with EINTR.
1426 */
1427 ret = -EINTR;
1428 /*FALLTHRU*/
1429 default:
1430 aio_complete(req, ret, 0);
1431 return 0;
1432 }
1433}
1434
1435static ssize_t aio_read(struct kiocb *req, struct iocb *iocb, bool vectored,
1436 bool compat)
1418{ 1437{
1419 struct file *file = req->ki_filp; 1438 struct file *file = req->ki_filp;
1420 ssize_t ret;
1421 int rw;
1422 fmode_t mode;
1423 rw_iter_op *iter_op;
1424 struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs; 1439 struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
1425 struct iov_iter iter; 1440 struct iov_iter iter;
1441 ssize_t ret;
1426 1442
1427 switch (opcode) { 1443 if (unlikely(!(file->f_mode & FMODE_READ)))
1428 case IOCB_CMD_PREAD: 1444 return -EBADF;
1429 case IOCB_CMD_PREADV: 1445 if (unlikely(!file->f_op->read_iter))
1430 mode = FMODE_READ; 1446 return -EINVAL;
1431 rw = READ;
1432 iter_op = file->f_op->read_iter;
1433 goto rw_common;
1434
1435 case IOCB_CMD_PWRITE:
1436 case IOCB_CMD_PWRITEV:
1437 mode = FMODE_WRITE;
1438 rw = WRITE;
1439 iter_op = file->f_op->write_iter;
1440 goto rw_common;
1441rw_common:
1442 if (unlikely(!(file->f_mode & mode)))
1443 return -EBADF;
1444
1445 if (!iter_op)
1446 return -EINVAL;
1447
1448 if (opcode == IOCB_CMD_PREADV || opcode == IOCB_CMD_PWRITEV)
1449 ret = aio_setup_vectored_rw(rw, buf, len,
1450 &iovec, compat, &iter);
1451 else {
1452 ret = import_single_range(rw, buf, len, iovec, &iter);
1453 iovec = NULL;
1454 }
1455 if (!ret)
1456 ret = rw_verify_area(rw, file, &req->ki_pos,
1457 iov_iter_count(&iter));
1458 if (ret < 0) {
1459 kfree(iovec);
1460 return ret;
1461 }
1462
1463 get_file(file);
1464 if (rw == WRITE)
1465 file_start_write(file);
1466 1447
1467 ret = iter_op(req, &iter); 1448 ret = aio_setup_rw(READ, iocb, &iovec, vectored, compat, &iter);
1449 if (ret)
1450 return ret;
1451 ret = rw_verify_area(READ, file, &req->ki_pos, iov_iter_count(&iter));
1452 if (!ret)
1453 ret = aio_ret(req, file->f_op->read_iter(req, &iter));
1454 kfree(iovec);
1455 return ret;
1456}
1468 1457
1469 if (rw == WRITE) 1458static ssize_t aio_write(struct kiocb *req, struct iocb *iocb, bool vectored,
1470 file_end_write(file); 1459 bool compat)
1471 fput(file); 1460{
1472 kfree(iovec); 1461 struct file *file = req->ki_filp;
1473 break; 1462 struct iovec inline_vecs[UIO_FASTIOV], *iovec = inline_vecs;
1463 struct iov_iter iter;
1464 ssize_t ret;
1474 1465
1475 default: 1466 if (unlikely(!(file->f_mode & FMODE_WRITE)))
1476 pr_debug("EINVAL: no operation provided\n"); 1467 return -EBADF;
1468 if (unlikely(!file->f_op->write_iter))
1477 return -EINVAL; 1469 return -EINVAL;
1478 }
1479 1470
1480 if (ret != -EIOCBQUEUED) { 1471 ret = aio_setup_rw(WRITE, iocb, &iovec, vectored, compat, &iter);
1481 /* 1472 if (ret)
1482 * There's no easy way to restart the syscall since other AIO's 1473 return ret;
1483 * may be already running. Just fail this IO with EINTR. 1474 ret = rw_verify_area(WRITE, file, &req->ki_pos, iov_iter_count(&iter));
1484 */ 1475 if (!ret) {
1485 if (unlikely(ret == -ERESTARTSYS || ret == -ERESTARTNOINTR || 1476 file_start_write(file);
1486 ret == -ERESTARTNOHAND || 1477 ret = aio_ret(req, file->f_op->write_iter(req, &iter));
1487 ret == -ERESTART_RESTARTBLOCK)) 1478 file_end_write(file);
1488 ret = -EINTR;
1489 aio_complete(req, ret, 0);
1490 } 1479 }
1491 1480 kfree(iovec);
1492 return 0; 1481 return ret;
1493} 1482}
1494 1483
1495static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, 1484static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
1496 struct iocb *iocb, bool compat) 1485 struct iocb *iocb, bool compat)
1497{ 1486{
1498 struct aio_kiocb *req; 1487 struct aio_kiocb *req;
1488 struct file *file;
1499 ssize_t ret; 1489 ssize_t ret;
1500 1490
1501 /* enforce forwards compatibility on users */ 1491 /* enforce forwards compatibility on users */
@@ -1518,7 +1508,7 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
1518 if (unlikely(!req)) 1508 if (unlikely(!req))
1519 return -EAGAIN; 1509 return -EAGAIN;
1520 1510
1521 req->common.ki_filp = fget(iocb->aio_fildes); 1511 req->common.ki_filp = file = fget(iocb->aio_fildes);
1522 if (unlikely(!req->common.ki_filp)) { 1512 if (unlikely(!req->common.ki_filp)) {
1523 ret = -EBADF; 1513 ret = -EBADF;
1524 goto out_put_req; 1514 goto out_put_req;
@@ -1553,13 +1543,29 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
1553 req->ki_user_iocb = user_iocb; 1543 req->ki_user_iocb = user_iocb;
1554 req->ki_user_data = iocb->aio_data; 1544 req->ki_user_data = iocb->aio_data;
1555 1545
1556 ret = aio_run_iocb(&req->common, iocb->aio_lio_opcode, 1546 get_file(file);
1557 (char __user *)(unsigned long)iocb->aio_buf, 1547 switch (iocb->aio_lio_opcode) {
1558 iocb->aio_nbytes, 1548 case IOCB_CMD_PREAD:
1559 compat); 1549 ret = aio_read(&req->common, iocb, false, compat);
1560 if (ret) 1550 break;
1561 goto out_put_req; 1551 case IOCB_CMD_PWRITE:
1552 ret = aio_write(&req->common, iocb, false, compat);
1553 break;
1554 case IOCB_CMD_PREADV:
1555 ret = aio_read(&req->common, iocb, true, compat);
1556 break;
1557 case IOCB_CMD_PWRITEV:
1558 ret = aio_write(&req->common, iocb, true, compat);
1559 break;
1560 default:
1561 pr_debug("invalid aio operation %d\n", iocb->aio_lio_opcode);
1562 ret = -EINVAL;
1563 break;
1564 }
1565 fput(file);
1562 1566
1567 if (ret && ret != -EIOCBQUEUED)
1568 goto out_put_req;
1563 return 0; 1569 return 0;
1564out_put_req: 1570out_put_req:
1565 put_reqs_available(ctx, 1); 1571 put_reqs_available(ctx, 1);