diff options
author | Christoph Hellwig <hch@lst.de> | 2017-07-18 14:16:51 -0400 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2017-07-26 11:20:03 -0400 |
commit | 5b094d6dac0451ad89b1dc088395c7b399b7e9e8 (patch) | |
tree | 83ef91fc22af5f57c4f08902ec92b3d432d0f1b9 | |
parent | 6215894e11de224183c89b001f5363912442b489 (diff) |
xfs: fix multi-AG deadlock in xfs_bunmapi
Just like in the allocator we must avoid touching multiple AGs out of
order when freeing blocks, as freeing still locks the AGF and can cause
the same AB-BA deadlocks as in the allocation path.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reported-by: Nikolay Borisov <n.borisov.lkml@gmail.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index ee118ceb702f..c09c16b1ad3b 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c | |||
@@ -5435,6 +5435,7 @@ __xfs_bunmapi( | |||
5435 | xfs_fsblock_t sum; | 5435 | xfs_fsblock_t sum; |
5436 | xfs_filblks_t len = *rlen; /* length to unmap in file */ | 5436 | xfs_filblks_t len = *rlen; /* length to unmap in file */ |
5437 | xfs_fileoff_t max_len; | 5437 | xfs_fileoff_t max_len; |
5438 | xfs_agnumber_t prev_agno = NULLAGNUMBER, agno; | ||
5438 | 5439 | ||
5439 | trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_); | 5440 | trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_); |
5440 | 5441 | ||
@@ -5534,6 +5535,17 @@ __xfs_bunmapi( | |||
5534 | */ | 5535 | */ |
5535 | del = got; | 5536 | del = got; |
5536 | wasdel = isnullstartblock(del.br_startblock); | 5537 | wasdel = isnullstartblock(del.br_startblock); |
5538 | |||
5539 | /* | ||
5540 | * Make sure we don't touch multiple AGF headers out of order | ||
5541 | * in a single transaction, as that could cause AB-BA deadlocks. | ||
5542 | */ | ||
5543 | if (!wasdel) { | ||
5544 | agno = XFS_FSB_TO_AGNO(mp, del.br_startblock); | ||
5545 | if (prev_agno != NULLAGNUMBER && prev_agno > agno) | ||
5546 | break; | ||
5547 | prev_agno = agno; | ||
5548 | } | ||
5537 | if (got.br_startoff < start) { | 5549 | if (got.br_startoff < start) { |
5538 | del.br_startoff = start; | 5550 | del.br_startoff = start; |
5539 | del.br_blockcount -= start - got.br_startoff; | 5551 | del.br_blockcount -= start - got.br_startoff; |