Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm: update vma_modify_flags() to handle residual flags, document

The vma_modify_*() family of functions each either perform splits, a merge
or no changes at all in preparation for the requested modification to
occur.

When doing so for a VMA flags change, we currently don't account for any
flags which may remain (for instance, VM_SOFTDIRTY) despite the requested
change in the case that a merge succeeded.

This is made more important by subsequent patches which will introduce the
concept of sticky VMA flags which rely on this behaviour.

This patch fixes this by passing the VMA flags parameter as a pointer and
updating it accordingly on merge and updating callers to accommodate for
this.

Additionally, while we are here, we add kdocs for each of the
vma_modify_*() functions, as the fact that the requested modification is
not performed is confusing so it is useful to make this abundantly clear.

We also update the VMA userland tests to account for this change.

Link: https://lkml.kernel.org/r/23b5b549b0eaefb2922625626e58c2a352f3e93c.1763460113.git.lorenzo.stoakes@oracle.com
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Reviewed-by: Vlastimil Babka <vbabka@suse.cz>
Cc: Andrei Vagin <avagin@gmail.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: David Hildenbrand (Red Hat) <david@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Nico Pache <npache@redhat.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Lorenzo Stoakes and committed by
Andrew Morton
9119d6c2 56882250

+140 -66
+1 -1
mm/madvise.c
··· 167 167 range->start, range->end, anon_name); 168 168 else 169 169 vma = vma_modify_flags(&vmi, madv_behavior->prev, vma, 170 - range->start, range->end, new_flags); 170 + range->start, range->end, &new_flags); 171 171 172 172 if (IS_ERR(vma)) 173 173 return PTR_ERR(vma);
+1 -1
mm/mlock.c
··· 478 478 /* don't set VM_LOCKED or VM_LOCKONFAULT and don't count */ 479 479 goto out; 480 480 481 - vma = vma_modify_flags(vmi, *prev, vma, start, end, newflags); 481 + vma = vma_modify_flags(vmi, *prev, vma, start, end, &newflags); 482 482 if (IS_ERR(vma)) { 483 483 ret = PTR_ERR(vma); 484 484 goto out;
+1 -1
mm/mprotect.c
··· 756 756 newflags &= ~VM_ACCOUNT; 757 757 } 758 758 759 - vma = vma_modify_flags(vmi, *pprev, vma, start, end, newflags); 759 + vma = vma_modify_flags(vmi, *pprev, vma, start, end, &newflags); 760 760 if (IS_ERR(vma)) { 761 761 error = PTR_ERR(vma); 762 762 goto fail;
+5 -4
mm/mseal.c
··· 66 66 prev = vma; 67 67 68 68 for_each_vma_range(vmi, vma, end) { 69 - unsigned long curr_end = MIN(vma->vm_end, end); 69 + const unsigned long curr_end = MIN(vma->vm_end, end); 70 70 71 71 if (!(vma->vm_flags & VM_SEALED)) { 72 - vma = vma_modify_flags(&vmi, prev, vma, 73 - curr_start, curr_end, 74 - vma->vm_flags | VM_SEALED); 72 + vm_flags_t vm_flags = vma->vm_flags | VM_SEALED; 73 + 74 + vma = vma_modify_flags(&vmi, prev, vma, curr_start, 75 + curr_end, &vm_flags); 75 76 if (IS_ERR(vma)) 76 77 return PTR_ERR(vma); 77 78 vm_flags_set(vma, VM_SEALED);
+30 -26
mm/vma.c
··· 1638 1638 return vma; 1639 1639 } 1640 1640 1641 - struct vm_area_struct *vma_modify_flags( 1642 - struct vma_iterator *vmi, struct vm_area_struct *prev, 1643 - struct vm_area_struct *vma, unsigned long start, unsigned long end, 1644 - vm_flags_t vm_flags) 1641 + struct vm_area_struct *vma_modify_flags(struct vma_iterator *vmi, 1642 + struct vm_area_struct *prev, struct vm_area_struct *vma, 1643 + unsigned long start, unsigned long end, 1644 + vm_flags_t *vm_flags_ptr) 1645 1645 { 1646 1646 VMG_VMA_STATE(vmg, vmi, prev, vma, start, end); 1647 + const vm_flags_t vm_flags = *vm_flags_ptr; 1648 + struct vm_area_struct *ret; 1647 1649 1648 1650 vmg.vm_flags = vm_flags; 1649 1651 1650 - return vma_modify(&vmg); 1652 + ret = vma_modify(&vmg); 1653 + if (IS_ERR(ret)) 1654 + return ret; 1655 + 1656 + /* 1657 + * For a merge to succeed, the flags must match those requested. For 1658 + * flags which do not obey typical merge rules (i.e. do not need to 1659 + * match), we must let the caller know about them. 1660 + */ 1661 + if (vmg.state == VMA_MERGE_SUCCESS) 1662 + *vm_flags_ptr = ret->vm_flags; 1663 + return ret; 1651 1664 } 1652 1665 1653 - struct vm_area_struct 1654 - *vma_modify_name(struct vma_iterator *vmi, 1655 - struct vm_area_struct *prev, 1656 - struct vm_area_struct *vma, 1657 - unsigned long start, 1658 - unsigned long end, 1659 - struct anon_vma_name *new_name) 1666 + struct vm_area_struct *vma_modify_name(struct vma_iterator *vmi, 1667 + struct vm_area_struct *prev, struct vm_area_struct *vma, 1668 + unsigned long start, unsigned long end, 1669 + struct anon_vma_name *new_name) 1660 1670 { 1661 1671 VMG_VMA_STATE(vmg, vmi, prev, vma, start, end); 1662 1672 ··· 1675 1665 return vma_modify(&vmg); 1676 1666 } 1677 1667 1678 - struct vm_area_struct 1679 - *vma_modify_policy(struct vma_iterator *vmi, 1680 - struct vm_area_struct *prev, 1681 - struct vm_area_struct *vma, 1682 - unsigned long start, unsigned long end, 1683 - struct mempolicy *new_pol) 1668 + struct vm_area_struct *vma_modify_policy(struct vma_iterator *vmi, 1669 + struct vm_area_struct *prev, struct vm_area_struct *vma, 1670 + unsigned long start, unsigned long end, 1671 + struct mempolicy *new_pol) 1684 1672 { 1685 1673 VMG_VMA_STATE(vmg, vmi, prev, vma, start, end); 1686 1674 ··· 1687 1679 return vma_modify(&vmg); 1688 1680 } 1689 1681 1690 - struct vm_area_struct 1691 - *vma_modify_flags_uffd(struct vma_iterator *vmi, 1692 - struct vm_area_struct *prev, 1693 - struct vm_area_struct *vma, 1694 - unsigned long start, unsigned long end, 1695 - vm_flags_t vm_flags, 1696 - struct vm_userfaultfd_ctx new_ctx, 1697 - bool give_up_on_oom) 1682 + struct vm_area_struct *vma_modify_flags_uffd(struct vma_iterator *vmi, 1683 + struct vm_area_struct *prev, struct vm_area_struct *vma, 1684 + unsigned long start, unsigned long end, vm_flags_t vm_flags, 1685 + struct vm_userfaultfd_ctx new_ctx, bool give_up_on_oom) 1698 1686 { 1699 1687 VMG_VMA_STATE(vmg, vmi, prev, vma, start, end); 1700 1688
+100 -32
mm/vma.h
··· 263 263 void unmap_region(struct ma_state *mas, struct vm_area_struct *vma, 264 264 struct vm_area_struct *prev, struct vm_area_struct *next); 265 265 266 - /* We are about to modify the VMA's flags. */ 267 - __must_check struct vm_area_struct 268 - *vma_modify_flags(struct vma_iterator *vmi, 266 + /** 267 + * vma_modify_flags() - Peform any necessary split/merge in preparation for 268 + * setting VMA flags to *@vm_flags in the range @start to @end contained within 269 + * @vma. 270 + * @vmi: Valid VMA iterator positioned at @vma. 271 + * @prev: The VMA immediately prior to @vma or NULL if @vma is the first. 272 + * @vma: The VMA containing the range @start to @end to be updated. 273 + * @start: The start of the range to update. May be offset within @vma. 274 + * @end: The exclusive end of the range to update, may be offset within @vma. 275 + * @vm_flags_ptr: A pointer to the VMA flags that the @start to @end range is 276 + * about to be set to. On merge, this will be updated to include any additional 277 + * flags which remain in place. 278 + * 279 + * IMPORTANT: The actual modification being requested here is NOT applied, 280 + * rather the VMA is perhaps split, perhaps merged to accommodate the change, 281 + * and the caller is expected to perform the actual modification. 282 + * 283 + * In order to account for VMA flags which may persist (e.g. soft-dirty), the 284 + * @vm_flags_ptr parameter points to the requested flags which are then updated 285 + * so the caller, should they overwrite any existing flags, correctly retains 286 + * these. 287 + * 288 + * Returns: A VMA which contains the range @start to @end ready to have its 289 + * flags altered to *@vm_flags. 290 + */ 291 + __must_check struct vm_area_struct *vma_modify_flags(struct vma_iterator *vmi, 269 292 struct vm_area_struct *prev, struct vm_area_struct *vma, 270 293 unsigned long start, unsigned long end, 271 - vm_flags_t vm_flags); 294 + vm_flags_t *vm_flags_ptr); 272 295 273 - /* We are about to modify the VMA's anon_name. */ 274 - __must_check struct vm_area_struct 275 - *vma_modify_name(struct vma_iterator *vmi, 276 - struct vm_area_struct *prev, 277 - struct vm_area_struct *vma, 278 - unsigned long start, 279 - unsigned long end, 280 - struct anon_vma_name *new_name); 296 + /** 297 + * vma_modify_name() - Peform any necessary split/merge in preparation for 298 + * setting anonymous VMA name to @new_name in the range @start to @end contained 299 + * within @vma. 300 + * @vmi: Valid VMA iterator positioned at @vma. 301 + * @prev: The VMA immediately prior to @vma or NULL if @vma is the first. 302 + * @vma: The VMA containing the range @start to @end to be updated. 303 + * @start: The start of the range to update. May be offset within @vma. 304 + * @end: The exclusive end of the range to update, may be offset within @vma. 305 + * @new_name: The anonymous VMA name that the @start to @end range is about to 306 + * be set to. 307 + * 308 + * IMPORTANT: The actual modification being requested here is NOT applied, 309 + * rather the VMA is perhaps split, perhaps merged to accommodate the change, 310 + * and the caller is expected to perform the actual modification. 311 + * 312 + * Returns: A VMA which contains the range @start to @end ready to have its 313 + * anonymous VMA name changed to @new_name. 314 + */ 315 + __must_check struct vm_area_struct *vma_modify_name(struct vma_iterator *vmi, 316 + struct vm_area_struct *prev, struct vm_area_struct *vma, 317 + unsigned long start, unsigned long end, 318 + struct anon_vma_name *new_name); 281 319 282 - /* We are about to modify the VMA's memory policy. */ 283 - __must_check struct vm_area_struct 284 - *vma_modify_policy(struct vma_iterator *vmi, 285 - struct vm_area_struct *prev, 286 - struct vm_area_struct *vma, 320 + /** 321 + * vma_modify_policy() - Peform any necessary split/merge in preparation for 322 + * setting NUMA policy to @new_pol in the range @start to @end contained 323 + * within @vma. 324 + * @vmi: Valid VMA iterator positioned at @vma. 325 + * @prev: The VMA immediately prior to @vma or NULL if @vma is the first. 326 + * @vma: The VMA containing the range @start to @end to be updated. 327 + * @start: The start of the range to update. May be offset within @vma. 328 + * @end: The exclusive end of the range to update, may be offset within @vma. 329 + * @new_pol: The NUMA policy that the @start to @end range is about to be set 330 + * to. 331 + * 332 + * IMPORTANT: The actual modification being requested here is NOT applied, 333 + * rather the VMA is perhaps split, perhaps merged to accommodate the change, 334 + * and the caller is expected to perform the actual modification. 335 + * 336 + * Returns: A VMA which contains the range @start to @end ready to have its 337 + * NUMA policy changed to @new_pol. 338 + */ 339 + __must_check struct vm_area_struct *vma_modify_policy(struct vma_iterator *vmi, 340 + struct vm_area_struct *prev, struct vm_area_struct *vma, 287 341 unsigned long start, unsigned long end, 288 342 struct mempolicy *new_pol); 289 343 290 - /* We are about to modify the VMA's flags and/or uffd context. */ 291 - __must_check struct vm_area_struct 292 - *vma_modify_flags_uffd(struct vma_iterator *vmi, 293 - struct vm_area_struct *prev, 294 - struct vm_area_struct *vma, 295 - unsigned long start, unsigned long end, 296 - vm_flags_t vm_flags, 297 - struct vm_userfaultfd_ctx new_ctx, 298 - bool give_up_on_oom); 344 + /** 345 + * vma_modify_flags_uffd() - Peform any necessary split/merge in preparation for 346 + * setting VMA flags to @vm_flags and UFFD context to @new_ctx in the range 347 + * @start to @end contained within @vma. 348 + * @vmi: Valid VMA iterator positioned at @vma. 349 + * @prev: The VMA immediately prior to @vma or NULL if @vma is the first. 350 + * @vma: The VMA containing the range @start to @end to be updated. 351 + * @start: The start of the range to update. May be offset within @vma. 352 + * @end: The exclusive end of the range to update, may be offset within @vma. 353 + * @vm_flags: The VMA flags that the @start to @end range is about to be set to. 354 + * @new_ctx: The userfaultfd context that the @start to @end range is about to 355 + * be set to. 356 + * @give_up_on_oom: If an out of memory condition occurs on merge, simply give 357 + * up on it and treat the merge as best-effort. 358 + * 359 + * IMPORTANT: The actual modification being requested here is NOT applied, 360 + * rather the VMA is perhaps split, perhaps merged to accommodate the change, 361 + * and the caller is expected to perform the actual modification. 362 + * 363 + * Returns: A VMA which contains the range @start to @end ready to have its VMA 364 + * flags changed to @vm_flags and its userfaultfd context changed to @new_ctx. 365 + */ 366 + __must_check struct vm_area_struct *vma_modify_flags_uffd(struct vma_iterator *vmi, 367 + struct vm_area_struct *prev, struct vm_area_struct *vma, 368 + unsigned long start, unsigned long end, vm_flags_t vm_flags, 369 + struct vm_userfaultfd_ctx new_ctx, bool give_up_on_oom); 299 370 300 - __must_check struct vm_area_struct 301 - *vma_merge_new_range(struct vma_merge_struct *vmg); 371 + __must_check struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg); 302 372 303 - __must_check struct vm_area_struct 304 - *vma_merge_extend(struct vma_iterator *vmi, 305 - struct vm_area_struct *vma, 306 - unsigned long delta); 373 + __must_check struct vm_area_struct *vma_merge_extend(struct vma_iterator *vmi, 374 + struct vm_area_struct *vma, unsigned long delta); 307 375 308 376 void unlink_file_vma_batch_init(struct unlink_vma_file_batch *vb); 309 377
+2 -1
tools/testing/vma/vma.c
··· 339 339 struct mm_struct mm = {}; 340 340 struct vm_area_struct *init_vma = alloc_vma(&mm, 0, 0x3000, 0, vm_flags); 341 341 VMA_ITERATOR(vmi, &mm, 0x1000); 342 + vm_flags_t flags = VM_READ | VM_MAYREAD; 342 343 343 344 ASSERT_FALSE(attach_vma(&mm, init_vma)); 344 345 ··· 348 347 * performs the merge/split only. 349 348 */ 350 349 vma = vma_modify_flags(&vmi, init_vma, init_vma, 351 - 0x1000, 0x2000, VM_READ | VM_MAYREAD); 350 + 0x1000, 0x2000, &flags); 352 351 ASSERT_NE(vma, NULL); 353 352 /* We modify the provided VMA, and on split allocate new VMAs. */ 354 353 ASSERT_EQ(vma, init_vma);