f2fs-for-5.16-rc1

In this cycle, we've applied relatively small number of patches which fix subtle
 corner cases mainly, while introducing a new mount option to be able to fragment
 the disk intentionally for performance tests.
 
 Enhancement:
  - add a mount option to fragmente on-disk layout to understand the performance
  - support direct IO for multi-partitions
  - add a fault injection of dquot_initialize
 
 Bug fix:
  - address some lockdep complaints
  - fix a deadlock issue with quota
  - fix a memory tuning condition
  - fix compression condition to improve the ratio
  - fix disabling compression on the non-empty compressed file
  - invalidate cached pages before IPU/DIO writes
 
 And, we've added some minor clean-ups as usual.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE00UqedjCtOrGVvQiQBSofoJIUNIFAmGMILwACgkQQBSofoJI
 UNJDRA/+KPyCXdY0OqL26BuGKj+z7hW6bz7tlh6h3wdnPdsR/W3ehbqQEr3GBb+q
 yokmD75/in7vZwGsDHGowFWMAfWOHYEqHz5UAq91sHjhfZzLDNUgLFWJedBX2XJb
 UoEAa7KzRt9M9K2p/5vSTs07RN3okUiRkFhVBBQJIaL7xi6MpadN/XAqpyoBqsiP
 pAV6J3GF6WNF19P/hkN1CJI8rV+PFrvY6C23lMkP7mnsWh03jMSgDDuhLHMQpAba
 EJYq7QbSatsLDRdR+jUQwIfMucvvzN7M6ja9+NTGlbeACvND8vXKYXOwngCq9+je
 2PIU4J8zNqnEkLsPn8STm4zwZHCA7VFdeCobCZcaVZCZFBzVqCkVYE9wqFVaQmr1
 bCrRFvEb+D1pkHYFujVXwCAfPlO6twiAInFNMa3WQ3FduJq2nhc8OLCJJ46D1KT2
 ZzzLv2EIIlncxPvgLIhiEE9DgPOyV56PQAO3OTsBZcvycU32aHo4hyexju1ubKiD
 CZFEHLnPbxX8Ulh3NX4uUxqPAEVhM/aw4l4e8xhmVRY3uj75geY7M6rt1vD+Y5Et
 EwbUE8XbLy+GhqbbO/SX9G38pftOiIquH1J0RuhuVNNmkIDkQvnSNp8WqHTdjEJE
 NiHZ5bkRkii34Wfrax9UccqGDswh/gjHAXEfGD8nFfcQZwLP1n8=
 =KGQ3
 -----END PGP SIGNATURE-----

Merge tag 'f2fs-for-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs

Pull f2fs updates from Jaegeuk Kim:
 "In this cycle, we've applied relatively small number of patches which
  fix subtle corner cases mainly, while introducing a new mount option
  to be able to fragment the disk intentionally for performance tests.

  Enhancements:

   - add a mount option to fragmente on-disk layout to understand the
     performance

   - support direct IO for multi-partitions

   - add a fault injection of dquot_initialize

  Bug fixes:

   - address some lockdep complaints

   - fix a deadlock issue with quota

   - fix a memory tuning condition

   - fix compression condition to improve the ratio

   - fix disabling compression on the non-empty compressed file

   - invalidate cached pages before IPU/DIO writes

  And, we've added some minor clean-ups as usual"

* tag 'f2fs-for-5.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs:
  f2fs: fix UAF in f2fs_available_free_memory
  f2fs: invalidate META_MAPPING before IPU/DIO write
  f2fs: support fault injection for dquot_initialize()
  f2fs: fix incorrect return value in f2fs_sanity_check_ckpt()
  f2fs: compress: disallow disabling compress on non-empty compressed file
  f2fs: compress: fix overwrite may reduce compress ratio unproperly
  f2fs: multidevice: support direct IO
  f2fs: introduce fragment allocation mode mount option
  f2fs: replace snprintf in show functions with sysfs_emit
  f2fs: include non-compressed blocks in compr_written_block
  f2fs: fix wrong condition to trigger background checkpoint correctly
  f2fs: fix to use WHINT_MODE
  f2fs: fix up f2fs_lookup tracepoints
  f2fs: set SBI_NEED_FSCK flag when inconsistent node block found
  f2fs: introduce excess_dirty_threshold()
  f2fs: avoid attaching SB_ACTIVE flag during mount
  f2fs: quota: fix potential deadlock
  f2fs: should use GFP_NOFS for directory inodes
This commit is contained in:
Linus Torvalds 2021-11-13 11:20:22 -08:00
commit 5664896ba2
21 changed files with 359 additions and 106 deletions

View File

@ -512,3 +512,19 @@ Date: July 2021
Contact: "Daeho Jeong" <daehojeong@google.com> Contact: "Daeho Jeong" <daehojeong@google.com>
Description: You can control the multiplier value of bdi device readahead window size Description: You can control the multiplier value of bdi device readahead window size
between 2 (default) and 256 for POSIX_FADV_SEQUENTIAL advise option. between 2 (default) and 256 for POSIX_FADV_SEQUENTIAL advise option.
What: /sys/fs/f2fs/<disk>/max_fragment_chunk
Date: August 2021
Contact: "Daeho Jeong" <daehojeong@google.com>
Description: With "mode=fragment:block" mount options, we can scatter block allocation.
f2fs will allocate 1..<max_fragment_chunk> blocks in a chunk and make a hole
in the length of 1..<max_fragment_hole> by turns. This value can be set
between 1..512 and the default value is 4.
What: /sys/fs/f2fs/<disk>/max_fragment_hole
Date: August 2021
Contact: "Daeho Jeong" <daehojeong@google.com>
Description: With "mode=fragment:block" mount options, we can scatter block allocation.
f2fs will allocate 1..<max_fragment_chunk> blocks in a chunk and make a hole
in the length of 1..<max_fragment_hole> by turns. This value can be set
between 1..512 and the default value is 4.

View File

@ -197,10 +197,29 @@ fault_type=%d Support configuring fault injection type, should be
FAULT_DISCARD 0x000002000 FAULT_DISCARD 0x000002000
FAULT_WRITE_IO 0x000004000 FAULT_WRITE_IO 0x000004000
FAULT_SLAB_ALLOC 0x000008000 FAULT_SLAB_ALLOC 0x000008000
FAULT_DQUOT_INIT 0x000010000
=================== =========== =================== ===========
mode=%s Control block allocation mode which supports "adaptive" mode=%s Control block allocation mode which supports "adaptive"
and "lfs". In "lfs" mode, there should be no random and "lfs". In "lfs" mode, there should be no random
writes towards main area. writes towards main area.
"fragment:segment" and "fragment:block" are newly added here.
These are developer options for experiments to simulate filesystem
fragmentation/after-GC situation itself. The developers use these
modes to understand filesystem fragmentation/after-GC condition well,
and eventually get some insights to handle them better.
In "fragment:segment", f2fs allocates a new segment in ramdom
position. With this, we can simulate the after-GC condition.
In "fragment:block", we can scatter block allocation with
"max_fragment_chunk" and "max_fragment_hole" sysfs nodes.
We added some randomness to both chunk and hole size to make
it close to realistic IO pattern. So, in this mode, f2fs will allocate
1..<max_fragment_chunk> blocks in a chunk and make a hole in the
length of 1..<max_fragment_hole> by turns. With this, the newly
allocated blocks will be scattered throughout the whole partition.
Note that "fragment:block" implicitly enables "fragment:segment"
option for more randomness.
Please, use these options for your experiments and we strongly
recommend to re-format the filesystem after using these options.
io_bits=%u Set the bit size of write IO requests. It should be set io_bits=%u Set the bit size of write IO requests. It should be set
with "mode=lfs". with "mode=lfs".
usrquota Enable plain user disk quota accounting. usrquota Enable plain user disk quota accounting.

