|
@@ -5297,12 +5297,65 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
|
|
* page allocater never alloc memory from ISOLATE block.
|
|
* page allocater never alloc memory from ISOLATE block.
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+static int
|
|
|
|
+__count_immobile_pages(struct zone *zone, struct page *page, int count)
|
|
|
|
+{
|
|
|
|
+ unsigned long pfn, iter, found;
|
|
|
|
+ /*
|
|
|
|
+ * For avoiding noise data, lru_add_drain_all() should be called
|
|
|
|
+ * If ZONE_MOVABLE, the zone never contains immobile pages
|
|
|
|
+ */
|
|
|
|
+ if (zone_idx(zone) == ZONE_MOVABLE)
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE)
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ pfn = page_to_pfn(page);
|
|
|
|
+ for (found = 0, iter = 0; iter < pageblock_nr_pages; iter++) {
|
|
|
|
+ unsigned long check = pfn + iter;
|
|
|
|
+
|
|
|
|
+ if (!pfn_valid_within(check)) {
|
|
|
|
+ iter++;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ page = pfn_to_page(check);
|
|
|
|
+ if (!page_count(page)) {
|
|
|
|
+ if (PageBuddy(page))
|
|
|
|
+ iter += (1 << page_order(page)) - 1;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ if (!PageLRU(page))
|
|
|
|
+ found++;
|
|
|
|
+ /*
|
|
|
|
+ * If there are RECLAIMABLE pages, we need to check it.
|
|
|
|
+ * But now, memory offline itself doesn't call shrink_slab()
|
|
|
|
+ * and it still to be fixed.
|
|
|
|
+ */
|
|
|
|
+ /*
|
|
|
|
+ * If the page is not RAM, page_count()should be 0.
|
|
|
|
+ * we don't need more check. This is an _used_ not-movable page.
|
|
|
|
+ *
|
|
|
|
+ * The problematic thing here is PG_reserved pages. PG_reserved
|
|
|
|
+ * is set to both of a memory hole page and a _used_ kernel
|
|
|
|
+ * page at boot.
|
|
|
|
+ */
|
|
|
|
+ if (found > count)
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+bool is_pageblock_removable_nolock(struct page *page)
|
|
|
|
+{
|
|
|
|
+ struct zone *zone = page_zone(page);
|
|
|
|
+ return __count_immobile_pages(zone, page, 0);
|
|
|
|
+}
|
|
|
|
+
|
|
int set_migratetype_isolate(struct page *page)
|
|
int set_migratetype_isolate(struct page *page)
|
|
{
|
|
{
|
|
struct zone *zone;
|
|
struct zone *zone;
|
|
- struct page *curr_page;
|
|
|
|
- unsigned long flags, pfn, iter;
|
|
|
|
- unsigned long immobile = 0;
|
|
|
|
|
|
+ unsigned long flags, pfn;
|
|
struct memory_isolate_notify arg;
|
|
struct memory_isolate_notify arg;
|
|
int notifier_ret;
|
|
int notifier_ret;
|
|
int ret = -EBUSY;
|
|
int ret = -EBUSY;
|
|
@@ -5312,11 +5365,6 @@ int set_migratetype_isolate(struct page *page)
|
|
zone_idx = zone_idx(zone);
|
|
zone_idx = zone_idx(zone);
|
|
|
|
|
|
spin_lock_irqsave(&zone->lock, flags);
|
|
spin_lock_irqsave(&zone->lock, flags);
|
|
- if (get_pageblock_migratetype(page) == MIGRATE_MOVABLE ||
|
|
|
|
- zone_idx == ZONE_MOVABLE) {
|
|
|
|
- ret = 0;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
|
|
|
|
pfn = page_to_pfn(page);
|
|
pfn = page_to_pfn(page);
|
|
arg.start_pfn = pfn;
|
|
arg.start_pfn = pfn;
|
|
@@ -5338,21 +5386,18 @@ int set_migratetype_isolate(struct page *page)
|
|
notifier_ret = notifier_to_errno(notifier_ret);
|
|
notifier_ret = notifier_to_errno(notifier_ret);
|
|
if (notifier_ret)
|
|
if (notifier_ret)
|
|
goto out;
|
|
goto out;
|
|
-
|
|
|
|
- for (iter = pfn; iter < (pfn + pageblock_nr_pages); iter++) {
|
|
|
|
- if (!pfn_valid_within(pfn))
|
|
|
|
- continue;
|
|
|
|
-
|
|
|
|
- curr_page = pfn_to_page(iter);
|
|
|
|
- if (!page_count(curr_page) || PageLRU(curr_page))
|
|
|
|
- continue;
|
|
|
|
-
|
|
|
|
- immobile++;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (arg.pages_found == immobile)
|
|
|
|
|
|
+ /*
|
|
|
|
+ * FIXME: Now, memory hotplug doesn't call shrink_slab() by itself.
|
|
|
|
+ * We just check MOVABLE pages.
|
|
|
|
+ */
|
|
|
|
+ if (__count_immobile_pages(zone, page, arg.pages_found))
|
|
ret = 0;
|
|
ret = 0;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * immobile means "not-on-lru" paes. If immobile is larger than
|
|
|
|
+ * removable-by-driver pages reported by notifier, we'll fail.
|
|
|
|
+ */
|
|
|
|
+
|
|
out:
|
|
out:
|
|
if (!ret) {
|
|
if (!ret) {
|
|
set_pageblock_migratetype(page, MIGRATE_ISOLATE);
|
|
set_pageblock_migratetype(page, MIGRATE_ISOLATE);
|