Merge tag 'f2fs-for-4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 31 Dec 2018 17:41:37 +0000 (09:41 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 31 Dec 2018 17:41:37 +0000 (09:41 -0800)
Pull f2fs updates from Jaegeuk Kim:
 "In this round, we've focused on bug fixes since Pixel devices have
  been shipping with f2fs. Some of them were related to hardware
  encryption support which are actually not an issue in mainline, but
  would be better to merge them in order to avoid potential bugs.

  Enhancements:
   - do GC sub-sections when the section is large
   - add a flag in ioctl(SHUTDOWN) to trigger fsck for QA
   - use kvmalloc() in order to give another chance to avoid ENOMEM

  Bug fixes:
   - fix accessing memory boundaries in a malformed iamge
   - GC gives stale unencrypted block
   - GC counts in large sections
   - detect idle time more precisely
   - block allocation of DIO writes
   - race conditions between write_begin and write_checkpoint
   - allow GCs for node segments via ioctl()

  There are various clean-ups and minor bug fixes as well"

* tag 'f2fs-for-4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (43 commits)
  f2fs: sanity check of xattr entry size
  f2fs: fix use-after-free issue when accessing sbi->stat_info
  f2fs: check PageWriteback flag for ordered case
  f2fs: fix validation of the block count in sanity_check_raw_super
  f2fs: fix missing unlock(sbi->gc_mutex)
  f2fs: fix to dirty inode synchronously
  f2fs: clean up structure extent_node
  f2fs: fix block address for __check_sit_bitmap
  f2fs: fix sbi->extent_list corruption issue
  f2fs: clean up checkpoint flow
  f2fs: flush stale issued discard candidates
  f2fs: correct wrong spelling, issing_*
  f2fs: use kvmalloc, if kmalloc is failed
  f2fs: remove redundant comment of unused wio_mutex
  f2fs: fix to reorder set_page_dirty and wait_on_page_writeback
  f2fs: clear PG_writeback if IPU failed
  f2fs: add an ioctl() to explicitly trigger fsck later
  f2fs: avoid frequent costly fsck triggers
  f2fs: fix m_may_create to make OPU DIO write correctly
  f2fs: fix to update new block address correctly for OPU
  ...

1  2 
fs/f2fs/data.c

diff --combined fs/f2fs/data.c
index 008b74eff00dafd4d501d615c5c36a6c5ee3eac8,a0524616f3f160b2892513a11414ae2ea0c76aec..f91d8630c9a2d768d365e443811c37a4a1023a1e
@@@ -372,29 -372,6 +372,6 @@@ static bool __has_merged_page(struct f2
        return false;
  }
  
