mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-23 20:24:12 +08:00
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:
commit
5664896ba2
@ -512,3 +512,19 @@ Date: July 2021
|
||||
Contact: "Daeho Jeong" <daehojeong@google.com>
|
||||
Description: You can control the multiplier value of bdi device readahead window size
|
||||
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.
|
||||
|
@ -197,10 +197,29 @@ fault_type=%d Support configuring fault injection type, should be
|
||||
FAULT_DISCARD 0x000002000
|
||||
FAULT_WRITE_IO 0x000004000
|
||||
FAULT_SLAB_ALLOC 0x000008000
|
||||
FAULT_DQUOT_INIT 0x000010000
|
||||
=================== ===========
|
||||
mode=%s Control block allocation mode which supports "adaptive"
|
||||
and "lfs". In "lfs" mode, there should be no random
|
||||
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
|
||||
with "mode=lfs".
|
||||
usrquota Enable plain user disk quota accounting.
|
||||
|
@ -653,7 +653,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
return PTR_ERR(inode);
|
||||
}
|
||||
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err) {
|
||||
iput(inode);
|
||||
goto err_out;
|
||||
@ -705,9 +705,6 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
|
||||
}
|
||||
|
||||
#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
|
||||
* 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))
|
||||
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)) {
|
||||
ret = false;
|
||||
} else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) {
|
||||
|
@ -882,6 +882,25 @@ bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t 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)
|
||||
{
|
||||
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)) {
|
||||
err = f2fs_compress_pages(cc);
|
||||
if (err == -EAGAIN) {
|
||||
add_compr_block_stat(cc->inode, cc->cluster_size);
|
||||
goto write;
|
||||
} else if (err) {
|
||||
f2fs_put_rpages_wbc(cc, wbc, true, 1);
|
||||
|
@ -1465,10 +1465,15 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
|
||||
struct extent_info ei = {0, };
|
||||
block_t blkaddr;
|
||||
unsigned int start_pgofs;
|
||||
int bidx = 0;
|
||||
|
||||
if (!maxblocks)
|
||||
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_flags = 0;
|
||||
|
||||
@ -1491,6 +1496,21 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
|
||||
if (flag == F2FS_GET_BLOCK_DIO)
|
||||
f2fs_wait_on_block_writeback_range(inode,
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1609,6 +1629,9 @@ next_block:
|
||||
if (flag == F2FS_GET_BLOCK_PRE_AIO)
|
||||
goto skip;
|
||||
|
||||
if (map->m_multidev_dio)
|
||||
bidx = f2fs_target_device_index(sbi, blkaddr);
|
||||
|
||||
if (map->m_len == 0) {
|
||||
/* preallocated unwritten block should be mapped for fiemap. */
|
||||
if (blkaddr == NEW_ADDR)
|
||||
@ -1617,10 +1640,15 @@ next_block:
|
||||
|
||||
map->m_pblk = blkaddr;
|
||||
map->m_len = 1;
|
||||
|
||||
if (map->m_multidev_dio)
|
||||
map->m_bdev = FDEV(bidx).bdev;
|
||||
} else if ((map->m_pblk != NEW_ADDR &&
|
||||
blkaddr == (map->m_pblk + ofs)) ||
|
||||
(map->m_pblk == NEW_ADDR && blkaddr == NEW_ADDR) ||
|
||||
flag == F2FS_GET_BLOCK_PRE_DIO) {
|
||||
if (map->m_multidev_dio && map->m_bdev != FDEV(bidx).bdev)
|
||||
goto sync_out;
|
||||
ofs++;
|
||||
map->m_len++;
|
||||
} else {
|
||||
@ -1673,10 +1701,32 @@ skip:
|
||||
|
||||
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,
|
||||
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 (map->m_flags & F2FS_MAP_MAPPED) {
|
||||
@ -1696,7 +1746,7 @@ unlock_out:
|
||||
f2fs_balance_fs(sbi, dn.node_changed);
|
||||
}
|
||||
out:
|
||||
trace_f2fs_map_blocks(inode, map, err);
|
||||
trace_f2fs_map_blocks(inode, map, create, flag, 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);
|
||||
bh->b_state = (bh->b_state & ~F2FS_MAP_FLAGS) | map.m_flags;
|
||||
bh->b_size = blks_to_bytes(inode, map.m_len);
|
||||
|
||||
if (map.m_multidev_dio)
|
||||
bh->b_bdev = map.m_bdev;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@ -2989,6 +3042,10 @@ readd:
|
||||
need_readd = false;
|
||||
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
||||
if (f2fs_compressed_file(inode)) {
|
||||
void *fsdata = NULL;
|
||||
struct page *pagep;
|
||||
int ret2;
|
||||
|
||||
ret = f2fs_init_compress_ctx(&cc);
|
||||
if (ret) {
|
||||
done = 1;
|
||||
@ -3007,27 +3064,23 @@ readd:
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
goto lock_page;
|
||||
|
||||
if (f2fs_cluster_is_empty(&cc)) {
|
||||
void *fsdata = NULL;
|
||||
struct page *pagep;
|
||||
int ret2;
|
||||
if (!f2fs_cluster_is_empty(&cc))
|
||||
goto lock_page;
|
||||
|
||||
ret2 = f2fs_prepare_compress_overwrite(
|
||||
ret2 = f2fs_prepare_compress_overwrite(
|
||||
inode, &pagep,
|
||||
page->index, &fsdata);
|
||||
if (ret2 < 0) {
|
||||
ret = ret2;
|
||||
done = 1;
|
||||
break;
|
||||
} else if (ret2 &&
|
||||
!f2fs_compress_write_end(inode,
|
||||
fsdata, page->index,
|
||||
1)) {
|
||||
retry = 1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
goto lock_page;
|
||||
if (ret2 < 0) {
|
||||
ret = ret2;
|
||||
done = 1;
|
||||
break;
|
||||
} else if (ret2 &&
|
||||
(!f2fs_compress_write_end(inode,
|
||||
fsdata, page->index, 1) ||
|
||||
!f2fs_all_cluster_page_loaded(&cc,
|
||||
&pvec, i, nr_pages))) {
|
||||
retry = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -55,6 +55,7 @@ enum {
|
||||
FAULT_DISCARD,
|
||||
FAULT_WRITE_IO,
|
||||
FAULT_SLAB_ALLOC,
|
||||
FAULT_DQUOT_INIT,
|
||||
FAULT_MAX,
|
||||
};
|
||||
|
||||
@ -561,6 +562,9 @@ enum {
|
||||
|
||||
#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 */
|
||||
#define F2FS_MIN_EXTENT_LEN 64 /* minimum extent length */
|
||||
|
||||
@ -617,6 +621,7 @@ struct extent_tree {
|
||||
F2FS_MAP_UNWRITTEN)
|
||||
|
||||
struct f2fs_map_blocks {
|
||||
struct block_device *m_bdev; /* for multi-device dio */
|
||||
block_t m_pblk;
|
||||
block_t m_lblk;
|
||||
unsigned int m_len;
|
||||
@ -625,6 +630,7 @@ struct f2fs_map_blocks {
|
||||
pgoff_t *m_next_extent; /* point to next possible extent */
|
||||
int m_seg_type;
|
||||
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 */
|
||||
@ -1284,8 +1290,10 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
FS_MODE_ADAPTIVE, /* use both lfs/ssr allocation */
|
||||
FS_MODE_LFS, /* use lfs allocation only */
|
||||
FS_MODE_ADAPTIVE, /* use both lfs/ssr allocation */
|
||||
FS_MODE_LFS, /* use lfs allocation only */
|
||||
FS_MODE_FRAGMENT_SEG, /* segment fragmentation mode */
|
||||
FS_MODE_FRAGMENT_BLK, /* block fragmentation mode */
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -1728,12 +1736,15 @@ struct f2fs_sb_info {
|
||||
|
||||
/* For shrinker support */
|
||||
struct list_head s_list;
|
||||
struct mutex umount_mutex;
|
||||
unsigned int shrinker_run_no;
|
||||
|
||||
/* For multi devices */
|
||||
int s_ndevs; /* number of devices */
|
||||
struct f2fs_dev_info *devs; /* for device list */
|
||||
unsigned int dirty_device; /* for checkpoint data flush */
|
||||
spinlock_t dev_lock; /* protect dirty_device */
|
||||
struct mutex umount_mutex;
|
||||
unsigned int shrinker_run_no;
|
||||
bool aligned_blksize; /* all devices has the same logical blksize */
|
||||
|
||||
/* For write statistics */
|
||||
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 */
|
||||
|
||||
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
|
||||
struct kmem_cache *page_array_slab; /* page array entry */
|
||||
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);
|
||||
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_quota_sync(struct super_block *sb, int type);
|
||||
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,
|
||||
struct f2fs_summary *sum, int type,
|
||||
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,
|
||||
enum page_type type, bool ordered, bool locked);
|
||||
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 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
|
||||
*/
|
||||
@ -4027,6 +4054,8 @@ void f2fs_end_read_compressed_page(struct page *page, bool failed,
|
||||
block_t blkaddr);
|
||||
bool f2fs_cluster_is_empty(struct compress_ctx *cc);
|
||||
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);
|
||||
void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page);
|
||||
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))
|
||||
return true;
|
||||
if (S_ISREG(inode->i_mode) &&
|
||||
(get_dirty_pages(inode) || atomic_read(&fi->i_compr_blocks)))
|
||||
if (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode))
|
||||
return false;
|
||||
|
||||
fi->i_flags &= ~F2FS_COMPR_FL;
|
||||
@ -4302,6 +4330,16 @@ static inline int block_unaligned_IO(struct inode *inode,
|
||||
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,
|
||||
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))
|
||||
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;
|
||||
/*
|
||||
* for blkzoned device, fallback direct IO to buffered IO, so
|
||||
|
@ -786,7 +786,7 @@ int f2fs_truncate(struct inode *inode)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -916,7 +916,7 @@ int f2fs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
return err;
|
||||
|
||||
if (is_quota_modification(inode, attr)) {
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -3020,7 +3020,7 @@ static int f2fs_ioc_setproject(struct inode *inode, __u32 projid)
|
||||
}
|
||||
f2fs_put_page(ipage, 1);
|
||||
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include "f2fs.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;
|
||||
|
||||
/* 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)))
|
||||
p->offset = 0;
|
||||
else
|
||||
|
@ -192,7 +192,7 @@ int f2fs_convert_inline_inode(struct inode *inode)
|
||||
f2fs_hw_is_readonly(sbi) || f2fs_readonly(sbi->sb))
|
||||
return 0;
|
||||
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -527,7 +527,7 @@ make_now:
|
||||
inode->i_op = &f2fs_dir_inode_operations;
|
||||
inode->i_fop = &f2fs_dir_operations;
|
||||
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)) {
|
||||
if (file_is_encrypt(inode))
|
||||
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))
|
||||
goto no_delete;
|
||||
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err) {
|
||||
err = 0;
|
||||
set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
|
||||
|
@ -74,7 +74,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
if (err)
|
||||
goto fail_drop;
|
||||
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err)
|
||||
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))
|
||||
return -ENOSPC;
|
||||
|
||||
err = dquot_initialize(dir);
|
||||
err = f2fs_dquot_initialize(dir);
|
||||
if (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)))
|
||||
return -EXDEV;
|
||||
|
||||
err = dquot_initialize(dir);
|
||||
err = f2fs_dquot_initialize(dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -460,7 +460,7 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino)
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = dquot_initialize(dir);
|
||||
err = f2fs_dquot_initialize(dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -598,10 +598,10 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = dquot_initialize(dir);
|
||||
err = f2fs_dquot_initialize(dir);
|
||||
if (err)
|
||||
goto fail;
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
@ -675,7 +675,7 @@ static int f2fs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = dquot_initialize(dir);
|
||||
err = f2fs_dquot_initialize(dir);
|
||||
if (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)))
|
||||
return -EIO;
|
||||
|
||||
err = dquot_initialize(dir);
|
||||
err = f2fs_dquot_initialize(dir);
|
||||
if (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_fop = &f2fs_dir_operations;
|
||||
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);
|
||||
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))
|
||||
return -ENOSPC;
|
||||
|
||||
err = dquot_initialize(dir);
|
||||
err = f2fs_dquot_initialize(dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -841,7 +841,7 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry,
|
||||
struct inode *inode;
|
||||
int err;
|
||||
|
||||
err = dquot_initialize(dir);
|
||||
err = f2fs_dquot_initialize(dir);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -965,16 +965,16 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
return err;
|
||||
}
|
||||
|
||||
err = dquot_initialize(old_dir);
|
||||
err = f2fs_dquot_initialize(old_dir);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = dquot_initialize(new_dir);
|
||||
err = f2fs_dquot_initialize(new_dir);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (new_inode) {
|
||||
err = dquot_initialize(new_inode);
|
||||
err = f2fs_dquot_initialize(new_inode);
|
||||
if (err)
|
||||
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)))
|
||||
return -EXDEV;
|
||||
|
||||
err = dquot_initialize(old_dir);
|
||||
err = f2fs_dquot_initialize(old_dir);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = dquot_initialize(new_dir);
|
||||
err = f2fs_dquot_initialize(new_dir);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -1443,6 +1443,7 @@ page_hit:
|
||||
nid, nid_of_node(page), ino_of_node(page),
|
||||
ofs_of_node(page), cpver_of_node(page),
|
||||
next_blkaddr_of_node(page));
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
err = -EINVAL;
|
||||
out_err:
|
||||
ClearPageUptodate(page);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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 {
|
||||
FREE_NIDS, /* indicates the free nid list */
|
||||
NAT_ENTRIES, /* indicates the cached nat entry */
|
||||
|
@ -81,7 +81,7 @@ static struct fsync_inode_entry *add_fsync_inode(struct f2fs_sb_info *sbi,
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
@ -203,7 +203,7 @@ retry:
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
err = dquot_initialize(einode);
|
||||
err = f2fs_dquot_initialize(einode);
|
||||
if (err) {
|
||||
iput(einode);
|
||||
goto out_put;
|
||||
@ -508,7 +508,7 @@ got_it:
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
ret = dquot_initialize(inode);
|
||||
ret = f2fs_dquot_initialize(inode);
|
||||
if (ret) {
|
||||
iput(inode);
|
||||
return ret;
|
||||
@ -787,8 +787,6 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
||||
}
|
||||
|
||||
#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 */
|
||||
quota_enabled = f2fs_enable_quota_files(sbi, s_flags & SB_RDONLY);
|
||||
#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);
|
||||
if (!err)
|
||||
f2fs_bug_on(sbi, !list_empty(&inode_list));
|
||||
else {
|
||||
/* restore s_flags to let iput() trash data */
|
||||
sbi->sb->s_flags = s_flags;
|
||||
}
|
||||
else
|
||||
f2fs_bug_on(sbi, sbi->sb->s_flags & SB_ACTIVE);
|
||||
skip:
|
||||
fix_curseg_write_pointer = !check_only || list_empty(&inode_list);
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/timer.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/sched/signal.h>
|
||||
#include <linux/random.h>
|
||||
|
||||
#include "f2fs.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)
|
||||
{
|
||||
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
|
||||
f2fs_build_free_nids(sbi, false, false);
|
||||
|
||||
if (excess_dirty_nats(sbi) || excess_dirty_nodes(sbi) ||
|
||||
excess_prefree_segs(sbi))
|
||||
if (excess_dirty_nats(sbi) || excess_dirty_threshold(sbi) ||
|
||||
excess_prefree_segs(sbi) || !f2fs_space_for_roll_forward(sbi))
|
||||
goto do_sync;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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))
|
||||
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;
|
||||
|
||||
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 (__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;
|
||||
reset_curseg(sbi, type, 1);
|
||||
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,
|
||||
@ -2707,12 +2732,22 @@ static int __next_free_blkoff(struct f2fs_sb_info *sbi,
|
||||
static void __refresh_next_blkoff(struct f2fs_sb_info *sbi,
|
||||
struct curseg_info *seg)
|
||||
{
|
||||
if (seg->alloc_type == SSR)
|
||||
if (seg->alloc_type == SSR) {
|
||||
seg->next_blkoff =
|
||||
__next_free_blkoff(sbi, seg->segno,
|
||||
seg->next_blkoff + 1);
|
||||
else
|
||||
} else {
|
||||
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)
|
||||
@ -3485,24 +3520,30 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
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))
|
||||
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 */
|
||||
f2fs_set_dirty_device(sbi, fio->ino, devidx, FLUSH_INO);
|
||||
/* update device state for fsync */
|
||||
f2fs_set_dirty_device(sbi, ino, devidx, FLUSH_INO);
|
||||
|
||||
/* update device state for checkpoint */
|
||||
if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) {
|
||||
spin_lock(&sbi->dev_lock);
|
||||
f2fs_set_bit(devidx, (char *)&sbi->dirty_device);
|
||||
spin_unlock(&sbi->dev_lock);
|
||||
/* update device state for checkpoint */
|
||||
if (!f2fs_test_bit(devidx, (char *)&sbi->dirty_device)) {
|
||||
spin_lock(&sbi->dev_lock);
|
||||
f2fs_set_bit(devidx, (char *)&sbi->dirty_device);
|
||||
spin_unlock(&sbi->dev_lock);
|
||||
}
|
||||
|
||||
if (blkcnt <= blks)
|
||||
break;
|
||||
blkcnt -= blks;
|
||||
blkaddr += blks;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3529,7 +3570,7 @@ reallocate:
|
||||
goto reallocate;
|
||||
}
|
||||
|
||||
update_device_state(fio);
|
||||
f2fs_update_device_state(fio->sbi, fio->ino, fio->new_blkaddr, 1);
|
||||
|
||||
if (keep_order)
|
||||
up_read(&fio->sbi->io_order_lock);
|
||||
@ -3611,6 +3652,9 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
|
||||
goto drop_bio;
|
||||
}
|
||||
|
||||
invalidate_mapping_pages(META_MAPPING(sbi),
|
||||
fio->new_blkaddr, fio->new_blkaddr);
|
||||
|
||||
stat_inc_inplace_blocks(fio->sbi);
|
||||
|
||||
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
|
||||
err = f2fs_submit_page_bio(fio);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -314,6 +314,7 @@ struct curseg_info {
|
||||
unsigned short next_blkoff; /* next block offset to write */
|
||||
unsigned int zone; /* current zone number */
|
||||
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 */
|
||||
};
|
||||
|
||||
|
@ -58,6 +58,7 @@ const char *f2fs_fault_name[FAULT_MAX] = {
|
||||
[FAULT_DISCARD] = "discard error",
|
||||
[FAULT_WRITE_IO] = "write IO error",
|
||||
[FAULT_SLAB_ALLOC] = "slab alloc",
|
||||
[FAULT_DQUOT_INIT] = "dquot initialize",
|
||||
};
|
||||
|
||||
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;
|
||||
} else if (!strcmp(name, "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 {
|
||||
kfree(name);
|
||||
return -EINVAL;
|
||||
@ -1292,7 +1297,7 @@ default_check:
|
||||
/* Not pass down write hints if the number of active logs is lesser
|
||||
* 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;
|
||||
|
||||
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");
|
||||
else if (F2FS_OPTION(sbi).fs_mode == FS_MODE_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);
|
||||
if (test_opt(sbi, RESERVE_ROOT))
|
||||
seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u",
|
||||
@ -2491,6 +2500,16 @@ retry:
|
||||
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)
|
||||
{
|
||||
return F2FS_I(inode)->i_dquot;
|
||||
@ -2875,6 +2894,11 @@ static const struct quotactl_ops f2fs_quotactl_ops = {
|
||||
.get_nextdqblk = dquot_get_next_dqblk,
|
||||
};
|
||||
#else
|
||||
int f2fs_dquot_initialize(struct inode *inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f2fs_quota_sync(struct super_block *sb, int type)
|
||||
{
|
||||
return 0;
|
||||
@ -3486,7 +3510,7 @@ skip_cross:
|
||||
NR_CURSEG_PERSIST_TYPE + nat_bits_blocks >= blocks_per_seg)) {
|
||||
f2fs_warn(sbi, "Insane cp_payload: %u, nat_bits_blocks: %u)",
|
||||
cp_payload, nat_bits_blocks);
|
||||
return -EFSCORRUPTED;
|
||||
return 1;
|
||||
}
|
||||
|
||||
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->migration_granularity = sbi->segs_per_sec;
|
||||
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->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);
|
||||
unsigned int max_devices = MAX_DEVICES;
|
||||
unsigned int logical_blksize;
|
||||
int i;
|
||||
|
||||
/* Initialize single device information */
|
||||
@ -3766,6 +3793,9 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
|
||||
if (!sbi->devs)
|
||||
return -ENOMEM;
|
||||
|
||||
logical_blksize = bdev_logical_block_size(sbi->sb->s_bdev);
|
||||
sbi->aligned_blksize = true;
|
||||
|
||||
for (i = 0; i < max_devices; i++) {
|
||||
|
||||
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 */
|
||||
sbi->s_ndevs = i + 1;
|
||||
|
||||
if (logical_blksize != bdev_logical_block_size(FDEV(i).bdev))
|
||||
sbi->aligned_blksize = false;
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_ZONED
|
||||
if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM &&
|
||||
!f2fs_sb_has_blkzoned(sbi)) {
|
||||
@ -4351,6 +4384,8 @@ free_node_inode:
|
||||
free_stats:
|
||||
f2fs_destroy_stats(sbi);
|
||||
free_nm:
|
||||
/* stop discard thread before destroying node manager */
|
||||
f2fs_stop_discard_thread(sbi);
|
||||
f2fs_destroy_node_manager(sbi);
|
||||
free_sm:
|
||||
f2fs_destroy_segment_manager(sbi);
|
||||
|
@ -196,7 +196,7 @@ static ssize_t encoding_show(struct f2fs_attr *a,
|
||||
struct super_block *sb = sbi->sb;
|
||||
|
||||
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->version >> 16) & 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,
|
||||
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));
|
||||
}
|
||||
|
||||
@ -551,6 +551,22 @@ out:
|
||||
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;
|
||||
|
||||
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, 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, 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)
|
||||
static struct attribute *f2fs_attrs[] = {
|
||||
@ -859,6 +877,8 @@ static struct attribute *f2fs_attrs[] = {
|
||||
ATTR_LIST(seq_file_ra_mul),
|
||||
ATTR_LIST(gc_segment_mode),
|
||||
ATTR_LIST(gc_reclaimed_segments),
|
||||
ATTR_LIST(max_fragment_chunk),
|
||||
ATTR_LIST(max_fragment_hole),
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(f2fs);
|
||||
|
@ -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
|
||||
* evicting the inline data.
|
||||
*/
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -773,7 +773,7 @@ int f2fs_setxattr(struct inode *inode, int index, const char *name,
|
||||
if (!f2fs_is_checkpoint_ready(sbi))
|
||||
return -ENOSPC;
|
||||
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -570,9 +570,10 @@ TRACE_EVENT(f2fs_file_write_iter,
|
||||
);
|
||||
|
||||
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(
|
||||
__field(dev_t, dev)
|
||||
@ -583,11 +584,14 @@ TRACE_EVENT(f2fs_map_blocks,
|
||||
__field(unsigned int, m_flags)
|
||||
__field(int, m_seg_type)
|
||||
__field(bool, m_may_create)
|
||||
__field(bool, m_multidev_dio)
|
||||
__field(int, create)
|
||||
__field(int, flag)
|
||||
__field(int, ret)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->dev = inode->i_sb->s_dev;
|
||||
__entry->dev = map->m_bdev->bd_dev;
|
||||
__entry->ino = inode->i_ino;
|
||||
__entry->m_lblk = map->m_lblk;
|
||||
__entry->m_pblk = map->m_pblk;
|
||||
@ -595,12 +599,16 @@ TRACE_EVENT(f2fs_map_blocks,
|
||||
__entry->m_flags = map->m_flags;
|
||||
__entry->m_seg_type = map->m_seg_type;
|
||||
__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;
|
||||
),
|
||||
|
||||
TP_printk("dev = (%d,%d), ino = %lu, file offset = %llu, "
|
||||
"start blkaddr = 0x%llx, len = 0x%llx, flags = %u,"
|
||||
"seg_type = %d, may_create = %d, err = %d",
|
||||
"start blkaddr = 0x%llx, len = 0x%llx, flags = %u, "
|
||||
"seg_type = %d, may_create = %d, multidevice = %d, "
|
||||
"create = %d, flag = %d, err = %d",
|
||||
show_dev_ino(__entry),
|
||||
(unsigned long long)__entry->m_lblk,
|
||||
(unsigned long long)__entry->m_pblk,
|
||||
@ -608,6 +616,9 @@ TRACE_EVENT(f2fs_map_blocks,
|
||||
__entry->m_flags,
|
||||
__entry->m_seg_type,
|
||||
__entry->m_may_create,
|
||||
__entry->m_multidev_dio,
|
||||
__entry->create,
|
||||
__entry->flag,
|
||||
__entry->ret)
|
||||
);
|
||||
|
||||
@ -807,20 +818,20 @@ TRACE_EVENT(f2fs_lookup_start,
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(ino_t, ino)
|
||||
__field(const char *, name)
|
||||
__string(name, dentry->d_name.name)
|
||||
__field(unsigned int, flags)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->dev = dir->i_sb->s_dev;
|
||||
__entry->ino = dir->i_ino;
|
||||
__entry->name = dentry->d_name.name;
|
||||
__assign_str(name, dentry->d_name.name);
|
||||
__entry->flags = flags;
|
||||
),
|
||||
|
||||
TP_printk("dev = (%d,%d), pino = %lu, name:%s, flags:%u",
|
||||
show_dev_ino(__entry),
|
||||
__entry->name,
|
||||
__get_str(name),
|
||||
__entry->flags)
|
||||
);
|
||||
|
||||
@ -834,7 +845,7 @@ TRACE_EVENT(f2fs_lookup_end,
|
||||
TP_STRUCT__entry(
|
||||
__field(dev_t, dev)
|
||||
__field(ino_t, ino)
|
||||
__field(const char *, name)
|
||||
__string(name, dentry->d_name.name)
|
||||
__field(nid_t, cino)
|
||||
__field(int, err)
|
||||
),
|
||||
@ -842,14 +853,14 @@ TRACE_EVENT(f2fs_lookup_end,
|
||||
TP_fast_assign(
|
||||
__entry->dev = dir->i_sb->s_dev;
|
||||
__entry->ino = dir->i_ino;
|
||||
__entry->name = dentry->d_name.name;
|
||||
__assign_str(name, dentry->d_name.name);
|
||||
__entry->cino = ino;
|
||||
__entry->err = err;
|
||||
),
|
||||
|
||||
TP_printk("dev = (%d,%d), pino = %lu, name:%s, ino:%u, err:%d",
|
||||
show_dev_ino(__entry),
|
||||
__entry->name,
|
||||
__get_str(name),
|
||||
__entry->cino,
|
||||
__entry->err)
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user