Merge branch 'linux-linaro-lsk' into linux-linaro-lsk-android
authorMark Brown <broonie@linaro.org>
Tue, 1 Jul 2014 10:20:33 +0000 (11:20 +0100)
committerMark Brown <broonie@linaro.org>
Tue, 1 Jul 2014 10:20:33 +0000 (11:20 +0100)
1  2 
kernel/fork.c
mm/vmscan.c
net/ipv4/tcp_input.c

diff --combined kernel/fork.c
index 0aa1bb5c8d6edc7e60f41d9d84cfacec9cd37694,270c1dab674a59df3ea52c48e05ad9cca5246166..9ace35986f7e91c3c36bd3ad6756d2938d747395
@@@ -198,9 -198,6 +198,9 @@@ struct kmem_cache *vm_area_cachep
  /* SLAB cache for mm_struct structures (tsk->mm) */
  static struct kmem_cache *mm_cachep;
  
 +/* Notifier list called when a task struct is freed */
 +static ATOMIC_NOTIFIER_HEAD(task_free_notifier);
 +
  static void account_kernel_stack(struct thread_info *ti, int account)
  {
        struct zone *zone = page_zone(virt_to_page(ti));
@@@ -234,18 -231,6 +234,18 @@@ static inline void put_signal_struct(st
                free_signal_struct(sig);
  }
  
 +int task_free_register(struct notifier_block *n)
 +{
 +      return atomic_notifier_chain_register(&task_free_notifier, n);
 +}
 +EXPORT_SYMBOL(task_free_register);
 +
 +int task_free_unregister(struct notifier_block *n)
 +{
 +      return atomic_notifier_chain_unregister(&task_free_notifier, n);
 +}
 +EXPORT_SYMBOL(task_free_unregister);
 +
  void __put_task_struct(struct task_struct *tsk)
  {
        WARN_ON(!tsk->exit_state);
        delayacct_tsk_free(tsk);
        put_signal_struct(tsk->signal);
  
 +      atomic_notifier_call_chain(&task_free_notifier, 0, tsk);
        if (!profile_handoff_task(tsk))
                free_task(tsk);
  }
@@@ -713,8 -697,7 +713,8 @@@ struct mm_struct *mm_access(struct task
  
        mm = get_task_mm(task);
        if (mm && mm != current->mm &&
 -                      !ptrace_may_access(task, mode)) {
 +                      !ptrace_may_access(task, mode) &&
 +                      !capable(CAP_SYS_RESOURCE)) {
                mmput(mm);
                mm = ERR_PTR(-EACCES);
        }
@@@ -1624,10 -1607,12 +1624,12 @@@ long do_fork(unsigned long clone_flags
         */
        if (!IS_ERR(p)) {
                struct completion vfork;
+               struct pid *pid;
  
                trace_sched_process_fork(current, p);
  
-               nr = task_pid_vnr(p);
+               pid = get_task_pid(p, PIDTYPE_PID);
+               nr = pid_vnr(pid);
  
                if (clone_flags & CLONE_PARENT_SETTID)
                        put_user(nr, parent_tidptr);
  
                /* forking complete and child started to run, tell ptracer */
                if (unlikely(trace))
-                       ptrace_event(trace, nr);
+                       ptrace_event_pid(trace, pid);
  
                if (clone_flags & CLONE_VFORK) {
                        if (!wait_for_vfork_done(p, &vfork))
-                               ptrace_event(PTRACE_EVENT_VFORK_DONE, nr);
+                               ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);
                }
+               put_pid(pid);
        } else {
                nr = PTR_ERR(p);
        }
diff --combined mm/vmscan.c
index c3d074ea1371130625dc912f1a01c6715363b017,4e89500391dcbeb6a2ac13e0979e788e9caf0593..ec826b383b625b2840b31af6722bbf61f4d05f2c
@@@ -43,7 -43,6 +43,7 @@@
  #include <linux/sysctl.h>
  #include <linux/oom.h>
  #include <linux/prefetch.h>
 +#include <linux/debugfs.h>
  
  #include <asm/tlbflush.h>
  #include <asm/div64.h>
@@@ -156,39 -155,6 +156,39 @@@ static unsigned long get_lru_size(struc
        return zone_page_state(lruvec_zone(lruvec), NR_LRU_BASE + lru);
  }
  
 +struct dentry *debug_file;
 +
 +static int debug_shrinker_show(struct seq_file *s, void *unused)
 +{
 +      struct shrinker *shrinker;
 +      struct shrink_control sc;
 +
 +      sc.gfp_mask = -1;
 +      sc.nr_to_scan = 0;
 +
 +      down_read(&shrinker_rwsem);
 +      list_for_each_entry(shrinker, &shrinker_list, list) {
 +              int num_objs;
 +
 +              num_objs = shrinker->shrink(shrinker, &sc);
 +              seq_printf(s, "%pf %d\n", shrinker->shrink, num_objs);
 +      }
 +      up_read(&shrinker_rwsem);
 +      return 0;
 +}
 +
 +static int debug_shrinker_open(struct inode *inode, struct file *file)
 +{
 +        return single_open(file, debug_shrinker_show, inode->i_private);
 +}
 +
 +static const struct file_operations debug_shrinker_fops = {
 +        .open = debug_shrinker_open,
 +        .read = seq_read,
 +        .llseek = seq_lseek,
 +        .release = single_release,
 +};
 +
  /*
   * Add a shrinker callback to be called from the vm
   */
@@@ -201,15 -167,6 +201,15 @@@ void register_shrinker(struct shrinker 
  }
  EXPORT_SYMBOL(register_shrinker);
  
 +static int __init add_shrinker_debug(void)
 +{
 +      debugfs_create_file("shrinker", 0644, NULL, NULL,
 +                          &debug_shrinker_fops);
 +      return 0;
 +}
 +
 +late_initcall(add_shrinker_debug);
 +
  /*
   * Remove one
   */
@@@ -2329,10 -2286,17 +2329,17 @@@ static bool pfmemalloc_watermark_ok(pg_
  
        for (i = 0; i <= ZONE_NORMAL; i++) {
                zone = &pgdat->node_zones[i];
+               if (!populated_zone(zone))
+                       continue;
                pfmemalloc_reserve += min_wmark_pages(zone);
                free_pages += zone_page_state(zone, NR_FREE_PAGES);
        }
  
+       /* If there are no reserves (unexpected config) then do not throttle */
+       if (!pfmemalloc_reserve)
+               return true;
        wmark_ok = free_pages > pfmemalloc_reserve / 2;
  
        /* kswapd must be awake if processes are being throttled */
  static bool throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist,
                                        nodemask_t *nodemask)
  {
+       struct zoneref *z;
        struct zone *zone;
-       int high_zoneidx = gfp_zone(gfp_mask);
-       pg_data_t *pgdat;
+       pg_data_t *pgdat = NULL;
  
        /*
         * Kernel threads should not be throttled as they may be indirectly
        if (fatal_signal_pending(current))
                goto out;
  
-       /* Check if the pfmemalloc reserves are ok */
-       first_zones_zonelist(zonelist, high_zoneidx, NULL, &zone);
-       pgdat = zone->zone_pgdat;
-       if (pfmemalloc_watermark_ok(pgdat))
+       /*
+        * Check if the pfmemalloc reserves are ok by finding the first node
+        * with a usable ZONE_NORMAL or lower zone. The expectation is that
+        * GFP_KERNEL will be required for allocating network buffers when
+        * swapping over the network so ZONE_HIGHMEM is unusable.
+        *
+        * Throttling is based on the first usable node and throttled processes
+        * wait on a queue until kswapd makes progress and wakes them. There
+        * is an affinity then between processes waking up and where reclaim
+        * progress has been made assuming the process wakes on the same node.
+        * More importantly, processes running on remote nodes will not compete
+        * for remote pfmemalloc reserves and processes on different nodes
+        * should make reasonable progress.
+        */
+       for_each_zone_zonelist_nodemask(zone, z, zonelist,
+                                       gfp_mask, nodemask) {
+               if (zone_idx(zone) > ZONE_NORMAL)
+                       continue;
+               /* Throttle based on the first usable node */
+               pgdat = zone->zone_pgdat;
+               if (pfmemalloc_watermark_ok(pgdat))
+                       goto out;
+               break;
+       }
+       /* If no zone was usable by the allocation flags then do not throttle */
+       if (!pgdat)
                goto out;
  
        /* Account for the throttling */
@@@ -3102,7 -3090,10 +3133,10 @@@ static int kswapd(void *p
                }
        }
  
+       tsk->flags &= ~(PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD);
        current->reclaim_state = NULL;
+       lockdep_clear_current_reclaim_state();
        return 0;
  }
  
diff --combined net/ipv4/tcp_input.c
index aa5f3bfebabd0360b01d1beb857f234af598f092,ba7d2b7ad9f9910434cb2e6200c875ef95117e66..f8b30fb54a275b44010a5c05f5543bdc5fd79940
@@@ -98,7 -98,6 +98,7 @@@ int sysctl_tcp_thin_dupack __read_mostl
  
  int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
  int sysctl_tcp_early_retrans __read_mostly = 3;
 +int sysctl_tcp_default_init_rwnd __read_mostly = TCP_DEFAULT_INIT_RCVWND;
  
  #define FLAG_DATA             0x01 /* Incoming frame contained data.          */
  #define FLAG_WIN_UPDATE               0x02 /* Incoming ACK was a window update.       */
@@@ -352,14 -351,14 +352,14 @@@ static void tcp_grow_window(struct soc
  static void tcp_fixup_rcvbuf(struct sock *sk)
  {
        u32 mss = tcp_sk(sk)->advmss;
 -      u32 icwnd = TCP_DEFAULT_INIT_RCVWND;
 +      u32 icwnd = sysctl_tcp_default_init_rwnd;
        int rcvmem;
  
        /* Limit to 10 segments if mss <= 1460,
         * or 14600/mss segments, with a minimum of two segments.
         */
        if (mss > 1460)
 -              icwnd = max_t(u32, (1460 * TCP_DEFAULT_INIT_RCVWND) / mss, 2);
 +              icwnd = max_t(u32, (1460 * icwnd) / mss, 2);
  
        rcvmem = SKB_TRUESIZE(mss + MAX_TCP_HEADER);
        while (tcp_win_from_space(rcvmem) < mss)
@@@ -2721,13 -2720,12 +2721,12 @@@ static void tcp_process_loss(struct soc
        bool recovered = !before(tp->snd_una, tp->high_seq);
  
        if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */
-               if (flag & FLAG_ORIG_SACK_ACKED) {
-                       /* Step 3.b. A timeout is spurious if not all data are
-                        * lost, i.e., never-retransmitted data are (s)acked.
-                        */
-                       tcp_try_undo_loss(sk, true);
+               /* Step 3.b. A timeout is spurious if not all data are
+                * lost, i.e., never-retransmitted data are (s)acked.
+                */
+               if (tcp_try_undo_loss(sk, flag & FLAG_ORIG_SACK_ACKED))
                        return;
-               }
                if (after(tp->snd_nxt, tp->high_seq) &&
                    (flag & FLAG_DATA_SACKED || is_dupack)) {
                        tp->frto = 0; /* Loss was real: 2nd part of step 3.a */