From 5f380c7fa7e01f15ca0816bd241ece9a64a73192 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 7 Apr 2015 11:28:12 -0400 Subject: lift generic_write_checks() into callers of __generic_file_write_iter() Signed-off-by: Al Viro --- fs/ext4/file.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'fs/ext4/file.c') diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 9ad03036d9f5..f7cca423dded 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -132,9 +132,8 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ret = -EFBIG; goto errout; } - - if (pos + length > sbi->s_bitmap_maxbytes) - iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos); + iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos); + length = iov_iter_count(from); } iocb->private = &overwrite; @@ -172,7 +171,16 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) } } + ret = generic_write_checks(file, &iocb->ki_pos, &length, 0); + if (ret) + goto out; + + if (length == 0) + goto out; + + iov_iter_truncate(from, length); ret = __generic_file_write_iter(iocb, from); +out: mutex_unlock(&inode->i_mutex); if (ret > 0) { -- cgit v1.2.3 From 0fa6b005afdb3152ce85df963302e59b61115f9b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 4 Apr 2015 04:05:48 -0400 Subject: generic_write_checks(): drop isblk argument all remaining callers are passing 0; some just obscure that fact. Signed-off-by: Al Viro --- fs/ext4/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/ext4/file.c') diff --git a/fs/ext4/file.c b/fs/ext4/file.c index f7cca423dded..1f0afc181b7b 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -171,7 +171,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) } } - ret = generic_write_checks(file, &iocb->ki_pos, &length, 0); + ret = generic_write_checks(file, &iocb->ki_pos, &length); if (ret) goto out; -- cgit v1.2.3 From e768d7ff7b923a74a019d8782e6ee75dc1de12c1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 7 Apr 2015 14:48:22 -0400 Subject: ext4_file_write_iter: move generic_write_checks() up simpler that way... Signed-off-by: Al Viro --- fs/ext4/file.c | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'fs/ext4/file.c') diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 1f0afc181b7b..42b1fa33a17a 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -99,7 +99,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) int overwrite = 0; size_t length = iov_iter_count(from); ssize_t ret; - loff_t pos = iocb->ki_pos; + loff_t pos; /* * Unaligned direct AIO must be serialized; see comment above @@ -109,15 +109,22 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && !is_sync_kiocb(iocb) && (file->f_flags & O_APPEND || - ext4_unaligned_aio(inode, from, pos))) { + ext4_unaligned_aio(inode, from, iocb->ki_pos))) { aio_mutex = ext4_aio_mutex(inode); mutex_lock(aio_mutex); ext4_unwritten_wait(inode); } mutex_lock(&inode->i_mutex); - if (file->f_flags & O_APPEND) - iocb->ki_pos = pos = i_size_read(inode); + ret = generic_write_checks(file, &iocb->ki_pos, &length); + if (ret) + goto out; + + if (length == 0) + goto out; + + iov_iter_truncate(from, length); + pos = iocb->ki_pos; /* * If we have encountered a bitmap-format file, the size limit @@ -126,18 +133,16 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - if ((pos > sbi->s_bitmap_maxbytes) || - (pos == sbi->s_bitmap_maxbytes && length > 0)) { - mutex_unlock(&inode->i_mutex); + if (pos >= sbi->s_bitmap_maxbytes) { ret = -EFBIG; - goto errout; + goto out; } iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos); - length = iov_iter_count(from); } iocb->private = &overwrite; if (o_direct) { + length = iov_iter_count(from); blk_start_plug(&plug); @@ -171,16 +176,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) } } - ret = generic_write_checks(file, &iocb->ki_pos, &length); - if (ret) - goto out; - - if (length == 0) - goto out; - - iov_iter_truncate(from, length); ret = __generic_file_write_iter(iocb, from); -out: mutex_unlock(&inode->i_mutex); if (ret > 0) { @@ -193,7 +189,12 @@ out: if (o_direct) blk_finish_plug(&plug); -errout: + if (aio_mutex) + mutex_unlock(aio_mutex); + return ret; + +out: + mutex_unlock(&inode->i_mutex); if (aio_mutex) mutex_unlock(aio_mutex); return ret; -- cgit v1.2.3 From 3309dd04cbcd2cdad168485af5cf3576b5051e49 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 9 Apr 2015 12:55:47 -0400 Subject: switch generic_write_checks() to iocb and iter ... returning -E... upon error and amount of data left in iter after (possible) truncation upon success. Note, that normal case gives a non-zero (positive) return value, so any tests for != 0 _must_ be updated. Signed-off-by: Al Viro Conflicts: fs/ext4/file.c --- fs/ext4/file.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'fs/ext4/file.c') diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 42b1fa33a17a..c10785f10d1d 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -97,9 +97,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) struct blk_plug plug; int o_direct = io_is_direct(file); int overwrite = 0; - size_t length = iov_iter_count(from); ssize_t ret; - loff_t pos; /* * Unaligned direct AIO must be serialized; see comment above @@ -116,16 +114,10 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) } mutex_lock(&inode->i_mutex); - ret = generic_write_checks(file, &iocb->ki_pos, &length); - if (ret) + ret = generic_write_checks(iocb, from); + if (ret <= 0) goto out; - if (length == 0) - goto out; - - iov_iter_truncate(from, length); - pos = iocb->ki_pos; - /* * If we have encountered a bitmap-format file, the size limit * is smaller than s_maxbytes, which is for extent-mapped files. @@ -133,19 +125,19 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - if (pos >= sbi->s_bitmap_maxbytes) { + if (iocb->ki_pos >= sbi->s_bitmap_maxbytes) { ret = -EFBIG; goto out; } - iov_iter_truncate(from, sbi->s_bitmap_maxbytes - pos); + iov_iter_truncate(from, sbi->s_bitmap_maxbytes - iocb->ki_pos); } iocb->private = &overwrite; if (o_direct) { - length = iov_iter_count(from); + size_t length = iov_iter_count(from); + loff_t pos = iocb->ki_pos; blk_start_plug(&plug); - /* check whether we do a DIO overwrite or not */ if (ext4_should_dioread_nolock(inode) && !aio_mutex && !file->f_mapping->nrpages && pos + length <= i_size_read(inode)) { -- cgit v1.2.3 From 2ba48ce513c4e545318d22b138861d5876edf906 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 9 Apr 2015 13:52:01 -0400 Subject: mirror O_APPEND and O_DIRECT into iocb->ki_flags ... avoiding write_iter/fcntl races. Signed-off-by: Al Viro --- fs/ext4/file.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/ext4/file.c') diff --git a/fs/ext4/file.c b/fs/ext4/file.c index c10785f10d1d..53bbc0b1995f 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -95,7 +95,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) struct inode *inode = file_inode(iocb->ki_filp); struct mutex *aio_mutex = NULL; struct blk_plug plug; - int o_direct = io_is_direct(file); + int o_direct = iocb->ki_flags & IOCB_DIRECT; int overwrite = 0; ssize_t ret; @@ -106,7 +106,7 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (o_direct && ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && !is_sync_kiocb(iocb) && - (file->f_flags & O_APPEND || + (iocb->ki_flags & IOCB_APPEND || ext4_unaligned_aio(inode, from, iocb->ki_pos))) { aio_mutex = ext4_aio_mutex(inode); mutex_lock(aio_mutex); -- cgit v1.2.3