Skip to content

Commit caa5a4a

Browse files
Jaegeuk Kimpundiramit
authored andcommitted
f2fs: support IO alignment for DATA and NODE writes
commit 0a595ebaaa6b53a2226d3fee2a2fd616ea5ba378 upstream. This patch implements IO alignment by filling dummy blocks in DATA and NODE write bios. If we can guarantee, for example, 32KB or 64KB for such the IOs, we can eliminate underlying dummy page problem which FTL conducts in order to close MLC or TLC partial written pages. Note that, - it requires "-o mode=lfs". - IO size should be power of 2, not exceed BIO_MAX_PAGES, 256. - read IO is still 4KB. - do checkpoint at fsync, if dummy NODE page was written. Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
1 parent 1c2238b commit caa5a4a

6 files changed

Lines changed: 84 additions & 6 deletions

File tree

fs/f2fs/data.c

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,17 @@ static void f2fs_write_end_io(struct bio *bio)
9494
struct page *page = bvec->bv_page;
9595
enum count_type type = WB_DATA_TYPE(page);
9696

97+
if (IS_DUMMY_WRITTEN_PAGE(page)) {
98+
set_page_private(page, (unsigned long)NULL);
99+
ClearPagePrivate(page);
100+
unlock_page(page);
101+
mempool_free(page, sbi->write_io_dummy);
102+
103+
if (unlikely(bio->bi_error))
104+
f2fs_stop_checkpoint(sbi, true);
105+
continue;
106+
}
107+
97108
fscrypt_pullback_bio_page(&page, true);
98109

99110
if (unlikely(bio->bi_error)) {
@@ -172,10 +183,42 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi,
172183
struct bio *bio, enum page_type type)
173184
{
174185
if (!is_read_io(bio_op(bio))) {
186+
unsigned int start;
187+
175188
if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
176189
current->plug && (type == DATA || type == NODE))
177190
blk_finish_plug(current->plug);
191+
192+
if (type != DATA && type != NODE)
193+
goto submit_io;
194+
195+
start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS;
196+
start %= F2FS_IO_SIZE(sbi);
197+
198+
if (start == 0)
199+
goto submit_io;
200+
201+
/* fill dummy pages */
202+
for (; start < F2FS_IO_SIZE(sbi); start++) {
203+
struct page *page =
204+
mempool_alloc(sbi->write_io_dummy,
205+
GFP_NOIO | __GFP_ZERO | __GFP_NOFAIL);
206+
f2fs_bug_on(sbi, !page);
207+
208+
SetPagePrivate(page);
209+
set_page_private(page, (unsigned long)DUMMY_WRITTEN_PAGE);
210+
lock_page(page);
211+
if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE)
212+
f2fs_bug_on(sbi, 1);
213+
}
214+
/*
215+
* In the NODE case, we lose next block address chain. So, we
216+
* need to do checkpoint in f2fs_sync_file.
217+
*/
218+
if (type == NODE)
219+
set_sbi_flag(sbi, SBI_NEED_CP);
178220
}
221+
submit_io:
179222
if (is_read_io(bio_op(bio)))
180223
trace_f2fs_submit_read_bio(sbi->sb, type, bio);
181224
else
@@ -320,13 +363,14 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
320363
return 0;
321364
}
322365

