Skip to contentSkip to conversation

KVM: async_pf: use_mm/mm_users fixes

PATCH In review Oleg Nesterov 4 participants 16 messages Apr 21, 2014 – Apr 28, 2014 KVM

lore
Share & tools
lore
#0 lore raw

cover KVM: async_pf: use_mm/mm_users fixes

Hello.

Completely untested and I know nothing about kvm ;) Please review.

But use_mm() really looks misleading, and the usage of mm_users looks "obviously wrong". I already sent this change while we were discussing vmacache, but it was ignored. Since then kvm_async_page_present_sync() was added into async_pf_execute() into async_pf_execute(), but it seems to me that use_mm() is still unnecessary.

Oleg.

 virt/kvm/async_pf.c |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)
#1 lore raw

PATCH 1/2 KVM: async_pf: kill the unnecessary use_mm/unuse_mm async_pf_execute()

async_pf_execute() has no reasons to adopt apf->mm, gup(current, mm) should work just fine even if current has another or NULL ->mm.

Recently kvm_async_page_present_sync() was added insedie the "use_mm" section, but it seems that it doesn't need current->mm too.

---
 virt/kvm/async_pf.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)
virt/kvm/async_pf.c +0 -2
index 10df100..0ced4f3 100644
@@ -80,12 +80,10 @@ static void async_pf_execute(struct work_struct *work)
 
 	might_sleep();
 
-	use_mm(mm);
 	down_read(&mm->mmap_sem);
 	get_user_pages(current, mm, addr, 1, 1, 0, NULL, NULL);
 	up_read(&mm->mmap_sem);
 	kvm_async_page_present_sync(vcpu, apf);
-	unuse_mm(mm);
 
 	spin_lock(&vcpu->async_pf.lock);
 	list_add_tail(&apf->link, &vcpu->async_pf.done);
Signature · 1 line
1.5.5.1
#2 lore raw

Re: [PATCH 1/2] KVM: async_pf: kill the unnecessary use_mm/unuse_mm async_pf_execute()

Quoted 7 lines · Oleg Nesterov

async_pf_execute() has no reasons to adopt apf->mm, gup(current, mm) should work just fine even if current has another or NULL ->mm.

Recently kvm_async_page_present_sync() was added insedie the "use_mm" section, but it seems that it doesn't need current->mm too.

Indeed, use/unuse_mm should only be necessary for copy_to/from_user etc. This is fine for s390, but it seems that x86 kvm_arch_async_page_not_present might call apf_put_user which might call copy_to_user, so this is not ok, I guess.

Quoted 22 lines
---
 virt/kvm/async_pf.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)
virt/kvm/async_pf.c +0 -2
index 10df100..0ced4f3 100644
@@ -80,12 +80,10 @@ static void async_pf_execute(struct work_struct *work)
 
 	might_sleep();
 
-	use_mm(mm);
 	down_read(&mm->mmap_sem);
 	get_user_pages(current, mm, addr, 1, 1, 0, NULL, NULL);
 	up_read(&mm->mmap_sem);
 	kvm_async_page_present_sync(vcpu, apf);
-	unuse_mm(mm);
 
 	spin_lock(&vcpu->async_pf.lock);
 	list_add_tail(&apf->link, &vcpu->async_pf.done);
#3 lore raw

Re: [PATCH 1/2] KVM: async_pf: kill the unnecessary use_mm/unuse_mm async_pf_execute()

Quoted 4 lines · Christian Borntraeger
Quoted 3 lines · Oleg Nesterov

async_pf_execute() has no reasons to adopt apf->mm, gup(current, mm) should work just fine even if current has another or NULL ->mm.

Quoted 8 lines
Quoted 4 lines

Recently kvm_async_page_present_sync() was added insedie the "use_mm" section, but it seems that it doesn't need current->mm too.

Indeed, use/unuse_mm should only be necessary for copy_to/from_user etc. This is fine for s390, but it seems that x86 kvm_arch_async_page_not_present might call apf_put_user which might call copy_to_user, so this is not ok, I guess.

wanted to say kvm_arch_async_page_not_present, but I have to correct myself. x86 does the "page is there" in the cpu loop, not in the worker. The cpu look d oes have a valid mm. So this patch should be also ok.

