summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file.c
diff options
context:
space:
mode:
authorChandan Rajendra2016-01-21 11:26:03 +0100
committerDavid Sterba2016-02-01 19:24:29 +0100
commit27772b68f6994f0011690899c31717b7cbec51c9 (patch)
tree51c06f3d06a72082de3e63e6c7c2a9a710d4369b /fs/btrfs/file.c
parentBtrfs: Fix block size returned to user space (diff)
downloadkernel-qcow2-linux-27772b68f6994f0011690899c31717b7cbec51c9.tar.gz
kernel-qcow2-linux-27772b68f6994f0011690899c31717b7cbec51c9.tar.xz
kernel-qcow2-linux-27772b68f6994f0011690899c31717b7cbec51c9.zip
Btrfs: Clean pte corresponding to page straddling i_size
When extending a file by either "truncate up" or by writing beyond i_size, the page which had i_size needs to be marked "read only" so that future writes to the page via mmap interface causes btrfs_page_mkwrite() to be invoked. If not, a write performed after extending the file via the mmap interface will find the page to be writaeable and continue writing to the page without invoking btrfs_page_mkwrite() i.e. we end up writing to a file without reserving disk space. Signed-off-by: Chandan Rajendra <chandan@linux.vnet.ibm.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r--fs/btrfs/file.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 58bb29788f5f..953f0ad17802 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1778,6 +1778,8 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
ssize_t err;
loff_t pos;
size_t count;
+ loff_t oldsize;
+ int clean_page = 0;
mutex_lock(&inode->i_mutex);
err = generic_write_checks(iocb, from);
@@ -1816,14 +1818,17 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
pos = iocb->ki_pos;
count = iov_iter_count(from);
start_pos = round_down(pos, root->sectorsize);
- if (start_pos > i_size_read(inode)) {
+ oldsize = i_size_read(inode);
+ if (start_pos > oldsize) {
/* Expand hole size to cover write data, preventing empty gap */
end_pos = round_up(pos + count, root->sectorsize);
- err = btrfs_cont_expand(inode, i_size_read(inode), end_pos);
+ err = btrfs_cont_expand(inode, oldsize, end_pos);
if (err) {
mutex_unlock(&inode->i_mutex);
goto out;
}
+ if (start_pos > round_up(oldsize, root->sectorsize))
+ clean_page = 1;
}
if (sync)
@@ -1835,6 +1840,9 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
num_written = __btrfs_buffered_write(file, from, pos);
if (num_written > 0)
iocb->ki_pos = pos + num_written;
+ if (clean_page)
+ pagecache_isize_extended(inode, oldsize,
+ i_size_read(inode));
}
mutex_unlock(&inode->i_mutex);