Skip to content

Commit 6b225ba

Browse files
fdmananakdave
authored andcommitted
btrfs: fix mount failure due to past and transient device flush error
When we get an error flushing one device, during a super block commit, we record the error in the device structure, in the field 'last_flush_error'. This is used to later check if we should error out the super block commit, depending on whether the number of flush errors is greater than or equals to the maximum tolerated device failures for a raid profile. However if we get a transient device flush error, unmount the filesystem and later try to mount it, we can fail the mount because we treat that past error as critical and consider the device is missing. Even if it's very likely that the error will happen again, as it's probably due to a hardware related problem, there may be cases where the error might not happen again. One example is during testing, and a test case like the new generic/648 from fstests always triggers this. The test cases generic/019 and generic/475 also trigger this scenario, but very sporadically. When this happens we get an error like this: $ mount /dev/sdc /mnt mount: /mnt wrong fs type, bad option, bad superblock on /dev/sdc, missing codepage or helper program, or other error. $ dmesg (...) [12918.886926] BTRFS warning (device sdc): chunk 13631488 missing 1 devices, max tolerance is 0 for writable mount [12918.888293] BTRFS warning (device sdc): writable mount is not allowed due to too many missing devices [12918.890853] BTRFS error (device sdc): open_ctree failed The failure happens because when btrfs_check_rw_degradable() is called at mount time, or at remount from RO to RW time, is sees a non zero value in a device's ->last_flush_error attribute, and therefore considers that the device is 'missing'. Fix this by setting a device's ->last_flush_error to zero when we close a device, making sure the error is not seen on the next mount attempt. We only need to track flush errors during the current mount, so that we never commit a super block if such errors happened. Signed-off-by: Filipe Manana <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent acbee9a commit 6b225ba

File tree

1 file changed

+13
-0
lines changed

1 file changed

+13
-0
lines changed

fs/btrfs/volumes.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,19 @@ static void btrfs_close_one_device(struct btrfs_device *device)
11371137
atomic_set(&device->dev_stats_ccnt, 0);
11381138
extent_io_tree_release(&device->alloc_state);
11391139

1140+
/*
1141+
* Reset the flush error record. We might have a transient flush error
1142+
* in this mount, and if so we aborted the current transaction and set
1143+
* the fs to an error state, guaranteeing no super blocks can be further
1144+
* committed. However that error might be transient and if we unmount the
1145+
* filesystem and mount it again, we should allow the mount to succeed
1146+
* (btrfs_check_rw_degradable() should not fail) - if after mounting the
1147+
* filesystem again we still get flush errors, then we will again abort
1148+
* any transaction and set the error state, guaranteeing no commits of
1149+
* unsafe super blocks.
1150+
*/
1151+
device->last_flush_error = 0;
1152+
11401153
/* Verify the device is back in a pristine state */
11411154
ASSERT(!test_bit(BTRFS_DEV_STATE_FLUSH_SENT, &device->dev_state));
11421155
ASSERT(!test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state));

0 commit comments

Comments
 (0)