- static bool has_merged_page(struct f2fs_sb_info *sbi, struct inode *inode,
-                                               struct page *page, nid_t ino,
-                                               enum page_type type)
- {
-       enum page_type btype = PAGE_TYPE_OF_BIO(type);
-       enum temp_type temp;
-       struct f2fs_bio_info *io;
-       bool ret = false;
-       for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
-               io = sbi->write_io[btype] + temp;
-               down_read(&io->io_rwsem);
-               ret = __has_merged_page(io, inode, page, ino);
-               up_read(&io->io_rwsem);
-               /* TODO: use HOT temp only for meta pages now. */
-               if (ret || btype == META)
-                       break;
-       }
-       return ret;
- }
  static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi,
                                enum page_type type, enum temp_type temp)
  {
@@@ -420,13 -397,19 +397,19 @@@ static void __submit_merged_write_cond(
                                nid_t ino, enum page_type type, bool force)
  {
        enum temp_type temp;
-       if (!force && !has_merged_page(sbi, inode, page, ino, type))
-               return;
+       bool ret = true;
  
        for (temp = HOT; temp < NR_TEMP_TYPE; temp++) {
+               if (!force)     {
+                       enum page_type btype = PAGE_TYPE_OF_BIO(type);
+                       struct f2fs_bio_info *io = sbi->write_io[btype] + temp;
  
-               __f2fs_submit_merged_write(sbi, type, temp);
+                       down_read(&io->io_rwsem);
+                       ret = __has_merged_page(io, inode, page, ino);
+                       up_read(&io->io_rwsem);
+               }
+               if (ret)
+                       __f2fs_submit_merged_write(sbi, type, temp);
  
                /* TODO: use HOT temp only for meta pages now. */
                if (type >= META)
@@@ -643,7 -626,7 +626,7 @@@ static void __set_data_blkaddr(struct d
   */
  void f2fs_set_data_blkaddr(struct dnode_of_data *dn)
  {
-       f2fs_wait_on_page_writeback(dn->node_page, NODE, true);
+       f2fs_wait_on_page_writeback(dn->node_page, NODE, true, true);
        __set_data_blkaddr(dn);
        if (set_page_dirty(dn->node_page))
                dn->node_changed = true;
@@@ -673,7 -656,7 +656,7 @@@ int f2fs_reserve_new_blocks(struct dnod
        trace_f2fs_reserve_new_blocks(dn->inode, dn->nid,
                                                dn->ofs_in_node, count);
  
-       f2fs_wait_on_page_writeback(dn->node_page, NODE, true);
+       f2fs_wait_on_page_writeback(dn->node_page, NODE, true, true);
  
        for (; count > 0; dn->ofs_in_node++) {
                block_t blkaddr = datablock_addr(dn->inode,
@@@ -957,6 -940,9 +940,9 @@@ int f2fs_preallocate_blocks(struct kioc
                        return err;
        }
  
+       if (direct_io && allow_outplace_dio(inode, iocb, from))
+               return 0;
        if (is_inode_flag_set(inode, FI_NO_PREALLOC))
                return 0;
  
        map.m_next_pgofs = NULL;
        map.m_next_extent = NULL;
        map.m_seg_type = NO_CHECK_TYPE;
+       map.m_may_create = true;
  
        if (direct_io) {
                map.m_seg_type = f2fs_rw_hint_to_seg_type(iocb->ki_hint);
@@@ -1028,7 -1015,7 +1015,7 @@@ int f2fs_map_blocks(struct inode *inode
        unsigned int maxblocks = map->m_len;
        struct dnode_of_data dn;
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       int mode = create ? ALLOC_NODE : LOOKUP_NODE;
+       int mode = map->m_may_create ? ALLOC_NODE : LOOKUP_NODE;
        pgoff_t pgofs, end_offset, end;
        int err = 0, ofs = 1;
        unsigned int ofs_in_node, last_ofs_in_node;
        end = pgofs + maxblocks;
  
        if (!create && f2fs_lookup_extent_cache(inode, pgofs, &ei)) {
+               if (test_opt(sbi, LFS) && flag == F2FS_GET_BLOCK_DIO &&
+                                                       map->m_may_create)
+                       goto next_dnode;
                map->m_pblk = ei.blk + pgofs - ei.fofs;
                map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs);
                map->m_flags = F2FS_MAP_MAPPED;
        }
  
  next_dnode:
-       if (create)
+       if (map->m_may_create)
                __do_map_lock(sbi, flag, true);
  
        /* When reading holes, we need its node page */
@@@ -1099,11 -1090,13 +1090,13 @@@ next_block
  
        if (is_valid_data_blkaddr(sbi, blkaddr)) {
                /* use out-place-update for driect IO under LFS mode */
-               if (test_opt(sbi, LFS) && create &&
-                               flag == F2FS_GET_BLOCK_DIO) {
+               if (test_opt(sbi, LFS) && flag == F2FS_GET_BLOCK_DIO &&
+                                                       map->m_may_create) {
                        err = __allocate_data_block(&dn, map->m_seg_type);
-                       if (!err)
+                       if (!err) {
+                               blkaddr = dn.data_blkaddr;
                                set_inode_flag(inode, FI_APPEND_WRITE);
+                       }
                }
        } else {
                if (create) {
@@@ -1209,7 -1202,7 +1202,7 @@@ skip
  
        f2fs_put_dnode(&dn);
  
-       if (create) {
+       if (map->m_may_create) {
                __do_map_lock(sbi, flag, false);
                f2fs_balance_fs(sbi, dn.node_changed);
        }
@@@ -1235,7 -1228,7 +1228,7 @@@ sync_out
        }
        f2fs_put_dnode(&dn);
  unlock_out:
-       if (create) {
+       if (map->m_may_create) {
                __do_map_lock(sbi, flag, false);
                f2fs_balance_fs(sbi, dn.node_changed);
        }
@@@ -1257,6 -1250,7 +1250,7 @@@ bool f2fs_overwrite_io(struct inode *in
        map.m_next_pgofs = NULL;
        map.m_next_extent = NULL;
        map.m_seg_type = NO_CHECK_TYPE;
+       map.m_may_create = false;
        last_lblk = F2FS_BLK_ALIGN(pos + len);
  
        while (map.m_lblk < last_lblk) {
  
  static int __get_data_block(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh, int create, int flag,
-                       pgoff_t *next_pgofs, int seg_type)
+                       pgoff_t *next_pgofs, int seg_type, bool may_write)
  {
        struct f2fs_map_blocks map;
        int err;
        map.m_next_pgofs = next_pgofs;
        map.m_next_extent = NULL;
        map.m_seg_type = seg_type;
+       map.m_may_create = may_write;
  
        err = f2fs_map_blocks(inode, &map, create, flag);
        if (!err) {
@@@ -1297,16 -1292,25 +1292,25 @@@ static int get_data_block(struct inode 
  {
        return __get_data_block(inode, iblock, bh_result, create,
                                                        flag, next_pgofs,
-                                                       NO_CHECK_TYPE);
+                                                       NO_CHECK_TYPE, create);
+ }
+ static int get_data_block_dio_write(struct inode *inode, sector_t iblock,
+                       struct buffer_head *bh_result, int create)
+ {
+       return __get_data_block(inode, iblock, bh_result, create,
+                               F2FS_GET_BLOCK_DIO, NULL,
+                               f2fs_rw_hint_to_seg_type(inode->i_write_hint),
+                               true);
  }
  
  static int get_data_block_dio(struct inode *inode, sector_t iblock,
                        struct buffer_head *bh_result, int create)
  {
        return __get_data_block(inode, iblock, bh_result, create,
-                                               F2FS_GET_BLOCK_DIO, NULL,
-                                               f2fs_rw_hint_to_seg_type(
-                                                       inode->i_write_hint));
+                               F2FS_GET_BLOCK_DIO, NULL,
+                               f2fs_rw_hint_to_seg_type(inode->i_write_hint),
+                               false);
  }
  
  static int get_data_block_bmap(struct inode *inode, sector_t iblock,
  
        return __get_data_block(inode, iblock, bh_result, create,
                                                F2FS_GET_BLOCK_BMAP, NULL,
-                                               NO_CHECK_TYPE);
+                                               NO_CHECK_TYPE, create);
  }
  
  static inline sector_t logical_to_blk(struct inode *inode, loff_t offset)
@@@ -1525,6 -1529,7 +1529,7 @@@ static int f2fs_mpage_readpages(struct 
        map.m_next_pgofs = NULL;
        map.m_next_extent = NULL;
        map.m_seg_type = NO_CHECK_TYPE;
+       map.m_may_create = false;
  
        for (; nr_pages; nr_pages--) {
                if (pages) {
@@@ -1855,6 -1860,8 +1860,8 @@@ got_it
                if (fio->need_lock == LOCK_REQ)
                        f2fs_unlock_op(fio->sbi);
                err = f2fs_inplace_write_data(fio);
+               if (err && PageWriteback(page))
+                       end_page_writeback(page);
                trace_f2fs_do_write_data_page(fio->page, IPU);
                set_inode_flag(inode, FI_UPDATE_WRITE);
                return err;
@@@ -2142,12 -2149,11 +2149,11 @@@ continue_unlock
                        if (PageWriteback(page)) {
                                if (wbc->sync_mode != WB_SYNC_NONE)
                                        f2fs_wait_on_page_writeback(page,
-                                                               DATA, true);
+                                                       DATA, true, true);
                                else
                                        goto continue_unlock;
                        }
  
-                       BUG_ON(PageWriteback(page));
                        if (!clear_page_dirty_for_io(page))
                                goto continue_unlock;
  
@@@ -2324,6 -2330,7 +2330,7 @@@ static int prepare_write_begin(struct f
        bool locked = false;
        struct extent_info ei = {0,0,0};
        int err = 0;
+       int flag;
  
        /*
         * we already allocated all the blocks, so we don't need to get
                        !is_inode_flag_set(inode, FI_NO_PREALLOC))
                return 0;
  
+       /* f2fs_lock_op avoids race between write CP and convert_inline_page */
+       if (f2fs_has_inline_data(inode) && pos + len > MAX_INLINE_DATA(inode))
+               flag = F2FS_GET_BLOCK_DEFAULT;
+       else
+               flag = F2FS_GET_BLOCK_PRE_AIO;
        if (f2fs_has_inline_data(inode) ||
                        (pos & PAGE_MASK) >= i_size_read(inode)) {
-               __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
+               __do_map_lock(sbi, flag, true);
                locked = true;
        }
  restart:
                                f2fs_put_dnode(&dn);
                                __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO,
                                                                true);
+                               WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO);
                                locked = true;
                                goto restart;
                        }
@@@ -2386,7 -2400,7 +2400,7 @@@ out
        f2fs_put_dnode(&dn);
  unlock_out:
        if (locked)
-               __do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
+               __do_map_lock(sbi, flag, false);
        return err;
  }
  
@@@ -2457,7 -2471,7 +2471,7 @@@ repeat
                }
        }
  
-       f2fs_wait_on_page_writeback(page, DATA, false);
+       f2fs_wait_on_page_writeback(page, DATA, false, true);
  
        if (len == PAGE_SIZE || PageUptodate(page))
                return 0;
@@@ -2548,6 -2562,53 +2562,53 @@@ static int check_direct_IO(struct inod
        return 0;
  }
  
+ static void f2fs_dio_end_io(struct bio *bio)
+ {
+       struct f2fs_private_dio *dio = bio->bi_private;
+       dec_page_count(F2FS_I_SB(dio->inode),
+                       dio->write ? F2FS_DIO_WRITE : F2FS_DIO_READ);
+       bio->bi_private = dio->orig_private;
+       bio->bi_end_io = dio->orig_end_io;
+       kvfree(dio);
+       bio_endio(bio);
+ }
+ static void f2fs_dio_submit_bio(struct bio *bio, struct inode *inode,
+                                                       loff_t file_offset)
+ {
+       struct f2fs_private_dio *dio;
+       bool write = (bio_op(bio) == REQ_OP_WRITE);
+       int err;
+       dio = f2fs_kzalloc(F2FS_I_SB(inode),
+                       sizeof(struct f2fs_private_dio), GFP_NOFS);
+       if (!dio) {
+               err = -ENOMEM;
+               goto out;
+       }
+       dio->inode = inode;
+       dio->orig_end_io = bio->bi_end_io;
+       dio->orig_private = bio->bi_private;
+       dio->write = write;
+       bio->bi_end_io = f2fs_dio_end_io;
+       bio->bi_private = dio;
+       inc_page_count(F2FS_I_SB(inode),
+                       write ? F2FS_DIO_WRITE : F2FS_DIO_READ);
+       submit_bio(bio);
+       return;
+ out:
+       bio->bi_status = BLK_STS_IOERR;
+       bio_endio(bio);
+ }
  static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
  {
        struct address_space *mapping = iocb->ki_filp->f_mapping;
                        down_read(&fi->i_gc_rwsem[READ]);
        }
  
-       err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio);
+       err = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev,
+                       iter, rw == WRITE ? get_data_block_dio_write :
+                       get_data_block_dio, NULL, f2fs_dio_submit_bio,
+                       DIO_LOCKING | DIO_SKIP_HOLES);
  
        if (do_opu)
                up_read(&fi->i_gc_rwsem[READ]);
@@@ -2738,7 -2802,7 +2802,7 @@@ int f2fs_migrate_page(struct address_sp
         */
        extra_count = (atomic_written ? 1 : 0) - page_has_private(page);
        rc = migrate_page_move_mapping(mapping, newpage,
 -                              page, NULL, mode, extra_count);
 +                              page, mode, extra_count);
        if (rc != MIGRATEPAGE_SUCCESS) {
                if (atomic_written)
                        mutex_unlock(&fi->inmem_lock);