Quoted 29 lines
Quoted 13 lines
---
 virt/kvm/async_pf.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)
virt/kvm/async_pf.c +0 -0
index 10df100..0ced4f3 100644
@@ -80,12 +80,10 @@ static void async_pf_execute(struct work_struct *work)
 
 	might_sleep();

virt/kvm/async_pf.c static void async_pf_execute(struct work_struct *work) · line 89

Quoted 10 lines
virt/kvm/async_pf.c +0 -2
 
-	use_mm(mm);
 	down_read(&mm->mmap_sem);
 	get_user_pages(current, mm, addr, 1, 1, 0, NULL, NULL);
 	up_read(&mm->mmap_sem);
 	kvm_async_page_present_sync(vcpu, apf);
-	unuse_mm(mm);
 
 	spin_lock(&vcpu->async_pf.lock);
 	list_add_tail(&apf->link, &vcpu->async_pf.done);

--
To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#4 lore raw

Re: [PATCH 1/2] KVM: async_pf: kill the unnecessary use_mm/unuse_mm async_pf_execute()

Quoted 11 lines · Christian Borntraeger
Quoted 9 lines · Christian Borntraeger
Quoted 7 lines · Oleg Nesterov

async_pf_execute() has no reasons to adopt apf->mm, gup(current, mm) should work just fine even if current has another or NULL ->mm.

Recently kvm_async_page_present_sync() was added insedie the "use_mm" section, but it seems that it doesn't need current->mm too.

Quoted 7 lines
Quoted 3 lines

Indeed, use/unuse_mm should only be necessary for copy_to/from_user etc. This is fine for s390, but it seems that x86 kvm_arch_async_page_not_present might call apf_put_user which might call copy_to_user, so this is not ok, I guess.

wanted to say kvm_arch_async_page_not_present, but I have to correct myself. x86 does the "page is there" in the cpu loop, not in the worker. The cpu look d oes have a valid mm. So this patch should be also ok.

Thanks ;)

Btw, I forgot to mention this in the changelog, but

Quoted 10 lines
Quoted 10 lines

virt/kvm/async_pf.c static void async_pf_execute(struct work_struct *work) · line 88

Quoted 10 lines
virt/kvm/async_pf.c +0 -2
@@ -80,12 +80,10 @@ static void async_pf_execute(struct work_struct *work)
 
 	might_sleep();
 
-	use_mm(mm);
 	down_read(&mm->mmap_sem);
 	get_user_pages(current, mm, addr, 1, 1, 0, NULL, NULL);
 	up_read(&mm->mmap_sem);
 	kvm_async_page_present_sync(vcpu, apf);
-	unuse_mm(mm);

it can actually do

	get_user_pages(NULL, mm, addr, 1, 1, 0, NULL, NULL);

"task" is only used to increment task_struct->xxx_flt. I don't think async_pf_execute() actually needs this (current is PF_WQ_WORKER after all), but I didn't dare to do another change in the code I can hardly understand.

Oleg.

#5 lore raw

Re: [PATCH 1/2] KVM: async_pf: kill the unnecessary use_mm/unuse_mm async_pf_execute()

Hi,

Quoted 37 lines · Oleg Nesterov
Quoted 11 lines · Christian Borntraeger
Quoted 9 lines · Christian Borntraeger
Quoted 7 lines · Oleg Nesterov

async_pf_execute() has no reasons to adopt apf->mm, gup(current, mm) should work just fine even if current has another or NULL ->mm.

Recently kvm_async_page_present_sync() was added insedie the "use_mm" section, but it seems that it doesn't need current->mm too.

Quoted 7 lines
Quoted 3 lines

Indeed, use/unuse_mm should only be necessary for copy_to/from_user etc. This is fine for s390, but it seems that x86 kvm_arch_async_page_not_present might call apf_put_user which might call copy_to_user, so this is not ok, I guess.

wanted to say kvm_arch_async_page_not_present, but I have to correct myself. x86 does the "page is there" in the cpu loop, not in the worker. The cpu look d oes have a valid mm. So this patch should be also ok.

Thanks ;)

Btw, I forgot to mention this in the changelog, but

Quoted 10 lines
Quoted 10 lines

virt/kvm/async_pf.c static void async_pf_execute(struct work_struct *work) · line 88

