From: Thomas Weißschuh Date: Sun, 10 Sep 2023 20:46:00 +0000 (+0200) Subject: libblkid: prune unneeded buffers X-Git-Tag: v2.40-rc1~250 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77b85278ff625779d86b924903453d9c54280642;p=thirdparty%2Futil-linux.git libblkid: prune unneeded buffers When a new buffer is cached that is a superset of another existing buffer the old buffer can be removed as future requests can be satisfied by the new one. As probe functions can have local references to buffered data, delay the cleanup until the probefunc is finished to avoid accessing freed data. For the bcachefs.img testfile this reduces the final (maximal) cache from 34338 bytes in 54 buffers to 24760 bytes in 40 buffers. Signed-off-by: Thomas Weißschuh --- diff --git a/libblkid/src/blkidP.h b/libblkid/src/blkidP.h index 088a8a4c94..fb91185d0b 100644 --- a/libblkid/src/blkidP.h +++ b/libblkid/src/blkidP.h @@ -220,6 +220,7 @@ struct blkid_struct_probe struct blkid_chain *wipe_chain; /* superblock, partition, ... */ struct list_head buffers; /* list of buffers */ + struct list_head prunable_buffers; /* list of prunable buffers */ struct list_head hints; struct blkid_chain chains[BLKID_NCHAINS]; /* array of chains */ @@ -433,6 +434,8 @@ extern int blkid_probe_get_idmag(blkid_probe pr, const struct blkid_idinfo *id, uint64_t *offset, const struct blkid_idmag **res) __attribute__((nonnull(1))); +extern void blkid_probe_prune_buffers(blkid_probe pr); + /* returns superblock according to 'struct blkid_idmag' */ extern const unsigned char *blkid_probe_get_sb_buffer(blkid_probe pr, const struct blkid_idmag *mag, size_t size); #define blkid_probe_get_sb(_pr, _mag, type) \ diff --git a/libblkid/src/partitions/partitions.c b/libblkid/src/partitions/partitions.c index 1c344fd303..b142ff7d83 100644 --- a/libblkid/src/partitions/partitions.c +++ b/libblkid/src/partitions/partitions.c @@ -556,6 +556,7 @@ static int idinfo_probe(blkid_probe pr, const struct blkid_idinfo *id, DBG(LOWPROBE, ul_debug( "%s: ---> call probefunc()", id->name)); rc = id->probefunc(pr, mag); + blkid_probe_prune_buffers(pr); if (rc < 0) { /* reset after error */ reset_partlist(blkid_probe_get_partlist(pr)); diff --git a/libblkid/src/probe.c b/libblkid/src/probe.c index fa16f06082..6c17fb457c 100644 --- a/libblkid/src/probe.c +++ b/libblkid/src/probe.c @@ -156,6 +156,7 @@ blkid_probe blkid_new_probe(void) pr->chains[i].enabled = chains_drvs[i]->dflt_enabled; } INIT_LIST_HEAD(&pr->buffers); + INIT_LIST_HEAD(&pr->prunable_buffers); INIT_LIST_HEAD(&pr->values); INIT_LIST_HEAD(&pr->hints); return pr; @@ -646,6 +647,39 @@ static struct blkid_bufinfo *get_cached_buffer(blkid_probe pr, uint64_t off, uin return NULL; } +/* + * Mark smaller buffers that can be satisfied by bf as prunable + */ +static void mark_prunable_buffers(blkid_probe pr, const struct blkid_bufinfo *bf) +{ + struct list_head *p, *next; + + list_for_each_safe(p, next, &pr->buffers) { + struct blkid_bufinfo *x = + list_entry(p, struct blkid_bufinfo, bufs); + + if (bf->off <= x->off && bf->off + bf->len >= x->off + x->len) { + list_del(&x->bufs); + list_add(&x->bufs, &pr->prunable_buffers); + } + } +} + +/* + * Remove buffers that are marked as prunable + */ +void blkid_probe_prune_buffers(blkid_probe pr) +{ + struct list_head *p, *next; + + list_for_each_safe(p, next, &pr->prunable_buffers) { + struct blkid_bufinfo *x = + list_entry(p, struct blkid_bufinfo, bufs); + + remove_buffer(x); + } +} + /* * Zeroize in-memory data in already read buffer. The next blkid_probe_get_buffer() * will return modified buffer. This is usable when you want to call the same probing @@ -746,6 +780,7 @@ const unsigned char *blkid_probe_get_buffer(blkid_probe pr, uint64_t off, uint64 if (!bf) return NULL; + mark_prunable_buffers(pr, bf); list_add_tail(&bf->bufs, &pr->buffers); } @@ -775,6 +810,8 @@ int blkid_probe_reset_buffers(blkid_probe pr) pr->flags &= ~BLKID_FL_MODIF_BUFF; + blkid_probe_prune_buffers(pr); + if (list_empty(&pr->buffers)) return 0; diff --git a/libblkid/src/superblocks/superblocks.c b/libblkid/src/superblocks/superblocks.c index c7789a15be..e89af1b629 100644 --- a/libblkid/src/superblocks/superblocks.c +++ b/libblkid/src/superblocks/superblocks.c @@ -418,6 +418,7 @@ static int superblocks_probe(blkid_probe pr, struct blkid_chain *chn) if (id->probefunc) { DBG(LOWPROBE, ul_debug("\tcall probefunc()")); rc = id->probefunc(pr, mag); + blkid_probe_prune_buffers(pr); if (rc != BLKID_PROBE_OK) { blkid_probe_chain_reset_values(pr, chn); if (rc < 0) diff --git a/libblkid/src/topology/topology.c b/libblkid/src/topology/topology.c index cd1f4c25f7..1fe7c63943 100644 --- a/libblkid/src/topology/topology.c +++ b/libblkid/src/topology/topology.c @@ -146,6 +146,7 @@ blkid_topology blkid_probe_get_topology(blkid_probe pr) static int topology_probe(blkid_probe pr, struct blkid_chain *chn) { size_t i; + int rc; if (chn->idx < -1) return -1; @@ -182,7 +183,9 @@ static int topology_probe(blkid_probe pr, struct blkid_chain *chn) if (id->probefunc) { DBG(LOWPROBE, ul_debug("%s: call probefunc()", id->name)); - if (id->probefunc(pr, NULL) != 0) + rc = id->probefunc(pr, NULL); + blkid_probe_prune_buffers(pr); + if (rc != 0) continue; }