Hi Ingo,

Adds tunables in sysfs to modify a user's cpu share.

A directory is created in sysfs for each new user in the system.

        /sys/kernel/uids/<uid>/cpu_share

Reading this file returns the cpu shares granted for the user.
Writing into this file modifies the cpu share for the user. Only an 
administrator is allowed to modify a user's cpu share.

Ex: 
        # cd /sys/kernel/uids/
        # cat 512/cpu_share
        1024
        # echo 2048 > 512/cpu_share
        # cat 512/cpu_share
        2048
        #

Signed-off-by: Srivatsa Vaddagiri <[EMAIL PROTECTED]>
Signed-off-by: Dhaval Giani <[EMAIL PROTECTED]>

---
 include/linux/sched.h |   11 +++++
 kernel/ksysfs.c       |    4 +
 kernel/sched.c        |    5 ++
 kernel/user.c         |  110 +++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 129 insertions(+), 1 deletion(-)

Index: linux-2.6.23-rc8-sched-devel/include/linux/sched.h
===================================================================
--- linux-2.6.23-rc8-sched-devel.orig/include/linux/sched.h
+++ linux-2.6.23-rc8-sched-devel/include/linux/sched.h
@@ -86,6 +86,7 @@ struct sched_param {
 #include <linux/timer.h>
 #include <linux/hrtimer.h>
 #include <linux/task_io_accounting.h>
+#include <linux/kobject.h>
 
 #include <asm/processor.h>
 
@@ -598,9 +599,18 @@ struct user_struct {
 
 #ifdef CONFIG_FAIR_USER_SCHED
        struct task_group *tg;
+       struct kset kset;
+       struct subsys_attribute user_attr;
+       struct work_struct work;
 #endif
 };
 
+#ifdef CONFIG_FAIR_USER_SCHED
+extern int uids_kobject_init(void);
+#else
+static inline int uids_kobject_init(void) { return 0; }
+#endif
+
 extern struct user_struct *find_user(uid_t);
 
 extern struct user_struct root_user;
@@ -1846,6 +1856,7 @@ extern struct task_group *sched_create_g
 extern void sched_destroy_group(struct task_group *tg);
 extern void sched_move_task(struct task_struct *tsk);
 extern int sched_group_set_shares(struct task_group *tg, unsigned long shares);
+extern unsigned long sched_group_shares(struct task_group *tg);
 
 #endif
 
Index: linux-2.6.23-rc8-sched-devel/kernel/ksysfs.c
===================================================================
--- linux-2.6.23-rc8-sched-devel.orig/kernel/ksysfs.c
+++ linux-2.6.23-rc8-sched-devel/kernel/ksysfs.c
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kexec.h>
+#include <linux/sched.h>
 
 #define KERNEL_ATTR_RO(_name) \
 static struct subsys_attribute _name##_attr = __ATTR_RO(_name)
@@ -116,6 +117,9 @@ static int __init ksysfs_init(void)
                                              &notes_attr);
        }
 
+       if (!error)
+               error = uids_kobject_init();
+
        return error;
 }
 
Index: linux-2.6.23-rc8-sched-devel/kernel/sched.c
===================================================================
--- linux-2.6.23-rc8-sched-devel.orig/kernel/sched.c
+++ linux-2.6.23-rc8-sched-devel/kernel/sched.c
@@ -6928,4 +6928,9 @@ int sched_group_set_shares(struct task_g
        return 0;
 }
 
+unsigned long sched_group_shares(struct task_group *tg)
+{
+       return tg->shares;
+}
+
 #endif /* CONFIG_FAIR_GROUP_SCHED */
Index: linux-2.6.23-rc8-sched-devel/kernel/user.c
===================================================================
--- linux-2.6.23-rc8-sched-devel.orig/kernel/user.c
+++ linux-2.6.23-rc8-sched-devel/kernel/user.c
@@ -56,6 +56,62 @@ struct user_struct root_user = {
 };
 
 #ifdef CONFIG_FAIR_USER_SCHED
