xfs: normalize "infinite" retries in error configs

As it stands today, the "fail immediately" vs. "retry forever"
values for max_retries and retry_timeout_seconds in the xfs metadata
error configurations are not consistent.

A retry_timeout_seconds of 0 means "retry forever," but a
max_retries of 0 means "fail immediately."

retry_timeout_seconds < 0 is disallowed, while max_retries == -1
means "retry forever."

Make this consistent across the error configs, such that a value of
0 means "fail immediately" (i.e. wait 0 seconds, or retry 0 times),
and a value of -1 always means "retry forever."

This makes retry_timeout a signed long to accommodate the -1, even
though it stores jiffies.  Given our limit of a 1 day maximum
timeout, this should be sufficient even at much higher HZ values
than we have available today.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
Eric Sandeen 2016-09-14 07:51:30 +10:00 committed by Dave Chinner
parent 79c350e45e
commit 7716981273
3 changed files with 45 additions and 15 deletions

View File

@ -1095,7 +1095,8 @@ xfs_buf_iodone_callback_error(
bp->b_last_error != bp->b_error) { bp->b_last_error != bp->b_error) {
bp->b_flags |= (XBF_WRITE | XBF_DONE | XBF_WRITE_FAIL); bp->b_flags |= (XBF_WRITE | XBF_DONE | XBF_WRITE_FAIL);
bp->b_last_error = bp->b_error; bp->b_last_error = bp->b_error;
if (cfg->retry_timeout && !bp->b_first_retry_time) if (cfg->retry_timeout != XFS_ERR_RETRY_FOREVER &&
!bp->b_first_retry_time)
bp->b_first_retry_time = jiffies; bp->b_first_retry_time = jiffies;
xfs_buf_ioerror(bp, 0); xfs_buf_ioerror(bp, 0);
@ -1111,7 +1112,7 @@ xfs_buf_iodone_callback_error(
if (cfg->max_retries != XFS_ERR_RETRY_FOREVER && if (cfg->max_retries != XFS_ERR_RETRY_FOREVER &&
++bp->b_retries > cfg->max_retries) ++bp->b_retries > cfg->max_retries)
goto permanent_error; goto permanent_error;
if (cfg->retry_timeout && if (cfg->retry_timeout != XFS_ERR_RETRY_FOREVER &&
time_after(jiffies, cfg->retry_timeout + bp->b_first_retry_time)) time_after(jiffies, cfg->retry_timeout + bp->b_first_retry_time))
goto permanent_error; goto permanent_error;

View File

@ -57,10 +57,16 @@ enum {
#define XFS_ERR_RETRY_FOREVER -1 #define XFS_ERR_RETRY_FOREVER -1
/*
* Although retry_timeout is in jiffies which is normally an unsigned long,
* we limit the retry timeout to 86400 seconds, or one day. So even a
* signed 32-bit long is sufficient for a HZ value up to 24855. Making it
* signed lets us store the special "-1" value, meaning retry forever.
*/
struct xfs_error_cfg { struct xfs_error_cfg {
struct xfs_kobj kobj; struct xfs_kobj kobj;
int max_retries; int max_retries;
unsigned long retry_timeout; /* in jiffies, 0 = no timeout */ long retry_timeout; /* in jiffies, -1 = infinite */
}; };
typedef struct xfs_mount { typedef struct xfs_mount {

View File

@ -393,9 +393,15 @@ max_retries_show(
struct kobject *kobject, struct kobject *kobject,
char *buf) char *buf)
{ {
int retries;
struct xfs_error_cfg *cfg = to_error_cfg(kobject); struct xfs_error_cfg *cfg = to_error_cfg(kobject);
return snprintf(buf, PAGE_SIZE, "%d\n", cfg->max_retries); if (cfg->retry_timeout == XFS_ERR_RETRY_FOREVER)
retries = -1;
else
retries = cfg->max_retries;
return snprintf(buf, PAGE_SIZE, "%d\n", retries);
} }
static ssize_t static ssize_t
@ -415,6 +421,9 @@ max_retries_store(
if (val < -1) if (val < -1)
return -EINVAL; return -EINVAL;
if (val == -1)
cfg->retry_timeout = XFS_ERR_RETRY_FOREVER;
else
cfg->max_retries = val; cfg->max_retries = val;
return count; return count;
} }
@ -425,10 +434,15 @@ retry_timeout_seconds_show(
struct kobject *kobject, struct kobject *kobject,
char *buf) char *buf)
{ {
int timeout;
struct xfs_error_cfg *cfg = to_error_cfg(kobject); struct xfs_error_cfg *cfg = to_error_cfg(kobject);
return snprintf(buf, PAGE_SIZE, "%ld\n", if (cfg->retry_timeout == XFS_ERR_RETRY_FOREVER)
jiffies_to_msecs(cfg->retry_timeout) / MSEC_PER_SEC); timeout = -1;
else
timeout = jiffies_to_msecs(cfg->retry_timeout) / MSEC_PER_SEC;
return snprintf(buf, PAGE_SIZE, "%d\n", timeout);
} }
static ssize_t static ssize_t
@ -445,11 +459,16 @@ retry_timeout_seconds_store(
if (ret) if (ret)
return ret; return ret;
/* 1 day timeout maximum */ /* 1 day timeout maximum, -1 means infinite */
if (val < 0 || val > 86400) if (val < -1 || val > 86400)
return -EINVAL; return -EINVAL;
if (val == -1)
cfg->retry_timeout = XFS_ERR_RETRY_FOREVER;
else {
cfg->retry_timeout = msecs_to_jiffies(val * MSEC_PER_SEC); cfg->retry_timeout = msecs_to_jiffies(val * MSEC_PER_SEC);
ASSERT(msecs_to_jiffies(val * MSEC_PER_SEC) < LONG_MAX);
}
return count; return count;
} }
XFS_SYSFS_ATTR_RW(retry_timeout_seconds); XFS_SYSFS_ATTR_RW(retry_timeout_seconds);
@ -519,18 +538,19 @@ struct xfs_error_init {
static const struct xfs_error_init xfs_error_meta_init[XFS_ERR_ERRNO_MAX] = { static const struct xfs_error_init xfs_error_meta_init[XFS_ERR_ERRNO_MAX] = {
{ .name = "default", { .name = "default",
.max_retries = XFS_ERR_RETRY_FOREVER, .max_retries = XFS_ERR_RETRY_FOREVER,
.retry_timeout = 0, .retry_timeout = XFS_ERR_RETRY_FOREVER,
}, },
{ .name = "EIO", { .name = "EIO",
.max_retries = XFS_ERR_RETRY_FOREVER, .max_retries = XFS_ERR_RETRY_FOREVER,
.retry_timeout = 0, .retry_timeout = XFS_ERR_RETRY_FOREVER,
}, },
{ .name = "ENOSPC", { .name = "ENOSPC",
.max_retries = XFS_ERR_RETRY_FOREVER, .max_retries = XFS_ERR_RETRY_FOREVER,
.retry_timeout = 0, .retry_timeout = XFS_ERR_RETRY_FOREVER,
}, },
{ .name = "ENODEV", { .name = "ENODEV",
.max_retries = 0, .max_retries = 0, /* We can't recover from devices disappearing */
.retry_timeout = 0,
}, },
}; };
@ -561,6 +581,9 @@ xfs_error_sysfs_init_class(
goto out_error; goto out_error;
cfg->max_retries = init[i].max_retries; cfg->max_retries = init[i].max_retries;
if (init[i].retry_timeout == XFS_ERR_RETRY_FOREVER)
cfg->retry_timeout = XFS_ERR_RETRY_FOREVER;
else
cfg->retry_timeout = msecs_to_jiffies( cfg->retry_timeout = msecs_to_jiffies(
init[i].retry_timeout * MSEC_PER_SEC); init[i].retry_timeout * MSEC_PER_SEC);
} }