|
@@ -126,10 +126,8 @@ void hmm_mm_destroy(struct mm_struct *mm)
|
|
|
kfree(mm->hmm);
|
|
|
}
|
|
|
|
|
|
-static void hmm_invalidate_range(struct hmm *hmm,
|
|
|
- enum hmm_update_type action,
|
|
|
- unsigned long start,
|
|
|
- unsigned long end)
|
|
|
+static int hmm_invalidate_range(struct hmm *hmm,
|
|
|
+ const struct hmm_update *update)
|
|
|
{
|
|
|
struct hmm_mirror *mirror;
|
|
|
struct hmm_range *range;
|
|
@@ -138,22 +136,30 @@ static void hmm_invalidate_range(struct hmm *hmm,
|
|
|
list_for_each_entry(range, &hmm->ranges, list) {
|
|
|
unsigned long addr, idx, npages;
|
|
|
|
|
|
- if (end < range->start || start >= range->end)
|
|
|
+ if (update->end < range->start || update->start >= range->end)
|
|
|
continue;
|
|
|
|
|
|
range->valid = false;
|
|
|
- addr = max(start, range->start);
|
|
|
+ addr = max(update->start, range->start);
|
|
|
idx = (addr - range->start) >> PAGE_SHIFT;
|
|
|
- npages = (min(range->end, end) - addr) >> PAGE_SHIFT;
|
|
|
+ npages = (min(range->end, update->end) - addr) >> PAGE_SHIFT;
|
|
|
memset(&range->pfns[idx], 0, sizeof(*range->pfns) * npages);
|
|
|
}
|
|
|
spin_unlock(&hmm->lock);
|
|
|
|
|
|
down_read(&hmm->mirrors_sem);
|
|
|
- list_for_each_entry(mirror, &hmm->mirrors, list)
|
|
|
- mirror->ops->sync_cpu_device_pagetables(mirror, action,
|
|
|
- start, end);
|
|
|
+ list_for_each_entry(mirror, &hmm->mirrors, list) {
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = mirror->ops->sync_cpu_device_pagetables(mirror, update);
|
|
|
+ if (!update->blockable && ret == -EAGAIN) {
|
|
|
+ up_read(&hmm->mirrors_sem);
|
|
|
+ return -EAGAIN;
|
|
|
+ }
|
|
|
+ }
|
|
|
up_read(&hmm->mirrors_sem);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static void hmm_release(struct mmu_notifier *mn, struct mm_struct *mm)
|
|
@@ -202,11 +208,16 @@ static void hmm_invalidate_range_end(struct mmu_notifier *mn,
|
|
|
unsigned long start,
|
|
|
unsigned long end)
|
|
|
{
|
|
|
+ struct hmm_update update;
|
|
|
struct hmm *hmm = mm->hmm;
|
|
|
|
|
|
VM_BUG_ON(!hmm);
|
|
|
|
|
|
- hmm_invalidate_range(mm->hmm, HMM_UPDATE_INVALIDATE, start, end);
|
|
|
+ update.start = start;
|
|
|
+ update.end = end;
|
|
|
+ update.event = HMM_UPDATE_INVALIDATE;
|
|
|
+ update.blockable = true;
|
|
|
+ hmm_invalidate_range(hmm, &update);
|
|
|
}
|
|
|
|
|
|
static const struct mmu_notifier_ops hmm_mmu_notifier_ops = {
|