cgroup: convert cgroup_ida to cgroup_idr
This enables us to lookup a cgroup by its id. v4: - add a comment for idr_remove() in cgroup_offline_fn(). v3: - on success, idr_alloc() returns the id but not 0, so fix the BUG_ON() in cgroup_init(). - pass the right value to idr_alloc() so that the id for dummy cgroup is 0. Signed-off-by: Li Zefan <lizefan@huawei.com> Reviewed-by: Michal Hocko <mhocko@suse.cz> Signed-off-by: Tejun Heo <tj@kernel.org>
This commit is contained in:
		
					parent
					
						
							
								6f4b7e632d
							
						
					
				
			
			
				commit
				
					
						4e96ee8e98
					
				
			
		
					 2 changed files with 29 additions and 8 deletions
				
			
		|  | @ -161,7 +161,7 @@ struct cgroup_name { | ||||||
| struct cgroup { | struct cgroup { | ||||||
| 	unsigned long flags;		/* "unsigned long" so bitops work */ | 	unsigned long flags;		/* "unsigned long" so bitops work */ | ||||||
| 
 | 
 | ||||||
| 	int id;				/* ida allocated in-hierarchy ID */ | 	int id;				/* idr allocated in-hierarchy ID */ | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * We link our 'sibling' struct into our parent's 'children'. | 	 * We link our 'sibling' struct into our parent's 'children'. | ||||||
|  | @ -322,7 +322,7 @@ struct cgroupfs_root { | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
| 
 | 
 | ||||||
| 	/* IDs for cgroups in this hierarchy */ | 	/* IDs for cgroups in this hierarchy */ | ||||||
| 	struct ida cgroup_ida; | 	struct idr cgroup_idr; | ||||||
| 
 | 
 | ||||||
| 	/* The path to use for release notifications. */ | 	/* The path to use for release notifications. */ | ||||||
| 	char release_agent_path[PATH_MAX]; | 	char release_agent_path[PATH_MAX]; | ||||||
|  |  | ||||||
|  | @ -866,8 +866,6 @@ static void cgroup_free_fn(struct work_struct *work) | ||||||
| 	 */ | 	 */ | ||||||
| 	dput(cgrp->parent->dentry); | 	dput(cgrp->parent->dentry); | ||||||
| 
 | 
 | ||||||
| 	ida_simple_remove(&cgrp->root->cgroup_ida, cgrp->id); |  | ||||||
| 
 |  | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Drop the active superblock reference that we took when we | 	 * Drop the active superblock reference that we took when we | ||||||
| 	 * created the cgroup. This will free cgrp->root, if we are | 	 * created the cgroup. This will free cgrp->root, if we are | ||||||
|  | @ -1379,6 +1377,7 @@ static void init_cgroup_root(struct cgroupfs_root *root) | ||||||
| 	cgrp->root = root; | 	cgrp->root = root; | ||||||
| 	RCU_INIT_POINTER(cgrp->name, &root_cgroup_name); | 	RCU_INIT_POINTER(cgrp->name, &root_cgroup_name); | ||||||
| 	init_cgroup_housekeeping(cgrp); | 	init_cgroup_housekeeping(cgrp); | ||||||
|  | 	idr_init(&root->cgroup_idr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int cgroup_init_root_id(struct cgroupfs_root *root, int start, int end) | static int cgroup_init_root_id(struct cgroupfs_root *root, int start, int end) | ||||||
|  | @ -1451,7 +1450,6 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts) | ||||||
| 	 */ | 	 */ | ||||||
| 	root->subsys_mask = opts->subsys_mask; | 	root->subsys_mask = opts->subsys_mask; | ||||||
| 	root->flags = opts->flags; | 	root->flags = opts->flags; | ||||||
| 	ida_init(&root->cgroup_ida); |  | ||||||
| 	if (opts->release_agent) | 	if (opts->release_agent) | ||||||
| 		strcpy(root->release_agent_path, opts->release_agent); | 		strcpy(root->release_agent_path, opts->release_agent); | ||||||
| 	if (opts->name) | 	if (opts->name) | ||||||
|  | @ -1467,7 +1465,7 @@ static void cgroup_free_root(struct cgroupfs_root *root) | ||||||
| 		/* hierarhcy ID shoulid already have been released */ | 		/* hierarhcy ID shoulid already have been released */ | ||||||
| 		WARN_ON_ONCE(root->hierarchy_id); | 		WARN_ON_ONCE(root->hierarchy_id); | ||||||
| 
 | 
 | ||||||
| 		ida_destroy(&root->cgroup_ida); | 		idr_destroy(&root->cgroup_idr); | ||||||
| 		kfree(root); | 		kfree(root); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -1582,6 +1580,11 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, | ||||||
| 		mutex_lock(&cgroup_mutex); | 		mutex_lock(&cgroup_mutex); | ||||||
| 		mutex_lock(&cgroup_root_mutex); | 		mutex_lock(&cgroup_root_mutex); | ||||||
| 
 | 
 | ||||||
|  | 		root_cgrp->id = idr_alloc(&root->cgroup_idr, root_cgrp, | ||||||
|  | 					   0, 1, GFP_KERNEL); | ||||||
|  | 		if (root_cgrp->id < 0) | ||||||
|  | 			goto unlock_drop; | ||||||
|  | 
 | ||||||
| 		/* Check for name clashes with existing mounts */ | 		/* Check for name clashes with existing mounts */ | ||||||
| 		ret = -EBUSY; | 		ret = -EBUSY; | ||||||
| 		if (strlen(root->name)) | 		if (strlen(root->name)) | ||||||
|  | @ -4253,7 +4256,11 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | ||||||
| 		goto err_free_cgrp; | 		goto err_free_cgrp; | ||||||
| 	rcu_assign_pointer(cgrp->name, name); | 	rcu_assign_pointer(cgrp->name, name); | ||||||
| 
 | 
 | ||||||
| 	cgrp->id = ida_simple_get(&root->cgroup_ida, 1, 0, GFP_KERNEL); | 	/*
 | ||||||
|  | 	 * Temporarily set the pointer to NULL, so idr_find() won't return | ||||||
|  | 	 * a half-baked cgroup. | ||||||
|  | 	 */ | ||||||
|  | 	cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL); | ||||||
| 	if (cgrp->id < 0) | 	if (cgrp->id < 0) | ||||||
| 		goto err_free_name; | 		goto err_free_name; | ||||||
| 
 | 
 | ||||||
|  | @ -4351,6 +4358,8 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	idr_replace(&root->cgroup_idr, cgrp, cgrp->id); | ||||||
|  | 
 | ||||||
| 	err = cgroup_addrm_files(cgrp, NULL, cgroup_base_files, true); | 	err = cgroup_addrm_files(cgrp, NULL, cgroup_base_files, true); | ||||||
| 	if (err) | 	if (err) | ||||||
| 		goto err_destroy; | 		goto err_destroy; | ||||||
|  | @ -4377,7 +4386,7 @@ err_free_all: | ||||||
| 	/* Release the reference count that we took on the superblock */ | 	/* Release the reference count that we took on the superblock */ | ||||||
| 	deactivate_super(sb); | 	deactivate_super(sb); | ||||||
| err_free_id: | err_free_id: | ||||||
| 	ida_simple_remove(&root->cgroup_ida, cgrp->id); | 	idr_remove(&root->cgroup_idr, cgrp->id); | ||||||
| err_free_name: | err_free_name: | ||||||
| 	kfree(rcu_dereference_raw(cgrp->name)); | 	kfree(rcu_dereference_raw(cgrp->name)); | ||||||
| err_free_cgrp: | err_free_cgrp: | ||||||
|  | @ -4570,6 +4579,14 @@ static void cgroup_offline_fn(struct work_struct *work) | ||||||
| 	/* delete this cgroup from parent->children */ | 	/* delete this cgroup from parent->children */ | ||||||
| 	list_del_rcu(&cgrp->sibling); | 	list_del_rcu(&cgrp->sibling); | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * We should remove the cgroup object from idr before its grace | ||||||
|  | 	 * period starts, so we won't be looking up a cgroup while the | ||||||
|  | 	 * cgroup is being freed. | ||||||
|  | 	 */ | ||||||
|  | 	idr_remove(&cgrp->root->cgroup_idr, cgrp->id); | ||||||
|  | 	cgrp->id = -1; | ||||||
|  | 
 | ||||||
| 	dput(d); | 	dput(d); | ||||||
| 
 | 
 | ||||||
| 	set_bit(CGRP_RELEASABLE, &parent->flags); | 	set_bit(CGRP_RELEASABLE, &parent->flags); | ||||||
|  | @ -4895,6 +4912,10 @@ int __init cgroup_init(void) | ||||||
| 
 | 
 | ||||||
| 	BUG_ON(cgroup_init_root_id(&cgroup_dummy_root, 0, 1)); | 	BUG_ON(cgroup_init_root_id(&cgroup_dummy_root, 0, 1)); | ||||||
| 
 | 
 | ||||||
|  | 	err = idr_alloc(&cgroup_dummy_root.cgroup_idr, cgroup_dummy_top, | ||||||
|  | 			0, 1, GFP_KERNEL); | ||||||
|  | 	BUG_ON(err < 0); | ||||||
|  | 
 | ||||||
| 	mutex_unlock(&cgroup_root_mutex); | 	mutex_unlock(&cgroup_root_mutex); | ||||||
| 	mutex_unlock(&cgroup_mutex); | 	mutex_unlock(&cgroup_mutex); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Li Zefan
				Li Zefan