summaryrefslogtreecommitdiffstats
path: root/fs/f2fs/checkpoint.c
diff options
context:
space:
mode:
authorChao Yu2016-05-07 10:15:05 +0200
committerJaegeuk Kim2016-05-07 19:44:54 +0200
commitf61cce5b81f91ba336184008b24baec84afbb3dd (patch)
tree3ff311a201679fe3b7e7c3d9fef7f737e80a0906 /fs/f2fs/checkpoint.c
parentfscrypto/f2fs: allow fs-specific key prefix for fs encryption (diff)
downloadkernel-qcow2-linux-f61cce5b81f91ba336184008b24baec84afbb3dd.tar.gz
kernel-qcow2-linux-f61cce5b81f91ba336184008b24baec84afbb3dd.tar.xz
kernel-qcow2-linux-f61cce5b81f91ba336184008b24baec84afbb3dd.zip
f2fs: fix inode cache leak
When testing f2fs with inline_dentry option, generic/342 reports: VFS: Busy inodes after unmount of dm-0. Self-destruct in 5 seconds. Have a nice day... After rmmod f2fs module, kenrel shows following dmesg: ============================================================================= BUG f2fs_inode_cache (Tainted: G O ): Objects remaining in f2fs_inode_cache on __kmem_cache_shutdown() ----------------------------------------------------------------------------- Disabling lock debugging due to kernel taint INFO: Slab 0xf51ca0e0 objects=22 used=1 fp=0xd1e6fc60 flags=0x40004080 CPU: 3 PID: 7455 Comm: rmmod Tainted: G B O 4.6.0-rc4+ #16 Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 00000086 00000086 d062fe18 c13a83a0 f51ca0e0 d062fe38 d062fea4 c11c7276 c1981040 f51ca0e0 00000016 00000001 d1e6fc60 40004080 656a624f 20737463 616d6572 6e696e69 6e692067 66326620 6e695f73 5f65646f 68636163 6e6f2065 Call Trace: [<c13a83a0>] dump_stack+0x5f/0x8f [<c11c7276>] slab_err+0x76/0x80 [<c11cbfc0>] ? __kmem_cache_shutdown+0x100/0x2f0 [<c11cbfc0>] ? __kmem_cache_shutdown+0x100/0x2f0 [<c11cbfe5>] __kmem_cache_shutdown+0x125/0x2f0 [<c1198a38>] kmem_cache_destroy+0x158/0x1f0 [<c176b43d>] ? mutex_unlock+0xd/0x10 [<f8f15aa3>] exit_f2fs_fs+0x4b/0x5a8 [f2fs] [<c10f596c>] SyS_delete_module+0x16c/0x1d0 [<c1001b10>] ? do_fast_syscall_32+0x30/0x1c0 [<c13c59bf>] ? __this_cpu_preempt_check+0xf/0x20 [<c10afa7d>] ? trace_hardirqs_on_caller+0xdd/0x210 [<c10ad50b>] ? trace_hardirqs_off+0xb/0x10 [<c1001b81>] do_fast_syscall_32+0xa1/0x1c0 [<c176d888>] sysenter_past_esp+0x45/0x74 INFO: Object 0xd1e6d9e0 @offset=6624 kmem_cache_destroy f2fs_inode_cache: Slab cache still has objects CPU: 3 PID: 7455 Comm: rmmod Tainted: G B O 4.6.0-rc4+ #16 Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 00000286 00000286 d062fef4 c13a83a0 f174b000 d062ff14 d062ff28 c1198ac7 c197fe18 f3c5b980 d062ff20 000d04f2 d062ff0c d062ff0c d062ff14 d062ff14 f8f20dc0 fffffff5 d062e000 d062ff30 f8f15aa3 d062ff7c c10f596c 73663266 Call Trace: [<c13a83a0>] dump_stack+0x5f/0x8f [<c1198ac7>] kmem_cache_destroy+0x1e7/0x1f0 [<f8f15aa3>] exit_f2fs_fs+0x4b/0x5a8 [f2fs] [<c10f596c>] SyS_delete_module+0x16c/0x1d0 [<c1001b10>] ? do_fast_syscall_32+0x30/0x1c0 [<c13c59bf>] ? __this_cpu_preempt_check+0xf/0x20 [<c10afa7d>] ? trace_hardirqs_on_caller+0xdd/0x210 [<c10ad50b>] ? trace_hardirqs_off+0xb/0x10 [<c1001b81>] do_fast_syscall_32+0xa1/0x1c0 [<c176d888>] sysenter_past_esp+0x45/0x74 The reason is: in recovery flow, we use delayed iput mechanism for directory which has recovered dentry block. It means the reference of inode will be held until last dirty dentry page being writebacked. But when we mount f2fs with inline_dentry option, during recovery, dirent may only be recovered into dir inode page rather than dentry page, so there are no chance for us to release inode reference in ->writepage when writebacking last dentry page. We can call paired iget/iput explicityly for inline_dentry case, but for non-inline_dentry case, iput will call writeback_single_inode to write all data pages synchronously, but during recovery, ->writepages of f2fs skips writing all pages, result in losing dirent. This patch fixes this issue by obsoleting old mechanism, and introduce a new dir_list to hold all directory inodes which has recovered datas until finishing recovery. Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs/f2fs/checkpoint.c')
-rw-r--r--fs/f2fs/checkpoint.c16
1 files changed, 0 insertions, 16 deletions
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 432a6baa61d1..6402e9372f6c 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -794,19 +794,9 @@ void update_dirty_page(struct inode *inode, struct page *page)
f2fs_trace_pid(page);
}
-void add_dirty_dir_inode(struct inode *inode)
-{
- struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-
- spin_lock(&sbi->inode_lock[DIR_INODE]);
- __add_dirty_inode(inode, DIR_INODE);
- spin_unlock(&sbi->inode_lock[DIR_INODE]);
-}
-
void remove_dirty_inode(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct f2fs_inode_info *fi = F2FS_I(inode);
enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE;
if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
@@ -816,12 +806,6 @@ void remove_dirty_inode(struct inode *inode)
spin_lock(&sbi->inode_lock[type]);
__remove_dirty_inode(inode, type);
spin_unlock(&sbi->inode_lock[type]);
-
- /* Only from the recovery routine */
- if (is_inode_flag_set(fi, FI_DELAY_IPUT)) {
- clear_inode_flag(fi, FI_DELAY_IPUT);
- iput(inode);
- }
}
int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)