Merge tag 'f2fs-for-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeu...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 31 May 2022 23:52:59 +0000 (16:52 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 31 May 2022 23:52:59 +0000 (16:52 -0700)
Pull f2fs updates from Jaegeuk Kim:
 "In this round, we've refactored the existing atomic write support
  implemented by in-memory operations to have storing data in disk
  temporarily, which can give us a benefit to accept more atomic writes.

  At the same time, we removed the existing volatile write support.

  We've also revisited the file pinning and GC flows and found some
  corner cases which contributeed abnormal system behaviours.

  As usual, there're several minor code refactoring for readability,
  sanity check, and clean ups.

  Enhancements:

   - allow compression for mmap files in compress_mode=user

   - kill volatile write support

   - change the current atomic write way

   - give priority to select unpinned section for foreground GC

   - introduce data read/write showing path info

   - remove unnecessary f2fs_lock_op in f2fs_new_inode

  Bug fixes:

   - fix the file pinning flow during checkpoint=disable and GCs

   - fix foreground and background GCs to select the right victims and
     get free sections on time

   - fix GC flags on defragmenting pages

   - avoid an infinite loop to flush node pages

   - fix fallocate to use file_modified to update permissions
     consistently"

* tag 'f2fs-for-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (40 commits)
  f2fs: fix to tag gcing flag on page during file defragment
  f2fs: replace F2FS_I(inode) and sbi by the local variable
  f2fs: add f2fs_init_write_merge_io function
  f2fs: avoid unneeded error handling for revoke_entry_slab allocation
  f2fs: allow compression for mmap files in compress_mode=user
  f2fs: fix typo in comment
  f2fs: make f2fs_read_inline_data() more readable
  f2fs: fix to do sanity check for inline inode
  f2fs: fix fallocate to use file_modified to update permissions consistently
  f2fs: don't use casefolded comparison for "." and ".."
  f2fs: do not stop GC when requiring a free section
  f2fs: keep wait_ms if EAGAIN happens
  f2fs: introduce f2fs_gc_control to consolidate f2fs_gc parameters
  f2fs: reject test_dummy_encryption when !CONFIG_FS_ENCRYPTION
  f2fs: kill volatile write support
  f2fs: change the current atomic write way
  f2fs: don't need inode lock for system hidden quota
  f2fs: stop allocating pinned sections if EAGAIN happens
  f2fs: skip GC if possible when checkpoint disabling
  f2fs: give priority to select unpinned section for foreground GC
  ...

1  2 
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/node.c
fs/f2fs/segment.c
fs/f2fs/super.c
fs/f2fs/verity.c
include/trace/events/f2fs.h

Simple merge
diff --cc fs/f2fs/data.c
@@@ -3314,8 -3341,103 +3342,102 @@@ unlock_out
        return err;
  }
  
