return written;
}
-static int ext4_dio_write_end_io(struct kiocb *iocb, ssize_t size,
- int error, unsigned int flags)
+static ssize_t ext4_dio_write_end_io(struct kiocb *iocb, struct iomap_dio *dio,
+ ssize_t size, int error, unsigned int flags)
{
loff_t offset = iocb->ki_pos;
struct inode *inode = file_inode(iocb->ki_filp);
+ ssize_t ret = 0;
- if (error)
- return error;
-
- if (size && flags & IOMAP_DIO_UNWRITTEN)
- return ext4_convert_unwritten_extents(NULL, inode,
- offset, size);
-
- return 0;
+ if (!error && size && (flags & IOMAP_DIO_UNWRITTEN))
+ ret = ext4_convert_unwritten_extents(NULL, inode, offset, size);
+ return iomap_dio_end_io(dio, ret);
}
static const struct iomap_dio_ops ext4_dio_write_ops = {
dio->submit.cookie = submit_bio(bio);
}
-static ssize_t iomap_dio_complete(struct iomap_dio *dio)
+ssize_t iomap_dio_end_io(struct iomap_dio *dio, int error)
{
- 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 = dio->error;
+ ssize_t ret = dio->size;
- if (dops && dops->end_io)
- ret = dops->end_io(iocb, dio->size, ret, dio->flags);
-
- if (likely(!ret)) {
- ret = dio->size;
- /* check for short read */
- if (offset + ret > dio->i_size &&
- !(dio->flags & IOMAP_DIO_WRITE))
- ret = dio->i_size - offset;
- iocb->ki_pos += ret;
- }
+ if (unlikely(error))
+ return error;
+
+ /* check for short read */
+ if (!(dio->flags & IOMAP_DIO_WRITE) && offset + ret > dio->i_size)
+ ret = dio->i_size - offset;
+ iocb->ki_pos += ret;
/*
* Try again to invalidate clean pages which might have been cached by
* ->end_io() when necessary, otherwise a racing buffer read would cache
* zeros from unwritten extents.
*/
- if (!dio->error &&
- (dio->flags & IOMAP_DIO_WRITE) && inode->i_mapping->nrpages) {
- int err;
- err = invalidate_inode_pages2_range(inode->i_mapping,
+ if ((dio->flags & IOMAP_DIO_WRITE) && inode->i_mapping->nrpages) {
+ if (invalidate_inode_pages2_range(inode->i_mapping,
offset >> PAGE_SHIFT,
- (offset + dio->size - 1) >> PAGE_SHIFT);
- if (err)
+ (offset + dio->size - 1) >> PAGE_SHIFT))
dio_warn_stale_pagecache(iocb->ki_filp);
}
* If this is a DSYNC write, make sure we push it to stable storage now
* that we've written data.
*/
- if (ret > 0 && (dio->flags & IOMAP_DIO_NEED_SYNC))
- ret = generic_write_sync(iocb, ret);
+ if ((dio->flags & IOMAP_DIO_NEED_SYNC) && ret > 0)
+ return generic_write_sync(iocb, ret);
+ return ret;
+}
+
+static ssize_t iomap_dio_complete(struct iomap_dio *dio)
+{
+ const struct iomap_dio_ops *dops = dio->dops;
+ ssize_t ret;
+
+ if (dops && dops->end_io)
+ ret = dops->end_io(dio->iocb, dio, dio->size, dio->error,
+ dio->flags);
+ else
+ ret = iomap_dio_end_io(dio, dio->error);
- inode_dio_end(file_inode(iocb->ki_filp));
+ inode_dio_end(file_inode(dio->iocb->ki_filp));
kfree(dio);
return ret;
return file_modified(file);
}
-static int
+static ssize_t
xfs_dio_write_end_io(
struct kiocb *iocb,
+ struct iomap_dio *dio,
ssize_t size,
int error,
unsigned flags)
if (error)
return error;
if (!size)
- return 0;
+ goto done;
/*
* Capture amount written on completion as we can't reliably account
if (flags & IOMAP_DIO_COW) {
error = xfs_reflink_end_cow(ip, offset, size);
if (error)
- goto out;
+ goto out_restore_nofs;
}
/*
*/
if (flags & IOMAP_DIO_UNWRITTEN) {
error = xfs_iomap_write_unwritten(ip, offset, size, true);
- goto out;
+ goto out_restore_nofs;
}
/*
spin_unlock(&ip->i_flags_lock);
}
-out:
+out_restore_nofs:
memalloc_nofs_restore(nofs_flag);
- return error;
+done:
+ return iomap_dio_end_io(dio, error);
}
static const struct iomap_dio_ops xfs_dio_write_ops = {
return generic_file_llseek_size(file, offset, whence, isize, isize);
}
-static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size,
- int error, unsigned int flags)
+static ssize_t zonefs_file_write_dio_end_io(struct kiocb *iocb,
+ struct iomap_dio *dio, ssize_t size, int error,
+ unsigned int flags)
{
struct inode *inode = file_inode(iocb->ki_filp);
struct zonefs_inode_info *zi = ZONEFS_I(inode);
mutex_unlock(&zi->i_truncate_mutex);
}
- return 0;
+ return iomap_dio_end_io(dio, 0);
}
static const struct iomap_dio_ops zonefs_write_dio_ops = {
return zonefs_file_buffered_write(iocb, from);
}
-static int zonefs_file_read_dio_end_io(struct kiocb *iocb, ssize_t size,
- int error, unsigned int flags)
+static ssize_t zonefs_file_read_dio_end_io(struct kiocb *iocb,
+ struct iomap_dio *dio, ssize_t size, int error,
+ unsigned int flags)
{
if (error) {
zonefs_io_error(file_inode(iocb->ki_filp), false);
return error;
}
- return 0;
+ return iomap_dio_end_io(dio, 0);
}
static const struct iomap_dio_ops zonefs_read_dio_ops = {
struct address_space;
struct fiemap_extent_info;
struct inode;
+struct iomap_dio;
struct iomap_writepage_ctx;
struct iov_iter;
struct kiocb;
#define IOMAP_DIO_COW (1 << 1) /* covers COW extent(s) */
struct iomap_dio_ops {
- int (*end_io)(struct kiocb *iocb, ssize_t size, int error,
- unsigned flags);
+ ssize_t (*end_io)(struct kiocb *iocb, struct iomap_dio *dio, ssize_t size,
+ int error, unsigned flags);
};
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);
int iomap_dio_iopoll(struct kiocb *kiocb, bool spin);
+ssize_t iomap_dio_end_io(struct iomap_dio *dio, int error);
#ifdef CONFIG_SWAP
struct file;