diff options
author | Chao Yu | 2018-08-05 23:02:22 +0800 |
---|---|---|
committer | Jaegeuk Kim | 2018-08-13 10:48:17 -0700 |
commit | c7079853c859c910b9d047a37891b4aafb8f8dd7 (patch) | |
tree | 9d5f827b0c96b80858080012618f1d634c1f3e1e /fs/f2fs | |
parent | 91291e9998d208370eb8156c760691b873bd7522 (diff) |
f2fs: avoid race between zero_range and background GC
Thread A Background GC
- f2fs_zero_range
- truncate_pagecache_range
- gc_data_segment
- get_read_data_page
- move_data_page
- set_page_dirty
- set_cold_data
- f2fs_do_zero_range
- dn->data_blkaddr = NEW_ADDR;
- f2fs_set_data_blkaddr
Actually, we don't need to set dirty & checked flag on the page, since
all valid data in the page should be zeroed by zero_range().
Use i_gc_rwsem[WRITE] to avoid such race condition.
Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs/f2fs')
-rw-r--r-- | fs/f2fs/file.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 67c9c2d4e2d9..4cb02027827e 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1314,8 +1314,6 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, if (ret) goto out_sem; - truncate_pagecache_range(inode, offset, offset + len - 1); - pg_start = ((unsigned long long) offset) >> PAGE_SHIFT; pg_end = ((unsigned long long) offset + len) >> PAGE_SHIFT; @@ -1345,12 +1343,19 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, unsigned int end_offset; pgoff_t end; + down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); + + truncate_pagecache_range(inode, + (loff_t)index << PAGE_SHIFT, + ((loff_t)pg_end << PAGE_SHIFT) - 1); + f2fs_lock_op(sbi); set_new_dnode(&dn, inode, NULL, NULL, 0); ret = f2fs_get_dnode_of_data(&dn, index, ALLOC_NODE); if (ret) { f2fs_unlock_op(sbi); + up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); goto out; } @@ -1359,7 +1364,9 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, ret = f2fs_do_zero_range(&dn, index, end); f2fs_put_dnode(&dn); + f2fs_unlock_op(sbi); + up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); f2fs_balance_fs(sbi, dn.node_changed); |