[Devel] [PATCH RH7] cgroup: rework reference acquisition for cgroup_find_inode

Pavel Tikhomirov ptikhomirov at virtuozzo.com
Mon Oct 26 11:02:19 MSK 2020



On 10/26/20 9:48 AM, Andrey Zhadchenko wrote:
> Use more generic igrab instead of atomic inc. Move cgroup_hash_del to eviction
> stage to avoid deadlock.
> 
> Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
> ---
>   kernel/cgroup.c | 25 ++++++++-----------------
>   1 file changed, 8 insertions(+), 17 deletions(-)
> 
> diff --git a/kernel/cgroup.c b/kernel/cgroup.c
> index 27d7a5e..3bcbae9 100644
> --- a/kernel/cgroup.c
> +++ b/kernel/cgroup.c
> @@ -1522,21 +1522,10 @@ static struct inode *cgroup_find_inode(unsigned long fh[2], char take_ref)
>   	struct inode *ret = NULL;
>   
>   	spin_lock(&cgroup_inode_table_lock);
> -	item = cgroup_find_item_no_lock(fh);
>   
> -	/*
> -	 * If we need to increase refcount, we should be aware of possible
> -	 * deadlock. Another thread may have started deleting this inode:
> -	 * iput->iput_final->cgroup_delete_inode->cgroup_hash_del
> -	 * If we just call igrab, it will try to take i_lock and this will
> -	 * result in deadlock, because deleting thread has already taken it
> -	 * and waits on cgroup_inode_table_lock to find inode in hashtable.
> -	 *
> -	 * If i_count is zero, someone is deleting it -> skip.
> -	 */
> -	if (take_ref && item)
> -		if (!atomic_inc_not_zero(&item->inode->i_count))
> -			item = NULL;
> +	item = cgroup_find_item_no_lock(fh);
> +	if (item && take_ref && !igrab(item->inode))
> +		item = NULL;
>   
>   	spin_unlock(&cgroup_inode_table_lock);
>   
> @@ -1634,15 +1623,17 @@ static const struct export_operations cgroup_export_ops = {
>   	.fh_to_dentry	= cgroup_fh_to_dentry,
>   };
>   
> -static int cgroup_delete_inode(struct inode *inode)
> +static void cgroup_evict_inode(struct inode *inode)
>   {
>   	cgroup_hash_del(inode);
> -	return generic_delete_inode(inode);
> +	clear_inode(inode);
> +	truncate_inode_pages_final(&inode->i_data);

Why clear_inode/truncate_inode_pages_final order is different from the 
order in evict()? And probably also we need to call cgroup_hash_del 
after clear_inode to be consistent with mqueue_evict_inode.

I don't like different order of calls in different places, though it is 
probably ok now, this can hurt in future.

>   }
>   
>   static const struct super_operations cgroup_ops = {
>   	.statfs = simple_statfs,
> -	.drop_inode = cgroup_delete_inode,
> +	.drop_inode = generic_delete_inode,
> +	.evict_inode = cgroup_evict_inode,
>   	.show_options = cgroup_show_options,
>   #ifdef CONFIG_VE
>   	.show_path = cgroup_show_path,
> 

-- 
Best regards, Tikhomirov Pavel
Software Developer, Virtuozzo.


More information about the Devel mailing list