diff options
author | Bob Peterson <rpeterso@redhat.com> | 2009-08-24 05:44:18 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2009-08-24 05:44:18 -0400 |
commit | d34843d0c4a20872f3f3bfb510328bd043b939ff (patch) | |
tree | f10ab461e0a7e3923856b56eeba75383dffafac7 | |
parent | cd0120751d631bc4b99f180c1c22de2caca98207 (diff) |
GFS2: Add "-o errors=panic|withdraw" mount options
This patch adds "-o errors=panic" and "-o errors=withdraw" to the
gfs2 mount options. The "errors=withdraw" option is today's
current behaviour, meaning to withdraw from the file system if a
non-serious gfs2 error occurs. The new "errors=panic" option
tells gfs2 to force a kernel panic if a non-serious gfs2 file
system error occurs. This may be useful, for example, where
fabric-level fencing is used that has no way to reboot (such as
fence_scsi).
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r-- | fs/gfs2/incore.h | 7 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 1 | ||||
-rw-r--r-- | fs/gfs2/super.c | 36 | ||||
-rw-r--r-- | fs/gfs2/util.c | 41 |
4 files changed, 71 insertions, 14 deletions
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 61801ada36f0..1d11e6e0373e 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -406,6 +406,12 @@ struct gfs2_statfs_change_host { | |||
406 | #define GFS2_DATA_WRITEBACK 1 | 406 | #define GFS2_DATA_WRITEBACK 1 |
407 | #define GFS2_DATA_ORDERED 2 | 407 | #define GFS2_DATA_ORDERED 2 |
408 | 408 | ||
409 | #define GFS2_ERRORS_DEFAULT GFS2_ERRORS_WITHDRAW | ||
410 | #define GFS2_ERRORS_WITHDRAW 0 | ||
411 | #define GFS2_ERRORS_CONTINUE 1 /* place holder for future feature */ | ||
412 | #define GFS2_ERRORS_RO 2 /* place holder for future feature */ | ||
413 | #define GFS2_ERRORS_PANIC 3 | ||
414 | |||
409 | struct gfs2_args { | 415 | struct gfs2_args { |
410 | char ar_lockproto[GFS2_LOCKNAME_LEN]; /* Name of the Lock Protocol */ | 416 | char ar_lockproto[GFS2_LOCKNAME_LEN]; /* Name of the Lock Protocol */ |
411 | char ar_locktable[GFS2_LOCKNAME_LEN]; /* Name of the Lock Table */ | 417 | char ar_locktable[GFS2_LOCKNAME_LEN]; /* Name of the Lock Table */ |
@@ -422,6 +428,7 @@ struct gfs2_args { | |||
422 | unsigned int ar_data:2; /* ordered/writeback */ | 428 | unsigned int ar_data:2; /* ordered/writeback */ |
423 | unsigned int ar_meta:1; /* mount metafs */ | 429 | unsigned int ar_meta:1; /* mount metafs */ |
424 | unsigned int ar_discard:1; /* discard requests */ | 430 | unsigned int ar_discard:1; /* discard requests */ |
431 | unsigned int ar_errors:2; /* errors=withdraw | panic */ | ||
425 | int ar_commit; /* Commit interval */ | 432 | int ar_commit; /* Commit interval */ |
426 | }; | 433 | }; |
427 | 434 | ||
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 39021c020176..165518a1041e 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -1168,6 +1168,7 @@ static int fill_super(struct super_block *sb, void *data, int silent) | |||
1168 | sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT; | 1168 | sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT; |
1169 | sdp->sd_args.ar_data = GFS2_DATA_DEFAULT; | 1169 | sdp->sd_args.ar_data = GFS2_DATA_DEFAULT; |
1170 | sdp->sd_args.ar_commit = 60; | 1170 | sdp->sd_args.ar_commit = 60; |
1171 | sdp->sd_args.ar_errors = GFS2_ERRORS_DEFAULT; | ||
1171 | 1172 | ||
1172 | error = gfs2_mount_args(sdp, &sdp->sd_args, data); | 1173 | error = gfs2_mount_args(sdp, &sdp->sd_args, data); |
1173 | if (error) { | 1174 | if (error) { |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 85bd2bc8c1de..7a5c128e8776 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
@@ -68,6 +68,8 @@ enum { | |||
68 | Opt_discard, | 68 | Opt_discard, |
69 | Opt_nodiscard, | 69 | Opt_nodiscard, |
70 | Opt_commit, | 70 | Opt_commit, |
71 | Opt_err_withdraw, | ||
72 | Opt_err_panic, | ||
71 | Opt_error, | 73 | Opt_error, |
72 | }; | 74 | }; |
73 | 75 | ||
@@ -97,6 +99,8 @@ static const match_table_t tokens = { | |||
97 | {Opt_discard, "discard"}, | 99 | {Opt_discard, "discard"}, |
98 | {Opt_nodiscard, "nodiscard"}, | 100 | {Opt_nodiscard, "nodiscard"}, |
99 | {Opt_commit, "commit=%d"}, | 101 | {Opt_commit, "commit=%d"}, |
102 | {Opt_err_withdraw, "errors=withdraw"}, | ||
103 | {Opt_err_panic, "errors=panic"}, | ||
100 | {Opt_error, NULL} | 104 | {Opt_error, NULL} |
101 | }; | 105 | }; |
102 | 106 | ||
@@ -152,6 +156,11 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) | |||
152 | args->ar_localcaching = 1; | 156 | args->ar_localcaching = 1; |
153 | break; | 157 | break; |
154 | case Opt_debug: | 158 | case Opt_debug: |
159 | if (args->ar_errors == GFS2_ERRORS_PANIC) { | ||
160 | fs_info(sdp, "-o debug and -o errors=panic " | ||
161 | "are mutually exclusive.\n"); | ||
162 | return -EINVAL; | ||
163 | } | ||
155 | args->ar_debug = 1; | 164 | args->ar_debug = 1; |
156 | break; | 165 | break; |
157 | case Opt_nodebug: | 166 | case Opt_nodebug: |
@@ -205,6 +214,17 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) | |||
205 | return rv ? rv : -EINVAL; | 214 | return rv ? rv : -EINVAL; |
206 | } | 215 | } |
207 | break; | 216 | break; |
217 | case Opt_err_withdraw: | ||
218 | args->ar_errors = GFS2_ERRORS_WITHDRAW; | ||
219 | break; | ||
220 | case Opt_err_panic: | ||
221 | if (args->ar_debug) { | ||
222 | fs_info(sdp, "-o debug and -o errors=panic " | ||
223 | "are mutually exclusive.\n"); | ||
224 | return -EINVAL; | ||
225 | } | ||
226 | args->ar_errors = GFS2_ERRORS_PANIC; | ||
227 | break; | ||
208 | case Opt_error: | 228 | case Opt_error: |
209 | default: | 229 | default: |
210 | fs_info(sdp, "invalid mount option: %s\n", o); | 230 | fs_info(sdp, "invalid mount option: %s\n", o); |
@@ -1226,6 +1246,22 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
1226 | lfsecs = sdp->sd_tune.gt_log_flush_secs; | 1246 | lfsecs = sdp->sd_tune.gt_log_flush_secs; |
1227 | if (lfsecs != 60) | 1247 | if (lfsecs != 60) |
1228 | seq_printf(s, ",commit=%d", lfsecs); | 1248 | seq_printf(s, ",commit=%d", lfsecs); |
1249 | if (args->ar_errors != GFS2_ERRORS_DEFAULT) { | ||
1250 | const char *state; | ||
1251 | |||
1252 | switch (args->ar_errors) { | ||
1253 | case GFS2_ERRORS_WITHDRAW: | ||
1254 | state = "withdraw"; | ||
1255 | break; | ||
1256 | case GFS2_ERRORS_PANIC: | ||
1257 | state = "panic"; | ||
1258 | break; | ||
1259 | default: | ||
1260 | state = "unknown"; | ||
1261 | break; | ||
1262 | } | ||
1263 | seq_printf(s, ",errors=%s", state); | ||
1264 | } | ||
1229 | return 0; | 1265 | return 0; |
1230 | } | 1266 | } |
1231 | 1267 | ||
diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 9d12b1118ba0..f6a7efa34eb9 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c | |||
@@ -38,24 +38,30 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...) | |||
38 | const struct lm_lockops *lm = ls->ls_ops; | 38 | const struct lm_lockops *lm = ls->ls_ops; |
39 | va_list args; | 39 | va_list args; |
40 | 40 | ||
41 | if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) | 41 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW && |
42 | test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags)) | ||
42 | return 0; | 43 | return 0; |
43 | 44 | ||
44 | va_start(args, fmt); | 45 | va_start(args, fmt); |
45 | vprintk(fmt, args); | 46 | vprintk(fmt, args); |
46 | va_end(args); | 47 | va_end(args); |
47 | 48 | ||
48 | fs_err(sdp, "about to withdraw this file system\n"); | 49 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) { |
49 | BUG_ON(sdp->sd_args.ar_debug); | 50 | fs_err(sdp, "about to withdraw this file system\n"); |
51 | BUG_ON(sdp->sd_args.ar_debug); | ||
50 | 52 | ||
51 | kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE); | 53 | kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE); |
52 | 54 | ||
53 | if (lm->lm_unmount) { | 55 | if (lm->lm_unmount) { |
54 | fs_err(sdp, "telling LM to unmount\n"); | 56 | fs_err(sdp, "telling LM to unmount\n"); |
55 | lm->lm_unmount(sdp); | 57 | lm->lm_unmount(sdp); |
58 | } | ||
59 | fs_err(sdp, "withdrawn\n"); | ||
60 | dump_stack(); | ||
56 | } | 61 | } |
57 | fs_err(sdp, "withdrawn\n"); | 62 | |
58 | dump_stack(); | 63 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) |
64 | panic("GFS2: fsid=%s: panic requested.\n", sdp->sd_fsname); | ||
59 | 65 | ||
60 | return -1; | 66 | return -1; |
61 | } | 67 | } |
@@ -93,17 +99,24 @@ int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion, | |||
93 | gfs2_tune_get(sdp, gt_complain_secs) * HZ)) | 99 | gfs2_tune_get(sdp, gt_complain_secs) * HZ)) |
94 | return -2; | 100 | return -2; |
95 | 101 | ||
96 | printk(KERN_WARNING | 102 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) |
97 | "GFS2: fsid=%s: warning: assertion \"%s\" failed\n" | 103 | printk(KERN_WARNING |
98 | "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", | 104 | "GFS2: fsid=%s: warning: assertion \"%s\" failed\n" |
99 | sdp->sd_fsname, assertion, | 105 | "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", |
100 | sdp->sd_fsname, function, file, line); | 106 | sdp->sd_fsname, assertion, |
107 | sdp->sd_fsname, function, file, line); | ||
101 | 108 | ||
102 | if (sdp->sd_args.ar_debug) | 109 | if (sdp->sd_args.ar_debug) |
103 | BUG(); | 110 | BUG(); |
104 | else | 111 | else |
105 | dump_stack(); | 112 | dump_stack(); |
106 | 113 | ||
114 | if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC) | ||
115 | panic("GFS2: fsid=%s: warning: assertion \"%s\" failed\n" | ||
116 | "GFS2: fsid=%s: function = %s, file = %s, line = %u\n", | ||
117 | sdp->sd_fsname, assertion, | ||
118 | sdp->sd_fsname, function, file, line); | ||
119 | |||
107 | sdp->sd_last_warning = jiffies; | 120 | sdp->sd_last_warning = jiffies; |
108 | 121 | ||
109 | return -1; | 122 | return -1; |