diff mbox series

[v3,3/9] mm: slightly clarify KSM logic in do_swap_page()

Message ID 20220131162940.210846-4-david@redhat.com (mailing list archive)
State New
Headers show
Series mm: COW fixes part 1: fix the COW security issue for THP and swap | expand

Commit Message

David Hildenbrand Jan. 31, 2022, 4:29 p.m. UTC
Let's make it clearer that KSM might only have to copy a page
in case we have a page in the swapcache, not if we allocated a fresh
page and bypassed the swapcache. While at it, add a comment why this is
usually necessary and merge the two swapcache conditions.

Signed-off-by: David Hildenbrand <david@redhat.com>
---
 mm/memory.c | 38 +++++++++++++++++++++++---------------
 1 file changed, 23 insertions(+), 15 deletions(-)

Comments

Vlastimil Babka March 9, 2022, 6:03 p.m. UTC | #1
On 1/31/22 17:29, David Hildenbrand wrote:
> Let's make it clearer that KSM might only have to copy a page
> in case we have a page in the swapcache, not if we allocated a fresh
> page and bypassed the swapcache. While at it, add a comment why this is
> usually necessary and merge the two swapcache conditions.
> 
> Signed-off-by: David Hildenbrand <david@redhat.com>

Acked-by: Vlastimil Babka <vbabka@suse.cz>


