diff options
author | Christoph Hellwig <hch@lst.de> | 2018-03-27 13:18:57 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2018-05-02 13:57:24 -0400 |
commit | a3c0d439e4d92411c2b4b21a526a4de720d0806b (patch) | |
tree | 6acf05c9788bc140f2687d04a2d8c4f70800cdd9 /fs/aio.c | |
parent | 54843f875f7a9f802bbb0d9895c3266b4a0b2f37 (diff) |
aio: implement IOCB_CMD_FSYNC and IOCB_CMD_FDSYNC
Simple workqueue offload for now, but prepared for adding a real aio_fsync
method if the need arises. Based on an earlier patch from Dave Chinner.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs/aio.c')
-rw-r--r-- | fs/aio.c | 43 |
1 files changed, 43 insertions, 0 deletions
@@ -156,6 +156,12 @@ struct kioctx { | |||
156 | unsigned id; | 156 | unsigned id; |
157 | }; | 157 | }; |
158 | 158 | ||
159 | struct fsync_iocb { | ||
160 | struct work_struct work; | ||
161 | struct file *file; | ||
162 | bool datasync; | ||
163 | }; | ||
164 | |||
159 | /* | 165 | /* |
160 | * We use ki_cancel == KIOCB_CANCELLED to indicate that a kiocb has been either | 166 | * We use ki_cancel == KIOCB_CANCELLED to indicate that a kiocb has been either |
161 | * cancelled or completed (this makes a certain amount of sense because | 167 | * cancelled or completed (this makes a certain amount of sense because |
@@ -172,6 +178,7 @@ struct kioctx { | |||
172 | struct aio_kiocb { | 178 | struct aio_kiocb { |
173 | union { | 179 | union { |
174 | struct kiocb rw; | 180 | struct kiocb rw; |
181 | struct fsync_iocb fsync; | ||
175 | }; | 182 | }; |
176 | 183 | ||
177 | struct kioctx *ki_ctx; | 184 | struct kioctx *ki_ctx; |
@@ -1573,6 +1580,36 @@ out_fput: | |||
1573 | return ret; | 1580 | return ret; |
1574 | } | 1581 | } |
1575 | 1582 | ||
1583 | static void aio_fsync_work(struct work_struct *work) | ||
1584 | { | ||
1585 | struct fsync_iocb *req = container_of(work, struct fsync_iocb, work); | ||
1586 | int ret; | ||
1587 | |||
1588 | ret = vfs_fsync(req->file, req->datasync); | ||
1589 | fput(req->file); | ||
1590 | aio_complete(container_of(req, struct aio_kiocb, fsync), ret, 0); | ||
1591 | } | ||
1592 | |||
1593 | static int aio_fsync(struct fsync_iocb *req, struct iocb *iocb, bool datasync) | ||
1594 | { | ||
1595 | if (unlikely(iocb->aio_buf || iocb->aio_offset || iocb->aio_nbytes || | ||
1596 | iocb->aio_rw_flags)) | ||
1597 | return -EINVAL; | ||
1598 | |||
1599 | req->file = fget(iocb->aio_fildes); | ||
1600 | if (unlikely(!req->file)) | ||
1601 | return -EBADF; | ||
1602 | if (unlikely(!req->file->f_op->fsync)) { | ||
1603 | fput(req->file); | ||
1604 | return -EINVAL; | ||
1605 | } | ||
1606 | |||
1607 | req->datasync = datasync; | ||
1608 | INIT_WORK(&req->work, aio_fsync_work); | ||
1609 | schedule_work(&req->work); | ||
1610 | return -EIOCBQUEUED; | ||
1611 | } | ||
1612 | |||
1576 | static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | 1613 | static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, |
1577 | struct iocb *iocb, bool compat) | 1614 | struct iocb *iocb, bool compat) |
1578 | { | 1615 | { |
@@ -1636,6 +1673,12 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1636 | case IOCB_CMD_PWRITEV: | 1673 | case IOCB_CMD_PWRITEV: |
1637 | ret = aio_write(&req->rw, iocb, true, compat); | 1674 | ret = aio_write(&req->rw, iocb, true, compat); |
1638 | break; | 1675 | break; |
1676 | case IOCB_CMD_FSYNC: | ||
1677 | ret = aio_fsync(&req->fsync, iocb, false); | ||
1678 | break; | ||
1679 | case IOCB_CMD_FDSYNC: | ||
1680 | ret = aio_fsync(&req->fsync, iocb, true); | ||
1681 | break; | ||
1639 | default: | 1682 | default: |
1640 | pr_debug("invalid aio operation %d\n", iocb->aio_lio_opcode); | 1683 | pr_debug("invalid aio operation %d\n", iocb->aio_lio_opcode); |
1641 | ret = -EINVAL; | 1684 | ret = -EINVAL; |