Using destroy_super() in alloc_super() fail path is bad, because:

* It will trigger WARN_ON(!list_empty(&s->s_mounts)) since s_mounts is
  initialized after several 'goto fail's.
* It will call kfree_rcu() to free the super block although kfree() is
  obviously enough there.
* The list_lru structure was initially implemented without the ability
  to destroy an uninitialized object in mind.

I'm going to replace the conventional list_lru with per-memcg lru to
implement per-memcg slab reclaim. This new structure will fail
destruction of objects that haven't been properly initialized so let's
inline appropriate snippets from destroy_super() to alloc_super() fail
path instead of using the whole function there.

Signed-off-by: Vladimir Davydov <vdavy...@parallels.com>
Cc: Al Viro <v...@zeniv.linux.org.uk>
---
 fs/super.c |    9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/fs/super.c b/fs/super.c
index e5f6c2c..cece164 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -185,8 +185,10 @@ static struct super_block *alloc_super(struct 
file_system_type *type, int flags)
 
        if (list_lru_init(&s->s_dentry_lru))
                goto fail;
-       if (list_lru_init(&s->s_inode_lru))
+       if (list_lru_init(&s->s_inode_lru)) {
+               list_lru_destroy(&s->s_dentry_lru);
                goto fail;
+       }
 
        INIT_LIST_HEAD(&s->s_mounts);
        init_rwsem(&s->s_umount);
@@ -227,7 +229,10 @@ static struct super_block *alloc_super(struct 
file_system_type *type, int flags)
        return s;
 
 fail:
-       destroy_super(s);
+       for (i = 0; i < SB_FREEZE_LEVELS; i++)
+               percpu_counter_destroy(&s->s_writers.counter[i]);
+       security_sb_free(s);
+       kfree(s);
        return NULL;
 }
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to