GFS2: Add "-o errors=panic|withdraw" mount options
authorBob Peterson <rpeterso@redhat.com>
Mon, 24 Aug 2009 09:44:18 +0000 (10:44 +0100)
committerSteven Whitehouse <swhiteho@redhat.com>
Mon, 24 Aug 2009 09:44:18 +0000 (10:44 +0100)
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>
fs/gfs2/incore.h
fs/gfs2/ops_fstype.c
fs/gfs2/super.c
fs/gfs2/util.c

index 61801ad..1d11e6e 100644 (file)
@@ -406,6 +406,12 @@ struct gfs2_statfs_change_host {
 #define GFS2_DATA_WRITEBACK    1
 #define GFS2_DATA_ORDERED      2
 
+#define GFS2_ERRORS_DEFAULT     GFS2_ERRORS_WITHDRAW
+#define GFS2_ERRORS_WITHDRAW    0
+#define GFS2_ERRORS_CONTINUE    1 /* place holder for future feature */
+#define GFS2_ERRORS_RO          2 /* place holder for future feature */
+#define GFS2_ERRORS_PANIC       3
+
 struct gfs2_args {
        char ar_lockproto[GFS2_LOCKNAME_LEN];   /* Name of the Lock Protocol */
        char ar_locktable[GFS2_LOCKNAME_LEN];   /* Name of the Lock Table */
@@ -422,6 +428,7 @@ struct gfs2_args {
        unsigned int ar_data:2;                 /* ordered/writeback */
        unsigned int ar_meta:1;                 /* mount metafs */
        unsigned int ar_discard:1;              /* discard requests */
+       unsigned int ar_errors:2;               /* errors=withdraw | panic */
        int ar_commit;                          /* Commit interval */
 };
 
index 39021c0..165518a 100644 (file)
@@ -1168,6 +1168,7 @@ static int fill_super(struct super_block *sb, void *data, int silent)
        sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT;
        sdp->sd_args.ar_data = GFS2_DATA_DEFAULT;
        sdp->sd_args.ar_commit = 60;
+       sdp->sd_args.ar_errors = GFS2_ERRORS_DEFAULT;
 
        error = gfs2_mount_args(sdp, &sdp->sd_args, data);
        if (error) {
index 85bd2bc..7a5c128 100644 (file)
@@ -68,6 +68,8 @@ enum {
        Opt_discard,
        Opt_nodiscard,
        Opt_commit,
+       Opt_err_withdraw,
+       Opt_err_panic,
        Opt_error,
 };
 
@@ -97,6 +99,8 @@ static const match_table_t tokens = {
        {Opt_discard, "discard"},
        {Opt_nodiscard, "nodiscard"},
        {Opt_commit, "commit=%d"},
+       {Opt_err_withdraw, "errors=withdraw"},
+       {Opt_err_panic, "errors=panic"},
        {Opt_error, NULL}
 };
 
@@ -152,6 +156,11 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
                        args->ar_localcaching = 1;
                        break;
                case Opt_debug:
+                       if (args->ar_errors == GFS2_ERRORS_PANIC) {
+                               fs_info(sdp, "-o debug and -o errors=panic "
+                                      "are mutually exclusive.\n");
+                               return -EINVAL;
+                       }
                        args->ar_debug = 1;
                        break;
                case Opt_nodebug:
@@ -205,6 +214,17 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
                                return rv ? rv : -EINVAL;
                        }
                        break;
+               case Opt_err_withdraw:
+                       args->ar_errors = GFS2_ERRORS_WITHDRAW;
+                       break;
+               case Opt_err_panic:
+                       if (args->ar_debug) {
+                               fs_info(sdp, "-o debug and -o errors=panic "
+                                       "are mutually exclusive.\n");
+                               return -EINVAL;
+                       }
+                       args->ar_errors = GFS2_ERRORS_PANIC;
+                       break;
                case Opt_error:
                default:
                        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)
        lfsecs = sdp->sd_tune.gt_log_flush_secs;
        if (lfsecs != 60)
                seq_printf(s, ",commit=%d", lfsecs);
+       if (args->ar_errors != GFS2_ERRORS_DEFAULT) {
+               const char *state;
+
+               switch (args->ar_errors) {
+               case GFS2_ERRORS_WITHDRAW:
+                       state = "withdraw";
+                       break;
+               case GFS2_ERRORS_PANIC:
+                       state = "panic";
+                       break;
+               default:
+                       state = "unknown";
+                       break;
+               }
+               seq_printf(s, ",errors=%s", state);
+       }
        return 0;
 }
 
index 9d12b11..f6a7efa 100644 (file)
@@ -38,24 +38,30 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
        const struct lm_lockops *lm = ls->ls_ops;
        va_list args;
 
-       if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+       if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW &&
+           test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
                return 0;
 
        va_start(args, fmt);
        vprintk(fmt, args);
        va_end(args);
 
-       fs_err(sdp, "about to withdraw this file system\n");
-       BUG_ON(sdp->sd_args.ar_debug);
+       if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW) {
+               fs_err(sdp, "about to withdraw this file system\n");
+               BUG_ON(sdp->sd_args.ar_debug);
 
-       kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE);
+               kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE);
 
-       if (lm->lm_unmount) {
-               fs_err(sdp, "telling LM to unmount\n");
-               lm->lm_unmount(sdp);
+               if (lm->lm_unmount) {
+                       fs_err(sdp, "telling LM to unmount\n");
+                       lm->lm_unmount(sdp);
+               }
+               fs_err(sdp, "withdrawn\n");
+               dump_stack();
        }
-       fs_err(sdp, "withdrawn\n");
-       dump_stack();
+
+       if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC)
+               panic("GFS2: fsid=%s: panic requested.\n", sdp->sd_fsname);
 
        return -1;
 }
@@ -93,17 +99,24 @@ int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion,
                        gfs2_tune_get(sdp, gt_complain_secs) * HZ))
                return -2;
 
-       printk(KERN_WARNING
-              "GFS2: fsid=%s: warning: assertion \"%s\" failed\n"
-              "GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
-              sdp->sd_fsname, assertion,
-              sdp->sd_fsname, function, file, line);
+       if (sdp->sd_args.ar_errors == GFS2_ERRORS_WITHDRAW)
+               printk(KERN_WARNING
+                      "GFS2: fsid=%s: warning: assertion \"%s\" failed\n"
+                      "GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
+                      sdp->sd_fsname, assertion,
+                      sdp->sd_fsname, function, file, line);
 
        if (sdp->sd_args.ar_debug)
                BUG();
        else
                dump_stack();
 
+       if (sdp->sd_args.ar_errors == GFS2_ERRORS_PANIC)
+               panic("GFS2: fsid=%s: warning: assertion \"%s\" failed\n"
+                     "GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
+                     sdp->sd_fsname, assertion,
+                     sdp->sd_fsname, function, file, line);
+
        sdp->sd_last_warning = jiffies;
 
        return -1;