Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2 * linux/mm/page_isolation.c
  3 */
  4
  5#include <linux/mm.h>
  6#include <linux/page-isolation.h>
  7#include <linux/pageblock-flags.h>
  8#include "internal.h"
  9
 10static inline struct page *
 11__first_valid_page(unsigned long pfn, unsigned long nr_pages)
 12{
 13	int i;
 14	for (i = 0; i < nr_pages; i++)
 15		if (pfn_valid_within(pfn + i))
 16			break;
 17	if (unlikely(i == nr_pages))
 18		return NULL;
 19	return pfn_to_page(pfn + i);
 20}
 21
 22/*
 23 * start_isolate_page_range() -- make page-allocation-type of range of pages
 24 * to be MIGRATE_ISOLATE.
 25 * @start_pfn: The lower PFN of the range to be isolated.
 26 * @end_pfn: The upper PFN of the range to be isolated.
 
 27 *
 28 * Making page-allocation-type to be MIGRATE_ISOLATE means free pages in
 29 * the range will never be allocated. Any free pages and pages freed in the
 30 * future will not be allocated again.
 31 *
 32 * start_pfn/end_pfn must be aligned to pageblock_order.
 33 * Returns 0 on success and -EBUSY if any part of range cannot be isolated.
 34 */
 35int
 36start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn)
 37{
 38	unsigned long pfn;
 39	unsigned long undo_pfn;
 40	struct page *page;
 41
 42	BUG_ON((start_pfn) & (pageblock_nr_pages - 1));
 43	BUG_ON((end_pfn) & (pageblock_nr_pages - 1));
 44
 45	for (pfn = start_pfn;
 46	     pfn < end_pfn;
 47	     pfn += pageblock_nr_pages) {
 48		page = __first_valid_page(pfn, pageblock_nr_pages);
 49		if (page && set_migratetype_isolate(page)) {
 50			undo_pfn = pfn;
 51			goto undo;
 52		}
 53	}
 54	return 0;
 55undo:
 56	for (pfn = start_pfn;
 57	     pfn < undo_pfn;
 58	     pfn += pageblock_nr_pages)
 59		unset_migratetype_isolate(pfn_to_page(pfn));
 60
 61	return -EBUSY;
 62}
 63
 64/*
 65 * Make isolated pages available again.
 66 */
 67int
 68undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn)
 69{
 70	unsigned long pfn;
 71	struct page *page;
 72	BUG_ON((start_pfn) & (pageblock_nr_pages - 1));
 73	BUG_ON((end_pfn) & (pageblock_nr_pages - 1));
 74	for (pfn = start_pfn;
 75	     pfn < end_pfn;
 76	     pfn += pageblock_nr_pages) {
 77		page = __first_valid_page(pfn, pageblock_nr_pages);
 78		if (!page || get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
 79			continue;
 80		unset_migratetype_isolate(page);
 81	}
 82	return 0;
 83}
 84/*
 85 * Test all pages in the range is free(means isolated) or not.
 86 * all pages in [start_pfn...end_pfn) must be in the same zone.
 87 * zone->lock must be held before call this.
 88 *
 89 * Returns 1 if all pages in the range is isolated.
 90 */
 91static int
 92__test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn)
 93{
 94	struct page *page;
 95
 96	while (pfn < end_pfn) {
 97		if (!pfn_valid_within(pfn)) {
 98			pfn++;
 99			continue;
100		}
101		page = pfn_to_page(pfn);
102		if (PageBuddy(page))
103			pfn += 1 << page_order(page);
104		else if (page_count(page) == 0 &&
105				page_private(page) == MIGRATE_ISOLATE)
106			pfn += 1;
107		else
108			break;
109	}
110	if (pfn < end_pfn)
111		return 0;
112	return 1;
113}
114
115int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
116{
117	unsigned long pfn, flags;
118	struct page *page;
119	struct zone *zone;
120	int ret;
121
122	/*
123	 * Note: pageblock_nr_page != MAX_ORDER. Then, chunks of free page
124	 * is not aligned to pageblock_nr_pages.
125	 * Then we just check pagetype fist.
126	 */
127	for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
128		page = __first_valid_page(pfn, pageblock_nr_pages);
129		if (page && get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
130			break;
131	}
132	page = __first_valid_page(start_pfn, end_pfn - start_pfn);
133	if ((pfn < end_pfn) || !page)
134		return -EBUSY;
135	/* Check all pages are free or Marked as ISOLATED */
136	zone = page_zone(page);
137	spin_lock_irqsave(&zone->lock, flags);
138	ret = __test_page_isolated_in_pageblock(start_pfn, end_pfn);
139	spin_unlock_irqrestore(&zone->lock, flags);
140	return ret ? 0 : -EBUSY;
141}
v3.5.6
  1/*
  2 * linux/mm/page_isolation.c
  3 */
  4
  5#include <linux/mm.h>
  6#include <linux/page-isolation.h>
  7#include <linux/pageblock-flags.h>
  8#include "internal.h"
  9
 10static inline struct page *
 11__first_valid_page(unsigned long pfn, unsigned long nr_pages)
 12{
 13	int i;
 14	for (i = 0; i < nr_pages; i++)
 15		if (pfn_valid_within(pfn + i))
 16			break;
 17	if (unlikely(i == nr_pages))
 18		return NULL;
 19	return pfn_to_page(pfn + i);
 20}
 21
 22/*
 23 * start_isolate_page_range() -- make page-allocation-type of range of pages
 24 * to be MIGRATE_ISOLATE.
 25 * @start_pfn: The lower PFN of the range to be isolated.
 26 * @end_pfn: The upper PFN of the range to be isolated.
 27 * @migratetype: migrate type to set in error recovery.
 28 *
 29 * Making page-allocation-type to be MIGRATE_ISOLATE means free pages in
 30 * the range will never be allocated. Any free pages and pages freed in the
 31 * future will not be allocated again.
 32 *
 33 * start_pfn/end_pfn must be aligned to pageblock_order.
 34 * Returns 0 on success and -EBUSY if any part of range cannot be isolated.
 35 */
 36int start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
 37			     unsigned migratetype)
 38{
 39	unsigned long pfn;
 40	unsigned long undo_pfn;
 41	struct page *page;
 42
 43	BUG_ON((start_pfn) & (pageblock_nr_pages - 1));
 44	BUG_ON((end_pfn) & (pageblock_nr_pages - 1));
 45
 46	for (pfn = start_pfn;
 47	     pfn < end_pfn;
 48	     pfn += pageblock_nr_pages) {
 49		page = __first_valid_page(pfn, pageblock_nr_pages);
 50		if (page && set_migratetype_isolate(page)) {
 51			undo_pfn = pfn;
 52			goto undo;
 53		}
 54	}
 55	return 0;
 56undo:
 57	for (pfn = start_pfn;
 58	     pfn < undo_pfn;
 59	     pfn += pageblock_nr_pages)
 60		unset_migratetype_isolate(pfn_to_page(pfn), migratetype);
 61
 62	return -EBUSY;
 63}
 64
 65/*
 66 * Make isolated pages available again.
 67 */
 68int undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn,
 69			    unsigned migratetype)
 70{
 71	unsigned long pfn;
 72	struct page *page;
 73	BUG_ON((start_pfn) & (pageblock_nr_pages - 1));
 74	BUG_ON((end_pfn) & (pageblock_nr_pages - 1));
 75	for (pfn = start_pfn;
 76	     pfn < end_pfn;
 77	     pfn += pageblock_nr_pages) {
 78		page = __first_valid_page(pfn, pageblock_nr_pages);
 79		if (!page || get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
 80			continue;
 81		unset_migratetype_isolate(page, migratetype);
 82	}
 83	return 0;
 84}
 85/*
 86 * Test all pages in the range is free(means isolated) or not.
 87 * all pages in [start_pfn...end_pfn) must be in the same zone.
 88 * zone->lock must be held before call this.
 89 *
 90 * Returns 1 if all pages in the range are isolated.
 91 */
 92static int
 93__test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn)
 94{
 95	struct page *page;
 96
 97	while (pfn < end_pfn) {
 98		if (!pfn_valid_within(pfn)) {
 99			pfn++;
100			continue;
101		}
102		page = pfn_to_page(pfn);
103		if (PageBuddy(page))
104			pfn += 1 << page_order(page);
105		else if (page_count(page) == 0 &&
106				page_private(page) == MIGRATE_ISOLATE)
107			pfn += 1;
108		else
109			break;
110	}
111	if (pfn < end_pfn)
112		return 0;
113	return 1;
114}
115
116int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn)
117{
118	unsigned long pfn, flags;
119	struct page *page;
120	struct zone *zone;
121	int ret;
122
123	/*
124	 * Note: pageblock_nr_page != MAX_ORDER. Then, chunks of free page
125	 * is not aligned to pageblock_nr_pages.
126	 * Then we just check pagetype fist.
127	 */
128	for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) {
129		page = __first_valid_page(pfn, pageblock_nr_pages);
130		if (page && get_pageblock_migratetype(page) != MIGRATE_ISOLATE)
131			break;
132	}
133	page = __first_valid_page(start_pfn, end_pfn - start_pfn);
134	if ((pfn < end_pfn) || !page)
135		return -EBUSY;
136	/* Check all pages are free or Marked as ISOLATED */
137	zone = page_zone(page);
138	spin_lock_irqsave(&zone->lock, flags);
139	ret = __test_page_isolated_in_pageblock(start_pfn, end_pfn);
140	spin_unlock_irqrestore(&zone->lock, flags);
141	return ret ? 0 : -EBUSY;
142}