Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 27772b68 authored by Chandan Rajendra's avatar Chandan Rajendra Committed by David Sterba
Browse files

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: default avatarChandan Rajendra <chandan@linux.vnet.ibm.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 5a2834f8
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -4899,7 +4899,6 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
	}

	if (newsize > oldsize) {
		truncate_pagecache(inode, newsize);
		/*
		 * Don't do an expanding truncate while snapshoting is ongoing.
		 * This is to ensure the snapshot captures a fully consistent
@@ -4922,6 +4921,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)

		i_size_write(inode, newsize);
		btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL);
		pagecache_isize_extended(inode, oldsize, newsize);
		ret = btrfs_update_inode(trans, root, inode);
		btrfs_end_write_no_snapshoting(root);
		btrfs_end_transaction(trans, root);