lockd: Add helper to sanity check incoming NOTIFY requests
[safe/jmp/linux-2.6] / kernel / user.c
index 7f17e6e..865ecf5 100644 (file)
 #include <linux/module.h>
 #include <linux/user_namespace.h>
 
+struct user_namespace init_user_ns = {
+       .kref = {
+               .refcount       = ATOMIC_INIT(2),
+       },
+       .root_user = &root_user,
+};
+EXPORT_SYMBOL_GPL(init_user_ns);
+
 /*
  * UID task count cache, to get fast user lookup in "alloc_uid"
  * when changing user ID's (ie setuid() and friends).
@@ -45,11 +53,7 @@ struct user_struct root_user = {
        .files          = ATOMIC_INIT(0),
        .sigpending     = ATOMIC_INIT(0),
        .locked_shm     = 0,
-#ifdef CONFIG_KEYS
-       .uid_keyring    = &root_user_keyring,
-       .session_keyring = &root_session_keyring,
-#endif
-#ifdef CONFIG_FAIR_USER_SCHED
+#ifdef CONFIG_USER_SCHED
        .tg             = &init_task_group,
 #endif
 };
@@ -82,7 +86,7 @@ static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
        return NULL;
 }
 
-#ifdef CONFIG_FAIR_USER_SCHED
+#ifdef CONFIG_USER_SCHED
 
 static void sched_destroy_user(struct user_struct *up)
 {
@@ -93,7 +97,7 @@ static int sched_create_user(struct user_struct *up)
 {
        int rc = 0;
 
-       up->tg = sched_create_group();
+       up->tg = sched_create_group(&root_task_group);
        if (IS_ERR(up->tg))
                rc = -ENOMEM;
 
@@ -105,15 +109,15 @@ static void sched_switch_user(struct task_struct *p)
        sched_move_task(p);
 }
 
-#else  /* CONFIG_FAIR_USER_SCHED */
+#else  /* CONFIG_USER_SCHED */
 
 static void sched_destroy_user(struct user_struct *up) { }
 static int sched_create_user(struct user_struct *up) { return 0; }
 static void sched_switch_user(struct task_struct *p) { }
 
-#endif /* CONFIG_FAIR_USER_SCHED */
+#endif /* CONFIG_USER_SCHED */
 
-#if defined(CONFIG_FAIR_USER_SCHED) && defined(CONFIG_SYSFS)
+#if defined(CONFIG_USER_SCHED) && defined(CONFIG_SYSFS)
 
 static struct kset *uids_kset; /* represents the /sys/kernel/uids/ directory */
 static DEFINE_MUTEX(uids_mutex);
@@ -129,6 +133,7 @@ static inline void uids_mutex_unlock(void)
 }
 
 /* uid directory attributes */
+#ifdef CONFIG_FAIR_GROUP_SCHED
 static ssize_t cpu_shares_show(struct kobject *kobj,
                               struct kobj_attribute *attr,
                               char *buf)
@@ -155,10 +160,73 @@ static ssize_t cpu_shares_store(struct kobject *kobj,
 
 static struct kobj_attribute cpu_share_attr =
        __ATTR(cpu_share, 0644, cpu_shares_show, cpu_shares_store);
+#endif
+
+#ifdef CONFIG_RT_GROUP_SCHED
+static ssize_t cpu_rt_runtime_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr,
+                                  char *buf)
+{
+       struct user_struct *up = container_of(kobj, struct user_struct, kobj);
+
+       return sprintf(buf, "%lu\n", sched_group_rt_runtime(up->tg));
+}
+
+static ssize_t cpu_rt_runtime_store(struct kobject *kobj,
+                                   struct kobj_attribute *attr,
+                                   const char *buf, size_t size)
+{
+       struct user_struct *up = container_of(kobj, struct user_struct, kobj);
+       unsigned long rt_runtime;
+       int rc;
+
+       sscanf(buf, "%lu", &rt_runtime);
+
+       rc = sched_group_set_rt_runtime(up->tg, rt_runtime);
+
+       return (rc ? rc : size);
+}
+
+static struct kobj_attribute cpu_rt_runtime_attr =
+       __ATTR(cpu_rt_runtime, 0644, cpu_rt_runtime_show, cpu_rt_runtime_store);
+
+static ssize_t cpu_rt_period_show(struct kobject *kobj,
+                                  struct kobj_attribute *attr,
+                                  char *buf)
+{
+       struct user_struct *up = container_of(kobj, struct user_struct, kobj);
+
+       return sprintf(buf, "%lu\n", sched_group_rt_period(up->tg));
+}
+
+static ssize_t cpu_rt_period_store(struct kobject *kobj,
+                                   struct kobj_attribute *attr,
+                                   const char *buf, size_t size)
+{
+       struct user_struct *up = container_of(kobj, struct user_struct, kobj);
+       unsigned long rt_period;
+       int rc;
+
+       sscanf(buf, "%lu", &rt_period);
+
+       rc = sched_group_set_rt_period(up->tg, rt_period);
+
+       return (rc ? rc : size);
+}
+
+static struct kobj_attribute cpu_rt_period_attr =
+       __ATTR(cpu_rt_period, 0644, cpu_rt_period_show, cpu_rt_period_store);
+#endif
 
 /* default attributes per uid directory */
 static struct attribute *uids_attributes[] = {
+#ifdef CONFIG_FAIR_GROUP_SCHED
        &cpu_share_attr.attr,
+#endif
+#ifdef CONFIG_RT_GROUP_SCHED
+       &cpu_rt_runtime_attr.attr,
+       &cpu_rt_period_attr.attr,
+#endif
        NULL
 };
 