+
+static struct kobject uids_kobject;
+
+ssize_t cpu_shares_show(struct kset *kset, char *buffer)
+{
+       struct user_struct *up = container_of(kset, struct user_struct, kset);
+
+       return sprintf(buffer, "%lu\n", sched_group_shares(up->tg));
+}
+
+ssize_t cpu_shares_store(struct kset *kset, const char *buffer, size_t size)
+{
+       struct user_struct *up = container_of(kset, struct user_struct, kset);
+       unsigned long shares;
+       int rc;
+
+       sscanf(buffer, "%lu", &shares);
+
+       rc = sched_group_set_shares(up->tg, shares);
+
+       return (rc ? rc : size);
+}
+
+static void user_attr_init(struct subsys_attribute *sa, char *name, int mode)
+{
+       sa->attr.name = name;
+       sa->attr.mode = mode;
+       sa->show = cpu_shares_show;
+       sa->store = cpu_shares_store;
+}
+
+static int user_kobject_create(struct user_struct *up)
+{
+       struct kset *kset = &up->kset;
+       struct kobject *kobj = &kset->kobj;
+       int error;
+
+       memset(kset, 0, sizeof(struct kset));
+       kobj->parent = &uids_kobject;
+       kobject_set_name(kobj, "%d", up->uid);
+       kset_init(kset);
+       user_attr_init(&up->user_attr, "cpu_share", 0644);
+
+       error = kobject_add(kobj);
+
+       if (error)
+               goto done;
+
+       error = sysfs_create_file(kobj, &up->user_attr.attr);
+       if (error)
+               kobject_del(kobj);
+
+done:
+       return error;
+}
+
 static void sched_destroy_user(struct user_struct *up)
 {
        sched_destroy_group(up->tg);
@@ -77,11 +133,53 @@ static void sched_switch_user(struct tas
        sched_move_task(p);
 }
 
+int __init uids_kobject_init(void)
+{
+       int error;
+
+       uids_kobject.parent = &kernel_subsys.kobj;
+       kobject_set_name(&uids_kobject, "uids");
+       kobject_init(&uids_kobject);
+       error = kobject_add(&uids_kobject);
+
+       if (!error)
+               error = user_kobject_create(&root_user);
+
+       return error;
+}
+
+static void remove_user_sysfs_dir(struct work_struct *w)
+{
+       struct user_struct *up = container_of(w, struct user_struct, work);
+       struct kobject *kobj = &up->kset.kobj;
+
+       sysfs_remove_file(kobj, &up->user_attr.attr);
+       kobject_del(kobj);
+       kmem_cache_free(uid_cachep, up);
+}
+
+static inline void free_user(struct user_struct *up)
+{
+       struct kobject *kobj = &up->kset.kobj;
+
+       if (!kobj->sd)
+               return;
+
+       INIT_WORK(&up->work, remove_user_sysfs_dir);
+       schedule_work(&up->work);
+}
+
 #else  /* CONFIG_FAIR_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) { }
+static inline int user_kobject_create(struct user_struct *up) { return 0; }
+
+static inline void free_user(struct user_struct *up)
+{
+       kmem_cache_free(uid_cachep, up);
+}
 
 #endif /* CONFIG_FAIR_USER_SCHED */
 
@@ -145,7 +243,7 @@ void free_uid(struct user_struct *up)
                sched_destroy_user(up);
                key_put(up->uid_keyring);
                key_put(up->session_keyring);
-               kmem_cache_free(uid_cachep, up);
+               free_user(up);
        } else {
                local_irq_restore(flags);
        }
@@ -155,6 +253,7 @@ struct user_struct * alloc_uid(struct us
 {
        struct hlist_head *hashent = uidhashentry(ns, uid);
        struct user_struct *up;
+       int create_sysfs_dir = 0;
 
        spin_lock_irq(&uidhash_lock);
        up = uid_hash_find(uid, hashent);
@@ -205,10 +304,19 @@ struct user_struct * alloc_uid(struct us
                } else {
                        uid_hash_insert(new, hashent);
                        up = new;
+                       create_sysfs_dir = 1;
                }
                spin_unlock_irq(&uidhash_lock);
 
        }
+
+       if (create_sysfs_dir) {
+               if (user_kobject_create(up)) {
+                       free_uid(up);
+                       up = NULL;
+               }
+       }
+
        return up;
 }
 
-- 
regards,
Dhaval
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to