Skip to content

Commit e033f40

Browse files
Darrick J. Wongdchinner
authored andcommitted
xfs: on memory failure, only shut down fs after scanning all mappings
xfs_dax_failure_fn is used to scan the filesystem during a memory failure event to look for memory mappings to revoke. Unfortunately, if it encounters an rmap record for filesystem metadata, it will shut down the filesystem and the scan immediately. This means that we don't complete the mapping revocation scan and instead leave live mappings to failed memory. Fix the function to defer the shutdown until after we've finished culling mappings. While we're at it, add the usual "xfs_" prefix to struct failure_info, and actually initialize mf_flags. Fixes: 6f643c5 ("xfs: implement ->notify_failure() for XFS") Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
1 parent c098576 commit e033f40

File tree

1 file changed

+17
-9
lines changed

1 file changed

+17
-9
lines changed

fs/xfs/xfs_notify_failure.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,18 @@
2323
#include <linux/mm.h>
2424
#include <linux/dax.h>
2525

26-
struct failure_info {
26+
struct xfs_failure_info {
2727
xfs_agblock_t startblock;
2828
xfs_extlen_t blockcount;
2929
int mf_flags;
30+
bool want_shutdown;
3031
};
3132

3233
static pgoff_t
3334
xfs_failure_pgoff(
3435
struct xfs_mount *mp,
3536
const struct xfs_rmap_irec *rec,
36-
const struct failure_info *notify)
37+
const struct xfs_failure_info *notify)
3738
{
3839
loff_t pos = XFS_FSB_TO_B(mp, rec->rm_offset);
3940

@@ -47,7 +48,7 @@ static unsigned long
4748
xfs_failure_pgcnt(
4849
struct xfs_mount *mp,
4950
const struct xfs_rmap_irec *rec,
50-
const struct failure_info *notify)
51+
const struct xfs_failure_info *notify)
5152
{
5253
xfs_agblock_t end_rec;
5354
xfs_agblock_t end_notify;
@@ -71,13 +72,13 @@ xfs_dax_failure_fn(
7172
{
7273
struct xfs_mount *mp = cur->bc_mp;
7374
struct xfs_inode *ip;
74-
struct failure_info *notify = data;
75+
struct xfs_failure_info *notify = data;
7576
int error = 0;
7677

7778
if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) ||
7879
(rec->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))) {
79-
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK);
80-
return -EFSCORRUPTED;
80+
notify->want_shutdown = true;
81+
return 0;
8182
}
8283

8384
/* Get files that incore, filter out others that are not in use. */
@@ -86,8 +87,10 @@ xfs_dax_failure_fn(
8687
/* Continue the rmap query if the inode isn't incore */
8788
if (error == -ENODATA)
8889
return 0;
89-
if (error)
90-
return error;
90+
if (error) {
91+
notify->want_shutdown = true;
92+
return 0;
93+
}
9194

9295
error = mf_dax_kill_procs(VFS_I(ip)->i_mapping,
9396
xfs_failure_pgoff(mp, rec, notify),
@@ -104,6 +107,7 @@ xfs_dax_notify_ddev_failure(
104107
xfs_daddr_t bblen,
105108
int mf_flags)
106109
{
110+
struct xfs_failure_info notify = { .mf_flags = mf_flags };
107111
struct xfs_trans *tp = NULL;
108112
struct xfs_btree_cur *cur = NULL;
109113
struct xfs_buf *agf_bp = NULL;
@@ -120,7 +124,6 @@ xfs_dax_notify_ddev_failure(
120124
for (; agno <= end_agno; agno++) {
121125
struct xfs_rmap_irec ri_low = { };
122126
struct xfs_rmap_irec ri_high;
123-
struct failure_info notify;
124127
struct xfs_agf *agf;
125128
xfs_agblock_t agend;
126129
struct xfs_perag *pag;
@@ -161,6 +164,11 @@ xfs_dax_notify_ddev_failure(
161164
}
162165

163166
xfs_trans_cancel(tp);
167+
if (error || notify.want_shutdown) {
168+
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_ONDISK);
169+
if (!error)
170+
error = -EFSCORRUPTED;
171+
}
164172
return error;
165173
}
166174

0 commit comments

Comments
 (0)