diff options
| -rw-r--r-- | fs/f2fs/data.c | 2 | ||||
| -rw-r--r-- | fs/f2fs/f2fs.h | 1 | ||||
| -rw-r--r-- | fs/f2fs/gc.c | 20 | ||||
| -rw-r--r-- | fs/f2fs/super.c | 2 |
4 files changed, 25 insertions, 0 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index abf836b32..a61750b14 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1756,8 +1756,10 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb, trace_f2fs_direct_IO_enter(inode, offset, count, rw); + down_read(&F2FS_I(inode)->dio_rwsem[rw]); err = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, get_data_block_dio); + up_read(&F2FS_I(inode)->dio_rwsem[rw]); if (err < 0 && (rw & WRITE)) { if (err > 0) set_inode_flag(inode, FI_UPDATE_WRITE); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 981a13971..2494c74ab 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -485,6 +485,7 @@ struct f2fs_inode_info { struct list_head inmem_pages; /* inmemory pages managed by f2fs */ struct mutex inmem_lock; /* lock for inmemory pages */ struct extent_tree *extent_tree; /* cached extent_tree entry */ + struct rw_semaphore dio_rwsem[2];/* avoid racing between dio and gc */ }; static inline void get_extent_info(struct extent_info *ext, diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 1dd176555..ea8eb7daf 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -755,12 +755,32 @@ next_step: /* phase 3 */ inode = find_gc_inode(gc_list, dni.ino); if (inode) { + struct f2fs_inode_info *fi = F2FS_I(inode); + bool locked = false; + + if (S_ISREG(inode->i_mode)) { + if (!down_write_trylock(&fi->dio_rwsem[READ])) + continue; + if (!down_write_trylock( + &fi->dio_rwsem[WRITE])) { + up_write(&fi->dio_rwsem[READ]); + continue; + } + locked = true; + } + start_bidx = start_bidx_of_node(nofs, inode) + ofs_in_node; if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) move_encrypted_block(inode, start_bidx); else move_data_page(inode, start_bidx, gc_type); + + if (locked) { + up_write(&fi->dio_rwsem[WRITE]); + up_write(&fi->dio_rwsem[READ]); + } + stat_inc_data_blk_count(sbi, 1, gc_type); } } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index c63782ec3..78ef79e4f 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -568,6 +568,8 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) INIT_LIST_HEAD(&fi->gdirty_list); INIT_LIST_HEAD(&fi->inmem_pages); mutex_init(&fi->inmem_lock); + init_rwsem(&fi->dio_rwsem[READ]); + init_rwsem(&fi->dio_rwsem[WRITE]); /* Will be used by directory only */ fi->i_dir_level = F2FS_SB(sb)->dir_level; |
