struct ecryptfs_msg_ctx *msg_ctx;
        size_t msg_size;
        struct nsproxy *nsproxy;
-       struct user_namespace *current_user_ns;
+       struct user_namespace *tsk_user_ns;
        uid_t ctx_euid;
        int rc;
 
                mutex_unlock(&ecryptfs_daemon_hash_mux);
                goto wake_up;
        }
-       current_user_ns = nsproxy->user_ns;
+       tsk_user_ns = __task_cred(msg_ctx->task)->user->user_ns;
        ctx_euid = task_euid(msg_ctx->task);
-       rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, current_user_ns);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns);
        rcu_read_unlock();
        mutex_unlock(&ecryptfs_daemon_hash_mux);
        if (rc) {
                       euid, ctx_euid);
                goto unlock;
        }
-       if (current_user_ns != user_ns) {
+       if (tsk_user_ns != user_ns) {
                rc = -EBADMSG;
                printk(KERN_WARNING "%s: Received message from user_ns "
                       "[0x%p]; expected message from user_ns [0x%p]\n",
-                      __func__, user_ns, nsproxy->user_ns);
+                      __func__, user_ns, tsk_user_ns);
                goto unlock;
        }
        if (daemon->pid != pid) {
        uid_t euid = current_euid();
        int rc;
 
-       rc = ecryptfs_find_daemon_by_euid(&daemon, euid,
-                                         current->nsproxy->user_ns);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
        if (rc || !daemon) {
                rc = -ENOTCONN;
                printk(KERN_ERR "%s: User [%d] does not have a daemon "
 
 
        mutex_lock(&ecryptfs_daemon_hash_mux);
        /* TODO: Just use file->private_data? */
-       rc = ecryptfs_find_daemon_by_euid(&daemon, euid,
-                                         current->nsproxy->user_ns);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
        BUG_ON(rc || !daemon);
        mutex_lock(&daemon->mux);
        mutex_unlock(&ecryptfs_daemon_hash_mux);
                       "count; rc = [%d]\n", __func__, rc);
                goto out_unlock_daemon_list;
        }
-       rc = ecryptfs_find_daemon_by_euid(&daemon, euid,
-                                         current->nsproxy->user_ns);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
        if (rc || !daemon) {
-               rc = ecryptfs_spawn_daemon(&daemon, euid,
-                                          current->nsproxy->user_ns,
+               rc = ecryptfs_spawn_daemon(&daemon, euid, current_user_ns(),
                                           task_pid(current));
                if (rc) {
                        printk(KERN_ERR "%s: Error attempting to spawn daemon; "
        int rc;
 
        mutex_lock(&ecryptfs_daemon_hash_mux);
-       rc = ecryptfs_find_daemon_by_euid(&daemon, euid,
-                                         current->nsproxy->user_ns);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
        BUG_ON(rc || !daemon);
        mutex_lock(&daemon->mux);
        BUG_ON(daemon->pid != task_pid(current));
 
        mutex_lock(&ecryptfs_daemon_hash_mux);
        /* TODO: Just use file->private_data? */
-       rc = ecryptfs_find_daemon_by_euid(&daemon, euid,
-                                         current->nsproxy->user_ns);
+       rc = ecryptfs_find_daemon_by_euid(&daemon, euid, current_user_ns());
        BUG_ON(rc || !daemon);
        mutex_lock(&daemon->mux);
        if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
                goto check_list;
        }
        BUG_ON(euid != daemon->euid);
-       BUG_ON(current->nsproxy->user_ns != daemon->user_ns);
+       BUG_ON(current_user_ns() != daemon->user_ns);
        BUG_ON(task_pid(current) != daemon->pid);
        msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
                                   struct ecryptfs_msg_ctx, daemon_out_list);
                        goto out_free;
                }
                rc = ecryptfs_miscdev_response(&data[i], packet_size,
-                                              euid, current->nsproxy->user_ns,
+                                              euid, current_user_ns(),
                                               task_pid(current), seq);
                if (rc)
                        printk(KERN_WARNING "%s: Failed to deliver miscdev "
 
 } while (0)
 
 extern struct group_info *groups_alloc(int);
+extern struct group_info init_groups;
 extern void groups_free(struct group_info *);
 extern int set_current_groups(struct group_info *);
 extern int set_groups(struct cred *, struct group_info *);
 #define current_fsgid()        (current_cred_xxx(fsgid))
 #define current_cap()          (current_cred_xxx(cap_effective))
 #define current_user()         (current_cred_xxx(user))
+#define current_user_ns()      (current_cred_xxx(user)->user_ns)
 #define current_security()     (current_cred_xxx(security))
 
 #define current_uid_gid(_uid, _gid)            \
 
        .mnt_ns         = NULL,                                         \
        INIT_NET_NS(net_ns)                                             \
        INIT_IPC_NS(ipc_ns)                                             \
-       .user_ns        = &init_user_ns,                                \
 }
 
 #define INIT_SIGHAND(sighand) {                                                \
 
        struct ipc_namespace *ipc_ns;
        struct mnt_namespace *mnt_ns;
        struct pid_namespace *pid_ns;
-       struct user_namespace *user_ns;
        struct net           *net_ns;
 };
 extern struct nsproxy init_nsproxy;
 
        /* Hash table maintenance information */
        struct hlist_node uidhash_node;
        uid_t uid;
