Skip to content

Commit f847c69

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: allow out-place-update for direct IO in LFS mode
Normally, DIO uses in-pllace-update, but in LFS mode, f2fs doesn't allow triggering any in-place-update writes, so we fallback direct write to buffered write, result in bad performance of large size write. This patch adds to support triggering out-place-update for direct IO to enhance its performance. Note that it needs to exclude direct read IO during direct write, since new data writing to new block address will no be valid until write finished. storage: zram time xfs_io -f -d /mnt/f2fs/file -c "pwrite 0 1073741824" -c "fsync" Before: real 0m13.061s user 0m0.327s sys 0m12.486s After: real 0m6.448s user 0m0.228s sys 0m6.212s Signed-off-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent 39a8695 commit f847c69

File tree

3 files changed

+78
-14
lines changed

3 files changed

+78
-14
lines changed

fs/f2fs/data.c

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -893,7 +893,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
893893

894894
dn->data_blkaddr = datablock_addr(dn->inode,
895895
dn->node_page, dn->ofs_in_node);
896-
if (dn->data_blkaddr == NEW_ADDR)
896+
if (dn->data_blkaddr != NULL_ADDR)
897897
goto alloc;
898898

899899
if (unlikely((err = inc_valid_block_count(sbi, dn->inode, &count))))
@@ -947,7 +947,7 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
947947

948948
if (direct_io) {
949949
map.m_seg_type = f2fs_rw_hint_to_seg_type(iocb->ki_hint);
950-
flag = f2fs_force_buffered_io(inode, WRITE) ?
950+
flag = f2fs_force_buffered_io(inode, iocb, from) ?
951951
F2FS_GET_BLOCK_PRE_AIO :
952952
F2FS_GET_BLOCK_PRE_DIO;
953953
goto map_blocks;
@@ -1066,7 +1066,15 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
10661066
goto sync_out;
10671067
}
10681068

