Skip to content

Commit c01cbba

Browse files
Jérôme Glissetorvalds
authored andcommitted
mm/hmm: unregister mmu_notifier when last HMM client quit
This code was lost in translation at one point. This properly call mmu_notifier_unregister_no_release() once last user is gone. This fix the zombie mm_struct as without this patch we do not drop the refcount we have on it. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Jérôme Glisse <[email protected]> Cc: Evgeny Baskakov <[email protected]> Cc: Ralph Campbell <[email protected]> Cc: Mark Hairgrove <[email protected]> Cc: John Hubbard <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent e140151 commit c01cbba

File tree

1 file changed

+35
-3
lines changed

1 file changed

+35
-3
lines changed

mm/hmm.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,24 @@ int hmm_mirror_register(struct hmm_mirror *mirror, struct mm_struct *mm)
233233
if (!mm || !mirror || !mirror->ops)
234234
return -EINVAL;
235235

236+
again:
236237
mirror->hmm = hmm_register(mm);
237238
if (!mirror->hmm)
238239
return -ENOMEM;
239240

240241
down_write(&mirror->hmm->mirrors_sem);
241-
list_add(&mirror->list, &mirror->hmm->mirrors);
242-
up_write(&mirror->hmm->mirrors_sem);
242+
if (mirror->hmm->mm == NULL) {
243+
/*
244+
* A racing hmm_mirror_unregister() is about to destroy the hmm
245+
* struct. Try again to allocate a new one.
246+
*/
247+
up_write(&mirror->hmm->mirrors_sem);
248+
mirror->hmm = NULL;
249+
goto again;
250+
} else {
251+
list_add(&mirror->list, &mirror->hmm->mirrors);
252+
up_write(&mirror->hmm->mirrors_sem);
253+
}
243254

244255
return 0;
245256
}
@@ -254,11 +265,32 @@ EXPORT_SYMBOL(hmm_mirror_register);
254265
*/
255266
void hmm_mirror_unregister(struct hmm_mirror *mirror)
256267
{
257-
struct hmm *hmm = mirror->hmm;
268+
bool should_unregister = false;
269+
struct mm_struct *mm;
270+
struct hmm *hmm;
271+
272+
if (mirror->hmm == NULL)
273+
return;
258274

275+
hmm = mirror->hmm;
259276
down_write(&hmm->mirrors_sem);
260277
list_del_init(&mirror->list);
278+
should_unregister = list_empty(&hmm->mirrors);
279+
mirror->hmm = NULL;
280+
mm = hmm->mm;
281+
hmm->mm = NULL;
261282
up_write(&hmm->mirrors_sem);
283+
284+
if (!should_unregister || mm == NULL)
285+
return;
286+
287+
spin_lock(&mm->page_table_lock);
288+
if (mm->hmm == hmm)
289+
mm->hmm = NULL;
290+
spin_unlock(&mm->page_table_lock);
291+
292+
mmu_notifier_unregister_no_release(&hmm->mmu_notifier, mm);
293+
kfree(hmm);
262294
}
263295
EXPORT_SYMBOL(hmm_mirror_unregister);
264296

0 commit comments

Comments
 (0)