+       struct user_namespace *user_ns;
 
 #ifdef CONFIG_USER_SCHED
        struct task_group *tg;
 
 struct user_namespace {
        struct kref             kref;
        struct hlist_head       uidhash_table[UIDHASH_SZ];
-       struct user_struct      *root_user;
+       struct user_struct      *creator;
 };
 
 extern struct user_namespace init_user_ns;
        return ns;
 }
 
-extern struct user_namespace *copy_user_ns(int flags,
-                                          struct user_namespace *old_ns);
+extern int create_user_ns(struct cred *new);
 extern void free_user_ns(struct kref *kref);
 
 static inline void put_user_ns(struct user_namespace *ns)
        return &init_user_ns;
 }
 
-static inline struct user_namespace *copy_user_ns(int flags,
-                                                 struct user_namespace *old_ns)
+static inline int create_user_ns(struct cred *new)
 {
-       if (flags & CLONE_NEWUSER)
-               return ERR_PTR(-EINVAL);
-
-       return old_ns;
+       return -EINVAL;
 }
 
 static inline void put_user_ns(struct user_namespace *ns)
 
        struct thread_group_cred *tgcred;
 #endif
        struct cred *new;
+       int ret;
 
        mutex_init(&p->cred_exec_mutex);
 
        if (!new)
                return -ENOMEM;
 
+       if (clone_flags & CLONE_NEWUSER) {
+               ret = create_user_ns(new);
+               if (ret < 0)
+                       goto error_put;
+       }
+
 #ifdef CONFIG_KEYS
        /* new threads get their own thread keyrings if their parent already
         * had one */
        if (!(clone_flags & CLONE_THREAD)) {
                tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL);
                if (!tgcred) {
-                       put_cred(new);
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto error_put;
                }
                atomic_set(&tgcred->usage, 1);
                spin_lock_init(&tgcred->lock);
        atomic_inc(&new->user->processes);
        p->cred = p->real_cred = get_cred(new);
        return 0;
+
+error_put:
+       put_cred(new);
+       return ret;
 }
 
 /**
 
        if (atomic_read(&p->real_cred->user->processes) >=
                        p->signal->rlim[RLIMIT_NPROC].rlim_cur) {
                if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
-                   p->real_cred->user != current->nsproxy->user_ns->root_user)
+                   p->real_cred->user != INIT_USER)
                        goto bad_fork_free;
        }
 
        int trace = 0;
        long nr;
 
+       /*
+        * Do some preliminary argument and permissions checking before we
+        * actually start allocating stuff
+        */
+       if (clone_flags & CLONE_NEWUSER) {
+               if (clone_flags & CLONE_THREAD)
+                       return -EINVAL;
+               /* hopefully this check will go away when userns support is
+                * complete
+                */
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+       }
+
        /*
         * We hope to recycle these flags after 2.6.26
         */
        err = -EINVAL;
        if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
                                CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