Quoted 10 lines
virt/kvm/async_pf.c +0 -2
@@ -80,12 +80,10 @@ static void async_pf_execute(struct work_struct *work)
 
 	might_sleep();
 
-	use_mm(mm);
 	down_read(&mm->mmap_sem);
 	get_user_pages(current, mm, addr, 1, 1, 0, NULL, NULL);
 	up_read(&mm->mmap_sem);
 	kvm_async_page_present_sync(vcpu, apf);
-	unuse_mm(mm);

it can actually do

Quoted 6 lines
	get_user_pages(NULL, mm, addr, 1, 1, 0, NULL, NULL);

"task" is only used to increment task_struct->xxx_flt. I don't think async_pf_execute() actually needs this (current is PF_WQ_WORKER after all), but I didn't dare to do another change in the code I can hardly understand.

Considering the faults would be randomly distributed among the kworker threads my preference would also be for NULL instead of current.

ptrace and uprobes tends to be the only two places that look into other mm with gup, ptrace knows the exact pid that it is triggering the fault into, so it also can specify the correct task so the fault goes in the right task struct. uprobes uses NULL.

maintainer
#6 lore raw

Re: [PATCH 1/2] KVM: async_pf: kill the unnecessary use_mm/unuse_mm async_pf_execute()

Il 28/04/2014 16:06, Andrea Arcangeli ha scritto:

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

"task" is only used to increment task_struct->xxx_flt. I don't think async_pf_execute() actually needs this (current is PF_WQ_WORKER after all), but I didn't dare to do another change in the code I can hardly understand.

Quoted 7 lines

Considering the faults would be randomly distributed among the kworker threads my preference would also be for NULL instead of current.

ptrace and uprobes tends to be the only two places that look into other mm with gup, ptrace knows the exact pid that it is triggering the fault into, so it also can specify the correct task so the fault goes in the right task struct. uprobes uses NULL.

KVM knows the correct task (it was in current when kvm_create_vm was called), and doing accounting right would be nice. But I agree that NULL is less misleading than a dummy current, and I applied patch 3 too.

Paolo

#7 lore raw

PATCH 2/2 KVM: async_pf: mm->mm_users can not pin apf->mm

In reply to Oleg Nesterov

get_user_pages(mm) is simply wrong if mm->mm_users == 0 and exit_mmap/etc was already called (or is in progress), mm->mm_count can only pin mm->pgd and mm_struct itself.

Change kvm_setup_async_pf/async_pf_execute to inc/dec mm->mm_users.

kvm_create_vm/kvm_destroy_vm play with ->mm_count too but this case looks fine at first glance, it seems that this ->mm is only used to verify that current->mm == kvm->mm.

---
 virt/kvm/async_pf.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
virt/kvm/async_pf.c +4 -4
index 0ced4f3..cda703e 100644
@@ -99,7 +99,7 @@ static void async_pf_execute(struct work_struct *work)
 	if (waitqueue_active(&vcpu->wq))
 		wake_up_interruptible(&vcpu->wq);
 
-	mmdrop(mm);
+	mmput(mm);
 	kvm_put_kvm(vcpu->kvm);
 }
 
@@ -116,7 +116,7 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
 		flush_work(&work->work);
 #else
 		if (cancel_work_sync(&work->work)) {
-			mmdrop(work->mm);
+			mmput(work->mm);
 			kvm_put_kvm(vcpu->kvm); /* == work->vcpu->kvm */
 			kmem_cache_free(async_pf_cache, work);
 		}
@@ -181,7 +181,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva,
 	work->addr = hva;
 	work->arch = *arch;
 	work->mm = current->mm;
