Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm/balloon_compaction: use a device-independent balloon (list) lock

In order to remove the dependency on the page lock for balloon pages, we
need a lock that is independent of the page.

It's crucial that we can handle the scenario where balloon deflation
(clearing page->private) can race with page isolation (using page->private
to obtain the balloon_dev_info where the lock currently resides).

The current lock in balloon_dev_info is therefore not suitable.

Fortunately, we never really have more than a single balloon device per
VM, so we can just keep it simple and use a static lock to protect all
balloon devices.

Based on this change we will remove the dependency on the page lock next.

Link: https://lkml.kernel.org/r/20260119230133.3551867-9-david@kernel.org
Signed-off-by: David Hildenbrand (Red Hat) <david@kernel.org>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Christophe Leroy <christophe.leroy@csgroup.eu>
Cc: Eugenio Pérez <eperezma@redhat.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jason Wang <jasowang@redhat.com>
Cc: Jerrin Shaji George <jerrin.shaji-george@broadcom.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Oscar Salvador <osalvador@suse.de>
Cc: SeongJae Park <sj@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

David Hildenbrand (Red Hat) and committed by
Andrew Morton
8202313e c33b47c3

+22 -18
+2 -4
include/linux/balloon_compaction.h
··· 21 21 * i. Setting the PG_movable_ops flag and page->private with the following 22 22 * lock order 23 23 * +-page_lock(page); 24 - * +--spin_lock_irq(&b_dev_info->pages_lock); 24 + * +--spin_lock_irq(&balloon_pages_lock); 25 25 * 26 26 * ii. isolation or dequeueing procedure must remove the page from balloon 27 - * device page list under b_dev_info->pages_lock. 27 + * device page list under balloon_pages_lock 28 28 * 29 29 * The functions provided by this interface are placed to help on coping with 30 30 * the aforementioned balloon page corner case, as well as to ensure the simple ··· 52 52 */ 53 53 struct balloon_dev_info { 54 54 unsigned long isolated_pages; /* # of isolated pages for migration */ 55 - spinlock_t pages_lock; /* Protection to pages list */ 56 55 struct list_head pages; /* Pages enqueued & handled to Host */ 57 56 int (*migratepage)(struct balloon_dev_info *, struct page *newpage, 58 57 struct page *page, enum migrate_mode mode); ··· 70 71 static inline void balloon_devinfo_init(struct balloon_dev_info *balloon) 71 72 { 72 73 balloon->isolated_pages = 0; 73 - spin_lock_init(&balloon->pages_lock); 74 74 INIT_LIST_HEAD(&balloon->pages); 75 75 balloon->migratepage = NULL; 76 76 balloon->adjust_managed_page_count = false;
+20 -14
mm/balloon_compaction.c
··· 11 11 #include <linux/export.h> 12 12 #include <linux/balloon_compaction.h> 13 13 14 + /* 15 + * Lock protecting the balloon_dev_info of all devices. We don't really 16 + * expect more than one device. 17 + */ 18 + static DEFINE_SPINLOCK(balloon_pages_lock); 19 + 14 20 static void balloon_page_enqueue_one(struct balloon_dev_info *b_dev_info, 15 21 struct page *page) 16 22 { ··· 53 47 unsigned long flags; 54 48 size_t n_pages = 0; 55 49 56 - spin_lock_irqsave(&b_dev_info->pages_lock, flags); 50 + spin_lock_irqsave(&balloon_pages_lock, flags); 57 51 list_for_each_entry_safe(page, tmp, pages, lru) { 58 52 list_del(&page->lru); 59 53 balloon_page_enqueue_one(b_dev_info, page); 60 54 n_pages++; 61 55 } 62 - spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); 56 + spin_unlock_irqrestore(&balloon_pages_lock, flags); 63 57 return n_pages; 64 58 } 65 59 EXPORT_SYMBOL_GPL(balloon_page_list_enqueue); ··· 89 83 unsigned long flags; 90 84 size_t n_pages = 0; 91 85 92 - spin_lock_irqsave(&b_dev_info->pages_lock, flags); 86 + spin_lock_irqsave(&balloon_pages_lock, flags); 93 87 list_for_each_entry_safe(page, tmp, &b_dev_info->pages, lru) { 94 88 if (n_pages == n_req_pages) 95 89 break; ··· 112 106 dec_node_page_state(page, NR_BALLOON_PAGES); 113 107 n_pages++; 114 108 } 115 - spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); 109 + spin_unlock_irqrestore(&balloon_pages_lock, flags); 116 110 117 111 return n_pages; 118 112 } ··· 155 149 { 156 150 unsigned long flags; 157 151 158 - spin_lock_irqsave(&b_dev_info->pages_lock, flags); 152 + spin_lock_irqsave(&balloon_pages_lock, flags); 159 153 balloon_page_enqueue_one(b_dev_info, page); 160 - spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); 154 + spin_unlock_irqrestore(&balloon_pages_lock, flags); 161 155 } 162 156 EXPORT_SYMBOL_GPL(balloon_page_enqueue); 163 157 ··· 197 191 * BUG() here, otherwise the balloon driver may get stuck in 198 192 * an infinite loop while attempting to release all its pages. 199 193 */ 200 - spin_lock_irqsave(&b_dev_info->pages_lock, flags); 194 + spin_lock_irqsave(&balloon_pages_lock, flags); 201 195 if (unlikely(list_empty(&b_dev_info->pages) && 202 196 !b_dev_info->isolated_pages)) 203 197 BUG(); 204 - spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); 198 + spin_unlock_irqrestore(&balloon_pages_lock, flags); 205 199 return NULL; 206 200 } 207 201 return list_first_entry(&pages, struct page, lru); ··· 219 213 if (!b_dev_info) 220 214 return false; 221 215 222 - spin_lock_irqsave(&b_dev_info->pages_lock, flags); 216 + spin_lock_irqsave(&balloon_pages_lock, flags); 223 217 list_del(&page->lru); 224 218 b_dev_info->isolated_pages++; 225 - spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); 219 + spin_unlock_irqrestore(&balloon_pages_lock, flags); 226 220 227 221 return true; 228 222 } ··· 240 234 if (WARN_ON_ONCE(!b_dev_info)) 241 235 return; 242 236 243 - spin_lock_irqsave(&b_dev_info->pages_lock, flags); 237 + spin_lock_irqsave(&balloon_pages_lock, flags); 244 238 list_add(&page->lru, &b_dev_info->pages); 245 239 b_dev_info->isolated_pages--; 246 - spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); 240 + spin_unlock_irqrestore(&balloon_pages_lock, flags); 247 241 } 248 242 249 243 static int balloon_page_migrate(struct page *newpage, struct page *page, ··· 268 262 if (rc < 0 && rc != -ENOENT) 269 263 return rc; 270 264 271 - spin_lock_irqsave(&b_dev_info->pages_lock, flags); 265 + spin_lock_irqsave(&balloon_pages_lock, flags); 272 266 if (!rc) { 273 267 /* Insert the new page into the balloon list. */ 274 268 get_page(newpage); ··· 293 287 } 294 288 295 289 b_dev_info->isolated_pages--; 296 - spin_unlock_irqrestore(&b_dev_info->pages_lock, flags); 290 + spin_unlock_irqrestore(&balloon_pages_lock, flags); 297 291 298 292 /* Free the now-deflated page we isolated in balloon_page_isolate(). */ 299 293 balloon_page_finalize(page);