lowmem: get rid of the percentages
authorViktor Rosendahl <viktor.rosendahl@nokia.com>
Thu, 11 Sep 2008 16:20:35 +0000 (19:20 +0300)
committerTony Lindgren <tony@atomide.com>
Fri, 12 Sep 2008 18:11:39 +0000 (11:11 -0700)
The purpose of this patch is to get rid of the lame percentage calculations in
lowmem.c. Currently, the limits (measured in pages) are calculated from
percentages every time somebody from userspace requests some memory. With this
patch, the limits are in pages and furthermore, they are specified as minimum
amount of "free pages", instead of as maximum amount of "used pages". "Free"
means free pages or such pages that can easily be freed by the VM system.

This patch changes the names of the lowmem sysctl limits in /proc/sys/vm:
lowmem_deny_watermark        => lowmem_deny_watermark_pages
lowmem_notify_low      => lowmem_notify_low_pages
lowmem_notify_high       => lowmem_notify_high_pages

The following read only value disappears:
lowmem_used_pages

The following read only value is introduced:
lowmem_free_pages

The old value can be calculated from userspace with the following pseudocode:

if lowmem_free_pages < lowmem_allowed_pages
   lowmem_used_pages = lowmem_allowed_pages - lowmem_free_pages
else
   lowmem_used_pages = 0;