-	atomic_inc(&work->mm->mm_count);
+	atomic_inc(&work->mm->mm_users);
 	kvm_get_kvm(work->vcpu->kvm);
 
 	/* this can't really happen otherwise gfn_to_pfn_async
@@ -199,7 +199,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva,
 	return 1;
 retry_sync:
 	kvm_put_kvm(work->vcpu->kvm);
-	mmdrop(work->mm);
+	mmput(work->mm);
 	kmem_cache_free(async_pf_cache, work);
 	return 0;
 }
Signature · 1 line
1.5.5.1
#8 lore raw

Re: [PATCH 2/2] KVM: async_pf: mm->mm_users can not pin apf->mm

Quoted 11 lines · Oleg Nesterov

get_user_pages(mm) is simply wrong if mm->mm_users == 0 and exit_mmap/etc was already called (or is in progress), mm->mm_count can only pin mm->pgd and mm_struct itself.

Change kvm_setup_async_pf/async_pf_execute to inc/dec mm->mm_users.

kvm_create_vm/kvm_destroy_vm play with ->mm_count too but this case looks fine at first glance, it seems that this ->mm is only used to verify that current->mm == kvm->mm.

This looks fine, from what I can tell. The old code has the problem mentioned in your patch description, so your version is probably better.

Quoted 45 lines
---
 virt/kvm/async_pf.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
virt/kvm/async_pf.c +4 -4
index 0ced4f3..cda703e 100644
@@ -99,7 +99,7 @@ static void async_pf_execute(struct work_struct *work)
 	if (waitqueue_active(&vcpu->wq))
 		wake_up_interruptible(&vcpu->wq);
 
-	mmdrop(mm);
+	mmput(mm);
 	kvm_put_kvm(vcpu->kvm);
 }
 
@@ -116,7 +116,7 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
 		flush_work(&work->work);
 #else
 		if (cancel_work_sync(&work->work)) {
-			mmdrop(work->mm);
+			mmput(work->mm);
 			kvm_put_kvm(vcpu->kvm); /* == work->vcpu->kvm */
 			kmem_cache_free(async_pf_cache, work);
 		}
@@ -181,7 +181,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva,
 	work->addr = hva;
 	work->arch = *arch;
 	work->mm = current->mm;
