mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Busy extent tracking is primarily used to ensure that freed blocks are
not reused for data allocations before the transaction that deleted them
has been committed to stable storage, and secondarily to drive online
discard. None of the use cases applies to zoned RTGs, as the zoned
allocator can't overwrite blocks before resetting the zone, which already
flushes out all transactions touching the RTGs.
So the busy extent tracking is not needed for zoned RTGs, and also not
called for zoned RTGs. But somehow the code to skip allocating and
freeing the structure got lost during the zoned XFS upstreaming process.
This not only causes these structures to unnecessarily allocated, but can
also lead to memory leaks as the xg_busy_extents pointer in the
xfs_group structure is overlayed with the pointer for the linked list
of to be reset zones.
Stop allocating and freeing the structure to not pointlessly allocate
memory which is then leaked when the zone is reset.
Fixes: 080d01c41d
("xfs: implement zoned garbage collection")
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: <stable@vger.kernel.org> # v6.15
[cem: Fix type and add stable tag]
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
79 lines
2.7 KiB
C
79 lines
2.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
|
|
* Copyright (c) 2010 David Chinner.
|
|
* Copyright (c) 2011 Christoph Hellwig.
|
|
* All Rights Reserved.
|
|
*/
|
|
#ifndef __XFS_EXTENT_BUSY_H__
|
|
#define __XFS_EXTENT_BUSY_H__
|
|
|
|
struct xfs_group;
|
|
struct xfs_mount;
|
|
struct xfs_trans;
|
|
|
|
/*
|
|
* Busy block/extent entry. Indexed by a rbtree in the group to mark blocks
|
|
* that have been freed but whose transactions aren't committed to disk yet.
|
|
*/
|
|
struct xfs_extent_busy {
|
|
struct rb_node rb_node; /* group by-bno indexed search tree */
|
|
struct list_head list; /* transaction busy extent list */
|
|
struct xfs_group *group;
|
|
xfs_agblock_t bno;
|
|
xfs_extlen_t length;
|
|
unsigned int flags;
|
|
#define XFS_EXTENT_BUSY_DISCARDED 0x01 /* undergoing a discard op. */
|
|
#define XFS_EXTENT_BUSY_SKIP_DISCARD 0x02 /* do not discard */
|
|
};
|
|
|
|
/*
|
|
* List used to track groups of related busy extents all the way through
|
|
* to discard completion.
|
|
*/
|
|
struct xfs_busy_extents {
|
|
struct list_head extent_list;
|
|
struct work_struct endio_work;
|
|
|
|
/*
|
|
* Owner is the object containing the struct xfs_busy_extents to free
|
|
* once the busy extents have been processed. If only the
|
|
* xfs_busy_extents object needs freeing, then point this at itself.
|
|
*/
|
|
void *owner;
|
|
};
|
|
|
|
void xfs_extent_busy_insert(struct xfs_trans *tp, struct xfs_group *xg,
|
|
xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);
|
|
void xfs_extent_busy_insert_discard(struct xfs_group *xg, xfs_agblock_t bno,
|
|
xfs_extlen_t len, struct list_head *busy_list);
|
|
void xfs_extent_busy_clear(struct list_head *list, bool do_discard);
|
|
int xfs_extent_busy_search(struct xfs_group *xg, xfs_agblock_t bno,
|
|
xfs_extlen_t len);
|
|
void xfs_extent_busy_reuse(struct xfs_group *xg, xfs_agblock_t fbno,
|
|
xfs_extlen_t flen, bool userdata);
|
|
bool xfs_extent_busy_trim(struct xfs_group *xg, xfs_extlen_t minlen,
|
|
xfs_extlen_t maxlen, xfs_agblock_t *bno, xfs_extlen_t *len,
|
|
unsigned *busy_gen);
|
|
int xfs_extent_busy_flush(struct xfs_trans *tp, struct xfs_group *xg,
|
|
unsigned busy_gen, uint32_t alloc_flags);
|
|
void xfs_extent_busy_wait_all(struct xfs_mount *mp);
|
|
bool xfs_extent_busy_list_empty(struct xfs_group *xg, unsigned int *busy_gen);
|
|
struct xfs_extent_busy_tree *xfs_extent_busy_alloc(void);
|
|
|
|
int xfs_extent_busy_ag_cmp(void *priv, const struct list_head *a,
|
|
const struct list_head *b);
|
|
static inline void xfs_extent_busy_sort(struct list_head *list)
|
|
{
|
|
list_sort(NULL, list, xfs_extent_busy_ag_cmp);
|
|
}
|
|
|
|
/*
|
|
* Zoned RTGs don't need to track busy extents, as the actual block freeing only
|
|
* happens by a zone reset, which forces out all transactions that touched the
|
|
* to be reset zone first.
|
|
*/
|
|
#define xfs_group_has_extent_busy(mp, type) \
|
|
((type) == XG_TYPE_AG || !xfs_has_zoned((mp)))
|
|
|
|
#endif /* __XFS_EXTENT_BUSY_H__ */
|