iomap: move the iomap_dio_rw ->end_io callback into a structure
authorChristoph Hellwig <hch@lst.de>
Thu, 19 Sep 2019 22:32:45 +0000 (15:32 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Thu, 19 Sep 2019 22:32:45 +0000 (15:32 -0700)
Add a new iomap_dio_ops structure that for now just contains the end_io
handler.  This avoid storing the function pointer in a mutable structure,
which is a possible exploit vector for kernel code execution, and prepares
for adding a submit_io handler that btrfs needs.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
fs/iomap/direct-io.c
fs/xfs/xfs_file.c
include/linux/iomap.h

index 2ccf1c6..1fc28c2 100644 (file)
@@ -24,7 +24,7 @@
 
 struct iomap_dio {
        struct kiocb            *iocb;
-       iomap_dio_end_io_t      *end_io;
+       const struct iomap_dio_ops *dops;
        loff_t                  i_size;
        loff_t                  size;
        atomic_t                ref;
@@ -72,15 +72,14 @@ static void iomap_dio_submit_bio(struct iomap_dio *dio, struct iomap *iomap,
 
 static ssize_t iomap_dio_complete(struct iomap_dio *dio)
 {
+       const struct iomap_dio_ops *dops = dio->dops;
        struct kiocb *iocb = dio->iocb;
        struct inode *inode = file_inode(iocb->ki_filp);
        loff_t offset = iocb->ki_pos;
-       ssize_t ret;
+       ssize_t ret = dio->error;
 
-       if (dio->end_io)
-               ret = dio->end_io(iocb, dio->size, dio->error, dio->flags);
-       else
-               ret = dio->error;
+       if (dops && dops->end_io)
+               ret = dops->end_io(iocb, dio->size, ret, dio->flags);
 
        if (likely(!ret)) {
                ret = dio->size;
@@ -98,9 +97,9 @@ static ssize_t iomap_dio_complete(struct iomap_dio *dio)
         * one is a pretty crazy thing to do, so we don't support it 100%.  If
         * this invalidation fails, tough, the write still worked...
         *
-        * And this page cache invalidation has to be after dio->end_io(), as
-        * some filesystems convert unwritten extents to real allocations in
-        * end_io() when necessary, otherwise a racing buffer read would cache
+        * And this page cache invalidation has to be after ->end_io(), as some
+        * filesystems convert unwritten extents to real allocations in
+        * ->end_io() when necessary, otherwise a racing buffer read would cache
         * zeros from unwritten extents.
         */
        if (!dio->error &&
@@ -393,7 +392,7 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length,
  */
 ssize_t
 iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
-               const struct iomap_ops *ops, iomap_dio_end_io_t end_io)
+               const struct iomap_ops *ops, const struct iomap_dio_ops *dops)
 {
        struct address_space *mapping = iocb->ki_filp->f_mapping;
        struct inode *inode = file_inode(iocb->ki_filp);
@@ -418,7 +417,7 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
        atomic_set(&dio->ref, 1);
        dio->size = 0;
        dio->i_size = i_size_read(inode);
-       dio->end_io = end_io;
+       dio->dops = dops;
        dio->error = 0;
        dio->flags = 0;
 
index 7441129..21bd3d5 100644 (file)
@@ -442,6 +442,10 @@ out:
        return error;
 }
 
+static const struct iomap_dio_ops xfs_dio_write_ops = {
+       .end_io         = xfs_dio_write_end_io,
+};
+
 /*
  * xfs_file_dio_aio_write - handle direct IO writes
  *
@@ -542,7 +546,7 @@ xfs_file_dio_aio_write(
        }
 
        trace_xfs_file_direct_write(ip, count, iocb->ki_pos);
-       ret = iomap_dio_rw(iocb, from, &xfs_iomap_ops, xfs_dio_write_end_io);
+       ret = iomap_dio_rw(iocb, from, &xfs_iomap_ops, &xfs_dio_write_ops);
 
        /*
         * If unaligned, this is the only IO in-flight. If it has not yet
index 50bb746..7aa5d61 100644 (file)
@@ -188,10 +188,14 @@ sector_t iomap_bmap(struct address_space *mapping, sector_t bno,
  */
 #define IOMAP_DIO_UNWRITTEN    (1 << 0)        /* covers unwritten extent(s) */
 #define IOMAP_DIO_COW          (1 << 1)        /* covers COW extent(s) */
-typedef int (iomap_dio_end_io_t)(struct kiocb *iocb, ssize_t size, int error,
-                                unsigned int flags);
+
+struct iomap_dio_ops {
+       int (*end_io)(struct kiocb *iocb, ssize_t size, int error,
+                     unsigned flags);
+};
+
 ssize_t iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
-               const struct iomap_ops *ops, iomap_dio_end_io_t end_io);
+               const struct iomap_ops *ops, const struct iomap_dio_ops *dops);
 int iomap_dio_iopoll(struct kiocb *kiocb, bool spin);
 
 #ifdef CONFIG_SWAP