Merge tag 'mips_fixes_5.2_1' of git://git.kernel.org/pub/scm/linux/kernel/git/mips...
[linux-2.6-block.git] / drivers / hv / hv_balloon.c
index 7c6349a50ef173421cdafea3b289ae9868da711e..6fb4ea5f03046a1ee875cac7873cace30fc0bf75 100644 (file)
@@ -1,19 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2012, Microsoft Corporation.
  *
  * Author:
  *   K. Y. Srinivasan <kys@microsoft.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT.  See the GNU General Public License for more
- * details.
- *
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -681,8 +671,13 @@ static struct notifier_block hv_memory_nb = {
 /* Check if the particular page is backed and can be onlined and online it. */
 static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg)
 {
-       if (!has_pfn_is_backed(has, page_to_pfn(pg)))
+       if (!has_pfn_is_backed(has, page_to_pfn(pg))) {
+               if (!PageOffline(pg))
+                       __SetPageOffline(pg);
                return;
+       }
+       if (PageOffline(pg))
+               __ClearPageOffline(pg);
 
        /* This frame is currently backed; online the page. */
        __online_page_set_limits(pg);
@@ -771,7 +766,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
        }
 }
 
-static void hv_online_page(struct page *pg)
+static void hv_online_page(struct page *pg, unsigned int order)
 {
        struct hv_hotadd_state *has;
        unsigned long flags;
@@ -780,10 +775,11 @@ static void hv_online_page(struct page *pg)
        spin_lock_irqsave(&dm_device.ha_lock, flags);
        list_for_each_entry(has, &dm_device.ha_region_list, list) {
                /* The page belongs to a different HAS. */
-               if ((pfn < has->start_pfn) || (pfn >= has->end_pfn))
+               if ((pfn < has->start_pfn) ||
+                               (pfn + (1UL << order) > has->end_pfn))
                        continue;
 
-               hv_page_online_one(has, pg);
+               hv_bring_pgs_online(has, pfn, 1UL << order);
                break;
        }
        spin_unlock_irqrestore(&dm_device.ha_lock, flags);
@@ -1201,6 +1197,7 @@ static void free_balloon_pages(struct hv_dynmem_device *dm,
 
        for (i = 0; i < num_pages; i++) {
                pg = pfn_to_page(i + start_frame);
+               __ClearPageOffline(pg);
                __free_page(pg);
                dm->num_pages_ballooned--;
        }
@@ -1213,7 +1210,7 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm,
                                        struct dm_balloon_response *bl_resp,
                                        int alloc_unit)
 {
-       unsigned int i = 0;
+       unsigned int i, j;
        struct page *pg;
 
        if (num_pages < alloc_unit)
@@ -1245,6 +1242,10 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm,
                if (alloc_unit != 1)
                        split_page(pg, get_order(alloc_unit << PAGE_SHIFT));
 
+               /* mark all pages offline */
+               for (j = 0; j < (1 << get_order(alloc_unit << PAGE_SHIFT)); j++)
+                       __SetPageOffline(pg + j);
+
                bl_resp->range_count++;
                bl_resp->range_array[i].finfo.start_page =
                        page_to_pfn(pg);