Merge tag 'asoc-v5.4-2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[linux-2.6-block.git] / mm / vmalloc.c
index 4fa8d84599b0bad60d03c87243c9cf97ec9bb52e..7ba11e12a11f33b38a007a038bbfc7dee2fe48b3 100644 (file)
@@ -1258,6 +1258,12 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)
        if (unlikely(valist == NULL))
                return false;
 
+       /*
+        * First make sure the mappings are removed from all page-tables
+        * before they are freed.
+        */
+       vmalloc_sync_all();
+
        /*
         * TODO: to calculate a flush range without looping.
         * The list can be up to lazy_max_pages() elements.
@@ -3038,6 +3044,9 @@ EXPORT_SYMBOL(remap_vmalloc_range);
 /*
  * Implement a stub for vmalloc_sync_all() if the architecture chose not to
  * have one.
+ *
+ * The purpose of this function is to make sure the vmalloc area
+ * mappings are identical in all page-tables in the system.
  */
 void __weak vmalloc_sync_all(void)
 {
@@ -3269,10 +3278,20 @@ retry:
                if (va == NULL)
                        goto overflow;
 
+               /*
+                * If required width exeeds current VA block, move
+                * base downwards and then recheck.
+                */
+               if (base + end > va->va_end) {
+                       base = pvm_determine_end_from_reverse(&va, align) - end;
+                       term_area = area;
+                       continue;
+               }
+
                /*
                 * If this VA does not fit, move base downwards and recheck.
                 */
-               if (base + start < va->va_start || base + end > va->va_end) {
+               if (base + start < va->va_start) {
                        va = node_to_va(rb_prev(&va->rb_node));
                        base = pvm_determine_end_from_reverse(&va, align) - end;
                        term_area = area;