-                               CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER|
-                               CLONE_NEWNET))
+                               CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET))
                goto bad_unshare_out;
 
        /*
 
                goto out_pid;
        }
 
-       new_nsp->user_ns = copy_user_ns(flags, tsk->nsproxy->user_ns);
-       if (IS_ERR(new_nsp->user_ns)) {
-               err = PTR_ERR(new_nsp->user_ns);
-               goto out_user;
-       }
-
        new_nsp->net_ns = copy_net_ns(flags, tsk->nsproxy->net_ns);
        if (IS_ERR(new_nsp->net_ns)) {
                err = PTR_ERR(new_nsp->net_ns);
        return new_nsp;
 
 out_net:
-       if (new_nsp->user_ns)
-               put_user_ns(new_nsp->user_ns);
-out_user:
        if (new_nsp->pid_ns)
                put_pid_ns(new_nsp->pid_ns);
 out_pid:
        get_nsproxy(old_ns);
 
        if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-                               CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNET)))
+                               CLONE_NEWPID | CLONE_NEWNET)))
                return 0;
 
        if (!capable(CAP_SYS_ADMIN)) {
                put_ipc_ns(ns->ipc_ns);
        if (ns->pid_ns)
                put_pid_ns(ns->pid_ns);
-       if (ns->user_ns)
-               put_user_ns(ns->user_ns);
        put_net(ns->net_ns);
        kmem_cache_free(nsproxy_cachep, ns);
 }
        int err = 0;
 
        if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-                              CLONE_NEWUSER | CLONE_NEWNET)))
+                              CLONE_NEWNET)))
                return 0;
 
        if (!capable(CAP_SYS_ADMIN))
 
 {
        struct user_struct *new_user;
 
-       new_user = alloc_uid(current->nsproxy->user_ns, new->uid);
+       new_user = alloc_uid(current_user_ns(), new->uid);
        if (!new_user)
                return -EAGAIN;
 
        if (atomic_read(&new_user->processes) >=
                                current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
-                       new_user != current->nsproxy->user_ns->root_user) {
+                       new_user != INIT_USER) {
                free_uid(new_user);
                return -EAGAIN;
        }
 
 
 struct user_namespace init_user_ns = {
        .kref = {
-               .refcount       = ATOMIC_INIT(2),
+               .refcount       = ATOMIC_INIT(1),
        },
-       .root_user = &root_user,
+       .creator = &root_user,
 };
 EXPORT_SYMBOL_GPL(init_user_ns);
 
  */
 static DEFINE_SPINLOCK(uidhash_lock);
 
+/* root_user.__count is 2, 1 for init task cred, 1 for init_user_ns->creator */
 struct user_struct root_user = {
-       .__count        = ATOMIC_INIT(1),
+       .__count        = ATOMIC_INIT(2),
        .processes      = ATOMIC_INIT(1),
        .files          = ATOMIC_INIT(0),
        .sigpending     = ATOMIC_INIT(0),
        .locked_shm     = 0,
+       .user_ns        = &init_user_ns,
 #ifdef CONFIG_USER_SCHED
        .tg             = &init_task_group,
 #endif
  * IRQ state (as stored in flags) is restored and uidhash_lock released
  * upon function exit.
  */
-static inline void free_user(struct user_struct *up, unsigned long flags)
+static void free_user(struct user_struct *up, unsigned long flags)
 {
        /* restore back the count */
        atomic_inc(&up->__count);
        spin_unlock_irqrestore(&uidhash_lock, flags);
 
+       put_user_ns(up->user_ns);
        INIT_WORK(&up->work, remove_user_sysfs_dir);
        schedule_work(&up->work);
 }
  * IRQ state (as stored in flags) is restored and uidhash_lock released
  * upon function exit.
  */
-static inline void free_user(struct user_struct *up, unsigned long flags)
+static void free_user(struct user_struct *up, unsigned long flags)
 {
        uid_hash_remove(up);
        spin_unlock_irqrestore(&uidhash_lock, flags);
        sched_destroy_user(up);
        key_put(up->uid_keyring);
        key_put(up->session_keyring);
+       put_user_ns(up->user_ns);
        kmem_cache_free(uid_cachep, up);
 }
 
 {
        struct user_struct *ret;
        unsigned long flags;
-       struct user_namespace *ns = current->nsproxy->user_ns;
+       struct user_namespace *ns = current_user()->user_ns;
 
        spin_lock_irqsave(&uidhash_lock, flags);
        ret = uid_hash_find(uid, uidhashentry(ns, uid));
                if (sched_create_user(new) < 0)
                        goto out_free_user;
 
+               new->user_ns = get_user_ns(ns);
+
                if (uids_user_create(new))
                        goto out_destoy_sched;
 
                        up = new;
                }
                spin_unlock_irq(&uidhash_lock);
-
        }
 
        uids_mutex_unlock();
 
 out_destoy_sched:
        sched_destroy_user(new);