+ static int __find_data_block(struct inode *inode, pgoff_t index,
+                               block_t *blk_addr)
+ {
+       struct dnode_of_data dn;
+       struct page *ipage;
+       struct extent_info ei = {0, };
+       int err = 0;
+       ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino);
+       if (IS_ERR(ipage))
+               return PTR_ERR(ipage);
+       set_new_dnode(&dn, inode, ipage, ipage, 0);
+       if (f2fs_lookup_extent_cache(inode, index, &ei)) {
+               dn.data_blkaddr = ei.blk + index - ei.fofs;
+       } else {
+               /* hole case */
+               err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
+               if (err) {
+                       dn.data_blkaddr = NULL_ADDR;
+                       err = 0;
+               }
+       }
+       *blk_addr = dn.data_blkaddr;
+       f2fs_put_dnode(&dn);
+       return err;
+ }
+ static int __reserve_data_block(struct inode *inode, pgoff_t index,
+                               block_t *blk_addr, bool *node_changed)
+ {
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       struct dnode_of_data dn;
+       struct page *ipage;
+       int err = 0;
+       f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
+       ipage = f2fs_get_node_page(sbi, inode->i_ino);
+       if (IS_ERR(ipage)) {
+               err = PTR_ERR(ipage);
+               goto unlock_out;
+       }
+       set_new_dnode(&dn, inode, ipage, ipage, 0);
+       err = f2fs_get_block(&dn, index);
+       *blk_addr = dn.data_blkaddr;
+       *node_changed = dn.node_changed;
+       f2fs_put_dnode(&dn);
+ unlock_out:
+       f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
+       return err;
+ }
+ static int prepare_atomic_write_begin(struct f2fs_sb_info *sbi,
+                       struct page *page, loff_t pos, unsigned int len,
+                       block_t *blk_addr, bool *node_changed)
+ {
+       struct inode *inode = page->mapping->host;
+       struct inode *cow_inode = F2FS_I(inode)->cow_inode;
+       pgoff_t index = page->index;
+       int err = 0;
+       block_t ori_blk_addr;
+       /* If pos is beyond the end of file, reserve a new block in COW inode */
+       if ((pos & PAGE_MASK) >= i_size_read(inode))
+               return __reserve_data_block(cow_inode, index, blk_addr,
+                                       node_changed);
+       /* Look for the block in COW inode first */
+       err = __find_data_block(cow_inode, index, blk_addr);
+       if (err)
+               return err;
+       else if (*blk_addr != NULL_ADDR)
+               return 0;
+       /* Look for the block in the original inode */
+       err = __find_data_block(inode, index, &ori_blk_addr);
+       if (err)
+               return err;
+       /* Finally, we should reserve a new block in COW inode for the update */
+       err = __reserve_data_block(cow_inode, index, blk_addr, node_changed);
+       if (err)
+               return err;
+       if (ori_blk_addr != NULL_ADDR)
+               *blk_addr = ori_blk_addr;
+       return 0;
+ }
  static int f2fs_write_begin(struct file *file, struct address_space *mapping,
 -              loff_t pos, unsigned len, unsigned flags,
 -              struct page **pagep, void **fsdata)
 +              loff_t pos, unsigned len, struct page **pagep, void **fsdata)
  {
        struct inode *inode = mapping->host;
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
@@@ -3525,33 -3645,24 +3645,26 @@@ void f2fs_invalidate_folio(struct foli
        folio_detach_private(folio);
  }
  
 -int f2fs_release_page(struct page *page, gfp_t wait)
 +bool f2fs_release_folio(struct folio *folio, gfp_t wait)
  {
 -      /* If this is dirty page, keep PagePrivate */
 -      if (PageDirty(page))
 -              return 0;
 +      struct f2fs_sb_info *sbi;
 +
 +      /* If this is dirty folio, keep private data */
 +      if (folio_test_dirty(folio))
 +              return false;
  
-       /* This is atomic written page, keep Private */
-       if (page_private_atomic(&folio->page))
-               return false;
 -      if (test_opt(F2FS_P_SB(page), COMPRESS_CACHE)) {
 -              struct inode *inode = page->mapping->host;
 +      sbi = F2FS_M_SB(folio->mapping);
 +      if (test_opt(sbi, COMPRESS_CACHE)) {
 +              struct inode *inode = folio->mapping->host;
  
 -              if (inode->i_ino == F2FS_COMPRESS_INO(F2FS_I_SB(inode)))
 -                      clear_page_private_data(page);
 +              if (inode->i_ino == F2FS_COMPRESS_INO(sbi))
 +                      clear_page_private_data(&folio->page);
        }
  
 -      clear_page_private_gcing(page);
 +      clear_page_private_gcing(&folio->page);
  
 -      detach_page_private(page);
 -      set_page_private(page, 0);
 -      return 1;
 +      folio_detach_private(folio);
 +      return true;
  }
  
  static bool f2fs_dirty_data_folio(struct address_space *mapping,
diff --cc fs/f2fs/f2fs.h
Simple merge
diff --cc fs/f2fs/file.c
Simple merge
diff --cc fs/f2fs/node.c
Simple merge
Simple merge
diff --cc fs/f2fs/super.c
Simple merge
Simple merge
Simple merge