]> Pileus Git - ~andy/linux/blobdiff - mm/page-writeback.c
[CVE-2009-0029] System call wrapper special cases
[~andy/linux] / mm / page-writeback.c
index 4d4074cff300555aa1cb3608a63a85c82ebb0b71..b493db7841dc6c2db77d10eab751f6e1f62e7355 100644 (file)
@@ -68,6 +68,12 @@ static inline long sync_writeback_pages(void)
  */
 int dirty_background_ratio = 5;
 
+/*
+ * dirty_background_bytes starts at 0 (disabled) so that it is a function of
+ * dirty_background_ratio * the amount of dirtyable memory
+ */
+unsigned long dirty_background_bytes;
+
 /*
  * free highmem will not be subtracted from the total free memory
  * for calculating free ratios if vm_highmem_is_dirtyable is true
@@ -79,6 +85,12 @@ int vm_highmem_is_dirtyable;
  */
 int vm_dirty_ratio = 10;
 
+/*
+ * vm_dirty_bytes starts at 0 (disabled) so that it is a function of
+ * vm_dirty_ratio * the amount of dirtyable memory
+ */
+unsigned long vm_dirty_bytes;
+
 /*
  * The interval between `kupdate'-style writebacks, in jiffies
  */
@@ -135,23 +147,75 @@ static int calc_period_shift(void)
 {
        unsigned long dirty_total;
 
-       dirty_total = (vm_dirty_ratio * determine_dirtyable_memory()) / 100;
+       if (vm_dirty_bytes)
+               dirty_total = vm_dirty_bytes / PAGE_SIZE;
+       else
+               dirty_total = (vm_dirty_ratio * determine_dirtyable_memory()) /
+                               100;
        return 2 + ilog2(dirty_total - 1);
 }
 
 /*
- * update the period when the dirty ratio changes.
+ * update the period when the dirty threshold changes.
  */
+static void update_completion_period(void)
+{
+       int shift = calc_period_shift();
+       prop_change_shift(&vm_completions, shift);
+       prop_change_shift(&vm_dirties, shift);
+}
+
+int dirty_background_ratio_handler(struct ctl_table *table, int write,
+               struct file *filp, void __user *buffer, size_t *lenp,
+               loff_t *ppos)
+{
+       int ret;
+
+       ret = proc_dointvec_minmax(table, write, filp, buffer, lenp, ppos);
+       if (ret == 0 && write)
+               dirty_background_bytes = 0;
+       return ret;
+}
+
+int dirty_background_bytes_handler(struct ctl_table *table, int write,
+               struct file *filp, void __user *buffer, size_t *lenp,
+               loff_t *ppos)
+{
+       int ret;
+
+       ret = proc_doulongvec_minmax(table, write, filp, buffer, lenp, ppos);
+       if (ret == 0 && write)
+               dirty_background_ratio = 0;
+       return ret;
+}
+
 int dirty_ratio_handler(struct ctl_table *table, int write,
                struct file *filp, void __user *buffer, size_t *lenp,
                loff_t *ppos)
 {
        int old_ratio = vm_dirty_ratio;
-       int ret = proc_dointvec_minmax(table, write, filp, buffer, lenp, ppos);
+       int ret;
+
+       ret = proc_dointvec_minmax(table, write, filp, buffer, lenp, ppos);
        if (ret == 0 && write && vm_dirty_ratio != old_ratio) {
-               int shift = calc_period_shift();
-               prop_change_shift(&vm_completions, shift);
-               prop_change_shift(&vm_dirties, shift);
+               update_completion_period();
+               vm_dirty_bytes = 0;
+       }
+       return ret;
+}
+
+
+int dirty_bytes_handler(struct ctl_table *table, int write,
+               struct file *filp, void __user *buffer, size_t *lenp,
+               loff_t *ppos)
+{
+       int old_bytes = vm_dirty_bytes;
+       int ret;
+
+       ret = proc_doulongvec_minmax(table, write, filp, buffer, lenp, ppos);
+       if (ret == 0 && write && vm_dirty_bytes != old_bytes) {
+               update_completion_period();
+               vm_dirty_ratio = 0;
        }
        return ret;
 }
@@ -365,23 +429,29 @@ void
 get_dirty_limits(unsigned long *pbackground, unsigned long *pdirty,
                 unsigned long *pbdi_dirty, struct backing_dev_info *bdi)
 {
-       int background_ratio;           /* Percentages */
-       int dirty_ratio;
        unsigned long background;
        unsigned long dirty;
        unsigned long available_memory = determine_dirtyable_memory();
        struct task_struct *tsk;
 
-       dirty_ratio = vm_dirty_ratio;
-       if (dirty_ratio < 5)
-               dirty_ratio = 5;
+       if (vm_dirty_bytes)
+               dirty = DIV_ROUND_UP(vm_dirty_bytes, PAGE_SIZE);
+       else {
+               int dirty_ratio;
 
-       background_ratio = dirty_background_ratio;
-       if (background_ratio >= dirty_ratio)
-               background_ratio = dirty_ratio / 2;
+               dirty_ratio = vm_dirty_ratio;
+               if (dirty_ratio < 5)
+                       dirty_ratio = 5;
+               dirty = (dirty_ratio * available_memory) / 100;
+       }
+
+       if (dirty_background_bytes)
+               background = DIV_ROUND_UP(dirty_background_bytes, PAGE_SIZE);
+       else
+               background = (dirty_background_ratio * available_memory) / 100;
 
-       background = (background_ratio * available_memory) / 100;
-       dirty = (dirty_ratio * available_memory) / 100;
+       if (background >= dirty)
+               background = dirty / 2;
        tsk = current;
        if (tsk->flags & PF_LESS_THROTTLE || rt_task(tsk)) {
                background += background / 4;