The patch titled Subject: mm: provide mapping_wrprotect_page() function has been added to the -mm mm-unstable branch. Its filename is mm-provide-mapping_wrprotect_page-function.patch This patch will shortly appear at https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/mm-provide-mapping_wrprotect_page-function.patch This patch will later appear in the mm-unstable branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next via the mm-everything branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm and is updated there every 2-3 working days ------------------------------------------------------ From: Lorenzo Stoakes <lorenzo.stoakes@xxxxxxxxxx> Subject: mm: provide mapping_wrprotect_page() function Date: Fri, 31 Jan 2025 18:28:57 +0000 In the fb_defio video driver, page dirty state is used to determine when frame buffer pages have been changed, allowing for batched, deferred I/O to be performed for efficiency. This implementation had only one means of doing so effectively - the use of the folio_mkclean() function. However, this use of the function is inappropriate, as the fb_defio implementation allocates kernel memory to back the framebuffer, and then is forced to specified page->index, mapping fields in order to permit the folio_mkclean() rmap traversal to proceed correctly. It is not correct to specify these fields on kernel-allocated memory, and moreover since these are not folios, page->index, mapping are deprecated fields, soon to be removed. We therefore need to provide a means by which we can correctly traverse the reverse mapping and write-protect mappings for a page backing an address_space page cache object at a given offset. This patch provides this - mapping_wrprotect_page() allows for this operation to be performed for a specified address_space, offset and page, without requiring a folio nor, of course, an inappropriate use of page->index, mapping. With this provided, we can subequently adjust the fb_defio implementation to make use of this function and avoid incorrect invocation of folio_mkclean() and more importantly, incorrect manipulation of page->index, mapping fields. Link: https://lkml.kernel.org/r/c802c17cdba59e3455f3d7db07659d5da0ed6dc1.1738347308.git.lorenzo.stoakes@xxxxxxxxxx Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@xxxxxxxxxx> Cc: David Hildenbrand <david@xxxxxxxxxx> Cc: Helge Deller <deller@xxxxxx> Cc: Jaya Kumar <jayakumar.lkml@xxxxxxxxx> Cc: Kajtar Zsolt <soci@xxxxxxxxxxxxx> Cc: MaÃra Canal <mcanal@xxxxxxxxxx> Cc: Mattew Wilcox <willy@xxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- include/linux/rmap.h | 3 + mm/rmap.c | 73 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) --- a/include/linux/rmap.h~mm-provide-mapping_wrprotect_page-function +++ a/include/linux/rmap.h @@ -739,6 +739,9 @@ unsigned long page_address_in_vma(const */ int folio_mkclean(struct folio *); +int mapping_wrprotect_page(struct address_space *mapping, pgoff_t pgoff, + unsigned long nr_pages, struct page *page); + int pfn_mkclean_range(unsigned long pfn, unsigned long nr_pages, pgoff_t pgoff, struct vm_area_struct *vma); --- a/mm/rmap.c~mm-provide-mapping_wrprotect_page-function +++ a/mm/rmap.c @@ -1129,6 +1129,79 @@ int folio_mkclean(struct folio *folio) } EXPORT_SYMBOL_GPL(folio_mkclean); +struct wrprotect_file_state { + int cleaned; + pgoff_t pgoff; + unsigned long pfn; + unsigned long nr_pages; +}; + +static bool mapping_wrprotect_page_one(struct folio *folio, + struct vm_area_struct *vma, unsigned long address, void *arg) +{ + struct wrprotect_file_state *state = (struct wrprotect_file_state *)arg; + struct page_vma_mapped_walk pvmw = { + .pfn = state->pfn, + .nr_pages = state->nr_pages, + .pgoff = state->pgoff, + .vma = vma, + .address = address, + .flags = PVMW_SYNC, + }; + + state->cleaned += page_vma_mkclean_one(&pvmw); + + return true; +} + +static void __rmap_walk_file(struct folio *folio, struct address_space *mapping, + pgoff_t pgoff_start, unsigned long nr_pages, + struct rmap_walk_control *rwc, bool locked); + +/** + * mapping_wrprotect_page() - Write protect all mappings of this page. + * + * @mapping: The mapping whose reverse mapping should be traversed. + * @pgoff: The page offset at which @page is mapped within @mapping. + * @nr_pages: The number of physically contiguous base pages spanned. + * @page: The page mapped in @mapping at @pgoff. + * + * Traverses the reverse mapping, finding all VMAs which contain a shared + * mapping of the single @page in @mapping at offset @pgoff and write-protecting + * the mappings. + * + * The page does not have to be a folio, but rather can be a kernel allocation + * that is mapped into userland. We therefore do not require that the page maps + * to a folio with a valid mapping or index field, rather these are specified in + * @mapping and @pgoff. + * + * Return: the number of write-protected PTEs, or an error. + */ +int mapping_wrprotect_page(struct address_space *mapping, pgoff_t pgoff, + unsigned long nr_pages, struct page *page) +{ + struct wrprotect_file_state state = { + .cleaned = 0, + .pgoff = pgoff, + .pfn = page_to_pfn(page), + .nr_pages = nr_pages, + }; + struct rmap_walk_control rwc = { + .arg = (void *)&state, + .rmap_one = mapping_wrprotect_page_one, + .invalid_vma = invalid_mkclean_vma, + }; + + if (!mapping) + return 0; + + __rmap_walk_file(/* folio = */NULL, mapping, pgoff, nr_pages, &rwc, + /* locked = */false); + + return state.cleaned; +} +EXPORT_SYMBOL_GPL(mapping_wrprotect_page); + /** * pfn_mkclean_range - Cleans the PTEs (including PMDs) mapped with range of * [@pfn, @pfn + @nr_pages) at the specific offset (@pgoff) _ Patches currently in -mm which might be from lorenzo.stoakes@xxxxxxxxxx are mm-simplify-vma-merge-structure-and-expand-comments.patch mm-further-refactor-commit_merge.patch mm-eliminate-adj_start-parameter-from-commit_merge.patch mm-make-vmg-target-consistent-and-further-simplify-commit_merge.patch mm-completely-abstract-unnecessary-adj_start-calculation.patch mm-refactor-rmap_walk_file-to-separate-out-traversal-logic.patch mm-provide-mapping_wrprotect_page-function.patch fb_defio-do-not-use-deprecated-page-mapping-index-fields.patch