xfs: don't shut down the filesystem for media failures beyond end of log

If the filesystem has an external log device on pmem and the pmem
reports a media error beyond the end of the log area, don't shut down
the filesystem because we don't use that space.

Cc: <stable@vger.kernel.org> # v6.0
Fixes: 6f643c57d5 ("xfs: implement ->notify_failure() for XFS")
Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Darrick J. Wong 2024-12-17 13:43:06 -08:00
parent 9515572be6
commit f4ed930379
1 changed files with 82 additions and 39 deletions

View File

@ -153,6 +153,79 @@ xfs_dax_notify_failure_thaw(
thaw_super(sb, FREEZE_HOLDER_USERSPACE);
}
static int
xfs_dax_translate_range(
struct xfs_buftarg *btp,
u64 offset,
u64 len,
xfs_daddr_t *daddr,
uint64_t *bblen)
{
u64 dev_start = btp->bt_dax_part_off;
u64 dev_len = bdev_nr_bytes(btp->bt_bdev);
u64 dev_end = dev_start + dev_len - 1;
/* Notify failure on the whole device. */
if (offset == 0 && len == U64_MAX) {
offset = dev_start;
len = dev_len;
}
/* Ignore the range out of filesystem area */
if (offset + len - 1 < dev_start)
return -ENXIO;
if (offset > dev_end)
return -ENXIO;
/* Calculate the real range when it touches the boundary */
if (offset > dev_start)
offset -= dev_start;
else {
len -= dev_start - offset;
offset = 0;
}
if (offset + len - 1 > dev_end)
len = dev_end - offset + 1;
*daddr = BTOBB(offset);
*bblen = BTOBB(len);
return 0;
}
static int
xfs_dax_notify_logdev_failure(
struct xfs_mount *mp,
u64 offset,
u64 len,
int mf_flags)
{
xfs_daddr_t daddr;
uint64_t bblen;
int error;
/*
* Return ENXIO instead of shutting down the filesystem if the failed
* region is beyond the end of the log.
*/
error = xfs_dax_translate_range(mp->m_logdev_targp,
offset, len, &daddr, &bblen);
if (error)
return error;
/*
* In the pre-remove case the failure notification is attempting to
* trigger a force unmount. The expectation is that the device is
* still present, but its removal is in progress and can not be
* cancelled, proceed with accessing the log device.
*/
if (mf_flags & MF_MEM_PRE_REMOVE)
return 0;
xfs_err(mp, "ondisk log corrupt, shutting down fs!");
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK);
return -EFSCORRUPTED;
}
static int
xfs_dax_notify_ddev_failure(
struct xfs_mount *mp,
@ -263,8 +336,9 @@ xfs_dax_notify_failure(
int mf_flags)
{
struct xfs_mount *mp = dax_holder(dax_dev);
u64 ddev_start;
u64 ddev_end;
xfs_daddr_t daddr;
uint64_t bblen;
int error;
if (!(mp->m_super->s_flags & SB_BORN)) {
xfs_warn(mp, "filesystem is not ready for notify_failure()!");
@ -279,17 +353,7 @@ xfs_dax_notify_failure(
if (mp->m_logdev_targp && mp->m_logdev_targp->bt_daxdev == dax_dev &&
mp->m_logdev_targp != mp->m_ddev_targp) {
/*
* In the pre-remove case the failure notification is attempting
* to trigger a force unmount. The expectation is that the
* device is still present, but its removal is in progress and
* can not be cancelled, proceed with accessing the log device.
*/
if (mf_flags & MF_MEM_PRE_REMOVE)
return 0;
xfs_err(mp, "ondisk log corrupt, shutting down fs!");
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK);
return -EFSCORRUPTED;
return xfs_dax_notify_logdev_failure(mp, offset, len, mf_flags);
}
if (!xfs_has_rmapbt(mp)) {
@ -297,33 +361,12 @@ xfs_dax_notify_failure(
return -EOPNOTSUPP;
}
ddev_start = mp->m_ddev_targp->bt_dax_part_off;
ddev_end = ddev_start + bdev_nr_bytes(mp->m_ddev_targp->bt_bdev) - 1;
error = xfs_dax_translate_range(mp->m_ddev_targp, offset, len, &daddr,
&bblen);
if (error)
return error;
/* Notify failure on the whole device. */
if (offset == 0 && len == U64_MAX) {
offset = ddev_start;
len = bdev_nr_bytes(mp->m_ddev_targp->bt_bdev);
}
/* Ignore the range out of filesystem area */
if (offset + len - 1 < ddev_start)
return -ENXIO;
if (offset > ddev_end)
return -ENXIO;
/* Calculate the real range when it touches the boundary */
if (offset > ddev_start)
offset -= ddev_start;
else {
len -= ddev_start - offset;
offset = 0;
}
if (offset + len - 1 > ddev_end)
len = ddev_end - offset + 1;
return xfs_dax_notify_ddev_failure(mp, BTOBB(offset), BTOBB(len),
mf_flags);
return xfs_dax_notify_ddev_failure(mp, daddr, bblen, mf_flags);
}
const struct dax_holder_operations xfs_dax_holder_operations = {