|
14 | 14 | #include <linux/slab.h>
|
15 | 15 | #include <linux/module.h>
|
16 | 16 | #include <linux/balloon_compaction.h>
|
| 17 | +#include <linux/oom.h> |
17 | 18 | #include <linux/wait.h>
|
18 | 19 | #include <linux/mm.h>
|
19 | 20 | #include <linux/mount.h>
|
|
27 | 28 | */
|
28 | 29 | #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT)
|
29 | 30 | #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256
|
30 |
| -#define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80 |
| 31 | +/* Maximum number of (4k) pages to deflate on OOM notifications. */ |
| 32 | +#define VIRTIO_BALLOON_OOM_NR_PAGES 256 |
| 33 | +#define VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY 80 |
31 | 34 |
|
32 | 35 | #define VIRTIO_BALLOON_FREE_PAGE_ALLOC_FLAG (__GFP_NORETRY | __GFP_NOWARN | \
|
33 | 36 | __GFP_NOMEMALLOC)
|
@@ -112,8 +115,11 @@ struct virtio_balloon {
|
112 | 115 | /* Memory statistics */
|
113 | 116 | struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
|
114 | 117 |
|
115 |
| - /* To register a shrinker to shrink memory upon memory pressure */ |
| 118 | + /* Shrinker to return free pages - VIRTIO_BALLOON_F_FREE_PAGE_HINT */ |
116 | 119 | struct shrinker shrinker;
|
| 120 | + |
| 121 | + /* OOM notifier to deflate on OOM - VIRTIO_BALLOON_F_DEFLATE_ON_OOM */ |
| 122 | + struct notifier_block oom_nb; |
117 | 123 | };
|
118 | 124 |
|
119 | 125 | static struct virtio_device_id id_table[] = {
|
@@ -788,77 +794,36 @@ static unsigned long shrink_free_pages(struct virtio_balloon *vb,
|
788 | 794 | return blocks_freed * VIRTIO_BALLOON_HINT_BLOCK_PAGES;
|
789 | 795 | }
|
790 | 796 |
|
791 |
| -static unsigned long leak_balloon_pages(struct virtio_balloon *vb, |
792 |
| - unsigned long pages_to_free) |
793 |
| -{ |
794 |
| - return leak_balloon(vb, pages_to_free * VIRTIO_BALLOON_PAGES_PER_PAGE) / |
795 |
| - VIRTIO_BALLOON_PAGES_PER_PAGE; |
796 |
| -} |
797 |
| - |
798 |
| -static unsigned long shrink_balloon_pages(struct virtio_balloon *vb, |
799 |
| - unsigned long pages_to_free) |
800 |
| -{ |
801 |
| - unsigned long pages_freed = 0; |
802 |
| - |
803 |
| - /* |
804 |
| - * One invocation of leak_balloon can deflate at most |
805 |
| - * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it |
806 |
| - * multiple times to deflate pages till reaching pages_to_free. |
807 |
| - */ |
808 |
| - while (vb->num_pages && pages_freed < pages_to_free) |
809 |
| - pages_freed += leak_balloon_pages(vb, |
810 |
| - pages_to_free - pages_freed); |
811 |
| - |
812 |
| - update_balloon_size(vb); |
813 |
| - |
814 |
| - return pages_freed; |
815 |
| -} |
816 |
| - |
817 | 797 | static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker,
|
818 | 798 | struct shrink_control *sc)
|
819 | 799 | {
|
820 |
| - unsigned long pages_to_free, pages_freed = 0; |
821 | 800 | struct virtio_balloon *vb = container_of(shrinker,
|
822 | 801 | struct virtio_balloon, shrinker);
|
823 | 802 |
|
824 |
| - pages_to_free = sc->nr_to_scan; |
825 |
| - |
826 |
| - if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) |
827 |
| - pages_freed = shrink_free_pages(vb, pages_to_free); |
828 |
| - |
829 |
| - if (pages_freed >= pages_to_free) |
830 |
| - return pages_freed; |
831 |
| - |
832 |
| - pages_freed += shrink_balloon_pages(vb, pages_to_free - pages_freed); |
833 |
| - |
834 |
| - return pages_freed; |
| 803 | + return shrink_free_pages(vb, sc->nr_to_scan); |
835 | 804 | }
|
836 | 805 |
|
837 | 806 | static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker,
|
838 | 807 | struct shrink_control *sc)
|
839 | 808 | {
|
840 | 809 | struct virtio_balloon *vb = container_of(shrinker,
|
841 | 810 | struct virtio_balloon, shrinker);
|
842 |
| - unsigned long count; |
843 |
| - |
844 |
| - count = vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE; |
845 |
| - count += vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES; |
846 | 811 |
|
847 |
| - return count; |
| 812 | + return vb->num_free_page_blocks * VIRTIO_BALLOON_HINT_BLOCK_PAGES; |
848 | 813 | }
|
849 | 814 |
|
850 |
| -static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb) |
| 815 | +static int virtio_balloon_oom_notify(struct notifier_block *nb, |
| 816 | + unsigned long dummy, void *parm) |
851 | 817 | {
|
852 |
| - unregister_shrinker(&vb->shrinker); |
853 |
| -} |
| 818 | + struct virtio_balloon *vb = container_of(nb, |
| 819 | + struct virtio_balloon, oom_nb); |
| 820 | + unsigned long *freed = parm; |
854 | 821 |
|
855 |
| -static int virtio_balloon_register_shrinker(struct virtio_balloon *vb) |
856 |
| -{ |
857 |
| - vb->shrinker.scan_objects = virtio_balloon_shrinker_scan; |
858 |
| - vb->shrinker.count_objects = virtio_balloon_shrinker_count; |
859 |
| - vb->shrinker.seeks = DEFAULT_SEEKS; |
| 822 | + *freed += leak_balloon(vb, VIRTIO_BALLOON_OOM_NR_PAGES) / |
| 823 | + VIRTIO_BALLOON_PAGES_PER_PAGE; |
| 824 | + update_balloon_size(vb); |
860 | 825 |
|
861 |
| - return register_shrinker(&vb->shrinker); |
| 826 | + return NOTIFY_OK; |
862 | 827 | }
|
863 | 828 |
|
864 | 829 | static int virtballoon_probe(struct virtio_device *vdev)
|
@@ -935,22 +900,35 @@ static int virtballoon_probe(struct virtio_device *vdev)
|
935 | 900 | virtio_cwrite(vb->vdev, struct virtio_balloon_config,
|
936 | 901 | poison_val, &poison_val);
|
937 | 902 | }
|
938 |
| - } |
939 |
| - /* |
940 |
| - * We continue to use VIRTIO_BALLOON_F_DEFLATE_ON_OOM to decide if a |
941 |
| - * shrinker needs to be registered to relieve memory pressure. |
942 |
| - */ |
943 |
| - if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) { |
944 |
| - err = virtio_balloon_register_shrinker(vb); |
| 903 | + |
| 904 | + /* |
| 905 | + * We're allowed to reuse any free pages, even if they are |
| 906 | + * still to be processed by the host. |
| 907 | + */ |
| 908 | + vb->shrinker.scan_objects = virtio_balloon_shrinker_scan; |
| 909 | + vb->shrinker.count_objects = virtio_balloon_shrinker_count; |
| 910 | + vb->shrinker.seeks = DEFAULT_SEEKS; |
| 911 | + err = register_shrinker(&vb->shrinker); |
945 | 912 | if (err)
|
946 | 913 | goto out_del_balloon_wq;
|
947 | 914 | }
|
| 915 | + if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) { |
| 916 | + vb->oom_nb.notifier_call = virtio_balloon_oom_notify; |
| 917 | + vb->oom_nb.priority = VIRTIO_BALLOON_OOM_NOTIFY_PRIORITY; |
| 918 | + err = register_oom_notifier(&vb->oom_nb); |
| 919 | + if (err < 0) |
| 920 | + goto out_unregister_shrinker; |
| 921 | + } |
| 922 | + |
948 | 923 | virtio_device_ready(vdev);
|
949 | 924 |
|
950 | 925 | if (towards_target(vb))
|
951 | 926 | virtballoon_changed(vdev);
|
952 | 927 | return 0;
|
953 | 928 |
|
| 929 | +out_unregister_shrinker: |
| 930 | + if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) |
| 931 | + unregister_shrinker(&vb->shrinker); |
954 | 932 | out_del_balloon_wq:
|
955 | 933 | if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT))
|
956 | 934 | destroy_workqueue(vb->balloon_wq);
|
@@ -989,8 +967,11 @@ static void virtballoon_remove(struct virtio_device *vdev)
|
989 | 967 | {
|
990 | 968 | struct virtio_balloon *vb = vdev->priv;
|
991 | 969 |
|
992 |
| - if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) |
993 |
| - virtio_balloon_unregister_shrinker(vb); |
| 970 | + if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) |
| 971 | + unregister_oom_notifier(&vb->oom_nb); |
| 972 | + if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_FREE_PAGE_HINT)) |
| 973 | + unregister_shrinker(&vb->shrinker); |
| 974 | + |
994 | 975 | spin_lock_irq(&vb->stop_update_lock);
|
995 | 976 | vb->stop_update = true;
|
996 | 977 | spin_unlock_irq(&vb->stop_update_lock);
|
|
0 commit comments