f2fs: fix missing kmem_cache_free
Subsystems (2)
Jaegeuk Kim
maintainerPATCH 1/3 f2fs: fix missing kmem_cache_free
This patch fixes missing kmem_cache_free when handling errors.
--- fs/f2fs/node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/f2fs/node.c +1 -1
@@ -158,7 +158,7 @@ retry: head->entry_cnt =0 ;if (radix_tree_insert (&nm_i->nat_set_root, set, head)) { -cond_resched (); +kmem_cache_free (nat_entry_set_slab, head); goto retry; } }
Signature · 1 line
2.1.1
Jaegeuk Kim
maintainerPATCH 2/3 f2fs: use rw_semaphore for nat entry lock
Previoulsy, we used rwlock for nat_entry lock.
But, now we have a lot of complex operations in set_node_addr. (e.g., allocating kernel memories, handling radix_trees, and so on)
So, this patches tries to change spinlock to rw_semaphore to give CPUs to other threads.
--- fs/f2fs/f2fs.h | 2 +- fs/f2fs/node.c | 52 ++++++++++++++++++++++++++-------------------------- 2 files changed, 27 insertions(+), 27 deletions(-)
fs/f2fs/f2fs.h +1 -1
@@ -332,7 +332,7 @@ struct f2fs_nm_info {/* NAT cache management */ struct radix_tree_root nat_root;/* root of the nat entry cache */ struct radix_tree_root nat_set_root;/* root of the nat set cache */ -rwlock_t nat_tree_lock;/* protect nat_tree_lock */ +struct rw_semaphore nat_tree_lock;/* protect nat_tree_lock */ struct list_head nat_entries;/* cached nat entry list (clean) */ unsigned int nat_cnt;/* the # of cached nat entries */ unsigned int dirty_nat_cnt;/* total num of nat entries in set */
fs/f2fs/node.c +26 -26
189 lines not on this page · raw message
Signature · 9 lines
2.1.1 ------------------------------------------------------------------------------ Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server from Actuate! Instantly Supercharge Your Business Reports and Dashboards with Interactivity, Sharing, Native Excel Exports, App Integration & more Get technology previously reserved for billion-dollar corporations, FREE http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk
Jaegeuk Kim
maintainerPATCH 3/3 f2fs: call radix_tree_preload before radix_tree_insert
In reply to Jaegeuk KimThis patch tries to fix:
BUG: using smp_processor_id() in preemptible [00000000] code: f2fs_gc-254:0/384 (radix_tree_node_alloc+0x14/0x74) from [<c033d8a0>] (radix_tree_insert+0x110/0x200) (radix_tree_insert+0x110/0x200) from [<c02e8264>] (gc_data_segment+0x340/0x52c) (gc_data_segment+0x340/0x52c) from [<c02e8658>] (f2fs_gc+0x208/0x400) (f2fs_gc+0x208/0x400) from [<c02e8a98>] (gc_thread_func+0x248/0x28c) (gc_thread_func+0x248/0x28c) from [<c0139944>] (kthread+0xa0/0xac) (kthread+0xa0/0xac) from [<c0105ef8>] (ret_from_fork+0x14/0x3c)
The reason is that f2fs calls radix_tree_insert under enabled preemption. So, before calling it, we need to call radix_tree_preload.
Otherwise, we should use _GFP_WAIT for the radix tree, and use mutex or semaphore to cover the radix tree operations.
--- fs/f2fs/checkpoint.c | 8 ++++++++ fs/f2fs/gc.c | 6 ++---- fs/f2fs/node.c | 6 +++--- 3 files changed, 13 insertions(+), 7 deletions(-)
fs/f2fs/checkpoint.c +8 -0
@@ -304,6 +304,11 @@ static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)struct inode_management *im = &sbi->im[type];struct ino_entry *e; retry: +if (radix_tree_preload (GFP_NOFS )) { +cond_resched (); + goto retry; + } +spin_lock (&im->ino_lock); e =radix_tree_lookup (&im->ino_root, ino);
@@ -311,11 +316,13 @@ retry: e =kmem_cache_alloc (ino_entry_slab,GFP_ATOMIC );if (!e) {spin_unlock (&im->ino_lock); +radix_tree_preload_end (); goto retry; }if (radix_tree_insert (&im->ino_root, ino, e)) {spin_unlock (&im->ino_lock);kmem_cache_free (ino_entry_slab, e); +radix_tree_preload_end (); goto retry; }memset (e,0 ,sizeof (struct ino_entry ));
@@ -326,6 +333,7 @@ retry: im->ino_num++; }spin_unlock (&im->ino_lock); +radix_tree_preload_end (); }static void __remove_ino_entry (struct f2fs_sb_info *sbi,nid_t ino,int type)
fs/f2fs/gc.c +2 -4
@@ -351,7 +351,6 @@ static struct inode *find_gc_inode(struct gc_inode_list *gc_list, nid_t ino)static void add_gc_inode (struct gc_inode_list *gc_list,struct inode *inode) {struct inode_entry *new_ie; -int ret;if (inode ==find_gc_inode (gc_list, inode->i_ino)) {iput (inode);
@@ -361,8 +360,7 @@ retry: new_ie =f2fs_kmem_cache_alloc (winode_slab,GFP_NOFS ); new_ie->inode = inode; - ret =radix_tree_insert (&gc_list->iroot, inode->i_ino, new_ie); -if (ret) { +if (radix_tree_insert (&gc_list->iroot, inode->i_ino, new_ie)) {kmem_cache_free (winode_slab, new_ie); goto retry; }
@@ -703,7 +701,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi)struct cp_control cpc;struct gc_inode_list gc_list = { .ilist =LIST_HEAD_INIT (gc_list.ilist), - .iroot =RADIX_TREE_INIT (GFP_ATOMIC ), + .iroot =RADIX_TREE_INIT (GFP_NOFS ), }; cpc.reason =test_opt (sbi,FASTBOOT ) ?CP_UMOUNT :CP_SYNC ;
fs/f2fs/node.c +3 -3
@@ -1992,10 +1992,10 @@ static int init_node_manager(struct f2fs_sb_info *sbi) nm_i->nat_cnt =0 ; nm_i->ram_thresh =DEF_RAM_THRESHOLD ; -INIT_RADIX_TREE (&nm_i->free_nid_root,GFP_ATOMIC ); +INIT_RADIX_TREE (&nm_i->free_nid_root,GFP_NOIO );INIT_LIST_HEAD (&nm_i->free_nid_list); -INIT_RADIX_TREE (&nm_i->nat_root,GFP_ATOMIC ); -INIT_RADIX_TREE (&nm_i->nat_set_root,GFP_ATOMIC ); +INIT_RADIX_TREE (&nm_i->nat_root,GFP_NOIO ); +INIT_RADIX_TREE (&nm_i->nat_set_root,GFP_NOIO );INIT_LIST_HEAD (&nm_i->nat_entries);mutex_init (&nm_i->build_lock);
Signature · 1 line
2.1.1
Hi Jaegeuk,
Quoted 12 lines · Jaegeuk Kim
This patch fixes missing
kmem_cache_freewhen handling errors.Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)fs/f2fs/node.c +0
-0
fs/f2fs/node.c retry: · line 161
Quoted 5 lines
fs/f2fs/node.c +1
-1@@ -158,7 +158,7 @@ retry: head->entry_cnt =0 ;if (radix_tree_insert (&nm_i->nat_set_root, set, head)) { -cond_resched (); +kmem_cache_free (nat_entry_set_slab, head);
Why not reuse the allocated entry?
This routine is under nat_tree_lock, so the free_old->research->alloc_new is needless, because no other ones can race with us.
fs/f2fs/node.c retry: · line 162
Quoted 1 line
fs/f2fs/node.c +0
-0goto retry;
And radix_tree_insert can only fail -ENOMEM here, IMO, the in-time retry step makes very little sense here. How about retaining the "cond_resched()" and retry insert later?
If I misread something, please correct me.:)
Thanks,
Gu
Quoted 2 lines
fs/f2fs/node.c +0
-0} }
Jaegeuk Kim
maintainerHi Gu,
Quoted 17 lines · Gu Zheng
Hi Jaegeuk,
Quoted 14 lines · Jaegeuk Kim
This patch fixes missing
kmem_cache_freewhen handling errors.Signed-off-by Jaegeuk Kim <[email protected]>--- fs/f2fs/node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)fs/f2fs/node.c +0
-0@@ -158,7 +158,7 @@ retry: head->entry_cnt =0 ;
Quoted 7 lines
fs/f2fs/node.c retry: · line 161
Quoted 3 lines
fs/f2fs/node.c +1
-1if (radix_tree_insert (&nm_i->nat_set_root, set, head)) { -cond_resched (); +kmem_cache_free (nat_entry_set_slab, head);Why not reuse the allocated entry?
This routine is undernat_tree_lock, so thefree_old->research->alloc_newis needless, because no other ones can race with us.
IMO, this issue is quite different one that you're mentioning. This patch just fixes a missing kfree.
Quoted 6 lines
fs/f2fs/node.c retry: · line 162
Quoted 2 lines
fs/f2fs/node.c +0
-0goto retry;And
radix_tree_insertcan only fail-ENOMEMhere, IMO, the in-time retry step makes very little sense here. How about retaining the "cond_resched()" and retry insert later?
I think the following patches related to radix_tree_preload that I submitted would address that.
But, still it seems that I need to review the retrial paths again.
Thanks,
Quoted 8 lines
If I misread something, please correct me.:)
Thanks,
GuQuoted 2 lines
fs/f2fs/node.c +0
-0} }