mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-11-01 09:13:37 +00:00 
			
		
		
		
	fix struct user_info export's sysfs interaction
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>
This commit is contained in:
		
							parent
							
								
									386f275f5d
								
							
						
					
					
						commit
						eb41d9465c
					
				
					 3 changed files with 55 additions and 65 deletions
				
			
		| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										104
									
								
								kernel/user.c
									
										
									
									
									
								
							
							
						
						
									
										104
									
								
								kernel/user.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue