Blame view

mm/balloon_compaction.c 8.23 KB
457c89965   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
18468d93e   Rafael Aquini   mm: introduce a c...
2
3
4
5
6
7
8
9
10
11
12
  /*
   * mm/balloon_compaction.c
   *
   * Common interface for making balloon pages movable by compaction.
   *
   * Copyright (C) 2012, Red Hat, Inc.  Rafael Aquini <aquini@redhat.com>
   */
  #include <linux/mm.h>
  #include <linux/slab.h>
  #include <linux/export.h>
  #include <linux/balloon_compaction.h>
418a3ab1e   Nadav Amit   mm/balloon_compac...
13
14
15
16
17
18
19
20
21
22
  static void balloon_page_enqueue_one(struct balloon_dev_info *b_dev_info,
  				     struct page *page)
  {
  	/*
  	 * Block others from accessing the 'page' when we get around to
  	 * establishing additional references. We should be the only one
  	 * holding a reference to the 'page' at this point. If we are not, then
  	 * memory corruption is possible and we should stop execution.
  	 */
  	BUG_ON(!trylock_page(page));
418a3ab1e   Nadav Amit   mm/balloon_compac...
23
24
25
26
27
28
29
30
31
32
33
  	balloon_page_insert(b_dev_info, page);
  	unlock_page(page);
  	__count_vm_event(BALLOON_INFLATE);
  }
  
  /**
   * balloon_page_list_enqueue() - inserts a list of pages into the balloon page
   *				 list.
   * @b_dev_info: balloon device descriptor where we will insert a new page to
   * @pages: pages to enqueue - allocated using balloon_page_alloc.
   *
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
34
35
   * Driver must call this function to properly enqueue balloon pages before
   * definitively removing them from the guest system.
418a3ab1e   Nadav Amit   mm/balloon_compac...
36
37
38
39
40
41
42
43
44
45
46
47
   *
   * Return: number of pages that were enqueued.
   */
  size_t balloon_page_list_enqueue(struct balloon_dev_info *b_dev_info,
  				 struct list_head *pages)
  {
  	struct page *page, *tmp;
  	unsigned long flags;
  	size_t n_pages = 0;
  
  	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
  	list_for_each_entry_safe(page, tmp, pages, lru) {
dd4229067   Wei Wang   mm/balloon_compac...
48
  		list_del(&page->lru);
418a3ab1e   Nadav Amit   mm/balloon_compac...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  		balloon_page_enqueue_one(b_dev_info, page);
  		n_pages++;
  	}
  	spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
  	return n_pages;
  }
  EXPORT_SYMBOL_GPL(balloon_page_list_enqueue);
  
  /**
   * balloon_page_list_dequeue() - removes pages from balloon's page list and
   *				 returns a list of the pages.
   * @b_dev_info: balloon device decriptor where we will grab a page from.
   * @pages: pointer to the list of pages that would be returned to the caller.
   * @n_req_pages: number of requested pages.
   *
   * Driver must call this function to properly de-allocate a previous enlisted
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
65
   * balloon pages before definitively releasing it back to the guest system.
418a3ab1e   Nadav Amit   mm/balloon_compac...
66
67
68
   * This function tries to remove @n_req_pages from the ballooned pages and
   * return them to the caller in the @pages list.
   *
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
69
70
71
   * Note that this function may fail to dequeue some pages even if the balloon
   * isn't empty - since the page list can be temporarily empty due to compaction
   * of isolated pages.
418a3ab1e   Nadav Amit   mm/balloon_compac...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
   *
   * Return: number of pages that were added to the @pages list.
   */
  size_t balloon_page_list_dequeue(struct balloon_dev_info *b_dev_info,
  				 struct list_head *pages, size_t n_req_pages)
  {
  	struct page *page, *tmp;
  	unsigned long flags;
  	size_t n_pages = 0;
  
  	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
  	list_for_each_entry_safe(page, tmp, &b_dev_info->pages, lru) {
  		if (n_pages == n_req_pages)
  			break;
  
  		/*
  		 * Block others from accessing the 'page' while we get around to
  		 * establishing additional references and preparing the 'page'
  		 * to be released by the balloon driver.
  		 */
  		if (!trylock_page(page))
  			continue;
  
  		if (IS_ENABLED(CONFIG_BALLOON_COMPACTION) &&
  		    PageIsolated(page)) {
  			/* raced with isolation */
  			unlock_page(page);
  			continue;
  		}
  		balloon_page_delete(page);
  		__count_vm_event(BALLOON_DEFLATE);
  		list_add(&page->lru, pages);
  		unlock_page(page);
  		n_pages++;
  	}
  	spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
  
  	return n_pages;
  }
  EXPORT_SYMBOL_GPL(balloon_page_list_dequeue);
18468d93e   Rafael Aquini   mm: introduce a c...
112
  /*
c7cdff0e8   Michael S. Tsirkin   virtio_balloon: f...
113
   * balloon_page_alloc - allocates a new page for insertion into the balloon
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
114
   *			page list.
c7cdff0e8   Michael S. Tsirkin   virtio_balloon: f...
115
   *
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
116
117
118
119
120
   * Driver must call this function to properly allocate a new balloon page.
   * Driver must call balloon_page_enqueue before definitively removing the page
   * from the guest system.
   *
   * Return: struct page for the allocated page or NULL on allocation failure.
c7cdff0e8   Michael S. Tsirkin   virtio_balloon: f...
121
122
123
124
   */
  struct page *balloon_page_alloc(void)
  {
  	struct page *page = alloc_page(balloon_mapping_gfp_mask() |
02fa5d7b1   Nadav Amit   mm/balloon_compac...
125
126
  				       __GFP_NOMEMALLOC | __GFP_NORETRY |
  				       __GFP_NOWARN);
c7cdff0e8   Michael S. Tsirkin   virtio_balloon: f...
127
128
129
130
131
  	return page;
  }
  EXPORT_SYMBOL_GPL(balloon_page_alloc);
  
  /*
dd4229067   Wei Wang   mm/balloon_compac...
132
133
   * balloon_page_enqueue - inserts a new page into the balloon page list.
   *
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
134
   * @b_dev_info: balloon device descriptor where we will insert a new page
c7cdff0e8   Michael S. Tsirkin   virtio_balloon: f...
135
   * @page: new page to enqueue - allocated using balloon_page_alloc.
18468d93e   Rafael Aquini   mm: introduce a c...
136
   *
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
137
138
   * Drivers must call this function to properly enqueue a new allocated balloon
   * page before definitively removing the page from the guest system.
dd4229067   Wei Wang   mm/balloon_compac...
139
   *
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
140
141
142
   * Drivers must not call balloon_page_enqueue on pages that have been pushed to
   * a list with balloon_page_push before removing them with balloon_page_pop. To
   * enqueue a list of pages, use balloon_page_list_enqueue instead.
18468d93e   Rafael Aquini   mm: introduce a c...
143
   */
c7cdff0e8   Michael S. Tsirkin   virtio_balloon: f...
144
145
  void balloon_page_enqueue(struct balloon_dev_info *b_dev_info,
  			  struct page *page)
18468d93e   Rafael Aquini   mm: introduce a c...
146
147
  {
  	unsigned long flags;
18468d93e   Rafael Aquini   mm: introduce a c...
148

18468d93e   Rafael Aquini   mm: introduce a c...
149
  	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
418a3ab1e   Nadav Amit   mm/balloon_compac...
150
  	balloon_page_enqueue_one(b_dev_info, page);
18468d93e   Rafael Aquini   mm: introduce a c...
151
  	spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
18468d93e   Rafael Aquini   mm: introduce a c...
152
153
154
155
156
  }
  EXPORT_SYMBOL_GPL(balloon_page_enqueue);
  
  /*
   * balloon_page_dequeue - removes a page from balloon's page list and returns
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
157
   *			  its address to allow the driver to release the page.
18468d93e   Rafael Aquini   mm: introduce a c...
158
159
   * @b_dev_info: balloon device decriptor where we will grab a page from.
   *
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
   * Driver must call this function to properly dequeue a previously enqueued page
   * before definitively releasing it back to the guest system.
   *
   * Caller must perform its own accounting to ensure that this
   * function is called only if some pages are actually enqueued.
   *
   * Note that this function may fail to dequeue some pages even if there are
   * some enqueued pages - since the page list can be temporarily empty due to
   * the compaction of isolated pages.
   *
   * TODO: remove the caller accounting requirements, and allow caller to wait
   * until all pages can be dequeued.
   *
   * Return: struct page for the dequeued page, or NULL if no page was dequeued.
18468d93e   Rafael Aquini   mm: introduce a c...
174
175
176
   */
  struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info)
  {
18468d93e   Rafael Aquini   mm: introduce a c...
177
  	unsigned long flags;
418a3ab1e   Nadav Amit   mm/balloon_compac...
178
179
  	LIST_HEAD(pages);
  	int n_pages;
18468d93e   Rafael Aquini   mm: introduce a c...
180

418a3ab1e   Nadav Amit   mm/balloon_compac...
181
  	n_pages = balloon_page_list_dequeue(b_dev_info, &pages, 1);
18468d93e   Rafael Aquini   mm: introduce a c...
182

418a3ab1e   Nadav Amit   mm/balloon_compac...
183
  	if (n_pages != 1) {
18468d93e   Rafael Aquini   mm: introduce a c...
184
185
  		/*
  		 * If we are unable to dequeue a balloon page because the page
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
186
  		 * list is empty and there are no isolated pages, then something
18468d93e   Rafael Aquini   mm: introduce a c...
187
  		 * went out of track and some balloon pages are lost.
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
188
  		 * BUG() here, otherwise the balloon driver may get stuck in
18468d93e   Rafael Aquini   mm: introduce a c...
189
190
191
192
193
194
195
  		 * an infinite loop while attempting to release all its pages.
  		 */
  		spin_lock_irqsave(&b_dev_info->pages_lock, flags);
  		if (unlikely(list_empty(&b_dev_info->pages) &&
  			     !b_dev_info->isolated_pages))
  			BUG();
  		spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
418a3ab1e   Nadav Amit   mm/balloon_compac...
196
  		return NULL;
18468d93e   Rafael Aquini   mm: introduce a c...
197
  	}
418a3ab1e   Nadav Amit   mm/balloon_compac...
198
  	return list_first_entry(&pages, struct page, lru);
18468d93e   Rafael Aquini   mm: introduce a c...
199
200
201
202
  }
  EXPORT_SYMBOL_GPL(balloon_page_dequeue);
  
  #ifdef CONFIG_BALLOON_COMPACTION
18468d93e   Rafael Aquini   mm: introduce a c...
203

b1123ea6d   Minchan Kim   mm: balloon: use ...
204
  bool balloon_page_isolate(struct page *page, isolate_mode_t mode)
18468d93e   Rafael Aquini   mm: introduce a c...
205
  {
9d1ba8056   Konstantin Khlebnikov   mm/balloon_compac...
206
  	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
18468d93e   Rafael Aquini   mm: introduce a c...
207
  	unsigned long flags;
d6d86c0a7   Konstantin Khlebnikov   mm/balloon_compac...
208

18468d93e   Rafael Aquini   mm: introduce a c...
209
210
211
212
  	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
  	list_del(&page->lru);
  	b_dev_info->isolated_pages++;
  	spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
b1123ea6d   Minchan Kim   mm: balloon: use ...
213
214
  
  	return true;
18468d93e   Rafael Aquini   mm: introduce a c...
215
  }
b1123ea6d   Minchan Kim   mm: balloon: use ...
216
  void balloon_page_putback(struct page *page)
18468d93e   Rafael Aquini   mm: introduce a c...
217
  {
9d1ba8056   Konstantin Khlebnikov   mm/balloon_compac...
218
  	struct balloon_dev_info *b_dev_info = balloon_page_device(page);
18468d93e   Rafael Aquini   mm: introduce a c...
219
  	unsigned long flags;
d6d86c0a7   Konstantin Khlebnikov   mm/balloon_compac...
220

18468d93e   Rafael Aquini   mm: introduce a c...
221
222
223
224
225
  	spin_lock_irqsave(&b_dev_info->pages_lock, flags);
  	list_add(&page->lru, &b_dev_info->pages);
  	b_dev_info->isolated_pages--;
  	spin_unlock_irqrestore(&b_dev_info->pages_lock, flags);
  }
18468d93e   Rafael Aquini   mm: introduce a c...
226
227
  
  /* move_to_new_page() counterpart for a ballooned page */
b1123ea6d   Minchan Kim   mm: balloon: use ...
228
229
230
  int balloon_page_migrate(struct address_space *mapping,
  		struct page *newpage, struct page *page,
  		enum migrate_mode mode)
18468d93e   Rafael Aquini   mm: introduce a c...
231
  {
9d1ba8056   Konstantin Khlebnikov   mm/balloon_compac...
232
  	struct balloon_dev_info *balloon = balloon_page_device(page);
18468d93e   Rafael Aquini   mm: introduce a c...
233

2916ecc0f   Jérôme Glisse   mm/migrate: new m...
234
235
  	/*
  	 * We can not easily support the no copy case here so ignore it as it
cfe61801b   Michael S. Tsirkin   balloon: fix up c...
236
237
  	 * is unlikely to be used with balloon pages. See include/linux/hmm.h
  	 * for a user of the MIGRATE_SYNC_NO_COPY mode.
2916ecc0f   Jérôme Glisse   mm/migrate: new m...
238
239
240
  	 */
  	if (mode == MIGRATE_SYNC_NO_COPY)
  		return -EINVAL;
7db7671f8   Hugh Dickins   mm: page migratio...
241
242
  	VM_BUG_ON_PAGE(!PageLocked(page), page);
  	VM_BUG_ON_PAGE(!PageLocked(newpage), newpage);
18468d93e   Rafael Aquini   mm: introduce a c...
243

b1123ea6d   Minchan Kim   mm: balloon: use ...
244
245
  	return balloon->migratepage(balloon, newpage, page, mode);
  }
18468d93e   Rafael Aquini   mm: introduce a c...
246

b1123ea6d   Minchan Kim   mm: balloon: use ...
247
248
249
250
251
252
  const struct address_space_operations balloon_aops = {
  	.migratepage = balloon_page_migrate,
  	.isolate_page = balloon_page_isolate,
  	.putback_page = balloon_page_putback,
  };
  EXPORT_SYMBOL_GPL(balloon_aops);
18468d93e   Rafael Aquini   mm: introduce a c...
253

18468d93e   Rafael Aquini   mm: introduce a c...
254
  #endif /* CONFIG_BALLOON_COMPACTION */