View File

@ -653,7 +653,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
return PTR_ERR(inode); return PTR_ERR(inode);
} }
err = dquot_initialize(inode); err = f2fs_dquot_initialize(inode);
if (err) { if (err) {
iput(inode); iput(inode);
goto err_out; goto err_out;
@ -705,9 +705,6 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
} }
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
/* Needed for iput() to work correctly and not trash data */
sbi->sb->s_flags |= SB_ACTIVE;
/* /*
* Turn on quotas which were not enabled for read-only mounts if * Turn on quotas which were not enabled for read-only mounts if
* filesystem has quota feature, so that they are updated correctly. * filesystem has quota feature, so that they are updated correctly.
@ -1162,7 +1159,8 @@ static bool __need_flush_quota(struct f2fs_sb_info *sbi)
if (!is_journalled_quota(sbi)) if (!is_journalled_quota(sbi))
return false; return false;
down_write(&sbi->quota_sem); if (!down_write_trylock(&sbi->quota_sem))
return true;
if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH)) { if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH)) {
ret = false; ret = false;
} else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) { } else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) {

View File

@ -882,6 +882,25 @@ bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index)
return is_page_in_cluster(cc, index); return is_page_in_cluster(cc, index);
} }
bool f2fs_all_cluster_page_loaded(struct compress_ctx *cc, struct pagevec *pvec,
int index, int nr_pages)
{
unsigned long pgidx;
int i;
if (nr_pages - index < cc->cluster_size)
return false;
pgidx = pvec->pages[index]->index;
for (i = 1; i < cc->cluster_size; i++) {
if (pvec->pages[index + i]->index != pgidx + i)
return false;
}
return true;
}
static bool cluster_has_invalid_data(struct compress_ctx *cc) static bool cluster_has_invalid_data(struct compress_ctx *cc)
{ {
loff_t i_size = i_size_read(cc->inode); loff_t i_size = i_size_read(cc->inode);
@ -1531,6 +1550,7 @@ int f2fs_write_multi_pages(struct compress_ctx *cc,
if (cluster_may_compress(cc)) { if (cluster_may_compress(cc)) {
err = f2fs_compress_pages(cc); err = f2fs_compress_pages(cc);
if (err == -EAGAIN) { if (err == -EAGAIN) {
add_compr_block_stat(cc->inode, cc->cluster_size);
goto write; goto write;
} else if (err) { } else if (err) {
f2fs_put_rpages_wbc(cc, wbc, true, 1); f2fs_put_rpages_wbc(cc, wbc, true, 1);

View File

@ -1465,10 +1465,15 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
struct extent_info ei = {0, }; struct extent_info ei = {0, };
block_t blkaddr; block_t blkaddr;
unsigned int start_pgofs; unsigned int start_pgofs;
int bidx = 0;
if (!maxblocks) if (!maxblocks)
return 0; return 0;
map->m_bdev = inode->i_sb->s_bdev;
map->m_multidev_dio =
f2fs_allow_multi_device_dio(F2FS_I_SB(inode), flag);
map->m_len = 0; map->m_len = 0;
map->m_flags = 0; map->m_flags = 0;
@ -1491,6 +1496,21 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
if (flag == F2FS_GET_BLOCK_DIO) if (flag == F2FS_GET_BLOCK_DIO)
f2fs_wait_on_block_writeback_range(inode, f2fs_wait_on_block_writeback_range(inode,
map->m_pblk, map->m_len); map->m_pblk, map->m_len);
if (map->m_multidev_dio) {
block_t blk_addr = map->m_pblk;
bidx = f2fs_target_device_index(sbi, map->m_pblk);
map->m_bdev = FDEV(bidx).bdev;
map->m_pblk -= FDEV(bidx).start_blk;
map->m_len = min(map->m_len,
FDEV(bidx).end_blk + 1 - map->m_pblk);
if (map->m_may_create)
f2fs_update_device_state(sbi, inode->i_ino,
blk_addr, map->m_len);
}
goto out; goto out;
} }
@ -1609,6 +1629,9 @@ next_block:
if (flag == F2FS_GET_BLOCK_PRE_AIO) if (flag == F2FS_GET_BLOCK_PRE_AIO)
goto skip; goto skip;
if (map->m_multidev_dio)
bidx = f2fs_target_device_index(sbi, blkaddr);
if (map->m_len == 0) { if (map->m_len == 0) {
/* preallocated unwritten block should be mapped for fiemap. */ /* preallocated unwritten block should be mapped for fiemap. */
if (blkaddr == NEW_ADDR) if (blkaddr == NEW_ADDR)
@ -1617,10 +1640,15 @@ next_block:
map->m_pblk = blkaddr; map->m_pblk = blkaddr;
map->m_len = 1; map->m_len = 1;
if (map->m_multidev_dio)
map->m_bdev = FDEV(bidx).bdev;
} else if ((map->m_pblk != NEW_ADDR && } else if ((map->m_pblk != NEW_ADDR &&
blkaddr == (map->m_pblk + ofs)) || blkaddr == (map->m_pblk + ofs)) ||
(map->m_pblk == NEW_ADDR && blkaddr == NEW_ADDR) || (map->m_pblk == NEW_ADDR && blkaddr == NEW_ADDR) ||
flag == F2FS_GET_BLOCK_PRE_DIO) { flag == F2FS_GET_BLOCK_PRE_DIO) {
if (map->m_multidev_dio && map->m_bdev != FDEV(bidx).bdev)
goto sync_out;
ofs++; ofs++;
map->m_len++; map->m_len++;
} else { } else {
@ -1673,10 +1701,32 @@ skip:
sync_out: sync_out:
/* for hardware encryption, but to avoid potential issue in future */ if (flag == F2FS_GET_BLOCK_DIO && map->m_flags & F2FS_MAP_MAPPED) {
if (flag == F2FS_GET_BLOCK_DIO && map->m_flags & F2FS_MAP_MAPPED) /*
* for hardware encryption, but to avoid potential issue
* in future
*/
f2fs_wait_on_block_writeback_range(inode, f2fs_wait_on_block_writeback_range(inode,
map->m_pblk, map->m_len); map->m_pblk, map->m_len);
invalidate_mapping_pages(META_MAPPING(sbi),
map->m_pblk, map->m_pblk);
if (map->m_multidev_dio) {
block_t blk_addr = map->m_pblk;
bidx = f2fs_target_device_index(sbi, map->m_pblk);
map->m_bdev = FDEV(bidx).bdev;
map->m_pblk -= FDEV(bidx).start_blk;
if (map->m_may_create)
f2fs_update_device_state(sbi, inode->i_ino,
blk_addr, map->m_len);
f2fs_bug_on(sbi, blk_addr + map->m_len >
FDEV(bidx).end_blk + 1);
}
}
if (flag == F2FS_GET_BLOCK_PRECACHE) { if (flag == F2FS_GET_BLOCK_PRECACHE) {
if (map->m_flags & F2FS_MAP_MAPPED) { if (map->m_flags & F2FS_MAP_MAPPED) {
@ -1696,7 +1746,7 @@ unlock_out:
f2fs_balance_fs(sbi, dn.node_changed); f2fs_balance_fs(sbi, dn.node_changed);
} }
out: out:
trace_f2fs_map_blocks(inode, map, err); trace_f2fs_map_blocks(inode, map, create, flag, err);
return err; return err;
} }
@ -1755,6 +1805,9 @@ static int __get_data_block(struct inode *inode, sector_t iblock,
map_bh(bh, inode->i_sb, map.m_pblk); map_bh(bh, inode->i_sb, map.m_pblk);
bh->b_state = (bh->b_state & ~F2FS_MAP_FLAGS) | map.m_flags; bh->b_state = (bh->b_state & ~F2FS_MAP_FLAGS) | map.m_flags;
bh->b_size = blks_to_bytes(inode, map.m_len); bh->b_size = blks_to_bytes(inode, map.m_len);
if (map.m_multidev_dio)
bh->b_bdev = map.m_bdev;
} }
return err; return err;
} }
@ -2989,6 +3042,10 @@ readd:
need_readd = false; need_readd = false;
#ifdef CONFIG_F2FS_FS_COMPRESSION #ifdef CONFIG_F2FS_FS_COMPRESSION
if (f2fs_compressed_file(inode)) { if (f2fs_compressed_file(inode)) {
void *fsdata = NULL;
struct page *pagep;
int ret2;
ret = f2fs_init_compress_ctx(&cc); ret = f2fs_init_compress_ctx(&cc);
if (ret) { if (ret) {
done = 1; done = 1;
@ -3007,27 +3064,23 @@ readd:
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
goto lock_page; goto lock_page;
if (f2fs_cluster_is_empty(&cc)) { if (!f2fs_cluster_is_empty(&cc))
void *fsdata = NULL; goto lock_page;
struct page *pagep;
int ret2;
ret2 = f2fs_prepare_compress_overwrite( ret2 = f2fs_prepare_compress_overwrite(
inode, &pagep, inode, &pagep,
page->index, &fsdata); page->index, &fsdata);
if (ret2 < 0) { if (ret2 < 0) {
ret = ret2; ret = ret2;
done = 1; done = 1;
break; break;
} else if (ret2 && } else if (ret2 &&
!f2fs_compress_write_end(inode, (!f2fs_compress_write_end(inode,
fsdata, page->index, fsdata, page->index, 1) ||
1)) { !f2fs_all_cluster_page_loaded(&cc,
retry = 1; &pvec, i, nr_pages))) {
break; retry = 1;
} break;
} else {
goto lock_page;
} }
} }
#endif #endif

View File

@ -55,6 +55,7 @@ enum {
FAULT_DISCARD, FAULT_DISCARD,
FAULT_WRITE_IO, FAULT_WRITE_IO,
FAULT_SLAB_ALLOC, FAULT_SLAB_ALLOC,
FAULT_DQUOT_INIT,
FAULT_MAX, FAULT_MAX,
}; };
@ -561,6 +562,9 @@ enum {
#define MAX_DIR_RA_PAGES 4 /* maximum ra pages of dir */ #define MAX_DIR_RA_PAGES 4 /* maximum ra pages of dir */
/* dirty segments threshold for triggering CP */
#define DEFAULT_DIRTY_THRESHOLD 4
/* for in-memory extent cache entry */ /* for in-memory extent cache entry */
#define F2FS_MIN_EXTENT_LEN 64 /* minimum extent length */ #define F2FS_MIN_EXTENT_LEN 64 /* minimum extent length */
@ -617,6 +621,7 @@ struct extent_tree {
F2FS_MAP_UNWRITTEN) F2FS_MAP_UNWRITTEN)
struct f2fs_map_blocks { struct f2fs_map_blocks {
struct block_device *m_bdev; /* for multi-device dio */
block_t m_pblk; block_t m_pblk;
block_t m_lblk; block_t m_lblk;
unsigned int m_len; unsigned int m_len;
@ -625,6 +630,7 @@ struct f2fs_map_blocks {
pgoff_t *m_next_extent; /* point to next possible extent */ pgoff_t *m_next_extent; /* point to next possible extent */
int m_seg_type; int m_seg_type;
bool m_may_create; /* indicate it is from write path */ bool m_may_create; /* indicate it is from write path */
bool m_multidev_dio; /* indicate it allows multi-device dio */
}; };
/* for flag in get_data_block */ /* for flag in get_data_block */
@ -1284,8 +1290,10 @@ enum {
}; };
enum { enum {
FS_MODE_ADAPTIVE, /* use both lfs/ssr allocation */ FS_MODE_ADAPTIVE, /* use both lfs/ssr allocation */
FS_MODE_LFS, /* use lfs allocation only */ FS_MODE_LFS, /* use lfs allocation only */
FS_MODE_FRAGMENT_SEG, /* segment fragmentation mode */
FS_MODE_FRAGMENT_BLK, /* block fragmentation mode */
}; };
enum { enum {
@ -1728,12 +1736,15 @@ struct f2fs_sb_info {
/* For shrinker support */ /* For shrinker support */
struct list_head s_list; struct list_head s_list;
struct mutex umount_mutex;
unsigned int shrinker_run_no;
/* For multi devices */
int s_ndevs; /* number of devices */ int s_ndevs; /* number of devices */
struct f2fs_dev_info *devs; /* for device list */ struct f2fs_dev_info *devs; /* for device list */
unsigned int dirty_device; /* for checkpoint data flush */ unsigned int dirty_device; /* for checkpoint data flush */
spinlock_t dev_lock; /* protect dirty_device */ spinlock_t dev_lock; /* protect dirty_device */
struct mutex umount_mutex; bool aligned_blksize; /* all devices has the same logical blksize */
unsigned int shrinker_run_no;
/* For write statistics */ /* For write statistics */
u64 sectors_written_start; u64 sectors_written_start;
@ -1756,6 +1767,9 @@ struct f2fs_sb_info {
unsigned long seq_file_ra_mul; /* multiplier for ra_pages of seq. files in fadvise */ unsigned long seq_file_ra_mul; /* multiplier for ra_pages of seq. files in fadvise */
int max_fragment_chunk; /* max chunk size for block fragmentation mode */
int max_fragment_hole; /* max hole size for block fragmentation mode */
#ifdef CONFIG_F2FS_FS_COMPRESSION #ifdef CONFIG_F2FS_FS_COMPRESSION
struct kmem_cache *page_array_slab; /* page array entry */ struct kmem_cache *page_array_slab; /* page array entry */
unsigned int page_array_slab_size; /* default page array slab size */ unsigned int page_array_slab_size; /* default page array slab size */
@ -3363,6 +3377,7 @@ static inline int f2fs_add_link(struct dentry *dentry, struct inode *inode)
*/ */
int f2fs_inode_dirtied(struct inode *inode, bool sync); int f2fs_inode_dirtied(struct inode *inode, bool sync);
void f2fs_inode_synced(struct inode *inode); void f2fs_inode_synced(struct inode *inode);
int f2fs_dquot_initialize(struct inode *inode);
int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly); int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly);
int f2fs_quota_sync(struct super_block *sb, int type); int f2fs_quota_sync(struct super_block *sb, int type);
loff_t max_file_blocks(struct inode *inode); loff_t max_file_blocks(struct inode *inode);
@ -3492,6 +3507,8 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
block_t old_blkaddr, block_t *new_blkaddr, block_t old_blkaddr, block_t *new_blkaddr,
struct f2fs_summary *sum, int type, struct f2fs_summary *sum, int type,
struct f2fs_io_info *fio); struct f2fs_io_info *fio);
void f2fs_update_device_state(struct f2fs_sb_info *sbi, nid_t ino,
block_t blkaddr, unsigned int blkcnt);
void f2fs_wait_on_page_writeback(struct page *page, void f2fs_wait_on_page_writeback(struct page *page,
enum page_type type, bool ordered, bool locked); enum page_type type, bool ordered, bool locked);
void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr); void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr);
@ -3516,6 +3533,16 @@ unsigned int f2fs_usable_segs_in_sec(struct f2fs_sb_info *sbi,
unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi, unsigned int f2fs_usable_blks_in_seg(struct f2fs_sb_info *sbi,
unsigned int segno); unsigned int segno);
#define DEF_FRAGMENT_SIZE 4
#define MIN_FRAGMENT_SIZE 1
#define MAX_FRAGMENT_SIZE 512
static inline bool f2fs_need_rand_seg(struct f2fs_sb_info *sbi)
{
return F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_SEG ||
F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK;
}
/* /*
* checkpoint.c * checkpoint.c
*/ */
@ -4027,6 +4054,8 @@ void f2fs_end_read_compressed_page(struct page *page, bool failed,
block_t blkaddr); block_t blkaddr);
bool f2fs_cluster_is_empty(struct compress_ctx *cc); bool f2fs_cluster_is_empty(struct compress_ctx *cc);
bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index); bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index);
bool f2fs_all_cluster_page_loaded(struct compress_ctx *cc, struct pagevec *pvec,
int index, int nr_pages);
bool f2fs_sanity_check_cluster(struct dnode_of_data *dn); bool f2fs_sanity_check_cluster(struct dnode_of_data *dn);
void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page); void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page);
int f2fs_write_multi_pages(struct compress_ctx *cc, int f2fs_write_multi_pages(struct compress_ctx *cc,
@ -4152,8 +4181,7 @@ static inline bool f2fs_disable_compressed_file(struct inode *inode)
if (!f2fs_compressed_file(inode)) if (!f2fs_compressed_file(inode))
return true; return true;
if (S_ISREG(inode->i_mode) && if (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode))
(get_dirty_pages(inode) || atomic_read(&fi->i_compr_blocks)))
return false; return false;
fi->i_flags &= ~F2FS_COMPR_FL; fi->i_flags &= ~F2FS_COMPR_FL;
@ -4302,6 +4330,16 @@ static inline int block_unaligned_IO(struct inode *inode,
return align & blocksize_mask; return align & blocksize_mask;
} }
static inline bool f2fs_allow_multi_device_dio(struct f2fs_sb_info *sbi,
int flag)
{
if (!f2fs_is_multi_device(sbi))
return false;
if (flag != F2FS_GET_BLOCK_DIO)
return false;
return sbi->aligned_blksize;
}
static inline bool f2fs_force_buffered_io(struct inode *inode, static inline bool f2fs_force_buffered_io(struct inode *inode,
struct kiocb *iocb, struct iov_iter *iter) struct kiocb *iocb, struct iov_iter *iter)
{ {
@ -4310,7 +4348,9 @@ static inline bool f2fs_force_buffered_io(struct inode *inode,
if (f2fs_post_read_required(inode)) if (f2fs_post_read_required(inode))
return true; return true;
if (f2fs_is_multi_device(sbi))
/* disallow direct IO if any of devices has unaligned blksize */
if (f2fs_is_multi_device(sbi) && !sbi->aligned_blksize)
return true; return true;
/* /*
* for blkzoned device, fallback direct IO to buffered IO, so * for blkzoned device, fallback direct IO to buffered IO, so

View File

@ -786,7 +786,7 @@ int f2fs_truncate(struct inode *inode)
return -EIO; return -EIO;
} }
err = dquot_initialize(inode); err = f2fs_dquot_initialize(inode);
if (err) if (err)
return err; return err;
@ -916,7 +916,7 @@ int f2fs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
return err; return err;
if (is_quota_modification(inode, attr)) { if (is_quota_modification(inode, attr)) {
err = dquot_initialize(inode); err = f2fs_dquot_initialize(inode);
if (err) if (err)
return err; return err;
} }
@ -3020,7 +3020,7 @@ static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
} }
f2fs_put_page(ipage, 1); f2fs_put_page(ipage, 1);
err = dquot_initialize(inode); err = f2fs_dquot_initialize(inode);
if (err) if (err)
return err; return err;

View File

@ -14,6 +14,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <linux/random.h>
#include "f2fs.h" #include "f2fs.h"
#include "node.h" #include "node.h"
@ -257,7 +258,9 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
p->max_search = sbi->max_victim_search; p->max_search = sbi->max_victim_search;
/* let's select beginning hot/small space first in no_heap mode*/ /* let's select beginning hot/small space first in no_heap mode*/
if (test_opt(sbi, NOHEAP) && if (f2fs_need_rand_seg(sbi))
p->offset = prandom_u32() % (MAIN_SECS(sbi) * sbi->segs_per_sec);
else if (test_opt(sbi, NOHEAP) &&
(type == CURSEG_HOT_DATA || IS_NODESEG(type))) (type == CURSEG_HOT_DATA || IS_NODESEG(type)))
p->offset = 0; p->offset = 0;
else else

View File

@ -192,7 +192,7 @@ int f2fs_convert_inline_inode(struct inode *inode)
f2fs_hw_is_readonly(sbi) || f2fs_readonly(sbi->sb)) f2fs_hw_is_readonly(sbi) || f2fs_readonly(sbi->sb))
return 0; return 0;
err = dquot_initialize(inode); err = f2fs_dquot_initialize(inode);
if (err) if (err)
return err; return err;

View File

@ -527,7 +527,7 @@ make_now:
inode->i_op = &f2fs_dir_inode_operations; inode->i_op = &f2fs_dir_inode_operations;
inode->i_fop = &f2fs_dir_operations; inode->i_fop = &f2fs_dir_operations;
inode->i_mapping->a_ops = &f2fs_dblock_aops; inode->i_mapping->a_ops = &f2fs_dblock_aops;
inode_nohighmem(inode); mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
} else if (S_ISLNK(inode->i_mode)) { } else if (S_ISLNK(inode->i_mode)) {
if (file_is_encrypt(inode)) if (file_is_encrypt(inode))
inode->i_op = &f2fs_encrypted_symlink_inode_operations; inode->i_op = &f2fs_encrypted_symlink_inode_operations;
@ -754,7 +754,7 @@ void f2fs_evict_inode(struct inode *inode)
if (inode->i_nlink || is_bad_inode(inode)) if (inode->i_nlink || is_bad_inode(inode))
goto no_delete; goto no_delete;
err = dquot_initialize(inode); err = f2fs_dquot_initialize(inode);
if (err) { if (err) {
err = 0; err = 0;
set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);

View File

@ -74,7 +74,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
if (err) if (err)
goto fail_drop; goto fail_drop;
err = dquot_initialize(inode); err = f2fs_dquot_initialize(inode);
if (err) if (err)
goto fail_drop; goto fail_drop;
@ -345,7 +345,7 @@ static int f2fs_create(struct user_namespace *mnt_userns, struct inode *dir,
if (!f2fs_is_checkpoint_ready(sbi)) if (!f2fs_is_checkpoint_ready(sbi))
return -ENOSPC; return -ENOSPC;
err = dquot_initialize(dir); err = f2fs_dquot_initialize(dir);
if (err) if (err)
return err; return err;
@ -404,7 +404,7 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
F2FS_I(old_dentry->d_inode)->i_projid))) F2FS_I(old_dentry->d_inode)->i_projid)))
return -EXDEV; return -EXDEV;
err = dquot_initialize(dir); err = f2fs_dquot_initialize(dir);
if (err) if (err)
return err; return err;
@ -460,7 +460,7 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)
return 0; return 0;
} }
err = dquot_initialize(dir); err = f2fs_dquot_initialize(dir);
if (err) if (err)
return err; return err;
@ -598,10 +598,10 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
goto fail; goto fail;
} }
err = dquot_initialize(dir); err = f2fs_dquot_initialize(dir);
if (err) if (err)
goto fail; goto fail;
err = dquot_initialize(inode); err = f2fs_dquot_initialize(inode);
if (err) if (err)
goto fail; goto fail;
@ -675,7 +675,7 @@ static int f2fs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
if (err) if (err)
return err; return err;
err = dquot_initialize(dir); err = f2fs_dquot_initialize(dir);
if (err) if (err)
return err; return err;
@ -746,7 +746,7 @@ static int f2fs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return -EIO; return -EIO;
err = dquot_initialize(dir); err = f2fs_dquot_initialize(dir);
if (err) if (err)
return err; return err;
@ -757,7 +757,7 @@ static int f2fs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
inode->i_op = &f2fs_dir_inode_operations; inode->i_op = &f2fs_dir_inode_operations;
inode->i_fop = &f2fs_dir_operations; inode->i_fop = &f2fs_dir_operations;
inode->i_mapping->a_ops = &f2fs_dblock_aops; inode->i_mapping->a_ops = &f2fs_dblock_aops;
inode_nohighmem(inode); mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
set_inode_flag(inode, FI_INC_LINK); set_inode_flag(inode, FI_INC_LINK);
f2fs_lock_op(sbi); f2fs_lock_op(sbi);
@ -803,7 +803,7 @@ static int f2fs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
if (!f2fs_is_checkpoint_ready(sbi)) if (!f2fs_is_checkpoint_ready(sbi))
return -ENOSPC; return -ENOSPC;
err = dquot_initialize(dir); err = f2fs_dquot_initialize(dir);
if (err) if (err)
return err; return err;
@ -841,7 +841,7 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
struct inode *inode; struct inode *inode;
int err; int err;
err = dquot_initialize(dir); err = f2fs_dquot_initialize(dir);
if (err) if (err)
return err; return err;
@ -965,16 +965,16 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
return err; return err;
} }
err = dquot_initialize(old_dir); err = f2fs_dquot_initialize(old_dir);
if (err) if (err)
goto out; goto out;
err = dquot_initialize(new_dir); err = f2fs_dquot_initialize(new_dir);
if (err) if (err)
goto out; goto out;
if (new_inode) { if (new_inode) {
err = dquot_initialize(new_inode); err = f2fs_dquot_initialize(new_inode);
if (err) if (err)
goto out; goto out;
} }
@ -1138,11 +1138,11 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
F2FS_I(new_dentry->d_inode)->i_projid))) F2FS_I(new_dentry->d_inode)->i_projid)))
return -EXDEV; return -EXDEV;
err = dquot_initialize(old_dir); err = f2fs_dquot_initialize(old_dir);
if (err) if (err)
goto out; goto out;
err = dquot_initialize(new_dir); err = f2fs_dquot_initialize(new_dir);
if (err) if (err)
goto out; goto out;

