diff options
author | Jeff Mahoney <jeffm@suse.com> | 2011-10-03 23:22:31 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.cz> | 2012-03-21 20:45:29 -0400 |
commit | 8c3429300181be44b30f9f017d53dc717da56caa (patch) | |
tree | 76d2b3155bfff43ac4c96df7d6ccb723849c6e9f | |
parent | c16fa4f2ad19908a47c63d8fa436a1178438c7e7 (diff) |
btrfs: Add btrfs_panic()
As part of the effort to eliminate BUG_ON as an error handling
technique, we need to determine which errors are actual logic errors,
which are on-disk corruption, and which are normal runtime errors
e.g. -ENOMEM.
Annotating these error cases is helpful to understand and report them.
This patch adds a btrfs_panic() routine that will either panic
or BUG depending on the new -ofatal_errors={panic,bug} mount option.
Since there are still so many BUG_ONs, it defaults to BUG for now but I
expect that to change once the error handling effort has made
significant progress.
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
-rw-r--r-- | fs/btrfs/ctree.h | 11 | ||||
-rw-r--r-- | fs/btrfs/super.c | 50 |
2 files changed, 60 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 80b6486fd5e6..a97a67089755 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1503,6 +1503,7 @@ struct btrfs_ioctl_defrag_range_args { | |||
1503 | #define BTRFS_MOUNT_SKIP_BALANCE (1 << 19) | 1503 | #define BTRFS_MOUNT_SKIP_BALANCE (1 << 19) |
1504 | #define BTRFS_MOUNT_CHECK_INTEGRITY (1 << 20) | 1504 | #define BTRFS_MOUNT_CHECK_INTEGRITY (1 << 20) |
1505 | #define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21) | 1505 | #define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21) |
1506 | #define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR (1 << 22) | ||
1506 | 1507 | ||
1507 | #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) | 1508 | #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) |
1508 | #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) | 1509 | #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) |
@@ -2970,6 +2971,16 @@ do { \ | |||
2970 | __btrfs_std_error((fs_info), __func__, __LINE__, (errno));\ | 2971 | __btrfs_std_error((fs_info), __func__, __LINE__, (errno));\ |
2971 | } while (0) | 2972 | } while (0) |
2972 | 2973 | ||
2974 | void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function, | ||
2975 | unsigned int line, int errno, const char *fmt, ...); | ||
2976 | |||
2977 | #define btrfs_panic(fs_info, errno, fmt, args...) \ | ||
2978 | do { \ | ||
2979 | struct btrfs_fs_info *_i = (fs_info); \ | ||
2980 | __btrfs_panic(_i, __func__, __LINE__, errno, fmt, ##args); \ | ||
2981 | BUG_ON(!(_i->mount_opt & BTRFS_MOUNT_PANIC_ON_FATAL_ERROR)); \ | ||
2982 | } while (0) | ||
2983 | |||
2973 | /* acl.c */ | 2984 | /* acl.c */ |
2974 | #ifdef CONFIG_BTRFS_FS_POSIX_ACL | 2985 | #ifdef CONFIG_BTRFS_FS_POSIX_ACL |
2975 | struct posix_acl *btrfs_get_acl(struct inode *inode, int type); | 2986 | struct posix_acl *btrfs_get_acl(struct inode *inode, int type); |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 3ce97b217cbe..9774e38a0532 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -76,6 +76,9 @@ static const char *btrfs_decode_error(struct btrfs_fs_info *fs_info, int errno, | |||
76 | case -EROFS: | 76 | case -EROFS: |
77 | errstr = "Readonly filesystem"; | 77 | errstr = "Readonly filesystem"; |
78 | break; | 78 | break; |
79 | case -EEXIST: | ||
80 | errstr = "Object already exists"; | ||
81 | break; | ||
79 | default: | 82 | default: |
80 | if (nbuf) { | 83 | if (nbuf) { |
81 | if (snprintf(nbuf, 16, "error %d", -errno) >= 0) | 84 | if (snprintf(nbuf, 16, "error %d", -errno) >= 0) |
@@ -145,6 +148,36 @@ void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function, | |||
145 | btrfs_handle_error(fs_info); | 148 | btrfs_handle_error(fs_info); |
146 | } | 149 | } |
147 | 150 | ||
151 | /* | ||
152 | * __btrfs_panic decodes unexpected, fatal errors from the caller, | ||
153 | * issues an alert, and either panics or BUGs, depending on mount options. | ||
154 | */ | ||
155 | void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function, | ||
156 | unsigned int line, int errno, const char *fmt, ...) | ||
157 | { | ||
158 | char nbuf[16]; | ||
159 | char *s_id = "<unknown>"; | ||
160 | const char *errstr; | ||
161 | struct va_format vaf = { .fmt = fmt }; | ||
162 | va_list args; | ||
163 | |||
164 | if (fs_info) | ||
165 | s_id = fs_info->sb->s_id; | ||
166 | |||
167 | va_start(args, fmt); | ||
168 | vaf.va = &args; | ||
169 | |||
170 | errstr = btrfs_decode_error(fs_info, errno, nbuf); | ||
171 | if (fs_info->mount_opt & BTRFS_MOUNT_PANIC_ON_FATAL_ERROR) | ||
172 | panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (%s)\n", | ||
173 | s_id, function, line, &vaf, errstr); | ||
174 | |||
175 | printk(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (%s)\n", | ||
176 | s_id, function, line, &vaf, errstr); | ||
177 | va_end(args); | ||
178 | /* Caller calls BUG() */ | ||
179 | } | ||
180 | |||
148 | static void btrfs_put_super(struct super_block *sb) | 181 | static void btrfs_put_super(struct super_block *sb) |
149 | { | 182 | { |
150 | (void)close_ctree(btrfs_sb(sb)->tree_root); | 183 | (void)close_ctree(btrfs_sb(sb)->tree_root); |
@@ -166,7 +199,7 @@ enum { | |||
166 | Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, Opt_inode_cache, | 199 | Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, Opt_inode_cache, |
167 | Opt_no_space_cache, Opt_recovery, Opt_skip_balance, | 200 | Opt_no_space_cache, Opt_recovery, Opt_skip_balance, |
168 | Opt_check_integrity, Opt_check_integrity_including_extent_data, | 201 | Opt_check_integrity, Opt_check_integrity_including_extent_data, |
169 | Opt_check_integrity_print_mask, | 202 | Opt_check_integrity_print_mask, Opt_fatal_errors, |
170 | Opt_err, | 203 | Opt_err, |
171 | }; | 204 | }; |
172 | 205 | ||
@@ -206,6 +239,7 @@ static match_table_t tokens = { | |||
206 | {Opt_check_integrity, "check_int"}, | 239 | {Opt_check_integrity, "check_int"}, |
207 | {Opt_check_integrity_including_extent_data, "check_int_data"}, | 240 | {Opt_check_integrity_including_extent_data, "check_int_data"}, |
208 | {Opt_check_integrity_print_mask, "check_int_print_mask=%d"}, | 241 | {Opt_check_integrity_print_mask, "check_int_print_mask=%d"}, |
242 | {Opt_fatal_errors, "fatal_errors=%s"}, | ||
209 | {Opt_err, NULL}, | 243 | {Opt_err, NULL}, |
210 | }; | 244 | }; |
211 | 245 | ||
@@ -438,6 +472,18 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) | |||
438 | ret = -EINVAL; | 472 | ret = -EINVAL; |
439 | goto out; | 473 | goto out; |
440 | #endif | 474 | #endif |
475 | case Opt_fatal_errors: | ||
476 | if (strcmp(args[0].from, "panic") == 0) | ||
477 | btrfs_set_opt(info->mount_opt, | ||
478 | PANIC_ON_FATAL_ERROR); | ||
479 | else if (strcmp(args[0].from, "bug") == 0) | ||
480 | btrfs_clear_opt(info->mount_opt, | ||
481 | PANIC_ON_FATAL_ERROR); | ||
482 | else { | ||
483 | ret = -EINVAL; | ||
484 | goto out; | ||
485 | } | ||
486 | break; | ||
441 | case Opt_err: | 487 | case Opt_err: |
442 | printk(KERN_INFO "btrfs: unrecognized mount option " | 488 | printk(KERN_INFO "btrfs: unrecognized mount option " |
443 | "'%s'\n", p); | 489 | "'%s'\n", p); |
@@ -766,6 +812,8 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) | |||
766 | seq_puts(seq, ",inode_cache"); | 812 | seq_puts(seq, ",inode_cache"); |
767 | if (btrfs_test_opt(root, SKIP_BALANCE)) | 813 | if (btrfs_test_opt(root, SKIP_BALANCE)) |
768 | seq_puts(seq, ",skip_balance"); | 814 | seq_puts(seq, ",skip_balance"); |
815 | if (btrfs_test_opt(root, PANIC_ON_FATAL_ERROR)) | ||
816 | seq_puts(seq, ",fatal_errors=panic"); | ||
769 | return 0; | 817 | return 0; |
770 | } | 818 | } |
771 | 819 | ||