@@ -494,6 +494,7 @@ typedef void (*on_lock_fn_t)(struct kvm *kvm, unsigned long start,
struct kvm_useraddr_range {
unsigned long start;
unsigned long end;
+ struct inode *inode;
pte_t pte;
gfn_handler_t handler;
on_lock_fn_t on_lock;
@@ -544,14 +545,27 @@ static __always_inline int __kvm_handle_useraddr_range(struct kvm *kvm,
struct interval_tree_node *node;
slots = __kvm_memslots(kvm, i);
- useraddr_tree = &slots->hva_tree;
+ useraddr_tree = range->inode ? &slots->ofs_tree : &slots->hva_tree;
kvm_for_each_memslot_in_useraddr_range(node, useraddr_tree,
range->start, range->end - 1) {
unsigned long useraddr_start, useraddr_end;
+ unsigned long useraddr_base;
+
+ if (range->inode) {
+ slot = container_of(node, struct kvm_memory_slot,
+ ofs_node[slots->node_idx]);
+ if (!slot->file ||
+ slot->file->f_inode != range->inode)
+ continue;
+ useraddr_base = slot->ofs;
+ } else {
+ slot = container_of(node, struct kvm_memory_slot,
+ hva_node[slots->node_idx]);
+ useraddr_base = slot->userspace_addr;
+ }
- slot = container_of(node, struct kvm_memory_slot, hva_node[slots->node_idx]);
- useraddr_start = max(range->start, slot->userspace_addr);
- useraddr_end = min(range->end, slot->userspace_addr +
+ useraddr_start = max(range->start, useraddr_base);
+ useraddr_end = min(range->end, useraddr_base +
(slot->npages << PAGE_SHIFT));
/*
@@ -568,10 +582,10 @@ static __always_inline int __kvm_handle_useraddr_range(struct kvm *kvm,
* {gfn_start, gfn_start+1, ..., gfn_end-1}.
*/
gfn_range.start = useraddr_to_gfn_memslot(useraddr_start,
- slot, true);
+ slot, !range->inode);
gfn_range.end = useraddr_to_gfn_memslot(
useraddr_end + PAGE_SIZE - 1,
- slot, true);
+ slot, !range->inode);
gfn_range.slot = slot;
if (!locked) {
@@ -613,6 +627,7 @@ static __always_inline int kvm_handle_hva_range(struct mmu_notifier *mn,
.on_lock = (void *)kvm_null_fn,
.flush_on_ret = true,
.may_block = false,
+ .inode = NULL,
};
return __kvm_handle_useraddr_range(kvm, &range);
@@ -632,6 +647,7 @@ static __always_inline int kvm_handle_hva_range_no_flush(struct mmu_notifier *mn
.on_lock = (void *)kvm_null_fn,
.flush_on_ret = false,
.may_block = false,
+ .inode = NULL,
};
return __kvm_handle_useraddr_range(kvm, &range);
@@ -700,6 +716,7 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
.on_lock = kvm_inc_notifier_count,
.flush_on_ret = true,
.may_block = mmu_notifier_range_blockable(range),
+ .inode = NULL,
};
trace_kvm_unmap_hva_range(range->start, range->end);
@@ -751,6 +768,7 @@ static void kvm_mmu_notifier_invalidate_range_end(struct mmu_notifier *mn,
.on_lock = kvm_dec_notifier_count,
.flush_on_ret = false,
.may_block = mmu_notifier_range_blockable(range),
+ .inode = NULL,
};
bool wake;