View File

@ -1443,6 +1443,7 @@ page_hit:
nid, nid_of_node(page), ino_of_node(page), nid, nid_of_node(page), ino_of_node(page),
ofs_of_node(page), cpver_of_node(page), ofs_of_node(page), cpver_of_node(page),
next_blkaddr_of_node(page)); next_blkaddr_of_node(page));
set_sbi_flag(sbi, SBI_NEED_FSCK);
err = -EINVAL; err = -EINVAL;
out_err: out_err:
ClearPageUptodate(page); ClearPageUptodate(page);

View File

@ -138,11 +138,6 @@ static inline bool excess_cached_nats(struct f2fs_sb_info *sbi)
return NM_I(sbi)->nat_cnt[TOTAL_NAT] >= DEF_NAT_CACHE_THRESHOLD; return NM_I(sbi)->nat_cnt[TOTAL_NAT] >= DEF_NAT_CACHE_THRESHOLD;
} }
static inline bool excess_dirty_nodes(struct f2fs_sb_info *sbi)
{
return get_pages(sbi, F2FS_DIRTY_NODES) >= sbi->blocks_per_seg * 8;
}
enum mem_type { enum mem_type {
FREE_NIDS, /* indicates the free nid list */ FREE_NIDS, /* indicates the free nid list */
NAT_ENTRIES, /* indicates the cached nat entry */ NAT_ENTRIES, /* indicates the cached nat entry */

View File

@ -81,7 +81,7 @@ static struct fsync_inode_entry *add_fsync_inode(struct f2fs_sb_info *sbi,
if (IS_ERR(inode)) if (IS_ERR(inode))
return ERR_CAST(inode); return ERR_CAST(inode);
err = dquot_initialize(inode); err = f2fs_dquot_initialize(inode);
if (err) if (err)
goto err_out; goto err_out;
@ -203,7 +203,7 @@ retry:
goto out_put; goto out_put;
} }
err = dquot_initialize(einode); err = f2fs_dquot_initialize(einode);
if (err) { if (err) {
iput(einode); iput(einode);
goto out_put; goto out_put;
@ -508,7 +508,7 @@ got_it:
if (IS_ERR(inode)) if (IS_ERR(inode))
return PTR_ERR(inode); return PTR_ERR(inode);
ret = dquot_initialize(inode); ret = f2fs_dquot_initialize(inode);
if (ret) { if (ret) {
iput(inode); iput(inode);
return ret; return ret;
@ -787,8 +787,6 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
} }
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
/* Needed for iput() to work correctly and not trash data */
sbi->sb->s_flags |= SB_ACTIVE;
/* Turn on quotas so that they are updated correctly */ /* Turn on quotas so that they are updated correctly */
quota_enabled = f2fs_enable_quota_files(sbi, s_flags & SB_RDONLY); quota_enabled = f2fs_enable_quota_files(sbi, s_flags & SB_RDONLY);
#endif #endif
@ -816,10 +814,8 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
err = recover_data(sbi, &inode_list, &tmp_inode_list, &dir_list); err = recover_data(sbi, &inode_list, &tmp_inode_list, &dir_list);
if (!err) if (!err)
f2fs_bug_on(sbi, !list_empty(&inode_list)); f2fs_bug_on(sbi, !list_empty(&inode_list));
else { else
/* restore s_flags to let iput() trash data */ f2fs_bug_on(sbi, sbi->sb->s_flags & SB_ACTIVE);
sbi->sb->s_flags = s_flags;
}
skip: skip:
fix_curseg_write_pointer = !check_only || list_empty(&inode_list); fix_curseg_write_pointer = !check_only || list_empty(&inode_list);

View File

@ -15,6 +15,7 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <linux/random.h>
#include "f2fs.h" #include "f2fs.h"
#include "segment.h" #include "segment.h"
@ -529,6 +530,25 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
} }
} }
static inline bool excess_dirty_threshold(struct f2fs_sb_info *sbi)
{
int factor = rwsem_is_locked(&sbi->cp_rwsem) ? 3 : 2;
unsigned int dents = get_pages(sbi, F2FS_DIRTY_DENTS);
unsigned int qdata = get_pages(sbi, F2FS_DIRTY_QDATA);
unsigned int nodes = get_pages(sbi, F2FS_DIRTY_NODES);
unsigned int meta = get_pages(sbi, F2FS_DIRTY_META);
unsigned int imeta = get_pages(sbi, F2FS_DIRTY_IMETA);
unsigned int threshold = sbi->blocks_per_seg * factor *
DEFAULT_DIRTY_THRESHOLD;
unsigned int global_threshold = threshold * 3 / 2;
if (dents >= threshold || qdata >= threshold ||
nodes >= threshold || meta >= threshold ||
imeta >= threshold)
return true;
return dents + qdata + nodes + meta + imeta > global_threshold;
}
void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg) void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
{ {
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
@ -547,8 +567,8 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
else else
f2fs_build_free_nids(sbi, false, false); f2fs_build_free_nids(sbi, false, false);
if (excess_dirty_nats(sbi) || excess_dirty_nodes(sbi) || if (excess_dirty_nats(sbi) || excess_dirty_threshold(sbi) ||
excess_prefree_segs(sbi)) excess_prefree_segs(sbi) || !f2fs_space_for_roll_forward(sbi))
goto do_sync; goto do_sync;
/* there is background inflight IO or foreground operation recently */ /* there is background inflight IO or foreground operation recently */
@ -561,7 +581,7 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
goto do_sync; goto do_sync;
/* checkpoint is the only way to shrink partial cached entries */ /* checkpoint is the only way to shrink partial cached entries */
if (f2fs_available_free_memory(sbi, NAT_ENTRIES) || if (f2fs_available_free_memory(sbi, NAT_ENTRIES) &&
f2fs_available_free_memory(sbi, INO_ENTRIES)) f2fs_available_free_memory(sbi, INO_ENTRIES))
return; return;
@ -2630,6 +2650,8 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type)
unsigned short seg_type = curseg->seg_type; unsigned short seg_type = curseg->seg_type;
sanity_check_seg_type(sbi, seg_type); sanity_check_seg_type(sbi, seg_type);
if (f2fs_need_rand_seg(sbi))
return prandom_u32() % (MAIN_SECS(sbi) * sbi->segs_per_sec);
/* if segs_per_sec is large than 1, we need to keep original policy. */ /* if segs_per_sec is large than 1, we need to keep original policy. */
if (__is_large_section(sbi)) if (__is_large_section(sbi))
@ -2681,6 +2703,9 @@ static void new_curseg(struct f2fs_sb_info *sbi, int type, bool new_sec)
curseg->next_segno = segno; curseg->next_segno = segno;
reset_curseg(sbi, type, 1); reset_curseg(sbi, type, 1);
curseg->alloc_type = LFS; curseg->alloc_type = LFS;
if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK)
curseg->fragment_remained_chunk =
prandom_u32() % sbi->max_fragment_chunk + 1;
} }
static int __next_free_blkoff(struct f2fs_sb_info *sbi, static int __next_free_blkoff(struct f2fs_sb_info *sbi,
@ -2707,12 +2732,22 @@ static int __next_free_blkoff(struct f2fs_sb_info *sbi,
static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
struct curseg_info *seg) struct curseg_info *seg)
{ {
if (seg->alloc_type == SSR) if (seg->alloc_type == SSR) {
seg->next_blkoff = seg->next_blkoff =
__next_free_blkoff(sbi, seg->segno, __next_free_blkoff(sbi, seg->segno,
seg->next_blkoff + 1); seg->next_blkoff + 1);
else } else {
seg->next_blkoff++; seg->next_blkoff++;
if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) {
/* To allocate block chunks in different sizes, use random number */
if (--seg->fragment_remained_chunk <= 0) {
seg->fragment_remained_chunk =
prandom_u32() % sbi->max_fragment_chunk + 1;
seg->next_blkoff +=
prandom_u32() % sbi->max_fragment_hole + 1;
}
}
}
} }
bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
@ -3485,24 +3520,30 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
up_read(&SM_I(sbi)->curseg_lock); up_read(&SM_I(sbi)->curseg_lock);
} }
static void update_device_state(struct f2fs_io_info *fio) void f2fs_update_device_state(struct f2fs_sb_info *sbi, nid_t ino,
block_t blkaddr, unsigned int blkcnt)
{ {
struct f2fs_sb_info *sbi = fio->sbi;
unsigned int devidx;
if (!f2fs_is_multi_device(sbi)) if (!f2fs_is_multi_device(sbi))
return; return;
devidx = f2fs_target_device_index(sbi, fio->new_blkaddr); while (1) {
unsigned int devidx = f2fs_target_device_index(sbi, blkaddr);
unsigned int blks = FDEV(devidx).end_blk - blkaddr + 1;
/* update device state for fsync */ /* update device state for fsync */
f2fs_set_dirty_device(sbi, fio->ino, devidx, FLUSH_INO); f2fs_set_dirty_device(sbi, ino, devidx, FLUSH_INO);
/* update device state for checkpoint */ /* update device state for checkpoint */
if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) { if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) {
spin_lock(&sbi->dev_lock); spin_lock(&sbi->dev_lock);
f2fs_set_bit(devidx, (char *)&sbi->dirty_device); f2fs_set_bit(devidx, (char *)&sbi->dirty_device);
spin_unlock(&sbi->dev_lock); spin_unlock(&sbi->dev_lock);
}
if (blkcnt <= blks)
break;
blkcnt -= blks;
blkaddr += blks;
} }
} }
@ -3529,7 +3570,7 @@ reallocate:
goto reallocate; goto reallocate;
} }
update_device_state(fio); f2fs_update_device_state(fio->sbi, fio->ino, fio->new_blkaddr, 1);
if (keep_order) if (keep_order)
up_read(&fio->sbi->io_order_lock); up_read(&fio->sbi->io_order_lock);
@ -3611,6 +3652,9 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
goto drop_bio; goto drop_bio;
} }
invalidate_mapping_pages(META_MAPPING(sbi),
fio->new_blkaddr, fio->new_blkaddr);
stat_inc_inplace_blocks(fio->sbi); stat_inc_inplace_blocks(fio->sbi);
if (fio->bio && !(SM_I(sbi)->ipu_policy & (1 << F2FS_IPU_NOCACHE))) if (fio->bio && !(SM_I(sbi)->ipu_policy & (1 << F2FS_IPU_NOCACHE)))
@ -3618,7 +3662,8 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
else else
err = f2fs_submit_page_bio(fio); err = f2fs_submit_page_bio(fio);
if (!err) { if (!err) {
update_device_state(fio); f2fs_update_device_state(fio->sbi, fio->ino,
fio->new_blkaddr, 1);
f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE); f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE);
} }

