|
@@ -160,6 +160,32 @@ static void hmm_invalidate_range(struct hmm *hmm,
|
|
up_read(&hmm->mirrors_sem);
|
|
up_read(&hmm->mirrors_sem);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void hmm_release(struct mmu_notifier *mn, struct mm_struct *mm)
|
|
|
|
+{
|
|
|
|
+ struct hmm_mirror *mirror;
|
|
|
|
+ struct hmm *hmm = mm->hmm;
|
|
|
|
+
|
|
|
|
+ down_write(&hmm->mirrors_sem);
|
|
|
|
+ mirror = list_first_entry_or_null(&hmm->mirrors, struct hmm_mirror,
|
|
|
|
+ list);
|
|
|
|
+ while (mirror) {
|
|
|
|
+ list_del_init(&mirror->list);
|
|
|
|
+ if (mirror->ops->release) {
|
|
|
|
+ /*
|
|
|
|
+ * Drop mirrors_sem so callback can wait on any pending
|
|
|
|
+ * work that might itself trigger mmu_notifier callback
|
|
|
|
+ * and thus would deadlock with us.
|
|
|
|
+ */
|
|
|
|
+ up_write(&hmm->mirrors_sem);
|
|
|
|
+ mirror->ops->release(mirror);
|
|
|
|
+ down_write(&hmm->mirrors_sem);
|
|
|
|
+ }
|
|
|
|
+ mirror = list_first_entry_or_null(&hmm->mirrors,
|
|
|
|
+ struct hmm_mirror, list);
|
|
|
|
+ }
|
|
|
|
+ up_write(&hmm->mirrors_sem);
|
|
|
|
+}
|
|
|
|
+
|
|
static void hmm_invalidate_range_start(struct mmu_notifier *mn,
|
|
static void hmm_invalidate_range_start(struct mmu_notifier *mn,
|
|
struct mm_struct *mm,
|
|
struct mm_struct *mm,
|
|
unsigned long start,
|
|
unsigned long start,
|
|
@@ -185,6 +211,7 @@ static void hmm_invalidate_range_end(struct mmu_notifier *mn,
|
|
}
|
|
}
|
|
|
|
|
|
static const struct mmu_notifier_ops hmm_mmu_notifier_ops = {
|
|
static const struct mmu_notifier_ops hmm_mmu_notifier_ops = {
|
|
|
|
+ .release = hmm_release,
|
|
.invalidate_range_start = hmm_invalidate_range_start,
|
|
.invalidate_range_start = hmm_invalidate_range_start,
|
|
.invalidate_range_end = hmm_invalidate_range_end,
|
|
.invalidate_range_end = hmm_invalidate_range_end,
|
|
};
|
|
};
|
|
@@ -230,7 +257,7 @@ void hmm_mirror_unregister(struct hmm_mirror *mirror)
|
|
struct hmm *hmm = mirror->hmm;
|
|
struct hmm *hmm = mirror->hmm;
|
|
|
|
|
|
down_write(&hmm->mirrors_sem);
|
|
down_write(&hmm->mirrors_sem);
|
|
- list_del(&mirror->list);
|
|
|
|
|
|
+ list_del_init(&mirror->list);
|
|
up_write(&hmm->mirrors_sem);
|
|
up_write(&hmm->mirrors_sem);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(hmm_mirror_unregister);
|
|
EXPORT_SYMBOL(hmm_mirror_unregister);
|