Skip to content

Commit

Permalink
Fix abd leak, kmem_free correct size of abd_t
Browse files Browse the repository at this point in the history
Fix a leak of abd_t that manifested mostly when using
raidzN with at least as many columns as N (e.g. a
four-disk raidz2 but not a three-disk raidz2).
Sufficiently heavy raidz use would eventually run a system
out of memory.

Additionally:

* Switch abd_cache arena to FIRSTFIT, which empirically
improves perofrmance.

* Make abd_chunk_cache more performant and debuggable.

* Allocate the abd_zero_buf from abd_chunk_cache rather
than the heap.

* Don't try to reap non-existent qcaches in abd_cache arena.

* KM_PUSHPAGE->KM_SLEEP when allocating chunks from their
own arena

Reviewed-by: Matthew Ahrens <mahrens@delphix.com>
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Signed-off-by: Jorgen Lundman <lundman@lundman.net>
Co-authored-by: Sean Doran <smd@use.net>
Closes openzfs#12295
  • Loading branch information
lundman authored and behlendorf committed Aug 24, 2021
1 parent cb1a5ad commit 841e76e
Show file tree
Hide file tree
Showing 4 changed files with 10 additions and 6 deletions.
2 changes: 1 addition & 1 deletion include/sys/abd_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void abd_free_struct(abd_t *);
*/

abd_t *abd_alloc_struct_impl(size_t);
abd_t *abd_get_offset_scatter(abd_t *, abd_t *, size_t);
abd_t *abd_get_offset_scatter(abd_t *, abd_t *, size_t, size_t);
void abd_free_struct_impl(abd_t *);
void abd_alloc_chunks(abd_t *, size_t);
void abd_free_chunks(abd_t *);
Expand Down
9 changes: 6 additions & 3 deletions module/os/freebsd/zfs/abd_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -375,14 +375,17 @@ abd_alloc_for_io(size_t size, boolean_t is_metadata)
}

abd_t *
abd_get_offset_scatter(abd_t *abd, abd_t *sabd, size_t off)
abd_get_offset_scatter(abd_t *abd, abd_t *sabd, size_t off,
size_t size)
{
abd_verify(sabd);
ASSERT3U(off, <=, sabd->abd_size);

size_t new_offset = ABD_SCATTER(sabd).abd_offset + off;
uint_t chunkcnt = abd_scatter_chunkcnt(sabd) -
(new_offset / zfs_abd_chunk_size);
size_t chunkcnt = abd_chunkcnt_for_bytes(
(new_offset % zfs_abd_chunk_size) + size);

ASSERT3U(chunkcnt, <=, abd_scatter_chunkcnt(sabd));

/*
* If an abd struct is provided, it is only the minimum size. If we
Expand Down
3 changes: 2 additions & 1 deletion module/os/linux/zfs/abd_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,8 @@ abd_alloc_for_io(size_t size, boolean_t is_metadata)
}

abd_t *
abd_get_offset_scatter(abd_t *abd, abd_t *sabd, size_t off)
abd_get_offset_scatter(abd_t *abd, abd_t *sabd, size_t off,
size_t size)
{
int i = 0;
struct scatterlist *sg = NULL;
Expand Down
2 changes: 1 addition & 1 deletion module/zfs/abd.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ abd_get_offset_impl(abd_t *abd, abd_t *sabd, size_t off, size_t size)
}
ASSERT3U(left, ==, 0);
} else {
abd = abd_get_offset_scatter(abd, sabd, off);
abd = abd_get_offset_scatter(abd, sabd, off, size);
}

ASSERT3P(abd, !=, NULL);
Expand Down

0 comments on commit 841e76e

Please sign in to comment.