Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | /* * 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> /* * balloon_devinfo_alloc - allocates a balloon device information descriptor. * @balloon_dev_descriptor: pointer to reference the balloon device which * this struct balloon_dev_info will be servicing. * * Driver must call it to properly allocate and initialize an instance of * struct balloon_dev_info which will be used to reference a balloon device * as well as to keep track of the balloon device page list. */ struct balloon_dev_info *balloon_devinfo_alloc(void *balloon_dev_descriptor) { struct balloon_dev_info *b_dev_info; b_dev_info = kmalloc(sizeof(*b_dev_info), GFP_KERNEL); if (!b_dev_info) return ERR_PTR(-ENOMEM); b_dev_info->balloon_device = balloon_dev_descriptor; b_dev_info->mapping = NULL; b_dev_info->isolated_pages = 0; spin_lock_init(&b_dev_info->pages_lock); INIT_LIST_HEAD(&b_dev_info->pages); return b_dev_info; } EXPORT_SYMBOL_GPL(balloon_devinfo_alloc); /* * balloon_page_enqueue - allocates a new page and inserts it into the balloon * page list. * @b_dev_info: balloon device decriptor where we will insert a new page to * * Driver must call it to properly allocate a new enlisted balloon page * before definetively removing it from the guest system. * This function returns the page address for the recently enqueued page or * NULL in the case we fail to allocate a new page this turn. */ struct page *balloon_page_enqueue(struct balloon_dev_info *b_dev_info) { unsigned long flags; struct page *page = alloc_page(balloon_mapping_gfp_mask() | __GFP_NOMEMALLOC | __GFP_NORETRY); if (!page) return NULL; /* * 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. */ BUG_ON(!trylock_page(page)); spin_lock_irqsave(&b_dev_info->pages_lock, flags); balloon_page_insert(page, b_dev_info->mapping, &b_dev_info->pages); spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); unlock_page(page); return page; } EXPORT_SYMBOL_GPL(balloon_page_enqueue); /* * balloon_page_dequeue - removes a page from balloon's page list and returns * the its address to allow the driver release the page. * @b_dev_info: balloon device decriptor where we will grab a page from. * * Driver must call it to properly de-allocate a previous enlisted balloon page * before definetively releasing it back to the guest system. * This function returns the page address for the recently dequeued page or * NULL in the case we find balloon's page list temporarily empty due to * compaction isolated pages. */ struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info) { struct page *page, *tmp; unsigned long flags; bool dequeued_page; dequeued_page = false; list_for_each_entry_safe(page, tmp, &b_dev_info->pages, lru) { /* * Block others from accessing the 'page' while we get around * establishing additional references and preparing the 'page' * to be released by the balloon driver. */ if (trylock_page(page)) { #ifdef CONFIG_BALLOON_COMPACTION if (!PagePrivate(page)) { /* raced with isolation */ unlock_page(page); continue; } #endif spin_lock_irqsave(&b_dev_info->pages_lock, flags); balloon_page_delete(page); spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); unlock_page(page); dequeued_page = true; break; } } if (!dequeued_page) { /* * If we are unable to dequeue a balloon page because the page * list is empty and there is no isolated pages, then something * went out of track and some balloon pages are lost. * BUG() here, otherwise the balloon driver may get stuck into * 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); page = NULL; } return page; } EXPORT_SYMBOL_GPL(balloon_page_dequeue); #ifdef CONFIG_BALLOON_COMPACTION /* * balloon_mapping_alloc - allocates a special ->mapping for ballooned pages. * @b_dev_info: holds the balloon device information descriptor. * @a_ops: balloon_mapping address_space_operations descriptor. * * Driver must call it to properly allocate and initialize an instance of * struct address_space which will be used as the special page->mapping for * balloon device enlisted page instances. */ struct address_space *balloon_mapping_alloc(struct balloon_dev_info *b_dev_info, const struct address_space_operations *a_ops) { struct address_space *mapping; mapping = kmalloc(sizeof(*mapping), GFP_KERNEL); if (!mapping) return ERR_PTR(-ENOMEM); /* * Give a clean 'zeroed' status to all elements of this special * balloon page->mapping struct address_space instance. */ address_space_init_once(mapping); /* * Set mapping->flags appropriately, to allow balloon pages * ->mapping identification. */ mapping_set_balloon(mapping); mapping_set_gfp_mask(mapping, balloon_mapping_gfp_mask()); /* balloon's page->mapping->a_ops callback descriptor */ mapping->a_ops = a_ops; /* * Establish a pointer reference back to the balloon device descriptor * this particular page->mapping will be servicing. * This is used by compaction / migration procedures to identify and * access the balloon device pageset while isolating / migrating pages. * * As some balloon drivers can register multiple balloon devices * for a single guest, this also helps compaction / migration to * properly deal with multiple balloon pagesets, when required. */ mapping->private_data = b_dev_info; b_dev_info->mapping = mapping; return mapping; } EXPORT_SYMBOL_GPL(balloon_mapping_alloc); static inline void __isolate_balloon_page(struct page *page) { struct balloon_dev_info *b_dev_info = page->mapping->private_data; unsigned long flags; spin_lock_irqsave(&b_dev_info->pages_lock, flags); ClearPagePrivate(page); list_del(&page->lru); b_dev_info->isolated_pages++; spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); } static inline void __putback_balloon_page(struct page *page) { struct balloon_dev_info *b_dev_info = page->mapping->private_data; unsigned long flags; spin_lock_irqsave(&b_dev_info->pages_lock, flags); SetPagePrivate(page); list_add(&page->lru, &b_dev_info->pages); b_dev_info->isolated_pages--; spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); } static inline int __migrate_balloon_page(struct address_space *mapping, struct page *newpage, struct page *page, enum migrate_mode mode) { return page->mapping->a_ops->migratepage(mapping, newpage, page, mode); } /* __isolate_lru_page() counterpart for a ballooned page */ bool balloon_page_isolate(struct page *page) { /* * Avoid burning cycles with pages that are yet under __free_pages(), * or just got freed under us. * * In case we 'win' a race for a balloon page being freed under us and * raise its refcount preventing __free_pages() from doing its job * the put_page() at the end of this block will take care of * release this page, thus avoiding a nasty leakage. */ if (likely(get_page_unless_zero(page))) { /* * As balloon pages are not isolated from LRU lists, concurrent * compaction threads can race against page migration functions * as well as race against the balloon driver releasing a page. * * In order to avoid having an already isolated balloon page * being (wrongly) re-isolated while it is under migration, * or to avoid attempting to isolate pages being released by * the balloon driver, lets be sure we have the page lock * before proceeding with the balloon page isolation steps. */ if (likely(trylock_page(page))) { /* * A ballooned page, by default, has PagePrivate set. * Prevent concurrent compaction threads from isolating * an already isolated balloon page by clearing it. */ if (balloon_page_movable(page)) { __isolate_balloon_page(page); unlock_page(page); return true; } unlock_page(page); } put_page(page); } return false; } /* putback_lru_page() counterpart for a ballooned page */ void balloon_page_putback(struct page *page) { /* * 'lock_page()' stabilizes the page and prevents races against * concurrent isolation threads attempting to re-isolate it. */ lock_page(page); if (__is_movable_balloon_page(page)) { __putback_balloon_page(page); /* drop the extra ref count taken for page isolation */ put_page(page); } else { WARN_ON(1); dump_page(page); } unlock_page(page); } /* move_to_new_page() counterpart for a ballooned page */ int balloon_page_migrate(struct page *newpage, struct page *page, enum migrate_mode mode) { struct address_space *mapping; int rc = -EAGAIN; /* * Block others from accessing the 'newpage' when we get around to * establishing additional references. We should be the only one * holding a reference to the 'newpage' at this point. */ BUG_ON(!trylock_page(newpage)); if (WARN_ON(!__is_movable_balloon_page(page))) { dump_page(page); unlock_page(newpage); return rc; } mapping = page->mapping; if (mapping) rc = __migrate_balloon_page(mapping, newpage, page, mode); unlock_page(newpage); return rc; } #endif /* CONFIG_BALLOON_COMPACTION */ |