summaryrefslogtreecommitdiffstats
path: root/fs/f2fs/segment.c
diff options
context:
space:
mode:
authorChao Yu <yuchao0@huawei.com>2021-03-05 10:56:01 +0100
committerJaegeuk Kim <jaegeuk@kernel.org>2021-03-23 18:41:12 +0100
commite1175f02291141bbd924fc578299305fcde35855 (patch)
tree3be7f1f522ef272344c1583752f6247497912fec /fs/f2fs/segment.c
parentf2fs: expose # of overprivision segments (diff)
downloadlinux-e1175f02291141bbd924fc578299305fcde35855.tar.xz
linux-e1175f02291141bbd924fc578299305fcde35855.zip
f2fs: fix to align to section for fallocate() on pinned file
Now, fallocate() on a pinned file only allocates blocks which aligns to segment rather than section, so GC may try to migrate pinned file's block, and after several times of failure, pinned file's block could be migrated to other place, however user won't be aware of such condition, and then old obsolete block address may be readed/written incorrectly. To avoid such condition, let's try to allocate pinned file's blocks with section alignment. Signed-off-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs/f2fs/segment.c')
-rw-r--r--fs/f2fs/segment.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index b5a40a39a03f..f2b22da8c134 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2899,7 +2899,8 @@ unlock:
up_read(&SM_I(sbi)->curseg_lock);
}
-static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type)
+static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type,
+ bool new_sec)
{
struct curseg_info *curseg = CURSEG_I(sbi, type);
unsigned int old_segno;
@@ -2907,10 +2908,22 @@ static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type)
if (!curseg->inited)
goto alloc;
- if (!curseg->next_blkoff &&
- !get_valid_blocks(sbi, curseg->segno, false) &&
- !get_ckpt_valid_blocks(sbi, curseg->segno))
- return;
+ if (curseg->next_blkoff ||
+ get_valid_blocks(sbi, curseg->segno, new_sec))
+ goto alloc;
+
+ if (new_sec) {
+ unsigned int segno = START_SEGNO(curseg->segno);
+ int i;
+
+ for (i = 0; i < sbi->segs_per_sec; i++, segno++) {
+ if (get_ckpt_valid_blocks(sbi, segno))
+ goto alloc;
+ }
+ } else {
+ if (!get_ckpt_valid_blocks(sbi, curseg->segno))
+ return;
+ }
alloc:
old_segno = curseg->segno;
@@ -2918,10 +2931,15 @@ alloc:
locate_dirty_segment(sbi, old_segno);
}
-void f2fs_allocate_new_segment(struct f2fs_sb_info *sbi, int type)
+static void __allocate_new_section(struct f2fs_sb_info *sbi, int type)
+{
+ __allocate_new_segment(sbi, type, true);
+}
+
+void f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type)
{
down_write(&SIT_I(sbi)->sentry_lock);
- __allocate_new_segment(sbi, type);
+ __allocate_new_section(sbi, type);
up_write(&SIT_I(sbi)->sentry_lock);
}
@@ -2931,7 +2949,7 @@ void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi)
down_write(&SIT_I(sbi)->sentry_lock);
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++)
- __allocate_new_segment(sbi, i);
+ __allocate_new_segment(sbi, i, false);
up_write(&SIT_I(sbi)->sentry_lock);
}