Consider dnode_t allocations in dbuf cache size accounting

Entries in the dbuf cache contribute only the size of the dbuf data to
the cache size. Attached "user" data is not counted. This can lead to
the data currently "owned" by the cache consuming more memory accounting
appears to show. In some cases (eg a metadnode data block with all child
dnode_t slots allocated), the actual size can be as much as 3x as what
the cache believes it to be.

This is arguably correct behaviour, as the cache is only tracking the
size of the dbuf data, not even the overhead of the dbuf_t. On the other
hand, in the above case of dnodes, evicting cached metadnode dbufs is
the only current way to reclaim the dnode objects, and can lead to the
situation where the dbuf cache appears to be comfortably within its
target memory window and yet is holding enormous amounts of slab memory
that cannot be reclaimed.

This commit adds a facility for a dbuf user to artificially inflate the
apparent size of the dbuf for caching purposes. This at least allows for
cache tuning to be adjusted to match something closer to the real memory
overhead.

metadnode dbufs carry a >1KiB allocation per dnode in their user data.
This informs the dbuf cache machinery of that fact, allowing it to make
better decisions when evicting dbufs.

Sponsored-by: Klara, Inc.
Sponsored-by: Wasabi Technology, Inc.
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
Closes #15511
This commit is contained in:
Rob N
2023-11-18 08:25:53 +11:00
committed by GitHub
parent 6c6fae6fae
commit 92dc4ad83d
5 changed files with 102 additions and 26 deletions
+13
View File
@@ -652,6 +652,9 @@ typedef struct dmu_buf_user {
*/
taskq_ent_t dbu_tqent;
/* Size of user data, for inclusion in dbuf_cache accounting. */
uint64_t dbu_size;
/*
* This instance's eviction function pointers.
*
@@ -733,6 +736,16 @@ void *dmu_buf_replace_user(dmu_buf_t *db,
*/
void *dmu_buf_remove_user(dmu_buf_t *db, dmu_buf_user_t *user);
/*
* User data size accounting. This can be used to artifically inflate the size
* of the dbuf during cache accounting, so that dbuf_evict_thread evicts enough
* to satisfy memory reclaim requests. It's not used for anything else, and
* defaults to 0.
*/
uint64_t dmu_buf_user_size(dmu_buf_t *db);
void dmu_buf_add_user_size(dmu_buf_t *db, uint64_t nadd);
void dmu_buf_sub_user_size(dmu_buf_t *db, uint64_t nsub);
/*
* Returns the user data (dmu_buf_user_t *) associated with this dbuf.
*/