-	atomic_inc(&work->mm->mm_count);
+	atomic_inc(&work->mm->mm_users);
 	kvm_get_kvm(work->vcpu->kvm);
 
 	/* this can't really happen otherwise gfn_to_pfn_async
@@ -199,7 +199,7 @@ int kvm_setup_async_pf(struct kvm_vcpu *vcpu, gva_t gva, unsigned long hva,
 	return 1;
 retry_sync:
 	kvm_put_kvm(work->vcpu->kvm);
-	mmdrop(work->mm);
+	mmput(work->mm);
 	kmem_cache_free(async_pf_cache, work);
 	return 0;
 }
Acked-by on the v1 series
#9 lore raw
In reply to Oleg Nesterov
Quoted 10 lines · Oleg Nesterov

Hello.

Completely untested and I know nothing about kvm ;) Please review.

But use_mm() really looks misleading, and the usage of mm_users looks "obviously wrong". I already sent this change while we were discussing vmacache, but it was ignored. Since then kvm_async_page_present_sync() was added into async_pf_execute() into async_pf_execute(), but it seems to me that use_mm() is still unnecessary.

Quoted 5 lines

Oleg.

 virt/kvm/async_pf.c |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)

I gave both patches some testing on s390, seems fine. I think patch2 really does fix a bug. So if Paolo, Marcelo, Gleb agree (maybe do a test on x86 for async_pf) both patches are good to go. Given that somebody tests this on x86:

#10 lore raw
Quoted 18 lines · Christian Borntraeger
Quoted 10 lines · Oleg Nesterov

Hello.

Completely untested and I know nothing about kvm ;) Please review.

But use_mm() really looks misleading, and the usage of mm_users looks "obviously wrong". I already sent this change while we were discussing vmacache, but it was ignored. Since then kvm_async_page_present_sync() was added into async_pf_execute() into async_pf_execute(), but it seems to me that use_mm() is still unnecessary.

Quoted 5 lines

Oleg.

 virt/kvm/async_pf.c |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)
Quoted 5 lines

I gave both patches some testing on s390, seems fine. I think patch2 really does fix a bug. So if Paolo, Marcelo, Gleb agree (maybe do a test on x86 for async_pf) both patches are good to go. Given that somebody tests this on x86:

Thanks!

I think x86 should be fine, it doesn't select CONFIG_KVM_ASYNC_PF_SYNC and get_user_pages() is certainly fine without use_mm(). And I still think it should do get_user_pages(tsk => NULL) but this is minor.

Oleg.

maintainer
#11 lore raw
In reply to Oleg Nesterov

Il 21/04/2014 15:25, Oleg Nesterov ha scritto:

Quoted 10 lines

Hello.

Completely untested and I know nothing about kvm ;) Please review.

But use_mm() really looks misleading, and the usage of mm_users looks "obviously wrong". I already sent this change while we were discussing vmacache, but it was ignored. Since then kvm_async_page_present_sync() was added into async_pf_execute() into async_pf_execute(), but it seems to me that use_mm() is still unnecessary.

Quoted 5 lines

Oleg.

 virt/kvm/async_pf.c |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)

Applying patch 2 to kvm/master (for 3.15).

Patch 1 will be for 3.16 only, I'd like a review from Marcelo or Andrea though (that's "KVM: async_pf: kill the unnecessary use_mm/unuse_mm async_pf_execute()" for easier googling).

Paolo

Reviewed-by
#12 lore raw
Quoted 3 lines · Paolo Bonzini

Patch 1 will be for 3.16 only, I'd like a review from Marcelo or Andrea though (that's "KVM: async_pf: kill the unnecessary use_mm/unuse_mm async_pf_execute()" for easier googling).

Patch 1:

I think current->NULL would be better too.

#13 lore raw

[PATCH 3/2] KVM: async_pf: change async_pf_execute() to use get_user_pages(tsk => NULL)

Quoted 9 lines · Andrea Arcangeli
Quoted 3 lines · Paolo Bonzini

Patch 1 will be for 3.16 only, I'd like a review from Marcelo or Andrea though (that's "KVM: async_pf: kill the unnecessary use_mm/unuse_mm async_pf_execute()" for easier googling).

Patch 1:

Thanks,

Quoted 1 line

I think current->NULL would be better too.

OK, let me send the trivial one-liner then. I won't mind if you fold it into 1/2, or I can resend it with this change included.

Oleg.

#14 lore raw

[PATCH 3/2] KVM: async_pf: change async_pf_execute() to use get_user_pages(tsk => NULL)

async_pf_execute() passes tsk == current to gup(), this is doesn't hurt but unnecessary and misleading. "tsk" is only used to account the number of faults and current is the random workqueue thread.

---
 virt/kvm/async_pf.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
virt/kvm/async_pf.c +1 -1
index 0ced4f3..62f4223 100644
@@ -81,7 +81,7 @@ static void async_pf_execute(struct work_struct *work)
 	might_sleep();
 
 	down_read(&mm->mmap_sem);
-	get_user_pages(current, mm, addr, 1, 1, 0, NULL, NULL);
+	get_user_pages(NULL, mm, addr, 1, 1, 0, NULL, NULL);
 	up_read(&mm->mmap_sem);
 	kvm_async_page_present_sync(vcpu, apf);
 
Signature · 1 line
1.5.5.1
maintainer
#15 lore raw

Re: [PATCH 3/2] KVM: async_pf: change async_pf_execute() to use get_user_pages(tsk => NULL)

Il 28/04/2014 17:03, Oleg Nesterov ha scritto:

Quoted 15 lines

async_pf_execute() passes tsk == current to gup(), this is doesn't hurt but unnecessary and misleading. "tsk" is only used to account the number of faults and current is the random workqueue thread.

---
 virt/kvm/async_pf.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
virt/kvm/async_pf.c +0 -0
index 0ced4f3..62f4223 100644

virt/kvm/async_pf.c static void async_pf_execute(struct work_struct *work) · line 87

Quoted 8 lines
virt/kvm/async_pf.c +1 -1
@@ -81,7 +81,7 @@ static void async_pf_execute(struct work_struct *work)
 	might_sleep();
 
 	down_read(&mm->mmap_sem);
-	get_user_pages(current, mm, addr, 1, 1, 0, NULL, NULL);
+	get_user_pages(NULL, mm, addr, 1, 1, 0, NULL, NULL);
 	up_read(&mm->mmap_sem);
 	kvm_async_page_present_sync(vcpu, apf);
 

Thanks, added a Suggested-by for Andrea and applied together with 1/2 to kvm/queue.

(Actually, I'm back from a longish vacation and I have a pretty large queue, so I haven't even compile tested these for now. Once I get round to at least smoke-test them, I'll really push to kvm/queue).

Paolo