On Thu, Jul 22, 2021 at 02:52:28PM +0300, Dmitry Osipenko wrote: > I'm getting warnings that might be related to this patch. Thank you! This is a good report. I've trimmed away some of the unnecessary bits from below: > BUG: sleeping function called from invalid context at mm/util.c:761 > in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 29, name: kcompactd0 This is absolutely a result of this patch: for (i = 0; i < nr; i++) { cond_resched(); copy_highpage(folio_page(dst, i), folio_page(src, i)); } cond_resched() can sleep, of course. This is new; previously only copying huge pages would call cond_resched(). Now every page copy calls cond_resched(). > (___might_sleep) from (folio_copy+0x3f/0x84) > (folio_copy) from (folio_migrate_copy+0x11/0x1c) > (folio_migrate_copy) from (__buffer_migrate_page.part.0+0x215/0x238) > (__buffer_migrate_page.part.0) from (buffer_migrate_page_norefs+0x19/0x28) __buffer_migrate_page() is where we become atomic: if (check_refs) spin_lock(&mapping->private_lock); ... migrate_page_copy(newpage, page); ... if (check_refs) spin_unlock(&mapping->private_lock); > (buffer_migrate_page_norefs) from (move_to_new_page+0x4d/0x200) > (move_to_new_page) from (migrate_pages+0x521/0x72c) > (migrate_pages) from (compact_zone+0x589/0xb60) The obvious solution is just to change folio_copy(): { - unsigned i, nr = folio_nr_pages(src); + unsigned i = 0; + unsigned nr = folio_nr_pages(src); - for (i = 0; i < nr; i++) { - cond_resched(); + for (;;) { copy_highpage(folio_page(dst, i), folio_page(src, i)); + if (i++ == nr) + break; + cond_resched(); } } now it only calls cond_resched() for multi-page folios. But that leaves us with a bit of an ... impediment to using multi-page folios for buffer-head based filesystems (and block devices). I must admit to not knowing the buffer_head locking scheme quite as well as I would like to. Is it possible to drop this spinlock earlier?