Commit 7d0fb914 authored by Goldwyn Rodrigues's avatar Goldwyn Rodrigues Committed by Linus Torvalds

ocfs2: add errors=continue

OCFS2 is often used in high-availaibility systems.  However, ocfs2
converts the filesystem to read-only at the drop of the hat.  This may
not be necessary, since turning the filesystem read-only would affect
other running processes as well, decreasing availability.

This attempt is to add errors=continue, which would return the EIO to
the calling process and terminate furhter processing so that the
filesystem is not corrupted further.  However, the filesystem is not
converted to read-only.

As a future plan, I intend to create a small utility or extend
fsck.ocfs2 to fix small errors such as in the inode.  The input to the
utility such as the inode can come from the kernel logs so we don't have
to schedule a downtime for fixing small-enough errors.

The patch changes the ocfs2_error to return an error.  The error
returned depends on the mount option set.  If none is set, the default
is to turn the filesystem read-only.

Perhaps errors=continue is not the best option name.  Historically it is
used for making an attempt to progress in the current process itself.
Should we call it errors=eio? or errors=killproc? Suggestions/Comments
welcome.

Sources are available at:
  https://github.com/goldwynr/linux/tree/error-contSigned-off-by: default avatarGoldwyn Rodrigues <rgoldwyn@suse.com>
