diff options
| author | Mark Brown <broonie@kernel.org> | 2020-12-28 17:20:00 +0300 | 
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2020-12-28 17:20:00 +0300 | 
| commit | 2ae6f64ce1ce304b502461fdfe0b96c8171ae2cc (patch) | |
| tree | 88e987c447daf2c29e2d4c15e58d1029b0cc78c2 /drivers/xen/grant-table.c | |
| parent | 3b66e4a8e58a85af3212c7117d7a29c9ef6679a2 (diff) | |
| parent | 5c8fe583cce542aa0b84adc939ce85293de36e5e (diff) | |
| download | linux-2ae6f64ce1ce304b502461fdfe0b96c8171ae2cc.tar.xz | |
Merge tag 'v5.11-rc1' into regulator-5.11
Linux 5.11-rc1
Diffstat (limited to 'drivers/xen/grant-table.c')
| -rw-r--r-- | drivers/xen/grant-table.c | 123 | 
1 files changed, 123 insertions, 0 deletions
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c index 523dcdf39cc9..3729bea0c989 100644 --- a/drivers/xen/grant-table.c +++ b/drivers/xen/grant-table.c @@ -813,6 +813,129 @@ int gnttab_alloc_pages(int nr_pages, struct page **pages)  }  EXPORT_SYMBOL_GPL(gnttab_alloc_pages); +#ifdef CONFIG_XEN_UNPOPULATED_ALLOC +static inline void cache_init(struct gnttab_page_cache *cache) +{ +	cache->pages = NULL; +} + +static inline bool cache_empty(struct gnttab_page_cache *cache) +{ +	return !cache->pages; +} + +static inline struct page *cache_deq(struct gnttab_page_cache *cache) +{ +	struct page *page; + +	page = cache->pages; +	cache->pages = page->zone_device_data; + +	return page; +} + +static inline void cache_enq(struct gnttab_page_cache *cache, struct page *page) +{ +	page->zone_device_data = cache->pages; +	cache->pages = page; +} +#else +static inline void cache_init(struct gnttab_page_cache *cache) +{ +	INIT_LIST_HEAD(&cache->pages); +} + +static inline bool cache_empty(struct gnttab_page_cache *cache) +{ +	return list_empty(&cache->pages); +} + +static inline struct page *cache_deq(struct gnttab_page_cache *cache) +{ +	struct page *page; + +	page = list_first_entry(&cache->pages, struct page, lru); +	list_del(&page->lru); + +	return page; +} + +static inline void cache_enq(struct gnttab_page_cache *cache, struct page *page) +{ +	list_add(&page->lru, &cache->pages); +} +#endif + +void gnttab_page_cache_init(struct gnttab_page_cache *cache) +{ +	spin_lock_init(&cache->lock); +	cache_init(cache); +	cache->num_pages = 0; +} +EXPORT_SYMBOL_GPL(gnttab_page_cache_init); + +int gnttab_page_cache_get(struct gnttab_page_cache *cache, struct page **page) +{ +	unsigned long flags; + +	spin_lock_irqsave(&cache->lock, flags); + +	if (cache_empty(cache)) { +		spin_unlock_irqrestore(&cache->lock, flags); +		return gnttab_alloc_pages(1, page); +	} + +	page[0] = cache_deq(cache); +	cache->num_pages--; + +	spin_unlock_irqrestore(&cache->lock, flags); + +	return 0; +} +EXPORT_SYMBOL_GPL(gnttab_page_cache_get); + +void gnttab_page_cache_put(struct gnttab_page_cache *cache, struct page **page, +			   unsigned int num) +{ +	unsigned long flags; +	unsigned int i; + +	spin_lock_irqsave(&cache->lock, flags); + +	for (i = 0; i < num; i++) +		cache_enq(cache, page[i]); +	cache->num_pages += num; + +	spin_unlock_irqrestore(&cache->lock, flags); +} +EXPORT_SYMBOL_GPL(gnttab_page_cache_put); + +void gnttab_page_cache_shrink(struct gnttab_page_cache *cache, unsigned int num) +{ +	struct page *page[10]; +	unsigned int i = 0; +	unsigned long flags; + +	spin_lock_irqsave(&cache->lock, flags); + +	while (cache->num_pages > num) { +		page[i] = cache_deq(cache); +		cache->num_pages--; +		if (++i == ARRAY_SIZE(page)) { +			spin_unlock_irqrestore(&cache->lock, flags); +			gnttab_free_pages(i, page); +			i = 0; +			spin_lock_irqsave(&cache->lock, flags); +		} +	} + +	spin_unlock_irqrestore(&cache->lock, flags); + +	if (i != 0) +		gnttab_free_pages(i, page); +} +EXPORT_SYMBOL_GPL(gnttab_page_cache_shrink); +  void gnttab_pages_clear_private(int nr_pages, struct page **pages)  {  	int i;  | 