> ---
>  mm/memory.c | 38 +++++++++++++++++++++++---------------
>  1 file changed, 23 insertions(+), 15 deletions(-)
> 
> diff --git a/mm/memory.c b/mm/memory.c
> index 923165b4c27e..3c91294cca98 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3615,21 +3615,29 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
>  		goto out_release;
>  	}
>  
> -	/*
> -	 * Make sure try_to_free_swap or reuse_swap_page or swapoff did not
> -	 * release the swapcache from under us.  The page pin, and pte_same
> -	 * test below, are not enough to exclude that.  Even if it is still
> -	 * swapcache, we need to check that the page's swap has not changed.
> -	 */
> -	if (unlikely((!PageSwapCache(page) ||
> -			page_private(page) != entry.val)) && swapcache)
> -		goto out_page;
> -
> -	page = ksm_might_need_to_copy(page, vma, vmf->address);
> -	if (unlikely(!page)) {
> -		ret = VM_FAULT_OOM;
> -		page = swapcache;
> -		goto out_page;
> +	if (swapcache) {
> +		/*
> +		 * Make sure try_to_free_swap or reuse_swap_page or swapoff did
> +		 * not release the swapcache from under us.  The page pin, and
> +		 * pte_same test below, are not enough to exclude that.  Even if
> +		 * it is still swapcache, we need to check that the page's swap
> +		 * has not changed.
> +		 */
> +		if (unlikely(!PageSwapCache(page) ||
> +			     page_private(page) != entry.val))
> +			goto out_page;
> +
> +		/*
> +		 * KSM sometimes has to copy on read faults, for example, if
> +		 * page->index of !PageKSM() pages would be nonlinear inside the
> +		 * anon VMA -- PageKSM() is lost on actual swapout.
> +		 */
> +		page = ksm_might_need_to_copy(page, vma, vmf->address);
> +		if (unlikely(!page)) {
> +			ret = VM_FAULT_OOM;
> +			page = swapcache;
> +			goto out_page;
> +		}
>  	}
>  
>  	cgroup_throttle_swaprate(page, GFP_KERNEL);
Yang Shi March 9, 2022, 6:48 p.m. UTC | #2
On Mon, Jan 31, 2022 at 8:33 AM David Hildenbrand <david@redhat.com> wrote:
>
> Let's make it clearer that KSM might only have to copy a page
> in case we have a page in the swapcache, not if we allocated a fresh
> page and bypassed the swapcache. While at it, add a comment why this is
> usually necessary and merge the two swapcache conditions.
>
> Signed-off-by: David Hildenbrand <david@redhat.com>
> ---
>  mm/memory.c | 38 +++++++++++++++++++++++---------------
>  1 file changed, 23 insertions(+), 15 deletions(-)
>
> diff --git a/mm/memory.c b/mm/memory.c
> index 923165b4c27e..3c91294cca98 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3615,21 +3615,29 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
>                 goto out_release;
>         }
>
> -       /*
> -        * Make sure try_to_free_swap or reuse_swap_page or swapoff did not

We could remove the reference to "reuse_swap_page", right?

> -        * release the swapcache from under us.  The page pin, and pte_same
> -        * test below, are not enough to exclude that.  Even if it is still
> -        * swapcache, we need to check that the page's swap has not changed.
> -        */
> -       if (unlikely((!PageSwapCache(page) ||
> -                       page_private(page) != entry.val)) && swapcache)
> -               goto out_page;
> -
> -       page = ksm_might_need_to_copy(page, vma, vmf->address);
> -       if (unlikely(!page)) {
> -               ret = VM_FAULT_OOM;
> -               page = swapcache;
> -               goto out_page;
> +       if (swapcache) {
> +               /*
> +                * Make sure try_to_free_swap or reuse_swap_page or swapoff did
> +                * not release the swapcache from under us.  The page pin, and
> +                * pte_same test below, are not enough to exclude that.  Even if
> +                * it is still swapcache, we need to check that the page's swap
> +                * has not changed.
> +                */
> +               if (unlikely(!PageSwapCache(page) ||
> +                            page_private(page) != entry.val))
> +                       goto out_page;
> +
> +               /*
> +                * KSM sometimes has to copy on read faults, for example, if
> +                * page->index of !PageKSM() pages would be nonlinear inside the
> +                * anon VMA -- PageKSM() is lost on actual swapout.
> +                */
> +               page = ksm_might_need_to_copy(page, vma, vmf->address);
> +               if (unlikely(!page)) {
> +                       ret = VM_FAULT_OOM;
> +                       page = swapcache;
> +                       goto out_page;
> +               }
>         }
>
>         cgroup_throttle_swaprate(page, GFP_KERNEL);
> --
> 2.34.1
>
David Hildenbrand March 9, 2022, 7:15 p.m. UTC | #3
On 09.03.22 19:48, Yang Shi wrote:
> On Mon, Jan 31, 2022 at 8:33 AM David Hildenbrand <david@redhat.com> wrote:
>>
>> Let's make it clearer that KSM might only have to copy a page
>> in case we have a page in the swapcache, not if we allocated a fresh
>> page and bypassed the swapcache. While at it, add a comment why this is
>> usually necessary and merge the two swapcache conditions.
>>
>> Signed-off-by: David Hildenbrand <david@redhat.com>
>> ---
>>  mm/memory.c | 38 +++++++++++++++++++++++---------------
>>  1 file changed, 23 insertions(+), 15 deletions(-)
>>
>> diff --git a/mm/memory.c b/mm/memory.c
>> index 923165b4c27e..3c91294cca98 100644
>> --- a/mm/memory.c
>> +++ b/mm/memory.c
>> @@ -3615,21 +3615,29 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
>>                 goto out_release;
>>         }
>>
>> -       /*
>> -        * Make sure try_to_free_swap or reuse_swap_page or swapoff did not
> 
> We could remove the reference to "reuse_swap_page", right?
>
Yes, I noticed this a couple of days ago as well and already have a
patch prepared for that ("mm: adjust stale comment in do_swap_page()
mentioning reuse_swap_page()" at
https://github.com/davidhildenbrand/linux/commits/cow_fixes_part_3)

If Andrew wants, we can fix that up directly before sending upstream or
I'll simply include that patch when sending out part2 v2.

(I want to avoid sending another series just for this)

Thanks!
Andrew Morton March 9, 2022, 8:50 p.m. UTC | #4
On Wed, 9 Mar 2022 20:15:54 +0100 David Hildenbrand <david@redhat.com> wrote:

> On 09.03.22 19:48, Yang Shi wrote:
> > On Mon, Jan 31, 2022 at 8:33 AM David Hildenbrand <david@redhat.com> wrote:
> >>
> >> Let's make it clearer that KSM might only have to copy a page
> >> in case we have a page in the swapcache, not if we allocated a fresh
> >> page and bypassed the swapcache. While at it, add a comment why this is
> >> usually necessary and merge the two swapcache conditions.
> >>
> >> Signed-off-by: David Hildenbrand <david@redhat.com>
> >> ---
> >>  mm/memory.c | 38 +++++++++++++++++++++++---------------
> >>  1 file changed, 23 insertions(+), 15 deletions(-)
> >>
> >> diff --git a/mm/memory.c b/mm/memory.c
> >> index 923165b4c27e..3c91294cca98 100644
> >> --- a/mm/memory.c
> >> +++ b/mm/memory.c
> >> @@ -3615,21 +3615,29 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
> >>                 goto out_release;
> >>         }
> >>
> >> -       /*
> >> -        * Make sure try_to_free_swap or reuse_swap_page or swapoff did not
> > 
> > We could remove the reference to "reuse_swap_page", right?
> >
> Yes, I noticed this a couple of days ago as well and already have a
> patch prepared for that ("mm: adjust stale comment in do_swap_page()
> mentioning reuse_swap_page()" at
> https://github.com/davidhildenbrand/linux/commits/cow_fixes_part_3)
> 
> If Andrew wants, we can fix that up directly before sending upstream or
> I'll simply include that patch when sending out part2 v2.
> 
> (I want to avoid sending another series just for this)

Thanks, I did this.  The same change plus gratuitous comment reflowing.

--- a/mm/memory.c~mm-slightly-clarify-ksm-logic-in-do_swap_page-fix
+++ a/mm/memory.c
@@ -3609,11 +3609,11 @@ vm_fault_t do_swap_page(struct vm_fault
 
 	if (swapcache) {
 		/*
-		 * Make sure try_to_free_swap or reuse_swap_page or swapoff did
-		 * not release the swapcache from under us.  The page pin, and
-		 * pte_same test below, are not enough to exclude that.  Even if
-		 * it is still swapcache, we need to check that the page's swap
-		 * has not changed.
+		 * Make sure try_to_free_swap or swapoff did not release the
+		 * swapcache from under us.  The page pin, and pte_same test
+		 * below, are not enough to exclude that.  Even if it is still
+		 * swapcache, we need to check that the page's swap has not
+		 * changed.
 		 */
 		if (unlikely(!PageSwapCache(page) ||
 			     page_private(page) != entry.val))
