| From 5e33a2bd7ca7fa687fb0965869196eea6815d1f3 Mon Sep 17 00:00:00 2001 |
| From: Filipe Manana <fdmanana@suse.com> |
| Date: Thu, 25 Feb 2016 23:19:38 +0000 |
| Subject: Btrfs: do not collect ordered extents when logging that inode exists |
| |
| From: Filipe Manana <fdmanana@suse.com> |
| |
| commit 5e33a2bd7ca7fa687fb0965869196eea6815d1f3 upstream. |
| |
| When logging that an inode exists, for example as part of a directory |
| fsync operation, we were collecting any ordered extents for the inode but |
| we ended up doing nothing with them except tagging them as processed, by |
| setting the flag BTRFS_ORDERED_LOGGED on them, which prevented a |
| subsequent fsync of that inode (using the LOG_INODE_ALL mode) from |
| collecting and processing them. This created a time window where a second |
| fsync against the inode, using the fast path, ended up not logging the |
| checksums for the new extents but it logged the extents since they were |
| part of the list of modified extents. This happened because the ordered |
| extents were not collected and checksums were not yet added to the csum |
| tree - the ordered extents have not gone through btrfs_finish_ordered_io() |
| yet (which is where we add them to the csum tree by calling |
| inode.c:add_pending_csums()). |
| |
| So fix this by not collecting an inode's ordered extents if we are logging |
| it with the LOG_INODE_EXISTS mode. |
| |
| Signed-off-by: Filipe Manana <fdmanana@suse.com> |
| Signed-off-by: Chris Mason <clm@fb.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/btrfs/tree-log.c | 17 ++++++++++++++++- |
| 1 file changed, 16 insertions(+), 1 deletion(-) |
| |
| --- a/fs/btrfs/tree-log.c |
| +++ b/fs/btrfs/tree-log.c |
| @@ -4621,7 +4621,22 @@ static int btrfs_log_inode(struct btrfs_ |
| |
| mutex_lock(&BTRFS_I(inode)->log_mutex); |
| |
| - btrfs_get_logged_extents(inode, &logged_list, start, end); |
| + /* |
| + * Collect ordered extents only if we are logging data. This is to |
| + * ensure a subsequent request to log this inode in LOG_INODE_ALL mode |
| + * will process the ordered extents if they still exists at the time, |
| + * because when we collect them we test and set for the flag |
| + * BTRFS_ORDERED_LOGGED to prevent multiple log requests to process the |
| + * same ordered extents. The consequence for the LOG_INODE_ALL log mode |
| + * not processing the ordered extents is that we end up logging the |
| + * corresponding file extent items, based on the extent maps in the |
| + * inode's extent_map_tree's modified_list, without logging the |
| + * respective checksums (since the may still be only attached to the |
| + * ordered extents and have not been inserted in the csum tree by |
| + * btrfs_finish_ordered_io() yet). |
| + */ |
| + if (inode_only == LOG_INODE_ALL) |
| + btrfs_get_logged_extents(inode, &logged_list, start, end); |
| |
| /* |
| * a brute force approach to making sure we get the most uptodate |