View File

@ -314,6 +314,7 @@ struct curseg_info {
unsigned short next_blkoff; /* next block offset to write */ unsigned short next_blkoff; /* next block offset to write */
unsigned int zone; /* current zone number */ unsigned int zone; /* current zone number */
unsigned int next_segno; /* preallocated segment */ unsigned int next_segno; /* preallocated segment */
int fragment_remained_chunk; /* remained block size in a chunk for block fragmentation mode */
bool inited; /* indicate inmem log is inited */ bool inited; /* indicate inmem log is inited */
}; };

View File

@ -58,6 +58,7 @@ const char *f2fs_fault_name[FAULT_MAX] = {
[FAULT_DISCARD] = "discard error", [FAULT_DISCARD] = "discard error",
[FAULT_WRITE_IO] = "write IO error", [FAULT_WRITE_IO] = "write IO error",
[FAULT_SLAB_ALLOC] = "slab alloc", [FAULT_SLAB_ALLOC] = "slab alloc",
[FAULT_DQUOT_INIT] = "dquot initialize",
}; };
void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate, void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate,
@ -817,6 +818,10 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE; F2FS_OPTION(sbi).fs_mode = FS_MODE_ADAPTIVE;
} else if (!strcmp(name, "lfs")) { } else if (!strcmp(name, "lfs")) {
F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS; F2FS_OPTION(sbi).fs_mode = FS_MODE_LFS;
} else if (!strcmp(name, "fragment:segment")) {
F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_SEG;
} else if (!strcmp(name, "fragment:block")) {
F2FS_OPTION(sbi).fs_mode = FS_MODE_FRAGMENT_BLK;
} else { } else {
kfree(name); kfree(name);
return -EINVAL; return -EINVAL;
@ -1292,7 +1297,7 @@ default_check:
/* Not pass down write hints if the number of active logs is lesser /* Not pass down write hints if the number of active logs is lesser
* than NR_CURSEG_PERSIST_TYPE. * than NR_CURSEG_PERSIST_TYPE.
*/ */
if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_TYPE) if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_PERSIST_TYPE)
F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF; F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) { if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) {
@ -1896,6 +1901,10 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, "adaptive"); seq_puts(seq, "adaptive");
else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS) else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_LFS)
seq_puts(seq, "lfs"); seq_puts(seq, "lfs");
else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_SEG)
seq_puts(seq, "fragment:segment");
else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK)
seq_puts(seq, "fragment:block");
seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs); seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs);
if (test_opt(sbi, RESERVE_ROOT)) if (test_opt(sbi, RESERVE_ROOT))
seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u", seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u",
@ -2491,6 +2500,16 @@ retry:
return len - towrite; return len - towrite;
} }
int f2fs_dquot_initialize(struct inode *inode)
{
if (time_to_inject(F2FS_I_SB(inode), FAULT_DQUOT_INIT)) {
f2fs_show_injection_info(F2FS_I_SB(inode), FAULT_DQUOT_INIT);
return -ESRCH;
}
return dquot_initialize(inode);
}
static struct dquot **f2fs_get_dquots(struct inode *inode) static struct dquot **f2fs_get_dquots(struct inode *inode)
{ {
return F2FS_I(inode)->i_dquot; return F2FS_I(inode)->i_dquot;
@ -2875,6 +2894,11 @@ static const struct quotactl_ops f2fs_quotactl_ops = {
.get_nextdqblk = dquot_get_next_dqblk, .get_nextdqblk = dquot_get_next_dqblk,
}; };
#else #else
int f2fs_dquot_initialize(struct inode *inode)
{
return 0;
}
int f2fs_quota_sync(struct super_block *sb, int type) int f2fs_quota_sync(struct super_block *sb, int type)
{ {
return 0; return 0;
@ -3486,7 +3510,7 @@ skip_cross:
NR_CURSEG_PERSIST_TYPE + nat_bits_blocks >= blocks_per_seg)) { NR_CURSEG_PERSIST_TYPE + nat_bits_blocks >= blocks_per_seg)) {
f2fs_warn(sbi, "Insane cp_payload: %u, nat_bits_blocks: %u)", f2fs_warn(sbi, "Insane cp_payload: %u, nat_bits_blocks: %u)",
cp_payload, nat_bits_blocks); cp_payload, nat_bits_blocks);
return -EFSCORRUPTED; return 1;
} }
if (unlikely(f2fs_cp_error(sbi))) { if (unlikely(f2fs_cp_error(sbi))) {
@ -3522,6 +3546,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH; sbi->max_victim_search = DEF_MAX_VICTIM_SEARCH;
sbi->migration_granularity = sbi->segs_per_sec; sbi->migration_granularity = sbi->segs_per_sec;
sbi->seq_file_ra_mul = MIN_RA_MUL; sbi->seq_file_ra_mul = MIN_RA_MUL;
sbi->max_fragment_chunk = DEF_FRAGMENT_SIZE;
sbi->max_fragment_hole = DEF_FRAGMENT_SIZE;
sbi->dir_level = DEF_DIR_LEVEL; sbi->dir_level = DEF_DIR_LEVEL;
sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL; sbi->interval_time[CP_TIME] = DEF_CP_INTERVAL;
@ -3746,6 +3772,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
{ {
struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi); struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
unsigned int max_devices = MAX_DEVICES; unsigned int max_devices = MAX_DEVICES;
unsigned int logical_blksize;
int i; int i;
/* Initialize single device information */ /* Initialize single device information */
@ -3766,6 +3793,9 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
if (!sbi->devs) if (!sbi->devs)
return -ENOMEM; return -ENOMEM;
logical_blksize = bdev_logical_block_size(sbi->sb->s_bdev);
sbi->aligned_blksize = true;
for (i = 0; i < max_devices; i++) { for (i = 0; i < max_devices; i++) {
if (i > 0 && !RDEV(i).path[0]) if (i > 0 && !RDEV(i).path[0])
@ -3802,6 +3832,9 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
/* to release errored devices */ /* to release errored devices */
sbi->s_ndevs = i + 1; sbi->s_ndevs = i + 1;
if (logical_blksize != bdev_logical_block_size(FDEV(i).bdev))
sbi->aligned_blksize = false;
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM && if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM &&
!f2fs_sb_has_blkzoned(sbi)) { !f2fs_sb_has_blkzoned(sbi)) {
@ -4351,6 +4384,8 @@ free_node_inode:
free_stats: free_stats:
f2fs_destroy_stats(sbi); f2fs_destroy_stats(sbi);
free_nm: free_nm:
/* stop discard thread before destroying node manager */
f2fs_stop_discard_thread(sbi);
f2fs_destroy_node_manager(sbi); f2fs_destroy_node_manager(sbi);
free_sm: free_sm:
f2fs_destroy_segment_manager(sbi); f2fs_destroy_segment_manager(sbi);

View File

@ -196,7 +196,7 @@ static ssize_t encoding_show(struct f2fs_attr *a,
struct super_block *sb = sbi->sb; struct super_block *sb = sbi->sb;
if (f2fs_sb_has_casefold(sbi)) if (f2fs_sb_has_casefold(sbi))
return snprintf(buf, PAGE_SIZE, "%s (%d.%d.%d)\n", return sysfs_emit(buf, "%s (%d.%d.%d)\n",
sb->s_encoding->charset, sb->s_encoding->charset,
(sb->s_encoding->version >> 16) & 0xff, (sb->s_encoding->version >> 16) & 0xff,
(sb->s_encoding->version >> 8) & 0xff, (sb->s_encoding->version >> 8) & 0xff,
@ -245,7 +245,7 @@ static ssize_t avg_vblocks_show(struct f2fs_attr *a,
static ssize_t main_blkaddr_show(struct f2fs_attr *a, static ssize_t main_blkaddr_show(struct f2fs_attr *a,
struct f2fs_sb_info *sbi, char *buf) struct f2fs_sb_info *sbi, char *buf)
{ {
return snprintf(buf, PAGE_SIZE, "%llu\n", return sysfs_emit(buf, "%llu\n",
(unsigned long long)MAIN_BLKADDR(sbi)); (unsigned long long)MAIN_BLKADDR(sbi));
} }
@ -551,6 +551,22 @@ out:
return count; return count;
} }
if (!strcmp(a->attr.name, "max_fragment_chunk")) {
if (t >= MIN_FRAGMENT_SIZE && t <= MAX_FRAGMENT_SIZE)
sbi->max_fragment_chunk = t;
else
return -EINVAL;
return count;
}
if (!strcmp(a->attr.name, "max_fragment_hole")) {
if (t >= MIN_FRAGMENT_SIZE && t <= MAX_FRAGMENT_SIZE)
sbi->max_fragment_hole = t;
else
return -EINVAL;
return count;
}
*ui = (unsigned int)t; *ui = (unsigned int)t;
return count; return count;
@ -781,6 +797,8 @@ F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_age_threshold, age_threshold);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, seq_file_ra_mul, seq_file_ra_mul); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, seq_file_ra_mul, seq_file_ra_mul);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_segment_mode, gc_segment_mode); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_segment_mode, gc_segment_mode);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_reclaimed_segments, gc_reclaimed_segs); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_reclaimed_segments, gc_reclaimed_segs);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_fragment_chunk, max_fragment_chunk);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_fragment_hole, max_fragment_hole);
#define ATTR_LIST(name) (&f2fs_attr_##name.attr) #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
static struct attribute *f2fs_attrs[] = { static struct attribute *f2fs_attrs[] = {
@ -859,6 +877,8 @@ static struct attribute *f2fs_attrs[] = {
ATTR_LIST(seq_file_ra_mul), ATTR_LIST(seq_file_ra_mul),
ATTR_LIST(gc_segment_mode), ATTR_LIST(gc_segment_mode),
ATTR_LIST(gc_reclaimed_segments), ATTR_LIST(gc_reclaimed_segments),
ATTR_LIST(max_fragment_chunk),
ATTR_LIST(max_fragment_hole),
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(f2fs); ATTRIBUTE_GROUPS(f2fs);

View File

@ -136,7 +136,7 @@ static int f2fs_begin_enable_verity(struct file *filp)
* here and not rely on ->open() doing it. This must be done before * here and not rely on ->open() doing it. This must be done before
* evicting the inline data. * evicting the inline data.
*/ */
err = dquot_initialize(inode); err = f2fs_dquot_initialize(inode);
if (err) if (err)
return err; return err;

View File

@ -773,7 +773,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
if (!f2fs_is_checkpoint_ready(sbi)) if (!f2fs_is_checkpoint_ready(sbi))
return -ENOSPC; return -ENOSPC;
err = dquot_initialize(inode); err = f2fs_dquot_initialize(inode);
if (err) if (err)
return err; return err;

View File

@ -570,9 +570,10 @@ TRACE_EVENT(f2fs_file_write_iter,
); );
TRACE_EVENT(f2fs_map_blocks, TRACE_EVENT(f2fs_map_blocks,
TP_PROTO(struct inode *inode, struct f2fs_map_blocks *map, int ret), TP_PROTO(struct inode *inode, struct f2fs_map_blocks *map,
int create, int flag, int ret),
TP_ARGS(inode, map, ret), TP_ARGS(inode, map, create, flag, ret),
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
@ -583,11 +584,14 @@ TRACE_EVENT(f2fs_map_blocks,
__field(unsigned int, m_flags) __field(unsigned int, m_flags)
__field(int, m_seg_type) __field(int, m_seg_type)
__field(bool, m_may_create) __field(bool, m_may_create)
__field(bool, m_multidev_dio)
__field(int, create)
__field(int, flag)
__field(int, ret) __field(int, ret)
), ),
TP_fast_assign( TP_fast_assign(
__entry->dev = inode->i_sb->s_dev; __entry->dev = map->m_bdev->bd_dev;
__entry->ino = inode->i_ino; __entry->ino = inode->i_ino;
__entry->m_lblk = map->m_lblk; __entry->m_lblk = map->m_lblk;
__entry->m_pblk = map->m_pblk; __entry->m_pblk = map->m_pblk;
@ -595,12 +599,16 @@ TRACE_EVENT(f2fs_map_blocks,
__entry->m_flags = map->m_flags; __entry->m_flags = map->m_flags;
__entry->m_seg_type = map->m_seg_type; __entry->m_seg_type = map->m_seg_type;
__entry->m_may_create = map->m_may_create; __entry->m_may_create = map->m_may_create;
__entry->m_multidev_dio = map->m_multidev_dio;
__entry->create = create;
__entry->flag = flag;
__entry->ret = ret; __entry->ret = ret;
), ),
TP_printk("dev = (%d,%d), ino = %lu, file offset = %llu, " TP_printk("dev = (%d,%d), ino = %lu, file offset = %llu, "
"start blkaddr = 0x%llx, len = 0x%llx, flags = %u," "start blkaddr = 0x%llx, len = 0x%llx, flags = %u, "
"seg_type = %d, may_create = %d, err = %d", "seg_type = %d, may_create = %d, multidevice = %d, "
"create = %d, flag = %d, err = %d",
show_dev_ino(__entry), show_dev_ino(__entry),
(unsigned long long)__entry->m_lblk, (unsigned long long)__entry->m_lblk,
(unsigned long long)__entry->m_pblk, (unsigned long long)__entry->m_pblk,
@ -608,6 +616,9 @@ TRACE_EVENT(f2fs_map_blocks,
__entry->m_flags, __entry->m_flags,
__entry->m_seg_type, __entry->m_seg_type,
__entry->m_may_create, __entry->m_may_create,
__entry->m_multidev_dio,
__entry->create,
__entry->flag,
__entry->ret) __entry->ret)
); );
@ -807,20 +818,20 @@ TRACE_EVENT(f2fs_lookup_start,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
__field(ino_t, ino) __field(ino_t, ino)
__field(const char *, name) __string(name, dentry->d_name.name)
__field(unsigned int, flags) __field(unsigned int, flags)
), ),
TP_fast_assign( TP_fast_assign(
__entry->dev = dir->i_sb->s_dev; __entry->dev = dir->i_sb->s_dev;
__entry->ino = dir->i_ino; __entry->ino = dir->i_ino;
__entry->name = dentry->d_name.name; __assign_str(name, dentry->d_name.name);
__entry->flags = flags; __entry->flags = flags;
), ),
TP_printk("dev = (%d,%d), pino = %lu, name:%s, flags:%u", TP_printk("dev = (%d,%d), pino = %lu, name:%s, flags:%u",
show_dev_ino(__entry), show_dev_ino(__entry),
__entry->name, __get_str(name),
__entry->flags) __entry->flags)
); );
@ -834,7 +845,7 @@ TRACE_EVENT(f2fs_lookup_end,
TP_STRUCT__entry( TP_STRUCT__entry(
__field(dev_t, dev) __field(dev_t, dev)
__field(ino_t, ino) __field(ino_t, ino)
__field(const char *, name) __string(name, dentry->d_name.name)
__field(nid_t, cino) __field(nid_t, cino)
__field(int, err) __field(int, err)
), ),
@ -842,14 +853,14 @@ TRACE_EVENT(f2fs_lookup_end,
TP_fast_assign( TP_fast_assign(
__entry->dev = dir->i_sb->s_dev; __entry->dev = dir->i_sb->s_dev;
__entry->ino = dir->i_ino; __entry->ino = dir->i_ino;
__entry->name = dentry->d_name.name; __assign_str(name, dentry->d_name.name);
__entry->cino = ino; __entry->cino = ino;
__entry->err = err; __entry->err = err;
), ),
TP_printk("dev = (%d,%d), pino = %lu, name:%s, ino:%u, err:%d", TP_printk("dev = (%d,%d), pino = %lu, name:%s, ino:%u, err:%d",
show_dev_ino(__entry), show_dev_ino(__entry),
__entry->name, __get_str(name),
__entry->cino, __entry->cino,
__entry->err) __entry->err)
); );