return last_lower; /* Returns NULL if there is no overlap */
 }
 
-static struct memtype *memtype_rb_exact_match(struct rb_root *root,
-                               u64 start, u64 end)
+enum {
+       MEMTYPE_EXACT_MATCH     = 0,
+       MEMTYPE_END_MATCH       = 1
+};
+
+static struct memtype *memtype_rb_match(struct rb_root *root,
+                               u64 start, u64 end, int match_type)
 {
        struct memtype *match;
 
        while (match != NULL && match->start < end) {
                struct rb_node *node;
 
-               if (match->start == start && match->end == end)
+               if ((match_type == MEMTYPE_EXACT_MATCH) &&
+                   (match->start == start) && (match->end == end))
+                       return match;
+
+               if ((match_type == MEMTYPE_END_MATCH) &&
+                   (match->start < start) && (match->end == end))
                        return match;
 
                node = rb_next(&match->rb);
                        match = NULL;
        }
 
-       return NULL; /* Returns NULL if there is no exact match */
+       return NULL; /* Returns NULL if there is no match */
 }
 
 static int memtype_rb_check_conflict(struct rb_root *root,
 {
        struct memtype *data;
 
-       data = memtype_rb_exact_match(&memtype_rbroot, start, end);
-       if (!data)
-               goto out;
+       /*
+        * Since the memtype_rbroot tree allows overlapping ranges,
+        * rbt_memtype_erase() checks with EXACT_MATCH first, i.e. free
+        * a whole node for the munmap case.  If no such entry is found,
+        * it then checks with END_MATCH, i.e. shrink the size of a node
+        * from the end for the mremap case.
+        */
+       data = memtype_rb_match(&memtype_rbroot, start, end,
+                               MEMTYPE_EXACT_MATCH);
+       if (!data) {
+               data = memtype_rb_match(&memtype_rbroot, start, end,
+                                       MEMTYPE_END_MATCH);
+               if (!data)
+                       return ERR_PTR(-EINVAL);
+       }
+
+       if (data->start == start) {
+               /* munmap: erase this node */
+               rb_erase_augmented(&data->rb, &memtype_rbroot,
+                                       &memtype_rb_augment_cb);
+       } else {
+               /* mremap: update the end value of this node */
+               rb_erase_augmented(&data->rb, &memtype_rbroot,
+                                       &memtype_rb_augment_cb);
+               data->end = start;
+               data->subtree_max_end = data->end;
+               memtype_rb_insert(&memtype_rbroot, data);
+               return NULL;
+       }
 
-       rb_erase_augmented(&data->rb, &memtype_rbroot, &memtype_rb_augment_cb);
-out:
        return data;
 }