Re: [PATCH v3 2/3] mm: swap: drop dropbehind swap cache folios on writeback completion

From: Barry Song

Date: Thu Aug 20 2026 - 07:37:10 EST


On Wed, Aug 19, 2026 at 12:34 AM Alexandre Ghiti <alex@xxxxxxxx> wrote:
>
> A PG_dropbehind folio is dropped from its cache once writeback completes
> rather than left for reclaim to find later; this is implemented for file
> folios in folio_end_dropbehind(). Extend it to swap cache folios.
>
> The drop needs the folio and swap cluster locks and may sleep, but
> writeback can complete in interrupt context, so defer the work to a
> workqueue that runs once writeback has completed and frees the folios in
> batches.
>
> Suggested-by: Yosry Ahmed <yosry@xxxxxxxxxx>
> Suggested-by: Johannes Weiner <hannes@xxxxxxxxxxx>
> Suggested-by: Nhat Pham <nphamcs@xxxxxxxxx>
> Signed-off-by: Alexandre Ghiti <alex@xxxxxxxx>
> ---
[...]
>
> +static DEFINE_PER_CPU(struct llist_head, swap_dropbehind_llist);
> +
> +static bool swap_dropbehind_drop_folio(struct folio *folio)
> +{
> + struct mem_cgroup *memcg;
> + bool dropped = false;
> +
> + folio_lock(folio);
> +
> + /* The folio was allocated off the LRU and nothing re-adds it here. */
> + VM_WARN_ON_ONCE_FOLIO(folio_test_lru(folio), folio);

Hi Alexandre,
Thanks very much for your patch!

I don't quite understand why we only support NON-LRU folios. Does this
restriction prevent potential optimizations for madv_pageout?

Also, zram might benefit from your patch in the future with
asynchronous hardware compression and software compression such as
kcompressd[1].

[1] https://lore.kernel.org/linux-mm/20250430082651.3152444-1-qun-wei.lin@xxxxxxxxxxxx/

[...]
> +
> +/**
> + * swap_dropbehind_free_batch_folio - free a dropbehind swap cache folio into a batch
> + * @folio: the off-LRU folio whose writeback has completed
> + * @fbatch: batch of folios to free, flushed when full
> + */
> +static void swap_dropbehind_free_batch_folio(struct folio *folio,
> + struct folio_batch *fbatch)
> +{
> + if (swap_dropbehind_drop_folio(folio) && !folio_batch_add(fbatch, folio))
> + folios_put(fbatch);
> +}
> +
> +static void swap_dropbehind_workfn(struct work_struct *work)
> +{
> + struct folio_batch fbatch;
> + struct llist_node *pos, *next;
> + int cpu;
> +
> + folio_batch_init(&fbatch);
> + for_each_possible_cpu(cpu) {
> + pos = llist_del_all(per_cpu_ptr(&swap_dropbehind_llist, cpu));
> + llist_for_each_safe(pos, next, pos) {
> + struct folio *folio = container_of((struct list_head *)pos,
> + struct folio, lru);
> + swap_dropbehind_free_batch_folio(folio, &fbatch);
> + }
> + }
> + if (fbatch.nr)
> + folios_put(&fbatch);
> +}
> +
> +static DECLARE_WORK(swap_dropbehind_work, swap_dropbehind_workfn);
> +static struct workqueue_struct *swap_dropbehind_wq;
> +
> +void swap_writeback_dropbehind_folio(struct folio *folio)
> +{
> + llist_add((struct llist_node *)&folio->lru,
> + raw_cpu_ptr(&swap_dropbehind_llist));
> + queue_work(swap_dropbehind_wq, &swap_dropbehind_work);
> +}
> +

This is good. For file dropbehind, I see both F2FS [1] and block
devices [2] reinventing workqueues in their own filesystems or
drivers, while folio_end_dropbehind() simply benefits from its safe,
sleepable context. This seems a bit odd.

So I'm really curious whether this could be extended to file-backed
folios as well, so that those filesystems and device drivers don't
have to deal with this themselves.

[1] https://lore.kernel.org/all/20260820071438.695893-1-qiwenjie@xxxxxxxxxx/
[2] https://lore.kernel.org/all/20260730-blk-dontcache-v7-2-3e8e6850068d@xxxxxxxxxxxx/

Thanks
Barry