Btrfs: forced readonly mounts on errors
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/1 Btrfs: forced readonly mounts on errors
This patch comes from "Forced readonly mounts on errors" ideas.
As we know, this is the first step in being more fault tolerant of disk corruptions instead of just using BUG() statements.
The major content:
- add a framework for generating errors that should result in filesystems going readonly.
- keep FS state in disk super block.
- make sure that all of resource will be freed and released at umount time.
- make sure that after FS is forced readonly on error, there will be no more disk change before FS is corrected. For this, we should stop write operation.
After this patch is applied, the conversion from BUG() to such a framework can happen incrementally.
--- fs/btrfs/ctree.h | 24 +++ fs/btrfs/disk-io.c | 389 +++++++++++++++++++++++++++++++++++++++++++++++- fs/btrfs/disk-io.h | 1 + fs/btrfs/extent-tree.c | 11 ++ fs/btrfs/file.c | 11 ++ fs/btrfs/super.c | 88 +++++++++++ fs/btrfs/transaction.c | 3 + 7 files changed, 525 insertions(+), 2 deletions(-)
fs/btrfs/ctree.h +24 -0
@@ -294,6 +294,14 @@ static inline unsigned long btrfs_chunk_item_size(int num_stripes)#define BTRFS_FSID_SIZE 16#define BTRFS_HEADER_FLAG_WRITTEN (1ULL << 0)#define BTRFS_HEADER_FLAG_RELOC (1ULL << 1) + +/* +* File system states +*/ + +/* Errors detected */ +#define BTRFS_SUPER_FLAG_ERROR (1ULL << 2) +#define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32)#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33)
@@ -1050,6 +1058,9 @@ struct btrfs_fs_info {unsigned metadata_ratio;void *bdev_holder; + +/* filesystem state */ +u64 fs_state; };/*
@@ -2188,6 +2199,11 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,int btrfs_set_block_group_rw (struct btrfs_root *root,struct btrfs_block_group_cache *cache);void btrfs_put_block_group_cache (struct btrfs_fs_info *info); +int btrfs_error_unpin_extent_range (struct btrfs_root *root, +u64 start,u64 end); +int btrfs_error_discard_extent (struct btrfs_root *root,u64 bytenr, +u64 num_bytes); +/* ctree.c */ int btrfs_bin_search (struct extent_buffer *eb,struct btrfs_key *key,int level,int *slot);
@@ -2541,6 +2557,14 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);/* super.c */ int btrfs_parse_options (struct btrfs_root *root,char *options);int btrfs_sync_fs (struct super_block *sb,int wait); +void __btrfs_std_error (struct btrfs_fs_info *fs_info,const char *function, +unsigned int line,int errno); + +#define btrfs_std_error (fs_info, errno) \ +do { \ + if ((errno)) \ + __btrfs_std_error((fs_info), __func__, __LINE__, (errno));\ +} while (0)/* acl.c */ #ifdef CONFIG_BTRFS_FS_POSIX_ACL
fs/btrfs/disk-io.c +387 -2
420 lines not on this page · raw message
fs/btrfs/disk-io.h +1 -0
@@ -52,6 +52,7 @@ int write_ctree_super(struct btrfs_trans_handle *trans, struct btrfs_root *root, int max_mirrors);struct buffer_head *btrfs_read_dev_super (struct block_device *bdev);int btrfs_commit_super (struct btrfs_root *root); +int btrfs_error_commit_super (struct btrfs_root *root);struct extent_buffer *btrfs_find_tree_block (struct btrfs_root *root,u64 bytenr,u32 blocksize); struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
fs/btrfs/extent-tree.c +11 -0
@@ -8585,3 +8585,14 @@ out:btrfs_free_path (path);return ret; } + +int btrfs_error_unpin_extent_range (struct btrfs_root *root,u64 start,u64 end) +{ +return unpin_extent_range (root, start, end); +} + +int btrfs_error_discard_extent (struct btrfs_root *root,u64 bytenr, +u64 num_bytes) +{ +return btrfs_discard_extent (root, bytenr, num_bytes); +}
fs/btrfs/file.c +11 -0
@@ -890,6 +890,17 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,if (err) goto out; +/* +* If BTRFS flips readonly due to some impossible error +* (fs_info->fs_state now has BTRFS_SUPER_FLAG_ERROR), +* although we have opened a file as writable, we have +* to stop this write operation to ensure FS consistency. +*/ +if (root->fs_info->fs_state &BTRFS_SUPER_FLAG_ERROR ) { + err = -EROFS ; + goto out; + } +file_update_time (file);BTRFS_I (inode)->sequence++;
fs/btrfs/super.c +88 -0
94 lines not on this page · raw message
fs/btrfs/transaction.c +3 -0
@@ -181,6 +181,9 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,struct btrfs_trans_handle *h;struct btrfs_transaction *cur_trans;int ret; + +if (root->fs_info->fs_state &BTRFS_SUPER_FLAG_ERROR ) +return ERR_PTR (-EROFS ); again: h =kmem_cache_alloc (btrfs_trans_handle_cachep,GFP_NOFS );if (!h)
Signature · 1 line
1.6.5.2
Excerpts from liubo's message of 2011-01-06 06:30:25 -0500:
Quoted 14 lines
This patch comes from "Forced readonly mounts on errors" ideas.
As we know, this is the first step in being more fault tolerant of disk corruptions instead of just using
BUG()statements.The major content:
- add a framework for generating errors that should result in filesystems going readonly.
- keep FS state in disk super block.
- make sure that all of resource will be freed and released at umount time.
- make sure that after FS is forced readonly on error, there will be no more disk change before FS is corrected. For this, we should stop write operation.
Quoted 2 lines
After this patch is applied, the conversion from
BUG()to such a framework can happen incrementally.
I think this is a good overall framework and it will meet our needs nicely as we scale up the error handling in the filesystem.
One concern I have is where we save the error state to disk:
fs/btrfs/super.c line 93
Quoted 11 lines
fs/btrfs/super.c +11
-0+static void __save_error_info (struct btrfs_fs_info *fs_info) +{ +struct btrfs_super_block *disk_super = &fs_info->super_copy; + + fs_info->fs_state =BTRFS_SUPER_FLAG_ERROR ; + disk_super->flags |=cpu_to_le64 (BTRFS_SUPER_FLAG_ERROR ); + +mutex_lock (&fs_info->trans_mutex); +memcpy (&fs_info->super_for_commit, disk_super, +sizeof (fs_info->super_for_commit)); +mutex_unlock (&fs_info->trans_mutex);
The super_for_commit isn't changed until we have a fully consistent set of fields in the super block. The super_copy is changed as the transaction progresses.
So, this memcpy isn't quite safe. We should simply set the flag on the super_for_commit and the super_copy individually.
I'll make this change and pull it in. We can build from here.
-chris
Quoted 38 lines · Chris Mason
Excerpts from liubo's message of 2011-01-06 06:30:25 -0500:
Quoted 13 lines
This patch comes from "Forced readonly mounts on errors" ideas.
As we know, this is the first step in being more fault tolerant of disk corruptions instead of just using
BUG()statements.The major content:
- add a framework for generating errors that should result in filesystems going readonly.
- keep FS state in disk super block.
- make sure that all of resource will be freed and released at umount time.
- make sure that after FS is forced readonly on error, there will be no more disk change before FS is corrected. For this, we should stop write operation.Quoted 2 lines
After this patch is applied, the conversion from
BUG()to such a framework can happen incrementally.I think this is a good overall framework and it will meet our needs nicely as we scale up the error handling in the filesystem.
One concern I have is where we save the error state to disk:
fs/btrfs/super.c line 93
Quoted 11 lines
fs/btrfs/super.c +11
-0+static void __save_error_info (struct btrfs_fs_info *fs_info) +{ +struct btrfs_super_block *disk_super = &fs_info->super_copy; + + fs_info->fs_state =BTRFS_SUPER_FLAG_ERROR ; + disk_super->flags |=cpu_to_le64 (BTRFS_SUPER_FLAG_ERROR ); + +mutex_lock (&fs_info->trans_mutex); +memcpy (&fs_info->super_for_commit, disk_super, +sizeof (fs_info->super_for_commit)); +mutex_unlock (&fs_info->trans_mutex);The
super_for_commitisn't changed until we have a fully consistent set of fields in the super block. Thesuper_copyis changed as the transaction progresses.
Quoted 3 lines
So, this memcpy isn't quite safe. We should simply set the flag on the
super_for_commitand thesuper_copyindividually.
Got it, thanks for pointing it out.
Quoted 2 lines
I'll make this change and pull it in. We can build from here.
Great!
thanks,
Liubo
Quoted 6 lines
-chris
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html