+       put_user_ns(new->user_ns);
 out_free_user:
        kmem_cache_free(uid_cachep, new);
 out_unlock:
        return NULL;
 }
 
-#ifdef CONFIG_USER_NS
-void release_uids(struct user_namespace *ns)
-{
-       int i;
-       unsigned long flags;
-       struct hlist_head *head;
-       struct hlist_node *nd;
-
-       spin_lock_irqsave(&uidhash_lock, flags);
-       /*
-        * collapse the chains so that the user_struct-s will
-        * be still alive, but not in hashes. subsequent free_uid()
-        * will free them.
-        */
-       for (i = 0; i < UIDHASH_SZ; i++) {
-               head = ns->uidhash_table + i;
-               while (!hlist_empty(head)) {
-                       nd = head->first;
-                       hlist_del_init(nd);
-               }
-       }
-       spin_unlock_irqrestore(&uidhash_lock, flags);
-
-       free_uid(ns->root_user);
-}
-#endif
-
 static int __init uid_cache_init(void)
 {
        int n;
 
 #include <linux/nsproxy.h>
 #include <linux/slab.h>
 #include <linux/user_namespace.h>
+#include <linux/cred.h>
 
 /*
- * Clone a new ns copying an original user ns, setting refcount to 1
- * @old_ns: namespace to clone
- * Return NULL on error (failure to kmalloc), new ns otherwise
+ * Create a new user namespace, deriving the creator from the user in the
+ * passed credentials, and replacing that user with the new root user for the
+ * new namespace.
+ *
+ * This is called by copy_creds(), which will finish setting the target task's
+ * credentials.
  */
-static struct user_namespace *clone_user_ns(struct user_namespace *old_ns)
+int create_user_ns(struct cred *new)
 {
        struct user_namespace *ns;
-       struct user_struct *new_user;
-       struct cred *new;
+       struct user_struct *root_user;
        int n;
 
        ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL);
        if (!ns)
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
 
        kref_init(&ns->kref);
 
        for (n = 0; n < UIDHASH_SZ; ++n)
                INIT_HLIST_HEAD(ns->uidhash_table + n);
 
-       /* Insert new root user.  */
-       ns->root_user = alloc_uid(ns, 0);
-       if (!ns->root_user) {
+       /* Alloc new root user.  */
+       root_user = alloc_uid(ns, 0);
+       if (!root_user) {
                kfree(ns);
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
        }
 
-       /* Reset current->user with a new one */
-       new_user = alloc_uid(ns, current_uid());
-       if (!new_user) {
-               free_uid(ns->root_user);
-               kfree(ns);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       /* Install the new user */
-       new = prepare_creds();
-       if (!new) {
-               free_uid(new_user);
-               free_uid(ns->root_user);
-               kfree(ns);
-       }
-       free_uid(new->user);
-       new->user = new_user;
-       commit_creds(new);
-       return ns;
-}
-
-struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns)
-{
-       struct user_namespace *new_ns;
-
-       BUG_ON(!old_ns);
-       get_user_ns(old_ns);
-
-       if (!(flags & CLONE_NEWUSER))
-               return old_ns;
+       /* set the new root user in the credentials under preparation */
+       ns->creator = new->user;
+       new->user = root_user;
+       new->uid = new->euid = new->suid = new->fsuid = 0;
+       new->gid = new->egid = new->sgid = new->fsgid = 0;
+       put_group_info(new->group_info);
+       new->group_info = get_group_info(&init_groups);
+#ifdef CONFIG_KEYS
+       key_put(new->request_key_auth);
+       new->request_key_auth = NULL;
+#endif
+       /* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
 
-       new_ns = clone_user_ns(old_ns);
+       /* alloc_uid() incremented the userns refcount.  Just set it to 1 */
+       kref_set(&ns->kref, 1);
 
-       put_user_ns(old_ns);
-       return new_ns;
+       return 0;
 }
 
 void free_user_ns(struct kref *kref)
        struct user_namespace *ns;
 
        ns = container_of(kref, struct user_namespace, kref);
-       release_uids(ns);
+       free_uid(ns->creator);
        kfree(ns);
 }
 EXPORT_SYMBOL(free_user_ns);