fix struct user_info export's sysfs interaction
Kay Sievers [Fri, 2 Nov 2007 12:47:53 +0000 (13:47 +0100)]
Clean up the use of ksets and kobjects. Kobjects are instances of
objects (like struct user_info), ksets are collections of objects of a
similar type (like the uids directory containing the user_info directories).
So, use kobjects for the user_info directories, and a kset for the "uids"
directory.

On object cleanup, the final kobject_put() was missing.

Cc: Dhaval Giani <dhaval@linux.vnet.ibm.com>
Cc: Srivatsa Vaddagiri <vatsa@linux.vnet.ibm.com>
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

include/linux/sched.h
kernel/ksysfs.c
kernel/user.c

index cc14656..d6eacda 100644 (file)
@@ -552,18 +552,13 @@ struct user_struct {
 #ifdef CONFIG_FAIR_USER_SCHED
        struct task_group *tg;
 #ifdef CONFIG_SYSFS
-       struct kset kset;
-       struct subsys_attribute user_attr;
+       struct kobject kobj;
        struct work_struct work;
 #endif
 #endif
 };
 
-#ifdef CONFIG_FAIR_USER_SCHED
-extern int uids_kobject_init(void);
-#else
-static inline int uids_kobject_init(void) { return 0; }
-#endif
+extern int uids_sysfs_init(void);
 
 extern struct user_struct *find_user(uid_t);
 
index dd0f9e7..45e6465 100644 (file)
@@ -141,11 +141,8 @@ static int __init ksysfs_init(void)
                        goto group_exit;
        }
 
-       /*
-        * Create "/sys/kernel/uids" directory and corresponding root user's
-        * directory under it.
-        */
-       error = uids_kobject_init();
+       /* create the /sys/kernel/uids/ directory */
+       error = uids_sysfs_init();
        if (error)
                goto notes_exit;
 
index 80f1116..5a106f3 100644 (file)
@@ -115,7 +115,7 @@ static void sched_switch_user(struct task_struct *p) { }
 
 #if defined(CONFIG_FAIR_USER_SCHED) && defined(CONFIG_SYSFS)
 
-static struct kobject uids_kobject; /* represents /sys/kernel/uids directory */
+static struct kset *uids_kset; /* represents the /sys/kernel/uids/ directory */
 static DEFINE_MUTEX(uids_mutex);
 
 static inline void uids_mutex_lock(void)
@@ -128,86 +128,84 @@ static inline void uids_mutex_unlock(void)
        mutex_unlock(&uids_mutex);
 }
 
-/* return cpu shares held by the user */
-static ssize_t cpu_shares_show(struct kset *kset, char *buffer)
+/* uid directory attributes */
+static ssize_t cpu_shares_show(struct kobject *kobj,
+                              struct kobj_attribute *attr,
+                              char *buf)
 {
-       struct user_struct *up = container_of(kset, struct user_struct, kset);
+       struct user_struct *up = container_of(kobj, struct user_struct, kobj);
 
-       return sprintf(buffer, "%lu\n", sched_group_shares(up->tg));
+       return sprintf(buf, "%lu\n", sched_group_shares(up->tg));
 }
 
