Loading drivers/virtio/virtio_balloon.c +47 −6 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include <linux/balloon_compaction.h> #include <linux/oom.h> #include <linux/wait.h> #include <linux/mount.h> /* * Balloon device works in 4K page units. So each page is pointed to by Loading @@ -45,6 +46,10 @@ static int oom_pages = OOM_VBALLOON_DEFAULT_PAGES; module_param(oom_pages, int, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(oom_pages, "pages to free on OOM"); #ifdef CONFIG_BALLOON_COMPACTION static struct vfsmount *balloon_mnt; #endif struct virtio_balloon { struct virtio_device *vdev; struct virtqueue *inflate_vq, *deflate_vq, *stats_vq; Loading Loading @@ -484,8 +489,26 @@ static int virtballoon_migratepage(struct balloon_dev_info *vb_dev_info, put_page(page); /* balloon reference */ return MIGRATEPAGE_SUCCESS; return 0; } static struct dentry *balloon_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { static const struct dentry_operations ops = { .d_dname = simple_dname, }; return mount_pseudo(fs_type, "balloon-kvm:", NULL, &ops, BALLOON_KVM_MAGIC); } static struct file_system_type balloon_fs = { .name = "balloon-kvm", .mount = balloon_mount, .kill_sb = kill_anon_super, }; #endif /* CONFIG_BALLOON_COMPACTION */ static int virtballoon_probe(struct virtio_device *vdev) Loading Loading @@ -513,9 +536,6 @@ static int virtballoon_probe(struct virtio_device *vdev) vb->need_stats_update = 0; balloon_devinfo_init(&vb->vb_dev_info); #ifdef CONFIG_BALLOON_COMPACTION vb->vb_dev_info.migratepage = virtballoon_migratepage; #endif err = init_vqs(vb); if (err) Loading @@ -525,7 +545,27 @@ static int virtballoon_probe(struct virtio_device *vdev) vb->nb.priority = VIRTBALLOON_OOM_NOTIFY_PRIORITY; err = register_oom_notifier(&vb->nb); if (err < 0) goto out_oom_notify; goto out_del_vqs; #ifdef CONFIG_BALLOON_COMPACTION balloon_mnt = kern_mount(&balloon_fs); if (IS_ERR(balloon_mnt)) { err = PTR_ERR(balloon_mnt); unregister_oom_notifier(&vb->nb); goto out_del_vqs; } vb->vb_dev_info.migratepage = virtballoon_migratepage; vb->vb_dev_info.inode = alloc_anon_inode(balloon_mnt->mnt_sb); if (IS_ERR(vb->vb_dev_info.inode)) { err = PTR_ERR(vb->vb_dev_info.inode); kern_unmount(balloon_mnt); unregister_oom_notifier(&vb->nb); vb->vb_dev_info.inode = NULL; goto out_del_vqs; } vb->vb_dev_info.inode->i_mapping->a_ops = &balloon_aops; #endif virtio_device_ready(vdev); Loading @@ -539,7 +579,6 @@ static int virtballoon_probe(struct virtio_device *vdev) out_del_vqs: unregister_oom_notifier(&vb->nb); out_oom_notify: vdev->config->del_vqs(vdev); out_free_vb: kfree(vb); Loading Loading @@ -567,6 +606,8 @@ static void virtballoon_remove(struct virtio_device *vdev) unregister_oom_notifier(&vb->nb); kthread_stop(vb->thread); remove_common(vb); if (vb->vb_dev_info.inode) iput(vb->vb_dev_info.inode); kfree(vb); } Loading include/linux/balloon_compaction.h +17 −37 Original line number Diff line number Diff line Loading @@ -45,9 +45,11 @@ #define _LINUX_BALLOON_COMPACTION_H #include <linux/pagemap.h> #include <linux/page-flags.h> #include <linux/migrate.h> #include <linux/node.h> #include <linux/compaction.h> #include <linux/gfp.h> #include <linux/err.h> #include <linux/fs.h> /* * Balloon device information descriptor. Loading @@ -62,6 +64,7 @@ struct balloon_dev_info { struct list_head pages; /* Pages enqueued & handled to Host */ int (*migratepage)(struct balloon_dev_info *, struct page *newpage, struct page *page, enum migrate_mode mode); struct inode *inode; }; extern struct page *balloon_page_enqueue(struct balloon_dev_info *b_dev_info); Loading @@ -73,44 +76,18 @@ static inline void balloon_devinfo_init(struct balloon_dev_info *balloon) spin_lock_init(&balloon->pages_lock); INIT_LIST_HEAD(&balloon->pages); balloon->migratepage = NULL; balloon->inode = NULL; } #ifdef CONFIG_BALLOON_COMPACTION extern bool balloon_page_isolate(struct page *page); extern const struct address_space_operations balloon_aops; extern bool balloon_page_isolate(struct page *page, isolate_mode_t mode); extern void balloon_page_putback(struct page *page); extern int balloon_page_migrate(struct page *newpage, extern int balloon_page_migrate(struct address_space *mapping, struct page *newpage, struct page *page, enum migrate_mode mode); /* * __is_movable_balloon_page - helper to perform @page PageBalloon tests */ static inline bool __is_movable_balloon_page(struct page *page) { return PageBalloon(page); } /* * balloon_page_movable - test PageBalloon to identify balloon pages * and PagePrivate to check that the page is not * isolated and can be moved by compaction/migration. * * As we might return false positives in the case of a balloon page being just * released under us, this need to be re-tested later, under the page lock. */ static inline bool balloon_page_movable(struct page *page) { return PageBalloon(page) && PagePrivate(page); } /* * isolated_balloon_page - identify an isolated balloon page on private * compaction/migration page lists. */ static inline bool isolated_balloon_page(struct page *page) { return PageBalloon(page); } /* * balloon_page_insert - insert a page into the balloon's page list and make * the page->private assignment accordingly. Loading @@ -124,7 +101,7 @@ static inline void balloon_page_insert(struct balloon_dev_info *balloon, struct page *page) { __SetPageBalloon(page); SetPagePrivate(page); __SetPageMovable(page, balloon->inode->i_mapping); set_page_private(page, (unsigned long)balloon); list_add(&page->lru, &balloon->pages); } Loading @@ -140,12 +117,15 @@ static inline void balloon_page_insert(struct balloon_dev_info *balloon, static inline void balloon_page_delete(struct page *page) { __ClearPageBalloon(page); __ClearPageMovable(page); set_page_private(page, 0); if (PagePrivate(page)) { ClearPagePrivate(page); /* * No touch page.lru field once @page has been isolated * because VM is using the field. */ if (!PageIsolated(page)) list_del(&page->lru); } } /* * balloon_page_device - get the b_dev_info descriptor for the balloon device Loading include/uapi/linux/magic.h +1 −0 Original line number Diff line number Diff line Loading @@ -78,5 +78,6 @@ #define BTRFS_TEST_MAGIC 0x73727279 #define NSFS_MAGIC 0x6e736673 #define BPF_FS_MAGIC 0xcafe4a11 #define BALLOON_KVM_MAGIC 0x13661366 #endif /* __LINUX_MAGIC_H__ */ mm/balloon_compaction.c +17 −77 Original line number Diff line number Diff line Loading @@ -70,7 +70,7 @@ struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info) */ if (trylock_page(page)) { #ifdef CONFIG_BALLOON_COMPACTION if (!PagePrivate(page)) { if (PageIsolated(page)) { /* raced with isolation */ unlock_page(page); continue; Loading Loading @@ -106,110 +106,50 @@ EXPORT_SYMBOL_GPL(balloon_page_dequeue); #ifdef CONFIG_BALLOON_COMPACTION static inline void __isolate_balloon_page(struct page *page) bool balloon_page_isolate(struct page *page, isolate_mode_t mode) { struct balloon_dev_info *b_dev_info = balloon_page_device(page); 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); return true; } static inline void __putback_balloon_page(struct page *page) void balloon_page_putback(struct page *page) { struct balloon_dev_info *b_dev_info = balloon_page_device(page); 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); } /* __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, "not movable balloon 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) int balloon_page_migrate(struct address_space *mapping, struct page *newpage, struct page *page, enum migrate_mode mode) { struct balloon_dev_info *balloon = balloon_page_device(page); int rc = -EAGAIN; VM_BUG_ON_PAGE(!PageLocked(page), page); VM_BUG_ON_PAGE(!PageLocked(newpage), newpage); if (WARN_ON(!__is_movable_balloon_page(page))) { dump_page(page, "not movable balloon page"); return rc; return balloon->migratepage(balloon, newpage, page, mode); } if (balloon && balloon->migratepage) rc = balloon->migratepage(balloon, newpage, page, mode); 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); return rc; } #endif /* CONFIG_BALLOON_COMPACTION */ mm/compaction.c +0 −7 Original line number Diff line number Diff line Loading @@ -819,13 +819,6 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, * Skip any other type of page */ if (!PageLRU(page)) { if (unlikely(balloon_page_movable(page))) { if (balloon_page_isolate(page)) { /* Successfully isolated */ goto isolate_success; } } /* * __PageMovable can return false positive so we need * to verify it under page_lock. Loading Loading
drivers/virtio/virtio_balloon.c +47 −6 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ #include <linux/balloon_compaction.h> #include <linux/oom.h> #include <linux/wait.h> #include <linux/mount.h> /* * Balloon device works in 4K page units. So each page is pointed to by Loading @@ -45,6 +46,10 @@ static int oom_pages = OOM_VBALLOON_DEFAULT_PAGES; module_param(oom_pages, int, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(oom_pages, "pages to free on OOM"); #ifdef CONFIG_BALLOON_COMPACTION static struct vfsmount *balloon_mnt; #endif struct virtio_balloon { struct virtio_device *vdev; struct virtqueue *inflate_vq, *deflate_vq, *stats_vq; Loading Loading @@ -484,8 +489,26 @@ static int virtballoon_migratepage(struct balloon_dev_info *vb_dev_info, put_page(page); /* balloon reference */ return MIGRATEPAGE_SUCCESS; return 0; } static struct dentry *balloon_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { static const struct dentry_operations ops = { .d_dname = simple_dname, }; return mount_pseudo(fs_type, "balloon-kvm:", NULL, &ops, BALLOON_KVM_MAGIC); } static struct file_system_type balloon_fs = { .name = "balloon-kvm", .mount = balloon_mount, .kill_sb = kill_anon_super, }; #endif /* CONFIG_BALLOON_COMPACTION */ static int virtballoon_probe(struct virtio_device *vdev) Loading Loading @@ -513,9 +536,6 @@ static int virtballoon_probe(struct virtio_device *vdev) vb->need_stats_update = 0; balloon_devinfo_init(&vb->vb_dev_info); #ifdef CONFIG_BALLOON_COMPACTION vb->vb_dev_info.migratepage = virtballoon_migratepage; #endif err = init_vqs(vb); if (err) Loading @@ -525,7 +545,27 @@ static int virtballoon_probe(struct virtio_device *vdev) vb->nb.priority = VIRTBALLOON_OOM_NOTIFY_PRIORITY; err = register_oom_notifier(&vb->nb); if (err < 0) goto out_oom_notify; goto out_del_vqs; #ifdef CONFIG_BALLOON_COMPACTION balloon_mnt = kern_mount(&balloon_fs); if (IS_ERR(balloon_mnt)) { err = PTR_ERR(balloon_mnt); unregister_oom_notifier(&vb->nb); goto out_del_vqs; } vb->vb_dev_info.migratepage = virtballoon_migratepage; vb->vb_dev_info.inode = alloc_anon_inode(balloon_mnt->mnt_sb); if (IS_ERR(vb->vb_dev_info.inode)) { err = PTR_ERR(vb->vb_dev_info.inode); kern_unmount(balloon_mnt); unregister_oom_notifier(&vb->nb); vb->vb_dev_info.inode = NULL; goto out_del_vqs; } vb->vb_dev_info.inode->i_mapping->a_ops = &balloon_aops; #endif virtio_device_ready(vdev); Loading @@ -539,7 +579,6 @@ static int virtballoon_probe(struct virtio_device *vdev) out_del_vqs: unregister_oom_notifier(&vb->nb); out_oom_notify: vdev->config->del_vqs(vdev); out_free_vb: kfree(vb); Loading Loading @@ -567,6 +606,8 @@ static void virtballoon_remove(struct virtio_device *vdev) unregister_oom_notifier(&vb->nb); kthread_stop(vb->thread); remove_common(vb); if (vb->vb_dev_info.inode) iput(vb->vb_dev_info.inode); kfree(vb); } Loading
include/linux/balloon_compaction.h +17 −37 Original line number Diff line number Diff line Loading @@ -45,9 +45,11 @@ #define _LINUX_BALLOON_COMPACTION_H #include <linux/pagemap.h> #include <linux/page-flags.h> #include <linux/migrate.h> #include <linux/node.h> #include <linux/compaction.h> #include <linux/gfp.h> #include <linux/err.h> #include <linux/fs.h> /* * Balloon device information descriptor. Loading @@ -62,6 +64,7 @@ struct balloon_dev_info { struct list_head pages; /* Pages enqueued & handled to Host */ int (*migratepage)(struct balloon_dev_info *, struct page *newpage, struct page *page, enum migrate_mode mode); struct inode *inode; }; extern struct page *balloon_page_enqueue(struct balloon_dev_info *b_dev_info); Loading @@ -73,44 +76,18 @@ static inline void balloon_devinfo_init(struct balloon_dev_info *balloon) spin_lock_init(&balloon->pages_lock); INIT_LIST_HEAD(&balloon->pages); balloon->migratepage = NULL; balloon->inode = NULL; } #ifdef CONFIG_BALLOON_COMPACTION extern bool balloon_page_isolate(struct page *page); extern const struct address_space_operations balloon_aops; extern bool balloon_page_isolate(struct page *page, isolate_mode_t mode); extern void balloon_page_putback(struct page *page); extern int balloon_page_migrate(struct page *newpage, extern int balloon_page_migrate(struct address_space *mapping, struct page *newpage, struct page *page, enum migrate_mode mode); /* * __is_movable_balloon_page - helper to perform @page PageBalloon tests */ static inline bool __is_movable_balloon_page(struct page *page) { return PageBalloon(page); } /* * balloon_page_movable - test PageBalloon to identify balloon pages * and PagePrivate to check that the page is not * isolated and can be moved by compaction/migration. * * As we might return false positives in the case of a balloon page being just * released under us, this need to be re-tested later, under the page lock. */ static inline bool balloon_page_movable(struct page *page) { return PageBalloon(page) && PagePrivate(page); } /* * isolated_balloon_page - identify an isolated balloon page on private * compaction/migration page lists. */ static inline bool isolated_balloon_page(struct page *page) { return PageBalloon(page); } /* * balloon_page_insert - insert a page into the balloon's page list and make * the page->private assignment accordingly. Loading @@ -124,7 +101,7 @@ static inline void balloon_page_insert(struct balloon_dev_info *balloon, struct page *page) { __SetPageBalloon(page); SetPagePrivate(page); __SetPageMovable(page, balloon->inode->i_mapping); set_page_private(page, (unsigned long)balloon); list_add(&page->lru, &balloon->pages); } Loading @@ -140,12 +117,15 @@ static inline void balloon_page_insert(struct balloon_dev_info *balloon, static inline void balloon_page_delete(struct page *page) { __ClearPageBalloon(page); __ClearPageMovable(page); set_page_private(page, 0); if (PagePrivate(page)) { ClearPagePrivate(page); /* * No touch page.lru field once @page has been isolated * because VM is using the field. */ if (!PageIsolated(page)) list_del(&page->lru); } } /* * balloon_page_device - get the b_dev_info descriptor for the balloon device Loading
include/uapi/linux/magic.h +1 −0 Original line number Diff line number Diff line Loading @@ -78,5 +78,6 @@ #define BTRFS_TEST_MAGIC 0x73727279 #define NSFS_MAGIC 0x6e736673 #define BPF_FS_MAGIC 0xcafe4a11 #define BALLOON_KVM_MAGIC 0x13661366 #endif /* __LINUX_MAGIC_H__ */
mm/balloon_compaction.c +17 −77 Original line number Diff line number Diff line Loading @@ -70,7 +70,7 @@ struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info) */ if (trylock_page(page)) { #ifdef CONFIG_BALLOON_COMPACTION if (!PagePrivate(page)) { if (PageIsolated(page)) { /* raced with isolation */ unlock_page(page); continue; Loading Loading @@ -106,110 +106,50 @@ EXPORT_SYMBOL_GPL(balloon_page_dequeue); #ifdef CONFIG_BALLOON_COMPACTION static inline void __isolate_balloon_page(struct page *page) bool balloon_page_isolate(struct page *page, isolate_mode_t mode) { struct balloon_dev_info *b_dev_info = balloon_page_device(page); 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); return true; } static inline void __putback_balloon_page(struct page *page) void balloon_page_putback(struct page *page) { struct balloon_dev_info *b_dev_info = balloon_page_device(page); 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); } /* __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, "not movable balloon 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) int balloon_page_migrate(struct address_space *mapping, struct page *newpage, struct page *page, enum migrate_mode mode) { struct balloon_dev_info *balloon = balloon_page_device(page); int rc = -EAGAIN; VM_BUG_ON_PAGE(!PageLocked(page), page); VM_BUG_ON_PAGE(!PageLocked(newpage), newpage); if (WARN_ON(!__is_movable_balloon_page(page))) { dump_page(page, "not movable balloon page"); return rc; return balloon->migratepage(balloon, newpage, page, mode); } if (balloon && balloon->migratepage) rc = balloon->migratepage(balloon, newpage, page, mode); 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); return rc; } #endif /* CONFIG_BALLOON_COMPACTION */
mm/compaction.c +0 −7 Original line number Diff line number Diff line Loading @@ -819,13 +819,6 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, * Skip any other type of page */ if (!PageLRU(page)) { if (unlikely(balloon_page_movable(page))) { if (balloon_page_isolate(page)) { /* Successfully isolated */ goto isolate_success; } } /* * __PageMovable can return false positive so we need * to verify it under page_lock. Loading