Signed-off-by: default avatarMark Fasheh <mfasheh@suse.de>
Cc: Joel Becker <jlbec@evilplan.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 513e2dae
...@@ -286,6 +286,8 @@ enum ocfs2_mount_options ...@@ -286,6 +286,8 @@ enum ocfs2_mount_options
OCFS2_MOUNT_HB_GLOBAL = 1 << 14, /* Global heartbeat */ OCFS2_MOUNT_HB_GLOBAL = 1 << 14, /* Global heartbeat */
OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT = 1 << 15, /* Journal Async Commit */ OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT = 1 << 15, /* Journal Async Commit */
OCFS2_MOUNT_ERRORS_CONT = 1 << 16, /* Return EIO to the calling process on error */
OCFS2_MOUNT_ERRORS_ROFS = 1 << 17, /* Change filesystem to read-only on error */
}; };
#define OCFS2_OSB_SOFT_RO 0x0001 #define OCFS2_OSB_SOFT_RO 0x0001
......
...@@ -192,6 +192,7 @@ enum { ...@@ -192,6 +192,7 @@ enum {
Opt_resv_level, Opt_resv_level,
Opt_dir_resv_level, Opt_dir_resv_level,
Opt_journal_async_commit, Opt_journal_async_commit,
Opt_err_cont,
Opt_err, Opt_err,
}; };
...@@ -224,6 +225,7 @@ static const match_table_t tokens = { ...@@ -224,6 +225,7 @@ static const match_table_t tokens = {
{Opt_resv_level, "resv_level=%u"}, {Opt_resv_level, "resv_level=%u"},
{Opt_dir_resv_level, "dir_resv_level=%u"}, {Opt_dir_resv_level, "dir_resv_level=%u"},
{Opt_journal_async_commit, "journal_async_commit"}, {Opt_journal_async_commit, "journal_async_commit"},
{Opt_err_cont, "errors=continue"},
{Opt_err, NULL} {Opt_err, NULL}
}; };
...@@ -1330,10 +1332,19 @@ static int ocfs2_parse_options(struct super_block *sb, ...@@ -1330,10 +1332,19 @@ static int ocfs2_parse_options(struct super_block *sb,
mopt->mount_opt |= OCFS2_MOUNT_NOINTR; mopt->mount_opt |= OCFS2_MOUNT_NOINTR;
break; break;
case Opt_err_panic: case Opt_err_panic:
mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_CONT;
mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_ROFS;
mopt->mount_opt |= OCFS2_MOUNT_ERRORS_PANIC; mopt->mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
break; break;
case Opt_err_ro: case Opt_err_ro:
mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_CONT;
mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC; mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC;
mopt->mount_opt |= OCFS2_MOUNT_ERRORS_ROFS;
break;
case Opt_err_cont:
mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_ROFS;
mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC;
mopt->mount_opt |= OCFS2_MOUNT_ERRORS_CONT;
break; break;
case Opt_data_ordered: case Opt_data_ordered:
mopt->mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK; mopt->mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK;
...@@ -1530,6 +1541,8 @@ static int ocfs2_show_options(struct seq_file *s, struct dentry *root) ...@@ -1530,6 +1541,8 @@ static int ocfs2_show_options(struct seq_file *s, struct dentry *root)
if (opts & OCFS2_MOUNT_ERRORS_PANIC) if (opts & OCFS2_MOUNT_ERRORS_PANIC)
seq_printf(s, ",errors=panic"); seq_printf(s, ",errors=panic");
else if (opts & OCFS2_MOUNT_ERRORS_CONT)
seq_printf(s, ",errors=continue");
else else
seq_printf(s, ",errors=remount-ro"); seq_printf(s, ",errors=remount-ro");
...@@ -2539,31 +2552,43 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb) ...@@ -2539,31 +2552,43 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb)
memset(osb, 0, sizeof(struct ocfs2_super)); memset(osb, 0, sizeof(struct ocfs2_super));
} }
/* Put OCFS2 into a readonly state, or (if the user specifies it), /* Depending on the mount option passed, perform one of the following:
* panic(). We do not support continue-on-error operation. */ * Put OCFS2 into a readonly state (default)
static void ocfs2_handle_error(struct super_block *sb) * Return EIO so that only the process errs
* Fix the error as if fsck.ocfs2 -y
* panic
*/
static int ocfs2_handle_error(struct super_block *sb)
{ {
struct ocfs2_super *osb = OCFS2_SB(sb); struct ocfs2_super *osb = OCFS2_SB(sb);
int rv = 0;
if (osb->s_mount_opt & OCFS2_MOUNT_ERRORS_PANIC)
panic("OCFS2: (device %s): panic forced after error\n",
sb->s_id);
ocfs2_set_osb_flag(osb, OCFS2_OSB_ERROR_FS); ocfs2_set_osb_flag(osb, OCFS2_OSB_ERROR_FS);
pr_crit("On-disk corruption discovered. "
"Please run fsck.ocfs2 once the filesystem is unmounted.\n");
if (sb->s_flags & MS_RDONLY && if (osb->s_mount_opt & OCFS2_MOUNT_ERRORS_PANIC) {
(ocfs2_is_soft_readonly(osb) || panic("OCFS2: (device %s): panic forced after error\n",
ocfs2_is_hard_readonly(osb))) sb->s_id);
return; } else if (osb->s_mount_opt & OCFS2_MOUNT_ERRORS_CONT) {
pr_crit("OCFS2: Returning error to the calling process.\n");
printk(KERN_CRIT "File system is now read-only due to the potential " rv = -EIO;
"of on-disk corruption. Please run fsck.ocfs2 once the file " } else { /* default option */
"system is unmounted.\n"); rv = -EROFS;
sb->s_flags |= MS_RDONLY; if (sb->s_flags & MS_RDONLY &&
ocfs2_set_ro_flag(osb, 0); (ocfs2_is_soft_readonly(osb) ||
ocfs2_is_hard_readonly(osb)))
return rv;
pr_crit("OCFS2: File system is now read-only.\n");
sb->s_flags |= MS_RDONLY;
ocfs2_set_ro_flag(osb, 0);
}
return rv;
} }
void __ocfs2_error(struct super_block *sb, const char *function, int __ocfs2_error(struct super_block *sb, const char *function,
const char *fmt, ...) const char *fmt, ...)
{ {
struct va_format vaf; struct va_format vaf;
...@@ -2580,7 +2605,7 @@ void __ocfs2_error(struct super_block *sb, const char *function, ...@@ -2580,7 +2605,7 @@ void __ocfs2_error(struct super_block *sb, const char *function,
va_end(args); va_end(args);
ocfs2_handle_error(sb); return ocfs2_handle_error(sb);
} }
/* Handle critical errors. This is intentionally more drastic than /* Handle critical errors. This is intentionally more drastic than
......
...@@ -32,7 +32,7 @@ int ocfs2_publish_get_mount_state(struct ocfs2_super *osb, ...@@ -32,7 +32,7 @@ int ocfs2_publish_get_mount_state(struct ocfs2_super *osb,
int node_num); int node_num);
__printf(3, 4) __printf(3, 4)
void __ocfs2_error(struct super_block *sb, const char *function, int __ocfs2_error(struct super_block *sb, const char *function,
const char *fmt, ...); const char *fmt, ...);
#define ocfs2_error(sb, fmt, args...) __ocfs2_error(sb, __PRETTY_FUNCTION__, fmt, ##args) #define ocfs2_error(sb, fmt, args...) __ocfs2_error(sb, __PRETTY_FUNCTION__, fmt, ##args)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment