diff options
Diffstat (limited to 'fs/f2fs')
-rw-r--r-- | fs/f2fs/data.c | 20 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 1 | ||||
-rw-r--r-- | fs/f2fs/super.c | 2 |
3 files changed, 23 insertions, 0 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 20f31ff47e05..44645f4f914b 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -2298,6 +2298,7 @@ static int f2fs_mpage_readpages(struct inode *inode, unsigned nr_pages = rac ? readahead_count(rac) : 1; unsigned max_nr_pages = nr_pages; int ret = 0; + bool drop_ra = false; map.m_pblk = 0; map.m_lblk = 0; @@ -2308,10 +2309,26 @@ static int f2fs_mpage_readpages(struct inode *inode, map.m_seg_type = NO_CHECK_TYPE; map.m_may_create = false; + /* + * Two readahead threads for same address range can cause race condition + * which fragments sequential read IOs. So let's avoid each other. + */ + if (rac && readahead_count(rac)) { + if (READ_ONCE(F2FS_I(inode)->ra_offset) == readahead_index(rac)) + drop_ra = true; + else + WRITE_ONCE(F2FS_I(inode)->ra_offset, + readahead_index(rac)); + } + for (; nr_pages; nr_pages--) { if (rac) { page = readahead_page(rac); prefetchw(&page->flags); + if (drop_ra) { + f2fs_put_page(page, 1); + continue; + } } #ifdef CONFIG_F2FS_FS_COMPRESSION @@ -2374,6 +2391,9 @@ next_page: } if (bio) __submit_bio(F2FS_I_SB(inode), bio, DATA); + + if (rac && readahead_count(rac) && !drop_ra) + WRITE_ONCE(F2FS_I(inode)->ra_offset, -1); return ret; } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 4f1f1a3e3334..c98a9182862b 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -794,6 +794,7 @@ struct f2fs_inode_info { struct list_head inmem_pages; /* inmemory pages managed by f2fs */ struct task_struct *inmem_task; /* store inmemory task */ struct mutex inmem_lock; /* lock for inmemory pages */ + pgoff_t ra_offset; /* ongoing readahead offset */ struct extent_tree *extent_tree; /* cached extent_tree entry */ /* avoid racing between foreground op and gc */ diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 732652205737..80cb7cd358f8 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1015,6 +1015,8 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) /* Will be used by directory only */ fi->i_dir_level = F2FS_SB(sb)->dir_level; + fi->ra_offset = -1; + return &fi->vfs_inode; } |