323-
void f2fs_submit_page_mbio(struct f2fs_io_info *fio)
366+
int f2fs_submit_page_mbio(struct f2fs_io_info *fio)
324367
{
325368
struct f2fs_sb_info *sbi = fio->sbi;
326369
enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
327370
struct f2fs_bio_info *io;
328371
bool is_read = is_read_io(fio->op);
329372
struct page *bio_page;
373+
int err = 0;
330374

331375
io = is_read ? &sbi->read_io : &sbi->write_io[btype];
332376

@@ -347,6 +391,12 @@ void f2fs_submit_page_mbio(struct f2fs_io_info *fio)
347391
__submit_merged_bio(io);
348392
alloc_new:
349393
if (io->bio == NULL) {
394+
if ((fio->type == DATA || fio->type == NODE) &&
395+
fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) {
396+
err = -EAGAIN;
397+
dec_page_count(sbi, WB_DATA_TYPE(bio_page));
398+
goto out_fail;
399+
}
350400
io->bio = __bio_alloc(sbi, fio->new_blkaddr,
351401
BIO_MAX_PAGES, is_read);
352402
io->fio = *fio;
@@ -360,9 +410,10 @@ void f2fs_submit_page_mbio(struct f2fs_io_info *fio)
360410

361411
io->last_block_in_bio = fio->new_blkaddr;
362412
f2fs_trace_ios(fio, 0);
363-
413+
out_fail:
364414
up_write(&io->io_rwsem);
365415
trace_f2fs_submit_page_mbio(fio->page, fio);
416+
return err;
366417
}
367418

368419
static void __set_data_blkaddr(struct dnode_of_data *dn)

fs/f2fs/f2fs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,8 @@ struct f2fs_sb_info {
859859
struct f2fs_bio_info read_io; /* for read bios */
860860
struct f2fs_bio_info write_io[NR_PAGE_TYPE]; /* for write bios */
861861
struct mutex wio_mutex[NODE + 1]; /* bio ordering for NODE/DATA */
862+
int write_io_size_bits; /* Write IO size bits */
863+
mempool_t *write_io_dummy; /* Dummy pages */
862864

863865
/* for checkpoint */
864866
struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */
@@ -2241,7 +2243,7 @@ void f2fs_submit_merged_bio_cond(struct f2fs_sb_info *, struct inode *,
22412243
struct page *, nid_t, enum page_type, int);
22422244
void f2fs_flush_merged_bios(struct f2fs_sb_info *);
22432245
int f2fs_submit_page_bio(struct f2fs_io_info *);
2244-
void f2fs_submit_page_mbio(struct f2fs_io_info *);
2246+
int f2fs_submit_page_mbio(struct f2fs_io_info *);
22452247
struct block_device *f2fs_target_device(struct f2fs_sb_info *,
22462248
block_t, struct bio *);
22472249
int f2fs_target_device_index(struct f2fs_sb_info *, block_t);

fs/f2fs/segment.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,15 +1684,20 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
16841684
static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
16851685
{
16861686
int type = __get_segment_type(fio->page, fio->type);
1687+
int err;
16871688

16881689
if (fio->type == NODE || fio->type == DATA)
16891690
mutex_lock(&fio->sbi->wio_mutex[fio->type]);
1690-
1691+
reallocate:
16911692
allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
16921693
&fio->new_blkaddr, sum, type);
16931694

16941695
/* writeout dirty page into bdev */
1695-
f2fs_submit_page_mbio(fio);
1696+
err = f2fs_submit_page_mbio(fio);
1697+
if (err == -EAGAIN) {
1698+
fio->old_blkaddr = fio->new_blkaddr;
1699+
goto reallocate;
1700+
}
16961701

16971702
if (fio->type == NODE || fio->type == DATA)
16981703
mutex_unlock(&fio->sbi->wio_mutex[fio->type]);

fs/f2fs/segment.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,12 @@ struct segment_allocation {
186186
* the page is atomically written, and it is in inmem_pages list.
187187
*/
188188
#define ATOMIC_WRITTEN_PAGE ((unsigned long)-1)
189+
#define DUMMY_WRITTEN_PAGE ((unsigned long)-2)
189190

190191
#define IS_ATOMIC_WRITTEN_PAGE(page) \
191192
(page_private(page) == (unsigned long)ATOMIC_WRITTEN_PAGE)
193+
#define IS_DUMMY_WRITTEN_PAGE(page) \
194+
(page_private(page) == (unsigned long)DUMMY_WRITTEN_PAGE)
192195

193196
struct inmem_pages {
194197
struct list_head list;

fs/f2fs/super.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1764,6 +1764,8 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
17641764
FDEV(i).total_segments,
17651765
FDEV(i).start_blk, FDEV(i).end_blk);
17661766
}
1767+
f2fs_msg(sbi->sb, KERN_INFO,
1768+
"IO Block Size: %8d KB", F2FS_IO_SIZE_KB(sbi));
17671769
return 0;
17681770
}
17691771

@@ -1881,12 +1883,19 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
18811883
if (err)
18821884
goto free_options;
18831885

1886+
if (F2FS_IO_SIZE(sbi) > 1) {
1887+
sbi->write_io_dummy =
1888+
mempool_create_page_pool(F2FS_IO_SIZE(sbi) - 1, 0);
1889+
if (!sbi->write_io_dummy)
1890+
goto free_options;
1891+
}
1892+
18841893
/* get an inode for meta space */
18851894
sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
18861895
if (IS_ERR(sbi->meta_inode)) {
18871896
f2fs_msg(sb, KERN_ERR, "Failed to read F2FS meta data inode");
18881897
err = PTR_ERR(sbi->meta_inode);
1889-
goto free_options;
1898+
goto free_io_dummy;
18901899
}
18911900

18921901
err = get_valid_checkpoint(sbi);
@@ -2104,6 +2113,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
21042113
free_meta_inode:
21052114
make_bad_inode(sbi->meta_inode);
21062115
iput(sbi->meta_inode);
2116+
free_io_dummy:
2117+
mempool_destroy(sbi->write_io_dummy);
21072118
free_options:
21082119
destroy_percpu_info(sbi);
21092120
kfree(options);

include/linux/f2fs_fs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636
#define F2FS_NODE_INO(sbi) (sbi->node_ino_num)
3737
#define F2FS_META_INO(sbi) (sbi->meta_ino_num)
3838

39+
#define F2FS_IO_SIZE(sbi) (1 << (sbi)->write_io_size_bits) /* Blocks */
40+
#define F2FS_IO_SIZE_KB(sbi) (1 << ((sbi)->write_io_size_bits + 2)) /* KB */
41+
#define F2FS_IO_SIZE_BYTES(sbi) (1 << ((sbi)->write_io_size_bits + 12)) /* B */
42+
#define F2FS_IO_SIZE_BITS(sbi) ((sbi)->write_io_size_bits) /* power of 2 */
43+
#define F2FS_IO_SIZE_MASK(sbi) (F2FS_IO_SIZE(sbi) - 1)
44+
3945
/* This flag is used by node and meta inodes, and by recovery */
4046
#define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO)
4147
#define GFP_F2FS_HIGH_ZERO (GFP_NOFS | __GFP_ZERO | __GFP_HIGHMEM)

0 commit comments

Comments
 (0)