1069-
if (!is_valid_data_blkaddr(sbi, blkaddr)) {
1069+
if (is_valid_data_blkaddr(sbi, blkaddr)) {
1070+
/* use out-place-update for driect IO under LFS mode */
1071+
if (test_opt(sbi, LFS) && create &&
1072+
flag == F2FS_GET_BLOCK_DIO) {
1073+
err = __allocate_data_block(&dn, map->m_seg_type);
1074+
if (!err)
1075+
set_inode_flag(inode, FI_APPEND_WRITE);
1076+
}
1077+
} else {
10701078
if (create) {
10711079
if (unlikely(f2fs_cp_error(sbi))) {
10721080
err = -EIO;
@@ -2486,44 +2494,62 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
24862494
struct address_space *mapping = iocb->ki_filp->f_mapping;
24872495
struct inode *inode = mapping->host;
24882496
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
2497+
struct f2fs_inode_info *fi = F2FS_I(inode);
24892498
size_t count = iov_iter_count(iter);
24902499
loff_t offset = iocb->ki_pos;
24912500
int rw = iov_iter_rw(iter);
24922501
int err;
24932502
enum rw_hint hint = iocb->ki_hint;
24942503
int whint_mode = F2FS_OPTION(sbi).whint_mode;
2504+
bool do_opu;
24952505

24962506
err = check_direct_IO(inode, iter, offset);
24972507
if (err)
24982508
return err < 0 ? err : 0;
24992509

2500-
if (f2fs_force_buffered_io(inode, rw))
2510+
if (f2fs_force_buffered_io(inode, iocb, iter))
25012511
return 0;
25022512

2513+
do_opu = allow_outplace_dio(inode, iocb, iter);
2514+
25032515
trace_f2fs_direct_IO_enter(inode, offset, count, rw);
25042516

25052517
if (rw == WRITE && whint_mode == WHINT_MODE_OFF)
25062518
iocb->ki_hint = WRITE_LIFE_NOT_SET;
25072519

2508-
if (!down_read_trylock(&F2FS_I(inode)->i_gc_rwsem[rw])) {
2509-
if (iocb->ki_flags & IOCB_NOWAIT) {
2520+
if (iocb->ki_flags & IOCB_NOWAIT) {
2521+
if (!down_read_trylock(&fi->i_gc_rwsem[rw])) {
2522+
iocb->ki_hint = hint;
2523+
err = -EAGAIN;
2524+
goto out;
2525+
}
2526+
if (do_opu && !down_read_trylock(&fi->i_gc_rwsem[READ])) {
2527+
up_read(&fi->i_gc_rwsem[rw]);
25102528
iocb->ki_hint = hint;
25112529
err = -EAGAIN;
25122530
goto out;
25132531
}
2514-
down_read(&F2FS_I(inode)->i_gc_rwsem[rw]);
2532+
} else {
2533+
down_read(&fi->i_gc_rwsem[rw]);
2534+
if (do_opu)
2535+
down_read(&fi->i_gc_rwsem[READ]);
25152536
}
25162537

25172538
err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio);
2518-
up_read(&F2FS_I(inode)->i_gc_rwsem[rw]);
2539+
2540+
if (do_opu)
2541+
up_read(&fi->i_gc_rwsem[READ]);
2542+
2543+
up_read(&fi->i_gc_rwsem[rw]);
25192544

25202545
if (rw == WRITE) {
25212546
if (whint_mode == WHINT_MODE_OFF)
25222547
iocb->ki_hint = hint;
25232548
if (err > 0) {
25242549
f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_IO,
25252550
err);
2526-
set_inode_flag(inode, FI_UPDATE_WRITE);
2551+
if (!do_opu)
2552+
set_inode_flag(inode, FI_UPDATE_WRITE);
25272553
} else if (err < 0) {
25282554
f2fs_write_failed(mapping, offset + count);
25292555
}

fs/f2fs/f2fs.h

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#ifndef _LINUX_F2FS_H
99
#define _LINUX_F2FS_H
1010

11+
#include <linux/uio.h>
1112
#include <linux/types.h>
1213
#include <linux/page-flags.h>
1314
#include <linux/buffer_head.h>
@@ -3491,11 +3492,47 @@ static inline bool f2fs_may_encrypt(struct inode *inode)
34913492
#endif
34923493
}
34933494

3494-
static inline bool f2fs_force_buffered_io(struct inode *inode, int rw)
3495+
static inline int block_unaligned_IO(struct inode *inode,
3496+
struct kiocb *iocb, struct iov_iter *iter)
34953497
{
3496-
return (f2fs_post_read_required(inode) ||
3497-
(rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) ||
3498-
F2FS_I_SB(inode)->s_ndevs);
3498+
unsigned int i_blkbits = READ_ONCE(inode->i_blkbits);
3499+
unsigned int blocksize_mask = (1 << i_blkbits) - 1;
3500+
loff_t offset = iocb->ki_pos;
3501+
unsigned long align = offset | iov_iter_alignment(iter);
3502+
3503+
return align & blocksize_mask;
3504+
}
3505+
3506+
static inline int allow_outplace_dio(struct inode *inode,
3507+
struct kiocb *iocb, struct iov_iter *iter)
3508+
{
3509+
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3510+
int rw = iov_iter_rw(iter);
3511+
3512+
return (test_opt(sbi, LFS) && (rw == WRITE) &&
3513+
!block_unaligned_IO(inode, iocb, iter));
3514+
}
3515+
3516+
static inline bool f2fs_force_buffered_io(struct inode *inode,
3517+
struct kiocb *iocb, struct iov_iter *iter)
3518+
{
3519+
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
3520+
int rw = iov_iter_rw(iter);
3521+
3522+
if (f2fs_post_read_required(inode))
3523+
return true;
3524+
if (sbi->s_ndevs)
3525+
return true;
3526+
/*
3527+
* for blkzoned device, fallback direct IO to buffered IO, so
3528+
* all IOs can be serialized by log-structured write.
3529+
*/
3530+
if (f2fs_sb_has_blkzoned(sbi->sb))
3531+
return true;
3532+
if (test_opt(sbi, LFS) && (rw == WRITE) &&
3533+
block_unaligned_IO(inode, iocb, iter))
3534+
return true;
3535+
return false;
34993536
}
35003537

35013538
#ifdef CONFIG_F2FS_FAULT_INJECTION

fs/f2fs/file.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3001,7 +3001,8 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
30013001
if (!f2fs_overwrite_io(inode, iocb->ki_pos,
30023002
iov_iter_count(from)) ||
30033003
f2fs_has_inline_data(inode) ||
3004-
f2fs_force_buffered_io(inode, WRITE)) {
3004+
f2fs_force_buffered_io(inode,
3005+
iocb, from)) {
30053006
clear_inode_flag(inode,
30063007
FI_NO_PREALLOC);
30073008
inode_unlock(inode);

0 commit comments

Comments
 (0)