Merge tag 'for-5.12/block-2021-02-17' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / fs / iomap / direct-io.c
index 933f234..e2c4991 100644 (file)
@@ -201,6 +201,34 @@ iomap_dio_zero(struct iomap_dio *dio, struct iomap *iomap, loff_t pos,
        iomap_dio_submit_bio(dio, iomap, bio, pos);
 }
 
+/*
+ * Figure out the bio's operation flags from the dio request, the
+ * mapping, and whether or not we want FUA.  Note that we can end up
+ * clearing the WRITE_FUA flag in the dio request.
+ */
+static inline unsigned int
+iomap_dio_bio_opflags(struct iomap_dio *dio, struct iomap *iomap, bool use_fua)
+{
+       unsigned int opflags = REQ_SYNC | REQ_IDLE;
+
+       if (!(dio->flags & IOMAP_DIO_WRITE)) {
+               WARN_ON_ONCE(iomap->flags & IOMAP_F_ZONE_APPEND);
+               return REQ_OP_READ;
+       }
+
+       if (iomap->flags & IOMAP_F_ZONE_APPEND)
+               opflags |= REQ_OP_ZONE_APPEND;
+       else
+               opflags |= REQ_OP_WRITE;
+
+       if (use_fua)
+               opflags |= REQ_FUA;
+       else
+               dio->flags &= ~IOMAP_DIO_WRITE_FUA;
+
+       return opflags;
+}
+
 static loff_t
 iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
                struct iomap_dio *dio, struct iomap *iomap)
@@ -208,6 +236,7 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
        unsigned int blkbits = blksize_bits(bdev_logical_block_size(iomap->bdev));
        unsigned int fs_block_size = i_blocksize(inode), pad;
        unsigned int align = iov_iter_alignment(dio->submit.iter);
+       unsigned int bio_opf;
        struct bio *bio;
        bool need_zeroout = false;
        bool use_fua = false;
@@ -250,11 +279,8 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
        orig_count = iov_iter_count(dio->submit.iter);
        iov_iter_truncate(dio->submit.iter, length);
 
-       nr_pages = iov_iter_npages(dio->submit.iter, BIO_MAX_PAGES);
-       if (nr_pages <= 0) {
-               ret = nr_pages;
+       if (!iov_iter_count(dio->submit.iter))
                goto out;
-       }
 
        if (need_zeroout) {
                /* zero out from the start of the block to the write offset */
@@ -263,6 +289,14 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
                        iomap_dio_zero(dio, iomap, pos - pad, pad);
        }
 
+       /*
+        * Set the operation flags early so that bio_iov_iter_get_pages
+        * can set up the page vector appropriately for a ZONE_APPEND
+        * operation.
+        */
+       bio_opf = iomap_dio_bio_opflags(dio, iomap, use_fua);
+
+       nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter, BIO_MAX_PAGES);
        do {
                size_t n;
                if (dio->error) {
@@ -278,6 +312,7 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
                bio->bi_ioprio = dio->iocb->ki_ioprio;
                bio->bi_private = dio;
                bio->bi_end_io = iomap_dio_bio_end_io;
+               bio->bi_opf = bio_opf;
 
                ret = bio_iov_iter_get_pages(bio, dio->submit.iter);
                if (unlikely(ret)) {
@@ -293,14 +328,8 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
 
                n = bio->bi_iter.bi_size;
                if (dio->flags & IOMAP_DIO_WRITE) {
-                       bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
-                       if (use_fua)
-                               bio->bi_opf |= REQ_FUA;
-                       else
-                               dio->flags &= ~IOMAP_DIO_WRITE_FUA;
                        task_io_account_write(n);
                } else {
-                       bio->bi_opf = REQ_OP_READ;
                        if (dio->flags & IOMAP_DIO_DIRTY)
                                bio_set_pages_dirty(bio);
                }
@@ -308,7 +337,8 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
                dio->size += n;
                copied += n;
 
-               nr_pages = iov_iter_npages(dio->submit.iter, BIO_MAX_PAGES);
+               nr_pages = bio_iov_vecs_to_alloc(dio->submit.iter,
+                                                BIO_MAX_PAGES);
                iomap_dio_submit_bio(dio, iomap, bio, pos);
                pos += n;
        } while (nr_pages);
@@ -420,23 +450,22 @@ iomap_dio_actor(struct inode *inode, loff_t pos, loff_t length,
 struct iomap_dio *
 __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
                const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
-               bool wait_for_completion)
+               unsigned int dio_flags)
 {
        struct address_space *mapping = iocb->ki_filp->f_mapping;
        struct inode *inode = file_inode(iocb->ki_filp);
        size_t count = iov_iter_count(iter);
        loff_t pos = iocb->ki_pos;
        loff_t end = iocb->ki_pos + count - 1, ret = 0;
-       unsigned int flags = IOMAP_DIRECT;
+       bool wait_for_completion =
+               is_sync_kiocb(iocb) || (dio_flags & IOMAP_DIO_FORCE_WAIT);
+       unsigned int iomap_flags = IOMAP_DIRECT;
        struct blk_plug plug;
        struct iomap_dio *dio;
 
        if (!count)
                return NULL;
 
-       if (WARN_ON(is_sync_kiocb(iocb) && !wait_for_completion))
-               return ERR_PTR(-EIO);
-
        dio = kmalloc(sizeof(*dio), GFP_KERNEL);
        if (!dio)
                return ERR_PTR(-ENOMEM);
@@ -461,7 +490,7 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
                if (iter_is_iovec(iter))
                        dio->flags |= IOMAP_DIO_DIRTY;
        } else {
-               flags |= IOMAP_WRITE;
+               iomap_flags |= IOMAP_WRITE;
                dio->flags |= IOMAP_DIO_WRITE;
 
                /* for data sync or sync, we need sync completion processing */
@@ -483,7 +512,14 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
                        ret = -EAGAIN;
                        goto out_free_dio;
                }
-               flags |= IOMAP_NOWAIT;
+               iomap_flags |= IOMAP_NOWAIT;
+       }
+
+       if (dio_flags & IOMAP_DIO_OVERWRITE_ONLY) {
+               ret = -EAGAIN;
+               if (pos >= dio->i_size || pos + count > dio->i_size)
+                       goto out_free_dio;
+               iomap_flags |= IOMAP_OVERWRITE_ONLY;
        }
 
        ret = filemap_write_and_wait_range(mapping, pos, end);
@@ -514,7 +550,7 @@ __iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
 
        blk_start_plug(&plug);
        do {
-               ret = iomap_apply(inode, pos, count, flags, ops, dio,
+               ret = iomap_apply(inode, pos, count, iomap_flags, ops, dio,
                                iomap_dio_actor);
                if (ret <= 0) {
                        /* magic error code to fall back to buffered I/O */
@@ -598,11 +634,11 @@ EXPORT_SYMBOL_GPL(__iomap_dio_rw);
 ssize_t
 iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter,
                const struct iomap_ops *ops, const struct iomap_dio_ops *dops,
-               bool wait_for_completion)
+               unsigned int dio_flags)
 {
        struct iomap_dio *dio;
 
-       dio = __iomap_dio_rw(iocb, iter, ops, dops, wait_for_completion);
+       dio = __iomap_dio_rw(iocb, iter, ops, dops, dio_flags);
        if (IS_ERR_OR_NULL(dio))
                return PTR_ERR_OR_ZERO(dio);
        return iomap_dio_complete(dio);