diff options
| author | Nitesh Shetty <nj.shetty@samsung.com> | 2021-02-08 19:39:01 +0530 |
|---|---|---|
| committer | Chao Yu <yuchao0@huawei.com> | 2021-02-08 22:44:41 +0800 |
| commit | d6f32b90156624ae9dc06ef5873334a48e9b9806 (patch) | |
| tree | e0f9eadf2fdb586b66723315012db981e1a0737f | |
| parent | 3868cd6903c8f6f9e584f2484f63954eb36e2b92 (diff) | |
| download | linux-d6f32b90156624ae9dc06ef5873334a48e9b9806.tar.gz | |
f2fs: use BLK_COPY ioctl for gc.
Garbage collection for node block(f2fs_move_node_page) is modified to use
BLK_COPY ioctl.
BLK_COPY tries to leverage features such as simple copy(NVMe), xcopy,
if those in device copy feature is not available, then falls back to
normal copy. Although BLK_COPY can copy multiple source blocks into destination
at once, the present implementation focus on one source and one destination copy.
The patch tries to follow same path as current gc path, until the final
implementation in f2fs_submit_page_write, where IO's are tried to merge
if possible, if IO merging is not possible submit the previous pending
IO's and create a new f2fs IO.
In BLK_COPY GC implementation, pending IOs are just submitted irrespective of
merging condition and BLK_COPY is issued for current IO.
| -rw-r--r-- | fs/f2fs/data.c | 117 | ||||
| -rw-r--r-- | fs/f2fs/f2fs.h | 4 | ||||
| -rw-r--r-- | fs/f2fs/gc.c | 2 | ||||
| -rw-r--r-- | fs/f2fs/node.c | 11 | ||||
| -rw-r--r-- | fs/f2fs/segment.c | 12 |
5 files changed, 108 insertions, 38 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 179c95cf327ac..25ca795c6b2bc 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -571,6 +571,46 @@ static void __attach_io_flag(struct f2fs_io_info *fio) fio->op_flags |= REQ_FUA; } +/** + * __submit_copy_bio - issue BLK_COPY, + * BLK_COPY copies fio->old_blkaddr to fio->new_blkaddr + */ + +static int __submit_copy_bio(struct f2fs_io_info *fio) +{ + struct f2fs_sb_info *sbi = fio->sbi; + struct block_device *bdev = f2fs_target_device(fio->sbi, fio->old_blkaddr, NULL); + struct block_device *bdev2 = f2fs_target_device(fio->sbi, fio->new_blkaddr, NULL); + int ret = 0, i; + struct range_entry rlist; + + if (bdev != bdev2) + return -EAGAIN; + + /*TODO: temp error checks, need to figure out for different devices how to handle */ + if (!fio->old_blkaddr) { + printk("%s:%s:%d: old_blkaddr NULL \n", __FILE__, __func__, __LINE__); + BUG(); + } else if (!fio->new_blkaddr) { + printk("%s:%s:%d: new_blkaddr NULL \n", __FILE__, __func__, __LINE__); + BUG(); + } else if (!f2fs_target_device_index(fio->sbi, fio->old_blkaddr)) { + printk("%s:%s:%d: old_blkaddr device is CNS\n", __FILE__, __func__, __LINE__); + BUG(); + } else if (!f2fs_target_device_index(fio->sbi, fio->new_blkaddr)) { + printk("%s:%s:%d: new_blkaddr device is CNS\n", __FILE__, __func__, __LINE__); + BUG(); + } + + i = f2fs_target_device_index(fio->sbi, fio->old_blkaddr); + + rlist.src = (fio->old_blkaddr - FDEV(i).start_blk) << 12; + rlist.len = PAGE_SIZE; + ret = blkdev_issue_copy(bdev, 1, &rlist, bdev, (fio->new_blkaddr - FDEV(i).start_blk) << 12, 0); + + return ret; +} + static void __submit_merged_bio(struct f2fs_bio_info *io) { struct f2fs_io_info *fio = &io->fio; @@ -942,12 +982,13 @@ alloc_new: return 0; } -void f2fs_submit_page_write(struct f2fs_io_info *fio, int do_copy) +int f2fs_submit_page_write(struct f2fs_io_info *fio, int do_copy) { struct f2fs_sb_info *sbi = fio->sbi; enum page_type btype = PAGE_TYPE_OF_BIO(fio->type); struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp; struct page *bio_page; + int ret = 0; f2fs_bug_on(sbi, is_read_io(fio->op)); @@ -979,47 +1020,63 @@ next: inc_page_count(sbi, WB_DATA_TYPE(bio_page)); - if (io->bio && - (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio, - fio->new_blkaddr) || - !f2fs_crypt_mergeable_bio(io->bio, fio->page->mapping->host, - bio_page->index, fio))) - __submit_merged_bio(io); -alloc_new: - if (io->bio == NULL) { - if (F2FS_IO_ALIGNED(sbi) && - (fio->type == DATA || fio->type == NODE) && - fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) { - dec_page_count(sbi, WB_DATA_TYPE(bio_page)); - fio->retry = true; - goto skip; + if (do_copy) { + if (io->bio) + __submit_merged_bio(io); + + if (io->bio == NULL) { + if (F2FS_IO_ALIGNED(sbi) && + (fio->type == DATA || fio->type == NODE) && + fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) { + dec_page_count(sbi, WB_DATA_TYPE(bio_page)); + } } - io->bio = __bio_alloc(fio, BIO_MAX_PAGES); - f2fs_set_bio_crypt_ctx(io->bio, fio->page->mapping->host, + ret = __submit_copy_bio(fio); + } else { + if (io->bio && + (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio, + fio->new_blkaddr) || + !f2fs_crypt_mergeable_bio(io->bio, fio->page->mapping->host, + bio_page->index, fio))) + __submit_merged_bio(io); +alloc_new: + if (io->bio == NULL) { + if (F2FS_IO_ALIGNED(sbi) && + (fio->type == DATA || fio->type == NODE) && + fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) { + dec_page_count(sbi, WB_DATA_TYPE(bio_page)); + fio->retry = true; + goto skip; + } + io->bio = __bio_alloc(fio, BIO_MAX_PAGES); + f2fs_set_bio_crypt_ctx(io->bio, fio->page->mapping->host, bio_page->index, fio, GFP_NOIO); - io->fio = *fio; - } + io->fio = *fio; + } - if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) < PAGE_SIZE) { - __submit_merged_bio(io); - goto alloc_new; - } + if (bio_add_page(io->bio, bio_page, PAGE_SIZE, 0) < PAGE_SIZE) { + __submit_merged_bio(io); + goto alloc_new; + } - if (fio->io_wbc) - wbc_account_cgroup_owner(fio->io_wbc, bio_page, PAGE_SIZE); + if (fio->io_wbc) + wbc_account_cgroup_owner(fio->io_wbc, bio_page, PAGE_SIZE); - io->last_block_in_bio = fio->new_blkaddr; - f2fs_trace_ios(fio, 0); + io->last_block_in_bio = fio->new_blkaddr; + f2fs_trace_ios(fio, 0); - trace_f2fs_submit_page_write(fio->page, fio); + trace_f2fs_submit_page_write(fio->page, fio); skip: - if (fio->in_list) - goto next; + if (fio->in_list) + goto next; + } out: if (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN) || !f2fs_is_checkpoint_ready(sbi)) __submit_merged_bio(io); up_write(&io->io_rwsem); + + return ret; } static inline bool f2fs_need_verity(const struct inode *inode, pgoff_t idx) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index b0d5c5fbd63e0..6deb1fcdba93b 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3339,7 +3339,7 @@ void f2fs_update_meta_page(struct f2fs_sb_info *sbi, void *src, block_t blk_addr); void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page, enum iostat_type io_type); -void f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio, int do_copy); +int f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio, int do_copy); void f2fs_outplace_write_data(struct dnode_of_data *dn, struct f2fs_io_info *fio); int f2fs_inplace_write_data(struct f2fs_io_info *fio); @@ -3438,7 +3438,7 @@ void f2fs_submit_merged_ipu_write(struct f2fs_sb_info *sbi, void f2fs_flush_merged_writes(struct f2fs_sb_info *sbi); int f2fs_submit_page_bio(struct f2fs_io_info *fio); int f2fs_merge_page_bio(struct f2fs_io_info *fio); -void f2fs_submit_page_write(struct f2fs_io_info *fio, int do_copy); +int f2fs_submit_page_write(struct f2fs_io_info *fio, int do_copy); struct block_device *f2fs_target_device(struct f2fs_sb_info *sbi, block_t blk_addr, struct bio *bio); int f2fs_target_device_index(struct f2fs_sb_info *sbi, block_t blkaddr); diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 3bc375d0edb4e..9058cd8265338 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -919,7 +919,7 @@ next_step: continue; } - err = f2fs_move_node_page(node_page, gc_type, 0); + err = f2fs_move_node_page(node_page, gc_type, 1); if (!err && gc_type == FG_GC) submitted++; stat_inc_node_blk_count(sbi, 1, gc_type); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 17d91bff08cb2..37ce8469a8e30 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1523,6 +1523,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, .io_wbc = wbc, }; unsigned int seq; + int ret = 0; trace_f2fs_writepage(page, NODE); @@ -1588,7 +1589,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, ClearPageError(page); fio.old_blkaddr = ni.blk_addr; - f2fs_do_write_node_page(nid, &fio, do_copy); + ret = f2fs_do_write_node_page(nid, &fio, do_copy); set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(page)); dec_page_count(sbi, F2FS_DIRTY_NODES); up_read(&sbi->node_write); @@ -1607,6 +1608,12 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, if (submitted) *submitted = fio.submitted; + if (do_copy) { + if (f2fs_in_warm_node_list(sbi, page)) + f2fs_del_fsync_node_entry(sbi, page); + clear_cold_data(page); + } + if (do_balance) f2fs_balance_fs(sbi, false); return 0; @@ -1620,7 +1627,7 @@ int f2fs_move_node_page(struct page *node_page, int gc_type, int do_copy) { int err = 0; - if (gc_type == FG_GC) { + if (do_copy || (gc_type == FG_GC)) { struct writeback_control wbc = { .sync_mode = WB_SYNC_ALL, .nr_to_write = 1, diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index c2ef848c4606b..130848d4f11e1 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -3422,10 +3422,11 @@ static void update_device_state(struct f2fs_io_info *fio) } } -static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio, int do_copy) +static int do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio, int do_copy) { int type = __get_segment_type(fio); bool keep_order = (f2fs_lfs_mode(fio->sbi) && type == CURSEG_COLD_DATA); + int ret = 0; if (keep_order) down_read(&fio->sbi->io_order_lock); @@ -3447,6 +3448,8 @@ reallocate: if (keep_order) up_read(&fio->sbi->io_order_lock); + + return ret; } void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page, @@ -3476,14 +3479,17 @@ void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page, f2fs_update_iostat(sbi, io_type, F2FS_BLKSIZE); } -void f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio, int do_copy) +int f2fs_do_write_node_page(unsigned int nid, struct f2fs_io_info *fio, int do_copy) { struct f2fs_summary sum; + int ret = 0; set_summary(&sum, nid, 0, 0); - do_write_page(&sum, fio, do_copy); + ret = do_write_page(&sum, fio, do_copy); f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE); + + return ret; } void f2fs_outplace_write_data(struct dnode_of_data *dn, |
