Merge remote-tracking branch 'userns/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 3 Jun 2021 06:20:30 +0000 (16:20 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 3 Jun 2021 06:20:30 +0000 (16:20 +1000)
# Conflicts:
# include/linux/sched/user.h
# include/linux/user_namespace.h
# kernel/signal.c
# kernel/ucount.c

19 files changed:
1  2 
fs/hugetlbfs/inode.c
fs/proc/array.c
include/linux/cred.h
include/linux/hugetlb.h
include/linux/mm.h
include/linux/sched/user.h
include/linux/user_namespace.h
ipc/mqueue.c
kernel/cred.c
kernel/exit.c
kernel/fork.c
kernel/signal.c
kernel/sys.c
kernel/ucount.c
kernel/user_namespace.c
mm/mlock.c
mm/mmap.c
mm/shmem.c
tools/testing/selftests/Makefile

Simple merge
diff --cc fs/proc/array.c
Simple merge
Simple merge
Simple merge
Simple merge
index 3632c5d6ec55972cdd9fda98b0afe52e186d1e6a,82bd2532da6bcab440a599731f5c4ad4801fb679..2462f7d07695bc82b8f0604dd6d2cfecfc0e4f1e
@@@ -12,8 -12,9 +12,6 @@@
   */
  struct user_struct {
        refcount_t __count;     /* reference count */
-       atomic_t processes;     /* How many processes does this user have? */
-       atomic_t sigpending;    /* How many pending signals does this user have? */
 -#ifdef CONFIG_FANOTIFY
 -      atomic_t fanotify_listeners;
 -#endif
  #ifdef CONFIG_EPOLL
        atomic_long_t epoll_watches; /* The number of file descriptors currently watched */
  #endif
index 1d08dbbcfe32aba028a642e22ee5346c3b3da389,61794ae32fa8f253359facb6ed68efec46d57727..eb70cabe6e7f2f6362bde868a21dbf257701afe9
@@@ -49,11 -49,11 +49,15 @@@ enum ucount_type 
  #ifdef CONFIG_INOTIFY_USER
        UCOUNT_INOTIFY_INSTANCES,
        UCOUNT_INOTIFY_WATCHES,
 +#endif
 +#ifdef CONFIG_FANOTIFY
 +      UCOUNT_FANOTIFY_GROUPS,
 +      UCOUNT_FANOTIFY_MARKS,
  #endif
+       UCOUNT_RLIMIT_NPROC,
+       UCOUNT_RLIMIT_MSGQUEUE,
+       UCOUNT_RLIMIT_SIGPENDING,
+       UCOUNT_RLIMIT_MEMLOCK,
        UCOUNT_COUNTS,
  };
  
diff --cc ipc/mqueue.c
Simple merge
diff --cc kernel/cred.c
Simple merge
diff --cc kernel/exit.c
Simple merge
diff --cc kernel/fork.c
Simple merge
diff --cc kernel/signal.c
index f7c6ffcbd04407adf91a0594a949a7bd4ca1463f,9a6dab712123ee67c5e58e35e5044950f8634b90..5c3b983d283c8ce728f7e72bdf5f35968b393caf
@@@ -408,12 -410,11 +408,12 @@@ void task_join_group_stop(struct task_s
   *   appropriate lock must be held to stop the target task from exiting
   */
  static struct sigqueue *
 -__sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimit)
 +__sigqueue_alloc(int sig, struct task_struct *t, gfp_t gfp_flags,
 +               int override_rlimit, const unsigned int sigqueue_flags)
  {
        struct sigqueue *q = NULL;
-       struct user_struct *user;
-       int sigpending;
+       struct ucounts *ucounts = NULL;
+       long sigpending;
  
        /*
         * Protect access to @t credentials. This can go away when all
         * changes from/to zero.
         */
        rcu_read_lock();
-       user = __task_cred(t)->user;
-       sigpending = atomic_inc_return(&user->sigpending);
+       ucounts = task_ucounts(t);
+       sigpending = inc_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1);
        if (sigpending == 1)
-               get_uid(user);
+               ucounts = get_ucounts(ucounts);
        rcu_read_unlock();
  
-       if (override_rlimit || likely(sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
+       if (override_rlimit || (sigpending < LONG_MAX && sigpending <= task_rlimit(t, RLIMIT_SIGPENDING))) {
 -              q = kmem_cache_alloc(sigqueue_cachep, flags);
 +              /*
 +               * Preallocation does not hold sighand::siglock so it can't
 +               * use the cache. The lockless caching requires that only
 +               * one consumer and only one producer run at a time.
 +               */
 +              q = READ_ONCE(t->sigqueue_cache);
 +              if (!q || sigqueue_flags)
 +                      q = kmem_cache_alloc(sigqueue_cachep, gfp_flags);
 +              else
 +                      WRITE_ONCE(t->sigqueue_cache, NULL);
        } else {
                print_dropped_signal(sig);
        }
  
        if (unlikely(q == NULL)) {
-               if (atomic_dec_and_test(&user->sigpending))
-                       free_uid(user);
+               if (ucounts && dec_rlimit_ucounts(ucounts, UCOUNT_RLIMIT_SIGPENDING, 1))
+                       put_ucounts(ucounts);
        } else {
                INIT_LIST_HEAD(&q->list);
 -              q->flags = 0;
 +              q->flags = sigqueue_flags;
-               q->user = user;
+               q->ucounts = ucounts;
        }
        return q;
  }
  
@@@ -492,9 -452,11 +491,11 @@@ static void __sigqueue_free(struct sigq
  {
        if (q->flags & SIGQUEUE_PREALLOC)
                return;
-       if (atomic_dec_and_test(&q->user->sigpending))
-               free_uid(q->user);
+       if (q->ucounts && dec_rlimit_ucounts(q->ucounts, UCOUNT_RLIMIT_SIGPENDING, 1)) {
+               put_ucounts(q->ucounts);
+               q->ucounts = NULL;
+       }
 -      kmem_cache_free(sigqueue_cachep, q);
 +      sigqueue_cache_or_free(q);
  }
  
  void flush_sigqueue(struct sigpending *queue)
diff --cc kernel/sys.c
Simple merge
diff --cc kernel/ucount.c
index 8d8874f1c35e2b83b2908f2840d93ecca297e280,df84a2a63926979252dd0c7ce3251c9212bb79aa..87799e2379bd4a384671a0b54b3a38efcaf09f6e
@@@ -73,11 -79,11 +79,15 @@@ static struct ctl_table user_table[] = 
  #ifdef CONFIG_INOTIFY_USER
        UCOUNT_ENTRY("max_inotify_instances"),
        UCOUNT_ENTRY("max_inotify_watches"),
 +#endif
 +#ifdef CONFIG_FANOTIFY
 +      UCOUNT_ENTRY("max_fanotify_groups"),
 +      UCOUNT_ENTRY("max_fanotify_marks"),
  #endif
+       { },
+       { },
+       { },
+       { },
        { }
  };
  #endif /* CONFIG_SYSCTL */
Simple merge
diff --cc mm/mlock.c
Simple merge
diff --cc mm/mmap.c
Simple merge
diff --cc mm/shmem.c
Simple merge
Simple merge