diff options
| -rw-r--r-- | fs/f2fs/data.c | 6 | ||||
| -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, 28 insertions, 1 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 650099597dd2..adfe47b21991 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c | |||
| @@ -1716,6 +1716,7 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) | |||
| 1716 | struct inode *inode = mapping->host; | 1716 | struct inode *inode = mapping->host; |
| 1717 | size_t count = iov_iter_count(iter); | 1717 | size_t count = iov_iter_count(iter); |
| 1718 | loff_t offset = iocb->ki_pos; | 1718 | loff_t offset = iocb->ki_pos; |
| 1719 | int rw = iov_iter_rw(iter); | ||
| 1719 | int err; | 1720 | int err; |
| 1720 | 1721 | ||
| 1721 | err = check_direct_IO(inode, iter, offset); | 1722 | err = check_direct_IO(inode, iter, offset); |
| @@ -1729,8 +1730,11 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) | |||
| 1729 | 1730 | ||
| 1730 | trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); | 1731 | trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); |
| 1731 | 1732 | ||
| 1733 | down_read(&F2FS_I(inode)->dio_rwsem[rw]); | ||
| 1732 | err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio); | 1734 | err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio); |
| 1733 | if (iov_iter_rw(iter) == WRITE) { | 1735 | up_read(&F2FS_I(inode)->dio_rwsem[rw]); |
| 1736 | |||
| 1737 | if (rw == WRITE) { | ||
| 1734 | if (err > 0) | 1738 | if (err > 0) |
| 1735 | set_inode_flag(inode, FI_UPDATE_WRITE); | 1739 | set_inode_flag(inode, FI_UPDATE_WRITE); |
| 1736 | else if (err < 0) | 1740 | else if (err < 0) |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index b4a46b6823dc..211183c4e5c3 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
| @@ -454,6 +454,7 @@ struct f2fs_inode_info { | |||
| 454 | struct list_head inmem_pages; /* inmemory pages managed by f2fs */ | 454 | struct list_head inmem_pages; /* inmemory pages managed by f2fs */ |
| 455 | struct mutex inmem_lock; /* lock for inmemory pages */ | 455 | struct mutex inmem_lock; /* lock for inmemory pages */ |
| 456 | struct extent_tree *extent_tree; /* cached extent_tree entry */ | 456 | struct extent_tree *extent_tree; /* cached extent_tree entry */ |
| 457 | struct rw_semaphore dio_rwsem[2];/* avoid racing between dio and gc */ | ||
| 457 | }; | 458 | }; |
| 458 | 459 | ||
| 459 | static inline void get_extent_info(struct extent_info *ext, | 460 | static inline void get_extent_info(struct extent_info *ext, |
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index c61213785914..5c8acf754513 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c | |||
| @@ -755,12 +755,32 @@ next_step: | |||
| 755 | /* phase 3 */ | 755 | /* phase 3 */ |
| 756 | inode = find_gc_inode(gc_list, dni.ino); | 756 | inode = find_gc_inode(gc_list, dni.ino); |
| 757 | if (inode) { | 757 | if (inode) { |
| 758 | struct f2fs_inode_info *fi = F2FS_I(inode); | ||
| 759 | bool locked = false; | ||
| 760 | |||
| 761 | if (S_ISREG(inode->i_mode)) { | ||
| 762 | if (!down_write_trylock(&fi->dio_rwsem[READ])) | ||
| 763 | continue; | ||
| 764 | if (!down_write_trylock( | ||
| 765 | &fi->dio_rwsem[WRITE])) { | ||
| 766 | up_write(&fi->dio_rwsem[READ]); | ||
| 767 | continue; | ||
| 768 | } | ||
| 769 | locked = true; | ||
| 770 | } | ||
| 771 | |||
| 758 | start_bidx = start_bidx_of_node(nofs, inode) | 772 | start_bidx = start_bidx_of_node(nofs, inode) |
| 759 | + ofs_in_node; | 773 | + ofs_in_node; |
| 760 | if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) | 774 | if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) |
| 761 | move_encrypted_block(inode, start_bidx); | 775 | move_encrypted_block(inode, start_bidx); |
| 762 | else | 776 | else |
| 763 | move_data_page(inode, start_bidx, gc_type); | 777 | move_data_page(inode, start_bidx, gc_type); |
| 778 | |||
| 779 | if (locked) { | ||
| 780 | up_write(&fi->dio_rwsem[WRITE]); | ||
| 781 | up_write(&fi->dio_rwsem[READ]); | ||
| 782 | } | ||
| 783 | |||
| 764 | stat_inc_data_blk_count(sbi, 1, gc_type); | 784 | stat_inc_data_blk_count(sbi, 1, gc_type); |
| 765 | } | 785 | } |
| 766 | } | 786 | } |
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 451dfb4041e8..b97c065cbe74 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
| @@ -579,6 +579,8 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) | |||
| 579 | INIT_LIST_HEAD(&fi->gdirty_list); | 579 | INIT_LIST_HEAD(&fi->gdirty_list); |
| 580 | INIT_LIST_HEAD(&fi->inmem_pages); | 580 | INIT_LIST_HEAD(&fi->inmem_pages); |
| 581 | mutex_init(&fi->inmem_lock); | 581 | mutex_init(&fi->inmem_lock); |
| 582 | init_rwsem(&fi->dio_rwsem[READ]); | ||
| 583 | init_rwsem(&fi->dio_rwsem[WRITE]); | ||
| 582 | 584 | ||
| 583 | /* Will be used by directory only */ | 585 | /* Will be used by directory only */ |
| 584 | fi->i_dir_level = F2FS_SB(sb)->dir_level; | 586 | fi->i_dir_level = F2FS_SB(sb)->dir_level; |