-/* modify cpu shares held by the user */
-static ssize_t cpu_shares_store(struct kset *kset, const char *buffer,
-                               size_t size)
+static ssize_t cpu_shares_store(struct kobject *kobj,
+                               struct kobj_attribute *attr,
+                               const char *buf, size_t size)
 {
-       struct user_struct *up = container_of(kset, struct user_struct, kset);
+       struct user_struct *up = container_of(kobj, struct user_struct, kobj);
        unsigned long shares;
        int rc;
 
-       sscanf(buffer, "%lu", &shares);
+       sscanf(buf, "%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)
+static struct kobj_attribute cpu_share_attr =
+       __ATTR(cpu_share, 0644, cpu_shares_show, cpu_shares_store);
+
+/* default attributes per uid directory */
+static struct attribute *uids_attributes[] = {
+       &cpu_share_attr.attr,
+       NULL
+};
+
+/* the lifetime of user_struct is not managed by the core (now) */
+static void uids_release(struct kobject *kobj)
 {
-       sa->attr.name = name;
-       sa->attr.mode = mode;
-       sa->show = cpu_shares_show;
-       sa->store = cpu_shares_store;
+       return;
 }
 
-/* Create "/sys/kernel/uids/<uid>" directory and
- *  "/sys/kernel/uids/<uid>/cpu_share" file for this user.
- */
-static int user_kobject_create(struct user_struct *up)
+static struct kobj_type uids_ktype = {
+       .sysfs_ops = &kobj_sysfs_ops,
+       .default_attrs = uids_attributes,
+       .release = uids_release,
+};
+
+/* create /sys/kernel/uids/<uid>/cpu_share file for this user */
+static int uids_user_create(struct user_struct *up)
 {
-       struct kset *kset = &up->kset;
-       struct kobject *kobj = &kset->kobj;
+       struct kobject *kobj = &up->kobj;
        int error;
 
-       memset(kset, 0, sizeof(struct kset));
-       kobj->parent = &uids_kobject;   /* create under /sys/kernel/uids dir */
-       kobject_set_name(kobj, "%d", up->uid);
-       kset_init(kset);
-       user_attr_init(&up->user_attr, "cpu_share", 0644);
-
+       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)
                goto done;
 
-       error = sysfs_create_file(kobj, &up->user_attr.attr);
-       if (error)
-               kobject_del(kobj);
-
        kobject_uevent(kobj, KOBJ_ADD);
-
 done:
        return error;
 }
 
-/* create these in sysfs filesystem:
+/* create these entries in sysfs:
  *     "/sys/kernel/uids" directory
  *     "/sys/kernel/uids/0" directory (for root user)
  *     "/sys/kernel/uids/0/cpu_share" file (for root user)
  */
-int __init uids_kobject_init(void)
+int __init uids_sysfs_init(void)
 {
-       int error;
+       uids_kset = kset_create_and_add("uids", NULL, &kernel_kset->kobj);
+       if (!uids_kset)
+               return -ENOMEM;
 
-       /* create under /sys/kernel dir */
-       uids_kobject.parent = &kernel_kset->kobj;
-       uids_kobject.kset = kernel_kset;
-       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;
+       return uids_user_create(&root_user);
 }
 
 /* work function to remove sysfs directory for a user and free up
@@ -216,7 +214,6 @@ int __init uids_kobject_init(void)
 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;
        unsigned long flags;
        int remove_user = 0;
 
@@ -238,9 +235,9 @@ static void remove_user_sysfs_dir(struct work_struct *w)
        if (!remove_user)
                goto done;
 
-       sysfs_remove_file(kobj, &up->user_attr.attr);
-       kobject_uevent(kobj, KOBJ_REMOVE);
-       kobject_del(kobj);
+       kobject_uevent(&up->kobj, KOBJ_REMOVE);
+       kobject_del(&up->kobj);
+       kobject_put(&up->kobj);
 
        sched_destroy_user(up);
        key_put(up->uid_keyring);
@@ -267,7 +264,8 @@ static inline void free_user(struct user_struct *up, unsigned long flags)
 
 #else  /* CONFIG_FAIR_USER_SCHED && CONFIG_SYSFS */
 
-static inline int user_kobject_create(struct user_struct *up) { return 0; }
+int uids_sysfs_init(void) { return 0; }
+static inline int uids_user_create(struct user_struct *up) { return 0; }
 static inline void uids_mutex_lock(void) { }
 static inline void uids_mutex_unlock(void) { }
 
@@ -324,7 +322,7 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
        struct hlist_head *hashent = uidhashentry(ns, uid);
        struct user_struct *up;
 
-       /* Make uid_hash_find() + user_kobject_create() + uid_hash_insert()
+       /* Make uid_hash_find() + uids_user_create() + uid_hash_insert()
         * atomic.
         */
        uids_mutex_lock();
@@ -370,7 +368,7 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
                        return NULL;
                }
 
-               if (user_kobject_create(new)) {
+               if (uids_user_create(new)) {
                        sched_destroy_user(new);
                        key_put(new->uid_keyring);
                        key_put(new->session_keyring);