From: Vratislav Bendel vbendel@redhat.com
[upstream commit 19957a181608d25c8f4136652d0ea00b3738972d]
Due to an inverted logic mistake in xfs_buftarg_isolate() the xfs_buffers with zero b_lru_ref will take another trip around LRU, while isolating buffers with non-zero b_lru_ref.
Additionally those isolated buffers end up right back on the LRU once they are released, because b_lru_ref remains elevated.
Fix that circuitous route by leaving them on the LRU as originally intended.
[Additional description for the issue]
Due to this issue, buffers will spend one cycle less in the LRU than intended. If we initialize b_lru_ref to X, we intend the buffer to survive X shrinker calls, and on the X+1'th call to be taken off the LRU (and maybe freed). But with this issue, the buffer will be taken off the LRU and immediately re-added back. But this will happen X-1 times, because on the X'th time the b_lru_ref will be 0, and the buffer will not be re-added to the LRU. So the buffer will survive X-1 shrinker calls and not X as intended.
Furthermore, if somehow we end up with the buffer sitting on the LRU and having b_lru_ref==0, this buffer will never be taken off the LRU, due to the bug. Not sure that this can happen, because by default b_lru_ref is set to 1.
This issue existed since the introduction of lru in XFS buffer cache in commit "430cbeb86fdcbbdabea7d4aa65307de8de425350 xfs: add a lru to the XFS buffer cache".
However, the integration with the "list_lru" insfrastructure was done in kernel 3.12, in commit "e80dfa19976b884db1ac2bc5d7d6ca0a4027bd1c xfs: convert buftarg LRU to generic code"
Therefore this patch is relevant for all kernels from 3.12 to 4.15 (upstream fix was made in 4.16).
Signed-off-by: Alex Lyakas alex@zadara.com Signed-off-by: Vratislav Bendel vbendel@redhat.com Reviewed-by: Brian Foster bfoster@redhat.com Reviewed-by: Christoph Hellwig hch@lst.de Reviewed-by: Darrick J. Wong darrick.wong@oracle.com Signed-off-by: Darrick J. Wong darrick.wong@oracle.com (cherry picked from commit 19957a181608d25c8f4136652d0ea00b3738972d) --- fs/xfs/xfs_buf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 16f93d7..e4a6239 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1702,7 +1702,7 @@ struct xfs_buf * * zero. If the value is already zero, we need to reclaim the * buffer, otherwise it gets another trip through the LRU. */ - if (!atomic_add_unless(&bp->b_lru_ref, -1, 0)) { + if (atomic_add_unless(&bp->b_lru_ref, -1, 0)) { spin_unlock(&bp->b_lock); return LRU_ROTATE; }
On Thu, Oct 31, 2019 at 05:32:55PM +0200, Alex Lyakas wrote:
From: Vratislav Bendel vbendel@redhat.com
[upstream commit 19957a181608d25c8f4136652d0ea00b3738972d]
Due to an inverted logic mistake in xfs_buftarg_isolate() the xfs_buffers with zero b_lru_ref will take another trip around LRU, while isolating buffers with non-zero b_lru_ref.
Additionally those isolated buffers end up right back on the LRU once they are released, because b_lru_ref remains elevated.
Fix that circuitous route by leaving them on the LRU as originally intended.
[Additional description for the issue]
Due to this issue, buffers will spend one cycle less in the LRU than intended. If we initialize b_lru_ref to X, we intend the buffer to survive X shrinker calls, and on the X+1'th call to be taken off the LRU (and maybe freed). But with this issue, the buffer will be taken off the LRU and immediately re-added back. But this will happen X-1 times, because on the X'th time the b_lru_ref will be 0, and the buffer will not be re-added to the LRU. So the buffer will survive X-1 shrinker calls and not X as intended.
Furthermore, if somehow we end up with the buffer sitting on the LRU and having b_lru_ref==0, this buffer will never be taken off the LRU, due to the bug. Not sure that this can happen, because by default b_lru_ref is set to 1.
This issue existed since the introduction of lru in XFS buffer cache in commit "430cbeb86fdcbbdabea7d4aa65307de8de425350 xfs: add a lru to the XFS buffer cache".
However, the integration with the "list_lru" insfrastructure was done in kernel 3.12, in commit "e80dfa19976b884db1ac2bc5d7d6ca0a4027bd1c xfs: convert buftarg LRU to generic code"
Therefore this patch is relevant for all kernels from 3.12 to 4.15 (upstream fix was made in 4.16).
Signed-off-by: Alex Lyakas alex@zadara.com Signed-off-by: Vratislav Bendel vbendel@redhat.com Reviewed-by: Brian Foster bfoster@redhat.com Reviewed-by: Christoph Hellwig hch@lst.de Reviewed-by: Darrick J. Wong darrick.wong@oracle.com Signed-off-by: Darrick J. Wong darrick.wong@oracle.com (cherry picked from commit 19957a181608d25c8f4136652d0ea00b3738972d)
fs/xfs/xfs_buf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Now queued up, thanks.
greg k-h
linux-stable-mirror@lists.linaro.org