@@ -181,13 +249,12 @@ static int uids_user_create(struct user_struct *up)
        int error;
 
        memset(kobj, 0, sizeof(struct kobject));
-       kobj->ktype = &uids_ktype;
        kobj->kset = uids_kset;
-       kobject_init(kobj);
-       kobject_set_name(&up->kobj, "%d", up->uid);
-       error = kobject_add(kobj);
-       if (error)
+       error = kobject_init_and_add(kobj, &uids_ktype, NULL, "%d", up->uid);
+       if (error) {
+               kobject_put(kobj);
                goto done;
+       }
 
        kobject_uevent(kobj, KOBJ_ADD);
 done:
@@ -262,7 +329,7 @@ static inline void free_user(struct user_struct *up, unsigned long flags)
        schedule_work(&up->work);
 }
 
-#else  /* CONFIG_FAIR_USER_SCHED && CONFIG_SYSFS */
+#else  /* CONFIG_USER_SCHED && CONFIG_SYSFS */
 
 int uids_sysfs_init(void) { return 0; }
 static inline int uids_user_create(struct user_struct *up) { return 0; }
@@ -317,10 +384,10 @@ void free_uid(struct user_struct *up)
                local_irq_restore(flags);
 }
 
-struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
+struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
 {
        struct hlist_head *hashent = uidhashentry(ns, uid);
-       struct user_struct *up;
+       struct user_struct *up, *new;
 
        /* Make uid_hash_find() + uids_user_create() + uid_hash_insert()
         * atomic.
@@ -332,50 +399,18 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
        spin_unlock_irq(&uidhash_lock);
 
        if (!up) {
-               struct user_struct *new;
-
-               new = kmem_cache_alloc(uid_cachep, GFP_KERNEL);
-               if (!new) {
-                       uids_mutex_unlock();
-                       return NULL;
-               }
+               new = kmem_cache_zalloc(uid_cachep, GFP_KERNEL);
+               if (!new)
+                       goto out_unlock;
 
                new->uid = uid;
                atomic_set(&new->__count, 1);
-               atomic_set(&new->processes, 0);
-               atomic_set(&new->files, 0);
-               atomic_set(&new->sigpending, 0);
-#ifdef CONFIG_INOTIFY_USER
-               atomic_set(&new->inotify_watches, 0);
-               atomic_set(&new->inotify_devs, 0);
-#endif
-#ifdef CONFIG_POSIX_MQUEUE
-               new->mq_bytes = 0;
-#endif
-               new->locked_shm = 0;
-
-               if (alloc_uid_keyring(new, current) < 0) {
-                       kmem_cache_free(uid_cachep, new);
-                       uids_mutex_unlock();
-                       return NULL;
-               }
 
-               if (sched_create_user(new) < 0) {
-                       key_put(new->uid_keyring);
-                       key_put(new->session_keyring);
-                       kmem_cache_free(uid_cachep, new);
-                       uids_mutex_unlock();
-                       return NULL;
-               }
+               if (sched_create_user(new) < 0)
+                       goto out_free_user;
 
-               if (uids_user_create(new)) {
-                       sched_destroy_user(new);
-                       key_put(new->uid_keyring);
-                       key_put(new->session_keyring);
-                       kmem_cache_free(uid_cachep, new);
-                       uids_mutex_unlock();
-                       return NULL;
-               }
+               if (uids_user_create(new))
+                       goto out_destoy_sched;
 
                /*
                 * Before adding this, check whether we raced
@@ -384,7 +419,7 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
                spin_lock_irq(&uidhash_lock);
                up = uid_hash_find(uid, hashent);
                if (up) {
-                       /* This case is not possible when CONFIG_FAIR_USER_SCHED
+                       /* This case is not possible when CONFIG_USER_SCHED
                         * is defined, since we serialize alloc_uid() using
                         * uids_mutex. Hence no need to call
                         * sched_destroy_user() or remove_user_sysfs_dir().
@@ -403,6 +438,14 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
        uids_mutex_unlock();
 
        return up;
+
+out_destoy_sched:
+       sched_destroy_user(new);
+out_free_user:
+       kmem_cache_free(uid_cachep, new);
+out_unlock:
+       uids_mutex_unlock();
+       return NULL;
 }
 
 void switch_uid(struct user_struct *new_user)
@@ -435,6 +478,7 @@ void switch_uid(struct user_struct *new_user)
        suid_keys(current);
 }
 
+#ifdef CONFIG_USER_NS
 void release_uids(struct user_namespace *ns)
 {
        int i;
@@ -459,6 +503,7 @@ void release_uids(struct user_namespace *ns)
 
        free_uid(ns->root_user);
 }
+#endif
 
 static int __init uid_cache_init(void)
 {