Skip to content

Commit 19a269e

Browse files
Darrick J. Wonggregkh
authored andcommitted
xfs: don't shut down the filesystem for media failures beyond end of log
commit f4ed930 upstream. 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: <[email protected]> # v6.0 Fixes: 6f643c5 ("xfs: implement ->notify_failure() for XFS") Signed-off-by: "Darrick J. Wong" <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent eccc2df commit 19a269e

File tree

1 file changed

+82
-39
lines changed

1 file changed

+82
-39
lines changed

fs/xfs/xfs_notify_failure.c

Lines changed: 82 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,79 @@ xfs_dax_notify_failure_thaw(
153153
thaw_super(sb, FREEZE_HOLDER_USERSPACE);
154154
}
155155

156+
static int
157+
xfs_dax_translate_range(
158+
struct xfs_buftarg *btp,
159+
u64 offset,
160+
u64 len,
161+
xfs_daddr_t *daddr,
162+
uint64_t *bblen)
163+
{
164+
u64 dev_start = btp->bt_dax_part_off;
165+
u64 dev_len = bdev_nr_bytes(btp->bt_bdev);
166+
u64 dev_end = dev_start + dev_len - 1;
167+
168+
/* Notify failure on the whole device. */
169+
if (offset == 0 && len == U64_MAX) {
170+
offset = dev_start;
171+
len = dev_len;
172+
}
173+
174+
/* Ignore the range out of filesystem area */
175+
if (offset + len - 1 < dev_start)
176+
return -ENXIO;
177+
if (offset > dev_end)
178+
return -ENXIO;
179+
180+
/* Calculate the real range when it touches the boundary */
181+
if (offset > dev_start)
182+
offset -= dev_start;
183+
else {
184+
len -= dev_start - offset;
185+
offset = 0;
186+
}
187+
if (offset + len - 1 > dev_end)
188+
len = dev_end - offset + 1;
189+
190+
*daddr = BTOBB(offset);
191+
*bblen = BTOBB(len);
192+
return 0;
193+
}
194+
195+
static int
196+
xfs_dax_notify_logdev_failure(
197+
struct xfs_mount *mp,
198+
u64 offset,
199+
u64 len,
200+
int mf_flags)
201+
{
202+
xfs_daddr_t daddr;
203+
uint64_t bblen;
204+
int error;
205+
206+
/*
207+
* Return ENXIO instead of shutting down the filesystem if the failed
208+
* region is beyond the end of the log.
209+
*/
210+
error = xfs_dax_translate_range(mp->m_logdev_targp,
211+
offset, len, &daddr, &bblen);
212+
if (error)
213+
return error;
214+
215+
/*
216+
* In the pre-remove case the failure notification is attempting to
217+
* trigger a force unmount. The expectation is that the device is
218+
* still present, but its removal is in progress and can not be
219+
* cancelled, proceed with accessing the log device.
220+
*/
221+
if (mf_flags & MF_MEM_PRE_REMOVE)
222+
return 0;
223+
224+
xfs_err(mp, "ondisk log corrupt, shutting down fs!");
225+
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK);
226+
return -EFSCORRUPTED;
227+
}
228+
156229
static int
157230
xfs_dax_notify_ddev_failure(
158231
struct xfs_mount *mp,
@@ -263,8 +336,9 @@ xfs_dax_notify_failure(
263336
int mf_flags)
264337
{
265338
struct xfs_mount *mp = dax_holder(dax_dev);
266-
u64 ddev_start;
267-
u64 ddev_end;
339+
xfs_daddr_t daddr;
340+
uint64_t bblen;
341+
int error;
268342

269343
if (!(mp->m_super->s_flags & SB_BORN)) {
270344
xfs_warn(mp, "filesystem is not ready for notify_failure()!");
@@ -279,51 +353,20 @@ xfs_dax_notify_failure(
279353

280354
if (mp->m_logdev_targp && mp->m_logdev_targp->bt_daxdev == dax_dev &&
281355
mp->m_logdev_targp != mp->m_ddev_targp) {
282-
/*
283-
* In the pre-remove case the failure notification is attempting
284-
* to trigger a force unmount. The expectation is that the
285-
* device is still present, but its removal is in progress and
286-
* can not be cancelled, proceed with accessing the log device.
287-
*/
288-
if (mf_flags & MF_MEM_PRE_REMOVE)
289-
return 0;
290-
xfs_err(mp, "ondisk log corrupt, shutting down fs!");
291-
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK);
292-
return -EFSCORRUPTED;
356+
return xfs_dax_notify_logdev_failure(mp, offset, len, mf_flags);
293357
}
294358

295359
if (!xfs_has_rmapbt(mp)) {
296360
xfs_debug(mp, "notify_failure() needs rmapbt enabled!");
297361
return -EOPNOTSUPP;
298362
}
299363

300-
ddev_start = mp->m_ddev_targp->bt_dax_part_off;
301-
ddev_end = ddev_start + bdev_nr_bytes(mp->m_ddev_targp->bt_bdev) - 1;
302-
303-
/* Notify failure on the whole device. */
304-
if (offset == 0 && len == U64_MAX) {
305-
offset = ddev_start;
306-
len = bdev_nr_bytes(mp->m_ddev_targp->bt_bdev);
307-
}
308-
309-
/* Ignore the range out of filesystem area */
310-
if (offset + len - 1 < ddev_start)
311-
return -ENXIO;
312-
if (offset > ddev_end)
313-
return -ENXIO;
314-
315-
/* Calculate the real range when it touches the boundary */
316-
if (offset > ddev_start)
317-
offset -= ddev_start;
318-
else {
319-
len -= ddev_start - offset;
320-
offset = 0;
321-
}
322-
if (offset + len - 1 > ddev_end)
323-
len = ddev_end - offset + 1;
364+
error = xfs_dax_translate_range(mp->m_ddev_targp, offset, len, &daddr,
365+
&bblen);
366+
if (error)
367+
return error;
324368

325-
return xfs_dax_notify_ddev_failure(mp, BTOBB(offset), BTOBB(len),
326-
mf_flags);
369+
return xfs_dax_notify_ddev_failure(mp, daddr, bblen, mf_flags);
327370
}
328371

329372
const struct dax_holder_operations xfs_dax_holder_operations = {

0 commit comments

Comments
 (0)