diff mbox series

Patch

diff --git a/mm/memory.c b/mm/memory.c
index 923165b4c27e..3c91294cca98 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3615,21 +3615,29 @@  vm_fault_t do_swap_page(struct vm_fault *vmf)
 		goto out_release;
 	}
 
-	/*
-	 * Make sure try_to_free_swap or reuse_swap_page or swapoff did not
-	 * release the swapcache from under us.  The page pin, and pte_same
-	 * test below, are not enough to exclude that.  Even if it is still
-	 * swapcache, we need to check that the page's swap has not changed.
-	 */
-	if (unlikely((!PageSwapCache(page) ||
-			page_private(page) != entry.val)) && swapcache)
-		goto out_page;
-
-	page = ksm_might_need_to_copy(page, vma, vmf->address);
-	if (unlikely(!page)) {
-		ret = VM_FAULT_OOM;
-		page = swapcache;
-		goto out_page;
+	if (swapcache) {
+		/*
+		 * Make sure try_to_free_swap or reuse_swap_page or swapoff did
+		 * not release the swapcache from under us.  The page pin, and
+		 * pte_same test below, are not enough to exclude that.  Even if
+		 * it is still swapcache, we need to check that the page's swap
+		 * has not changed.
+		 */
+		if (unlikely(!PageSwapCache(page) ||
+			     page_private(page) != entry.val))
+			goto out_page;
+
+		/*
+		 * KSM sometimes has to copy on read faults, for example, if
+		 * page->index of !PageKSM() pages would be nonlinear inside the
+		 * anon VMA -- PageKSM() is lost on actual swapout.
+		 */
+		page = ksm_might_need_to_copy(page, vma, vmf->address);
+		if (unlikely(!page)) {
+			ret = VM_FAULT_OOM;
+			page = swapcache;
+			goto out_page;
+		}
 	}
 
 	cgroup_throttle_swaprate(page, GFP_KERNEL);