mirror of
https://github.com/torvalds/linux.git
synced 2026-09-14 16:10:02 +02:00
squashfs_cache_get() puts a task to sleep when its block is not cached and
every cache entry is busy. Those sleeps are non-exclusive, so the
nr_exclusive == 1 budget squashfs_cache_put() has always passed to
wake_up() is inert and one release makes every waiter runnable. A wakee
only returns to squashfs_cache_get() if it observes cache->unused before
the entry is reclaimed; later wakees see zero and re-queue inside
wait_event() without rescanning. One freed entry satisfies exactly one
capacity waiter, so waking the rest is waste.
On a Meta production host serving a Python web application from a packaged
squashfs image, a 30-second trace caught 1,045,132 cache-release wake
calls and 19,511,556 wakeups: 18.7 per release, although each release
added only one reusable cache entry. This was causing significant spikes
in CPU usage.
Make the waits exclusive, enqueueing while still holding cache->lock so
that a concurrent lookup either sees the waiter queued or the waiter sees
the block that lookup publishes. Two things follow.
A wakee cannot be assumed to consume the entry it was woken for: it may
find its own block published meanwhile, share that entry, and leave the
freed one unclaimed. So a wakee which shares hands its wakeup on to the
next waiter, as commit
|
||
|---|---|---|
| .. | ||
| block.c | ||
| cache.c | ||
| decompressor_multi_percpu.c | ||
| decompressor_multi.c | ||
| decompressor_single.c | ||
| decompressor.c | ||
| decompressor.h | ||
| dir.c | ||
| export.c | ||
| file_cache.c | ||
| file_direct.c | ||
| file.c | ||
| fragment.c | ||
| id.c | ||
| inode.c | ||
| Kconfig | ||
| lz4_wrapper.c | ||
| lzo_wrapper.c | ||
| Makefile | ||
| namei.c | ||
| page_actor.c | ||
| page_actor.h | ||
| squashfs_fs_i.h | ||
| squashfs_fs_sb.h | ||
| squashfs_fs.h | ||
| squashfs.h | ||
| super.c | ||
| symlink.c | ||
| xattr_id.c | ||
| xattr.c | ||
| xattr.h | ||
| xz_wrapper.c | ||
| zlib_wrapper.c | ||
| zstd_wrapper.c | ||