Skip to content

Commit 983d820

Browse files
fdmananakdave
authored andcommitted
btrfs: add missing inode updates on each iteration when replacing extents
When replacing file extents, called during fallocate, hole punching, clone and deduplication, we may not be able to replace/drop all the target file extent items with a single transaction handle. We may get -ENOSPC while doing it, in which case we release the transaction handle, balance the dirty pages of the btree inode, flush delayed items and get a new transaction handle to operate on what's left of the target range. By dropping and replacing file extent items we have effectively modified the inode, so we should bump its iversion and update its mtime/ctime before we update the inode item. This is because if the transaction we used for partially modifying the inode gets committed by someone after we release it and before we finish the rest of the range, a power failure happens, then after mounting the filesystem our inode has an outdated iversion and mtime/ctime, corresponding to the values it had before we changed it. So add the missing iversion and mtime/ctime updates. Reviewed-by: Boris Burkov <[email protected]> Signed-off-by: Filipe Manana <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent d459789 commit 983d820

File tree

4 files changed

+23
-0
lines changed

4 files changed

+23
-0
lines changed

fs/btrfs/ctree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,8 @@ struct btrfs_replace_extent_info {
13301330
* existing extent into a file range.
13311331
*/
13321332
bool is_new_extent;
1333+
/* Indicate if we should update the inode's mtime and ctime. */
1334+
bool update_times;
13331335
/* Meaningful only if is_new_extent is true. */
13341336
int qgroup_reserved;
13351337
/*

fs/btrfs/file.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,6 +2802,25 @@ int btrfs_replace_file_extents(struct btrfs_inode *inode,
28022802
extent_info->file_offset += replace_len;
28032803
}
28042804

2805+
/*
2806+
* We are releasing our handle on the transaction, balance the
2807+
* dirty pages of the btree inode and flush delayed items, and
2808+
* then get a new transaction handle, which may now point to a
2809+
* new transaction in case someone else may have committed the
2810+
* transaction we used to replace/drop file extent items. So
2811+
* bump the inode's iversion and update mtime and ctime except
2812+
* if we are called from a dedupe context. This is because a
2813+
* power failure/crash may happen after the transaction is
2814+
* committed and before we finish replacing/dropping all the
2815+
* file extent items we need.
2816+
*/
2817+
inode_inc_iversion(&inode->vfs_inode);
2818+
2819+
if (!extent_info || extent_info->update_times) {
2820+
inode->vfs_inode.i_mtime = current_time(&inode->vfs_inode);
2821+
inode->vfs_inode.i_ctime = inode->vfs_inode.i_mtime;
2822+
}
2823+
28052824
ret = btrfs_update_inode(trans, root, inode);
28062825
if (ret)
28072826
break;

fs/btrfs/inode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9897,6 +9897,7 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent(
98979897
extent_info.file_offset = file_offset;
98989898
extent_info.extent_buf = (char *)&stack_fi;
98999899
extent_info.is_new_extent = true;
9900+
extent_info.update_times = true;
99009901
extent_info.qgroup_reserved = qgroup_released;
99019902
extent_info.insertions = 0;
99029903

fs/btrfs/reflink.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
496496
clone_info.file_offset = new_key.offset;
497497
clone_info.extent_buf = buf;
498498
clone_info.is_new_extent = false;
499+
clone_info.update_times = !no_time_update;
499500
ret = btrfs_replace_file_extents(BTRFS_I(inode), path,
500501
drop_start, new_key.offset + datal - 1,
501502
&clone_info, &trans);

0 commit comments

Comments
 (0)