diff --git a/fs/block_dev.c b/fs/block_dev.c index d8dc3512e9273cc7b1b8a7fbef2855f70e062689..a063d4d8ac39f41e3c6dd6d10f954c5f2140cf41 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1660,12 +1660,8 @@ ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) blk_start_plug(&plug); ret = __generic_file_write_iter(iocb, from); - if (ret > 0) { - ssize_t err; - err = generic_write_sync(iocb, iocb->ki_pos - ret, ret); - if (err < 0) - ret = err; - } + if (ret > 0) + ret = generic_write_sync(iocb, ret); blk_finish_plug(&plug); return ret; } diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 35ce146cceec2ed52cf9e54de697334f67a4049b..ea9f10bb089ccd651b63a57ae19dd7c0d89cd392 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -1851,11 +1851,8 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb, spin_lock(&BTRFS_I(inode)->lock); BTRFS_I(inode)->last_sub_trans = root->log_transid; spin_unlock(&BTRFS_I(inode)->lock); - if (num_written > 0) { - err = generic_write_sync(iocb, pos, num_written); - if (err < 0) - num_written = err; - } + if (num_written > 0) + num_written = generic_write_sync(iocb, num_written); if (sync) atomic_dec(&BTRFS_I(inode)->sync_writers); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index b22b68ccfbe563112fe1823b8894d287e2a18aa2..9b51d4936a292e7fda96998f11635387cf567ee6 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -2687,11 +2687,8 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from) out: inode_unlock(inode); - if (rc > 0) { - ssize_t err = generic_write_sync(iocb, iocb->ki_pos - rc, rc); - if (err < 0) - rc = err; - } + if (rc > 0) + rc = generic_write_sync(iocb, rc); up_read(&cinode->lock_sem); return rc; } diff --git a/fs/direct-io.c b/fs/direct-io.c index f7bcc0193deed20a366f3631bc4a60c4ab308f2f..3bf3f20f8ecccee8d4219c44a405787bb624bb53 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -256,6 +256,7 @@ static ssize_t dio_complete(struct dio *dio, ssize_t ret, bool is_async) if (dio->end_io) { int err; + // XXX: ki_pos?? err = dio->end_io(dio->iocb, offset, ret, dio->private); if (err) ret = err; @@ -265,15 +266,15 @@ static ssize_t dio_complete(struct dio *dio, ssize_t ret, bool is_async) inode_dio_end(dio->inode); if (is_async) { - if (dio->rw & WRITE) { - int err; - - err = generic_write_sync(dio->iocb, offset, - transferred); - if (err < 0 && ret > 0) - ret = err; - } + /* + * generic_write_sync expects ki_pos to have been updated + * already, but the submission path only does this for + * synchronous I/O. + */ + dio->iocb->ki_pos += transferred; + if (dio->rw & WRITE) + ret = generic_write_sync(dio->iocb, transferred); dio->iocb->ki_complete(dio->iocb, ret, 0); } diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 1417e129be519f0d623a4438fd12d20ad2008693..00ff6912adb305f1b939e695257abd10f74a3616 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -169,13 +169,8 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ret = __generic_file_write_iter(iocb, from); inode_unlock(inode); - if (ret > 0) { - ssize_t err; - - err = generic_write_sync(iocb, iocb->ki_pos - ret, ret); - if (err < 0) - ret = err; - } + if (ret > 0) + ret = generic_write_sync(iocb, ret); if (o_direct) blk_finish_plug(&plug); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 51ed8388e66cdafb54d900a240f42ff2095fb6ab..28f75a1fe4a7223f9ef8c5825825ba9f5fb161d5 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1882,13 +1882,8 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) } inode_unlock(inode); - if (ret > 0) { - ssize_t err; - - err = generic_write_sync(iocb, iocb->ki_pos - ret, ret); - if (err < 0) - ret = err; - } + if (ret > 0) + ret = generic_write_sync(iocb, ret); return ret; } diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index be86de9a77d76033003b3cf01cfcf4fcc5f18018..0b9fca040b0cd6a15bb49c24948f72e077234394 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -1054,7 +1054,9 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, struct iov_iter *iter) if (i_size_read(inode) < iocb->ki_pos) i_size_write(inode, iocb->ki_pos); spin_unlock(&inode->i_lock); - generic_write_sync(iocb, pos, result); + + /* XXX: should check the generic_write_sync retval */ + generic_write_sync(iocb, result); } } nfs_direct_req_release(dreq); diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 10dc38cc02bb82575612c023cf9b5c59f970e8d1..5622ed5a201e3c23c9fdbf611a6c9dab0a50eb0d 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -1952,12 +1952,9 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) written = ntfs_perform_write(file, from, iocb->ki_pos); current->backing_dev_info = NULL; inode_unlock(vi); - if (likely(written > 0)) { - err = generic_write_sync(iocb, iocb->ki_pos, written); - if (err < 0) - written = 0; - } iocb->ki_pos += written; + if (likely(written > 0)) + written = generic_write_sync(iocb, written); return written ? written : err; } diff --git a/fs/udf/file.c b/fs/udf/file.c index 8e3d1ae53b11ddff95f1a4b3757cad38339a6ef2..632570617327564ce9ed1c8f7aaf757c1e2c543a 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -152,9 +152,7 @@ static ssize_t udf_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (retval > 0) { mark_inode_dirty(inode); - err = generic_write_sync(iocb, iocb->ki_pos - retval, retval); - if (err < 0) - retval = err; + retval = generic_write_sync(iocb, retval); } return retval; diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index b5d70e77195d599067b5f3c12522f969138a7f46..cd3540997d65ad4761e84625b82b0926646aab9b 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -903,14 +903,10 @@ xfs_file_write_iter( ret = xfs_file_buffered_aio_write(iocb, from); if (ret > 0) { - ssize_t err; - XFS_STATS_ADD(ip->i_mount, xs_write_bytes, ret); /* Handle various SYNC-type writes */ - err = generic_write_sync(iocb, iocb->ki_pos - ret, ret); - if (err < 0) - ret = err; + ret = generic_write_sync(iocb, ret); } return ret; } diff --git a/include/linux/fs.h b/include/linux/fs.h index 310ca1ed9293fc32bbd850eaa472a056c4eab1e7..f6a8ed86465174c201adbebd432f989e58bf3a54 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2487,13 +2487,25 @@ extern int filemap_fdatawrite_range(struct address_space *mapping, extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync); extern int vfs_fsync(struct file *file, int datasync); -static inline int generic_write_sync(struct kiocb *iocb, loff_t pos, loff_t count) -{ - if (!(iocb->ki_flags & IOCB_DSYNC)) - return 0; - return vfs_fsync_range(iocb->ki_filp, pos, pos + count - 1, - (iocb->ki_flags & IOCB_SYNC) ? 0 : 1); + +/* + * Sync the bytes written if this was a synchronous write. Expect ki_pos + * to already be updated for the write, and will return either the amount + * of bytes passed in, or an error if syncing the file failed. + */ +static inline ssize_t generic_write_sync(struct kiocb *iocb, ssize_t count) +{ + if (iocb->ki_flags & IOCB_DSYNC) { + int ret = vfs_fsync_range(iocb->ki_filp, + iocb->ki_pos - count, iocb->ki_pos - 1, + (iocb->ki_flags & IOCB_SYNC) ? 0 : 1); + if (ret) + return ret; + } + + return count; } + extern void emergency_sync(void); extern void emergency_remount(void); #ifdef CONFIG_BLOCK diff --git a/mm/filemap.c b/mm/filemap.c index 8345d6d3436ac4cc862f1aa1311a992a841a4d8c..182b21825255397d8691431f7f47673b52ff79c7 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2791,13 +2791,8 @@ ssize_t generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ret = __generic_file_write_iter(iocb, from); inode_unlock(inode); - if (ret > 0) { - ssize_t err; - - err = generic_write_sync(iocb, iocb->ki_pos - ret, ret); - if (err < 0) - ret = err; - } + if (ret > 0) + ret = generic_write_sync(iocb, ret); return ret; } EXPORT_SYMBOL(generic_file_write_iter);