diff mbox

fs: handle shrinker registration failure in sget_userns

Message ID 201711232235.CDI34369.FLOtQVHFSJOOMF@I-love.SAKURA.ne.jp (mailing list archive)
State New, archived
Headers show

Commit Message

Tetsuo Handa Nov. 23, 2017, 1:35 p.m. UTC
Jan Kara wrote:
> Looks good to me now. You can add:
> 
> Reviewed-by: Jan Kara <jack@suse.cz>
> 

It does not look good to me, for "goto fail" can call
destroy_unused_super() before s->s_shrink.list is initialized.
Also, the comment block saying "this object isn't exposed yet"
wants to be updated?

---
 fs/super.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

Comments

Michal Hocko Nov. 23, 2017, 1:46 p.m. UTC | #1
On Thu 23-11-17 22:35:34, Tetsuo Handa wrote:
> Jan Kara wrote:
> > Looks good to me now. You can add:
> > 
> > Reviewed-by: Jan Kara <jack@suse.cz>
> > 
> 
> It does not look good to me, for "goto fail" can call
> destroy_unused_super() before s->s_shrink.list is initialized.
> Also, the comment block saying "this object isn't exposed yet"
> wants to be updated?
> 
> ---
>  fs/super.c | 10 +++-------
>  1 file changed, 3 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/super.c b/fs/super.c
> index 80b118c..44f0c6b 100644
> --- a/fs/super.c
> +++ b/fs/super.c
> @@ -197,6 +197,7 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
>  	if (!s)
>  		return NULL;
>  
> +	INIT_LIST_HEAD(&s->s_shrink.list);
>  	INIT_LIST_HEAD(&s->s_mounts);
>  	s->s_user_ns = get_user_ns(user_ns);
>  

You are right. I will move it.

> @@ -260,9 +261,8 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
>  	s->s_shrink.count_objects = super_cache_count;
>  	s->s_shrink.batch = 1024;
>  	s->s_shrink.flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE;
> -	INIT_LIST_HEAD(&s->s_shrink.list);
> -	return s;
> -
> +	if (register_shrinker(&s->s_shrink) == 0)
> +		return s;
>  fail:
>  	destroy_unused_super(s);
>  	return NULL;

But I am not sure this is correct. So what protects shrinker invocation
while the object is not initialized yet?
Tetsuo Handa Nov. 23, 2017, 1:57 p.m. UTC | #2
Michal Hocko wrote:
> > @@ -260,9 +261,8 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
> >  	s->s_shrink.count_objects = super_cache_count;
> >  	s->s_shrink.batch = 1024;
> >  	s->s_shrink.flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE;
> > -	INIT_LIST_HEAD(&s->s_shrink.list);
> > -	return s;
> > -
> > +	if (register_shrinker(&s->s_shrink) == 0)
> > +		return s;
> >  fail:
> >  	destroy_unused_super(s);
> >  	return NULL;
> 
> But I am not sure this is correct. So what protects shrinker invocation
> while the object is not initialized yet?

Then, what protects shrinker invocation in your patch?
Your patch is calling register_shrinker() immediately after
alloc_super() succeeds. My patch just moved register_shrinker()
into alloc_super().

@@ -503,6 +512,10 @@ struct super_block *sget_userns(struct file_system_type *type,
 		s = alloc_super(type, (flags & ~SB_SUBMOUNT), user_ns);
 		if (!s)
 			return ERR_PTR(-ENOMEM);
+		if (register_shrinker(&s->s_shrink)) {
+			destroy_unused_super(s);
+			return ERR_PTR(-ENOMEM);
+		}
 		goto retry;
 	}
Michal Hocko Nov. 23, 2017, 2:06 p.m. UTC | #3
On Thu 23-11-17 22:57:06, Tetsuo Handa wrote:
> Michal Hocko wrote:
> > > @@ -260,9 +261,8 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
> > >  	s->s_shrink.count_objects = super_cache_count;
> > >  	s->s_shrink.batch = 1024;
> > >  	s->s_shrink.flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE;
> > > -	INIT_LIST_HEAD(&s->s_shrink.list);
> > > -	return s;
> > > -
> > > +	if (register_shrinker(&s->s_shrink) == 0)
> > > +		return s;
> > >  fail:
> > >  	destroy_unused_super(s);
> > >  	return NULL;
> > 
> > But I am not sure this is correct. So what protects shrinker invocation
> > while the object is not initialized yet?
> 
> Then, what protects shrinker invocation in your patch?

It is s_umount lock but that one is alreay held at the point where you
suggested register_shrinker. My bad, I could have noticed that. Feel
free to take over and send a patch. Considering I've screwed several
times already I do not feel I am the right one to send the fix.
Tetsuo Handa Nov. 23, 2017, 2:10 p.m. UTC | #4
Michal Hocko wrote:
> On Thu 23-11-17 22:57:06, Tetsuo Handa wrote:
> > Michal Hocko wrote:
> > > > @@ -260,9 +261,8 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags,
> > > >  	s->s_shrink.count_objects = super_cache_count;
> > > >  	s->s_shrink.batch = 1024;
> > > >  	s->s_shrink.flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE;
> > > > -	INIT_LIST_HEAD(&s->s_shrink.list);
> > > > -	return s;
> > > > -
> > > > +	if (register_shrinker(&s->s_shrink) == 0)
> > > > +		return s;
> > > >  fail:
> > > >  	destroy_unused_super(s);
> > > >  	return NULL;
> > > 
> > > But I am not sure this is correct. So what protects shrinker invocation
> > > while the object is not initialized yet?
> > 
> > Then, what protects shrinker invocation in your patch?
> 
> It is s_umount lock but that one is alreay held at the point where you
> suggested register_shrinker. My bad, I could have noticed that. Feel
> free to take over and send a patch. Considering I've screwed several
> times already I do not feel I am the right one to send the fix.
> 
I will wait for your posting. I feel we want to update the comment block
saying "this object isn't exposed yet", for it is confusing that we
already exposed the shrinker inside the object.
diff mbox

Patch

diff --git a/fs/super.c b/fs/super.c
index 80b118c..44f0c6b 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -197,6 +197,7 @@  static struct super_block *alloc_super(struct file_system_type *type, int flags,
 	if (!s)
 		return NULL;
 
+	INIT_LIST_HEAD(&s->s_shrink.list);
 	INIT_LIST_HEAD(&s->s_mounts);
 	s->s_user_ns = get_user_ns(user_ns);
 
@@ -260,9 +261,8 @@  static struct super_block *alloc_super(struct file_system_type *type, int flags,
 	s->s_shrink.count_objects = super_cache_count;
 	s->s_shrink.batch = 1024;
 	s->s_shrink.flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE;
-	INIT_LIST_HEAD(&s->s_shrink.list);
-	return s;
-
+	if (register_shrinker(&s->s_shrink) == 0)
+		return s;
 fail:
 	destroy_unused_super(s);
 	return NULL;
@@ -512,10 +512,6 @@  struct super_block *sget_userns(struct file_system_type *type,
 		s = alloc_super(type, (flags & ~SB_SUBMOUNT), user_ns);
 		if (!s)
 			return ERR_PTR(-ENOMEM);
-		if (register_shrinker(&s->s_shrink)) {
-			destroy_unused_super(s);
-			return ERR_PTR(-ENOMEM);
-		}
 		goto retry;
 	}