Note that the value of lowmem_free_pages is only accurate when the system is
rather low on memory (otherwise it's a bit too pessimistic), this was true also
for the lowmem_used_pages metric.

Signed-off-by: Viktor Rosendahl <viktor.rosendahl@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
security/lowmem.c

index a965676..2dc0c4a 100644 (file)
 #define LOWMEM_MAX_UIDS 8
 
 enum {
-       VM_LOWMEM_DENY = 1,
-       VM_LOWMEM_LEVEL1_NOTIFY,
-       VM_LOWMEM_LEVEL2_NOTIFY,
+       VM_LOWMEM_DENY_PAGES = 1,
+       VM_LOWMEM_NOTIFY_LOW_PAGES,
+       VM_LOWMEM_NOTIFY_HIGH_PAGES,
        VM_LOWMEM_NR_DECAY_PAGES,
        VM_LOWMEM_ALLOWED_UIDS,
        VM_LOWMEM_ALLOWED_PAGES,
-       VM_LOWMEM_USED_PAGES,
+       VM_LOWMEM_FREE_PAGES,
 };
 
-static unsigned int deny_percentage;
-static unsigned int l1_notify, l2_notify;
+static long deny_pages;
+static long notify_low_pages, notify_high_pages;
 static unsigned int nr_decay_pages;
 static unsigned long allowed_pages;
-static long used_pages;
+static unsigned long lowmem_free_pages;
 static unsigned int allowed_uids[LOWMEM_MAX_UIDS];
 static unsigned int minuid = 1;
 static unsigned int maxuid = 65535;
 
 static ctl_table lowmem_table[] = {
        {
-               .ctl_name = VM_LOWMEM_DENY,
-               .procname = "lowmem_deny_watermark",
-               .data = &deny_percentage,
-               .maxlen = sizeof(unsigned int),
+               .ctl_name = VM_LOWMEM_DENY_PAGES,
+               .procname = "lowmem_deny_watermark_pages",
+               .data = &deny_pages,
+               .maxlen = sizeof(long),
                .mode = 0644,
                .child = NULL,
                .proc_handler = &proc_dointvec,
                .strategy = &sysctl_intvec,
        }, {
-               .ctl_name = VM_LOWMEM_LEVEL1_NOTIFY,
-               .procname = "lowmem_notify_low",
-               .data = &l1_notify,
-               .maxlen = sizeof(unsigned int),
+               .ctl_name = VM_LOWMEM_NOTIFY_LOW_PAGES,
+               .procname = "lowmem_notify_low_pages",
+               .data = &notify_low_pages,
+               .maxlen = sizeof(long),
                .mode = 0644,
                .child = NULL,
                .proc_handler = &proc_dointvec,
                .strategy = &sysctl_intvec,
        }, {
-               .ctl_name = VM_LOWMEM_LEVEL2_NOTIFY,
-               .procname = "lowmem_notify_high",
-               .data = &l2_notify,
-               .maxlen = sizeof(unsigned int),
+               .ctl_name = VM_LOWMEM_NOTIFY_HIGH_PAGES,
+               .procname = "lowmem_notify_high_pages",
+               .data = &notify_high_pages,
+               .maxlen = sizeof(long),
                .mode = 0644,
                .child = NULL,
                .proc_handler = &proc_dointvec,
@@ -92,10 +92,10 @@ static ctl_table lowmem_table[] = {
                .proc_handler = &proc_dointvec,
                .strategy = &sysctl_intvec,
        }, {
-               .ctl_name = VM_LOWMEM_USED_PAGES,
-               .procname = "lowmem_used_pages",
-               .data = &used_pages,
-               .maxlen = sizeof(long),
+               .ctl_name = VM_LOWMEM_FREE_PAGES,
+               .procname = "lowmem_free_pages",
+               .data = &lowmem_free_pages,
+               .maxlen = sizeof(unsigned long),
                .mode = 0444,
                .child = NULL,
                .proc_handler = &proc_dointvec,
@@ -163,21 +163,18 @@ static void high_watermark_state(int new_state)
 static int low_vm_enough_memory(long pages)
 {
        unsigned long free, allowed;
-       long deny_threshold, level1, level2, used;
        int cap_sys_admin = 0, notify;
 
        if (cap_capable(current, CAP_SYS_ADMIN) == 0)
                cap_sys_admin = 1;
 
+       allowed = totalram_pages - hugetlb_total_pages();
+       allowed_pages = allowed;
+
        /* We activate ourselves only after both parameters have been
         * configured. */
-       if (deny_percentage == 0 || l1_notify == 0 || l2_notify == 0)
-               return __vm_enough_memory(pages, cap_sys_admin);
-
-       allowed = totalram_pages - hugetlb_total_pages();
-       deny_threshold = allowed * deny_percentage / 100;
-       level1 = allowed * l1_notify / 100;
-       level2 = allowed * l2_notify / 100;
+       if (deny_pages == 0 || notify_low_pages == 0 || notify_high_pages == 0)
+               return  __vm_enough_memory(pages, cap_sys_admin);
 
        vm_acct_memory(pages);
 
@@ -186,22 +183,16 @@ static int low_vm_enough_memory(long pages)
        free += nr_swap_pages;
        free += global_page_state(NR_SLAB_RECLAIMABLE);
 
-       used = allowed - free;
-       if (unlikely(used < 0))
-               used = 0;
-
-       /* The hot path, plenty of memory */
-       if (likely(used < level1))
+       if (likely(free > notify_low_pages))
                goto enough_memory;
 
        /* No luck, lets make it more expensive and try again.. */
-       used -= nr_free_pages();
+       free += nr_free_pages();
 
-       if (used >= deny_threshold) {
+       if (free < deny_pages) {
                int i;
 
-               allowed_pages = allowed;
-               used_pages = used;
+               lowmem_free_pages = free;
                low_watermark_state(1);
                high_watermark_state(1);
                /* Memory allocations by root are always allowed */
@@ -227,7 +218,7 @@ static int low_vm_enough_memory(long pages)
 
 enough_memory:
        /* See if we need to notify level 1 */
-       low_watermark_state(used >= level1);
+       low_watermark_state(free < notify_low_pages);
 
        /*
         * In the level 2 notification case things are more complicated,
@@ -236,13 +227,12 @@ enough_memory:
         * on the same watermark level ends up bouncing back and forth
         * when applications are being stupid.
         */
-       notify = used >= level2;
-       if (notify || used + nr_decay_pages < level2)
+       notify = free < notify_high_pages;
+       if (notify || free - nr_decay_pages > notify_high_pages)
                high_watermark_state(notify);
 
        /* We have plenty of memory */
-       allowed_pages = allowed;
-       used_pages = used;
+       lowmem_free_pages = free;
        return 0;
 }