This is btrfs' equivalent of XFS_IOC_GOINGDOWN or EXT4_IOC_SHUTDOWN, after entering the emergency shutdown state, all operations will return errors (-EIO), and can not be bring back to normal state until unmount. A new helper, btrfs_force_shutdown() is introduced, which will: - Mark the fs as error But without flipping the fs read-only. This is a special handling for the future shutdown ioctl, which will freeze the fs first, set the SHUTDOWN flag, thaw the fs. But the thaw path will no longer call the unfreeze_fs() call back if the superblock is already read-only. So to handle future shutdown correctly, we only mark the fs as error, without flipping it read-only. - Set the SHUTDOWN flag and output an message New users of those interfaces will be added when implementing shutdown ioctl support. Signed-off-by: Qu Wenruo <wqu@xxxxxxxx> --- fs/btrfs/fs.h | 28 ++++++++++++++++++++++++++++ fs/btrfs/messages.c | 1 + 2 files changed, 29 insertions(+) diff --git a/fs/btrfs/fs.h b/fs/btrfs/fs.h index d90304d4e32c..45185c095696 100644 --- a/fs/btrfs/fs.h +++ b/fs/btrfs/fs.h @@ -29,6 +29,7 @@ #include "extent-io-tree.h" #include "async-thread.h" #include "block-rsv.h" +#include "messages.h" struct inode; struct super_block; @@ -120,6 +121,12 @@ enum { /* No more delayed iput can be queued. */ BTRFS_FS_STATE_NO_DELAYED_IPUT, + /* + * Emergency shutdown, a step further than trans aborted by rejecting + * all operations. + */ + BTRFS_FS_STATE_EMERGENCY_SHUTDOWN, + BTRFS_FS_STATE_COUNT }; @@ -1100,6 +1107,27 @@ static inline void btrfs_wake_unfinished_drop(struct btrfs_fs_info *fs_info) (unlikely(test_bit(BTRFS_FS_STATE_LOG_CLEANUP_ERROR, \ &(fs_info)->fs_state))) +static inline bool btrfs_is_shutdown(struct btrfs_fs_info *fs_info) +{ + return test_bit(BTRFS_FS_STATE_EMERGENCY_SHUTDOWN, &fs_info->fs_state); +} + +static inline void btrfs_force_shutdown(struct btrfs_fs_info *fs_info) +{ + /* + * Here we do not want to use handle_fs_error(), which will mark + * the fs read-only. + * Some call sites like shutdown ioctl will mark the fs shutdown + * when the fs is frozen. But thaw path will handle RO and RW fs + * differently. + * + * So here we only mark the fs error without flipping it RO. + */ + WRITE_ONCE(fs_info->fs_error, -EIO); + if (!test_and_set_bit(BTRFS_FS_STATE_EMERGENCY_SHUTDOWN, &fs_info->fs_state)) + btrfs_info(fs_info, "emergency shutdown"); +} + /* * We use folio flag owner_2 to indicate there is an ordered extent with * unfinished IO. diff --git a/fs/btrfs/messages.c b/fs/btrfs/messages.c index 363fd28c0268..2bb4bcb7c2cd 100644 --- a/fs/btrfs/messages.c +++ b/fs/btrfs/messages.c @@ -23,6 +23,7 @@ static const char fs_state_chars[] = { [BTRFS_FS_STATE_NO_DATA_CSUMS] = 'C', [BTRFS_FS_STATE_SKIP_META_CSUMS] = 'S', [BTRFS_FS_STATE_LOG_CLEANUP_ERROR] = 'L', + [BTRFS_FS_STATE_EMERGENCY_SHUTDOWN] = 'E', }; static void btrfs_state_to_string(const struct btrfs_fs_info *info, char *buf) -- 2.50.0