FAILED: patch "[PATCH] jbd2: fix potential double free" failed to apply to 4.14-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.14-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 0d52154bb0a700abb459a2cbce0a30fc2549b67e Mon Sep 17 00:00:00 2001
From: Chengguang Xu <[email protected]>
Date: Fri, 10 May 2019 21:15:47 -0400
Subject: [PATCH] jbd2: fix potential double free
When failing from creating cache jbd2_inode_cache, we will destroy the previously created cache jbd2_handle_cache twice. This patch fixes this by moving each cache initialization/destruction to its own separate, individual function.
Signed-off-by Chengguang Xu <[email protected]>
Signed-off-by Theodore Ts'o <[email protected]>
fs/jbd2/journal.c +31 -18
@@ -2375,22 +2375,19 @@ static struct kmem_cache *jbd2_journal_head_cache;static atomic_t nr_journal_heads =ATOMIC_INIT (0 );#endif -static int jbd2_journal_init_journal_head_cache (void ) +static int __init jbd2_journal_init_journal_head_cache (void ) { -int retval; - -J_ASSERT (jbd2_journal_head_cache ==NULL ); +J_ASSERT (!jbd2_journal_head_cache); jbd2_journal_head_cache =kmem_cache_create ("jbd2_journal_head" ,sizeof (struct journal_head ),0 ,/* offset */ SLAB_TEMPORARY |SLAB_TYPESAFE_BY_RCU ,NULL );/* ctor */ - retval =0 ;if (!jbd2_journal_head_cache) { - retval = -ENOMEM ;printk (KERN_EMERG "JBD2: no memory for journal_head cache\n" ); +return -ENOMEM ; } -return retval; +return 0 ; }static void jbd2_journal_destroy_journal_head_cache (void )
@@ -2636,28 +2633,38 @@ static void __exit jbd2_remove_jbd_stats_proc_entry(void)struct kmem_cache *jbd2_handle_cache, *jbd2_inode_cache; +static int __init jbd2_journal_init_inode_cache (void ) +{ +J_ASSERT (!jbd2_inode_cache); + jbd2_inode_cache =KMEM_CACHE (jbd2_inode,0 ); +if (!jbd2_inode_cache) { +pr_emerg ("JBD2: failed to create inode cache\n" ); +return -ENOMEM ; + } +return 0 ; +} +static int __init jbd2_journal_init_handle_cache (void ) { +J_ASSERT (!jbd2_handle_cache); jbd2_handle_cache =KMEM_CACHE (jbd2_journal_handle,SLAB_TEMPORARY ); -if (jbd2_handle_cache ==NULL ) { +if (!jbd2_handle_cache) {printk (KERN_EMERG "JBD2: failed to create handle cache\n" );return -ENOMEM ; } - jbd2_inode_cache =KMEM_CACHE (jbd2_inode,0 ); -if (jbd2_inode_cache ==NULL ) { -printk (KERN_EMERG "JBD2: failed to create inode cache\n" ); -kmem_cache_destroy (jbd2_handle_cache); -return -ENOMEM ; - }return 0 ; } +static void jbd2_journal_destroy_inode_cache (void ) +{ +kmem_cache_destroy (jbd2_inode_cache); + jbd2_inode_cache =NULL ; +} +static void jbd2_journal_destroy_handle_cache (void ) {kmem_cache_destroy (jbd2_handle_cache); jbd2_handle_cache =NULL ; -kmem_cache_destroy (jbd2_inode_cache); - jbd2_inode_cache =NULL ; }/*
@@ -2668,11 +2675,15 @@ static int __init journal_init_caches(void) {int ret; - ret =jbd2_journal_init_revoke_caches (); + ret =jbd2_journal_init_revoke_record_cache (); +if (ret ==0 ) + ret =jbd2_journal_init_revoke_table_cache ();if (ret ==0 ) ret =jbd2_journal_init_journal_head_cache ();if (ret ==0 ) ret =jbd2_journal_init_handle_cache (); +if (ret ==0 ) + ret =jbd2_journal_init_inode_cache ();if (ret ==0 ) ret =jbd2_journal_init_transaction_cache ();return ret;
@@ -2680,9 +2691,11 @@ static int __init journal_init_caches(void)static void jbd2_journal_destroy_caches (void ) { -jbd2_journal_destroy_revoke_caches (); +jbd2_journal_destroy_revoke_record_cache (); +jbd2_journal_destroy_revoke_table_cache ();jbd2_journal_destroy_journal_head_cache ();jbd2_journal_destroy_handle_cache (); +jbd2_journal_destroy_inode_cache ();jbd2_journal_destroy_transaction_cache ();jbd2_journal_destroy_slabs (); }
fs/jbd2/revoke.c +20 -12
@@ -178,33 +178,41 @@ static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal,return NULL ; } -void jbd2_journal_destroy_revoke_caches (void ) +void jbd2_journal_destroy_revoke_record_cache (void ) {kmem_cache_destroy (jbd2_revoke_record_cache); jbd2_revoke_record_cache =NULL ; +} + +void jbd2_journal_destroy_revoke_table_cache (void ) +{kmem_cache_destroy (jbd2_revoke_table_cache); jbd2_revoke_table_cache =NULL ; } -int __init jbd2_journal_init_revoke_caches (void ) +int __init jbd2_journal_init_revoke_record_cache (void ) {J_ASSERT (!jbd2_revoke_record_cache); -J_ASSERT (!jbd2_revoke_table_cache); - jbd2_revoke_record_cache =KMEM_CACHE (jbd2_revoke_record_s,SLAB_HWCACHE_ALIGN |SLAB_TEMPORARY ); -if (!jbd2_revoke_record_cache) - goto record_cache_failure; +if (!jbd2_revoke_record_cache) { +pr_emerg ("JBD2: failed to create revoke_record cache\n" ); +return -ENOMEM ; + } +return 0 ; +} + +int __init jbd2_journal_init_revoke_table_cache (void ) +{ +J_ASSERT (!jbd2_revoke_table_cache); jbd2_revoke_table_cache =KMEM_CACHE (jbd2_revoke_table_s,SLAB_TEMPORARY ); -if (!jbd2_revoke_table_cache) - goto table_cache_failure; -return 0 ; -table_cache_failure: -jbd2_journal_destroy_revoke_caches (); -record_cache_failure: +if (!jbd2_revoke_table_cache) { +pr_emerg ("JBD2: failed to create revoke_table cache\n" );return -ENOMEM ; + } +return 0 ; }static struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table (int hash_size)
fs/jbd2/transaction.c +5 -3
@@ -42,9 +42,11 @@ int __init jbd2_journal_init_transaction_cache(void)0 ,SLAB_HWCACHE_ALIGN |SLAB_TEMPORARY , NULL); -if (transaction_cache) -return 0 ; -return -ENOMEM ; +if (!transaction_cache) { +pr_emerg ("JBD2: failed to create transaction cache\n" ); +return -ENOMEM ; + } +return 0 ; }void jbd2_journal_destroy_transaction_cache (void )
include/linux/jbd2.h +5 -3
@@ -1318,7 +1318,7 @@ extern void __wait_on_journal (journal_t *);/* Transaction cache support */ extern void jbd2_journal_destroy_transaction_cache (void ); -extern int jbd2_journal_init_transaction_cache (void ); +extern int __init jbd2_journal_init_transaction_cache (void );extern void jbd2_journal_free_transaction (transaction_t *);/*
@@ -1446,8 +1446,10 @@ static inline void jbd2_free_inode(struct jbd2_inode *jinode)/* Primary revoke support */ #define JOURNAL_REVOKE_DEFAULT_HASH 256extern int jbd2_journal_init_revoke (journal_t *,int ); -extern void jbd2_journal_destroy_revoke_caches (void ); -extern int jbd2_journal_init_revoke_caches (void ); +extern void jbd2_journal_destroy_revoke_record_cache (void ); +extern void jbd2_journal_destroy_revoke_table_cache (void ); +extern int __init jbd2_journal_init_revoke_record_cache (void ); +extern int __init jbd2_journal_init_revoke_table_cache (void );extern void jbd2_journal_destroy_revoke (journal_t *);extern int jbd2_journal_revoke (handle_t *,unsigned long long ,struct buffer_head *);