mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'f2fs-for-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim: "In this round, we've added two features: F2FS_IOC_START_ATOMIC_REPLACE and a per-block age-based extent cache. F2FS_IOC_START_ATOMIC_REPLACE is a variant of the previous atomic write feature which guarantees a per-file atomicity. It would be more efficient than AtomicFile implementation in Android framework. The per-block age-based extent cache implements another type of extent cache in memory which keeps the per-block age in a file, so that block allocator could split the hot and cold data blocks more accurately. Enhancements: - introduce F2FS_IOC_START_ATOMIC_REPLACE - refactor extent_cache to add a new per-block-age-based extent cache support - introduce discard_urgent_util, gc_mode, max_ordered_discard sysfs knobs - add proc entry to show discard_plist info - optimize iteration over sparse directories - add barrier mount option Bug fixes: - avoid victim selection from previous victim section - fix to enable compress for newly created file if extension matches - set zstd compress level correctly - initialize locks early in f2fs_fill_super() to fix bugs reported by syzbot - correct i_size change for atomic writes - allow to read node block after shutdown - allow to set compression for inlined file - fix gc mode when gc_urgent_high_remaining is 1 - should put a page when checking the summary info Minor fixes and various clean-ups in GC, discard, debugfs, sysfs, and doc" * tag 'f2fs-for-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (63 commits) f2fs: reset wait_ms to default if any of the victims have been selected f2fs: fix some format WARNING in debug.c and sysfs.c f2fs: don't call f2fs_issue_discard_timeout() when discard_cmd_cnt is 0 in f2fs_put_super() f2fs: fix iostat parameter for discard f2fs: Fix spelling mistake in label: free_bio_enrty_cache -> free_bio_entry_cache f2fs: add block_age-based extent cache f2fs: allocate the extent_cache by default f2fs: refactor extent_cache to support for read and more f2fs: remove unnecessary __init_extent_tree f2fs: move internal functions into extent_cache.c f2fs: specify extent cache for read explicitly f2fs: introduce f2fs_is_readonly() for readability f2fs: remove F2FS_SET_FEATURE() and F2FS_CLEAR_FEATURE() macro f2fs: do some cleanup for f2fs module init MAINTAINERS: Add f2fs bug tracker link f2fs: remove the unused flush argument to change_curseg f2fs: open code allocate_segment_by_default f2fs: remove struct segment_allocation default_salloc_ops f2fs: introduce discard_urgent_util sysfs node f2fs: define MIN_DISCARD_GRANULARITY macro ...
This commit is contained in:
commit
041fae9c10
24 files changed
+1654
-939
No files matched your search
@@ -99,6 +99,12 @@ Description: Controls the issue rate of discard commands that consist of small
|
||||
checkpoint is triggered, and issued during the checkpoint.
|
||||
By default, it is disabled with 0.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/max_ordered_discard
|
||||
Date: October 2022
|
||||
Contact: "Yangtao Li" <frank.li@vivo.com>
|
||||
Description: Controls the maximum ordered discard, the unit size is one block(4KB).
|
||||
Set it to 16 by default.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/max_discard_request
|
||||
Date: December 2021
|
||||
Contact: "Konstantin Vyshetsky" <vkon@google.com>
|
||||
@@ -132,7 +138,8 @@ Contact: "Chao Yu" <yuchao0@huawei.com>
|
||||
Description: Controls discard granularity of inner discard thread. Inner thread
|
||||
will not issue discards with size that is smaller than granularity.
|
||||
The unit size is one block(4KB), now only support configuring
|
||||
in range of [1, 512]. Default value is 4(=16KB).
|
||||
in range of [1, 512]. Default value is 16.
|
||||
For small devices, default value is 1.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/umount_discard_timeout
|
||||
Date: January 2019
|
||||
@@ -235,7 +242,7 @@ Description: Shows total written kbytes issued to disk.
|
||||
What: /sys/fs/f2fs/<disk>/features
|
||||
Date: July 2017
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description: <deprecated: should use /sys/fs/f2fs/<disk>/feature_list/
|
||||
Description: <deprecated: should use /sys/fs/f2fs/<disk>/feature_list/>
|
||||
Shows all enabled features in current device.
|
||||
Supported features:
|
||||
encryption, blkzoned, extra_attr, projquota, inode_checksum,
|
||||
@@ -592,10 +599,10 @@ Description: With "mode=fragment:block" mount options, we can scatter block allo
|
||||
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>/gc_urgent_high_remaining
|
||||
Date: December 2021
|
||||
Contact: "Daeho Jeong" <daehojeong@google.com>
|
||||
Description: You can set the trial count limit for GC urgent high mode with this value.
|
||||
What: /sys/fs/f2fs/<disk>/gc_remaining_trials
|
||||
Date: October 2022
|
||||
Contact: "Yangtao Li" <frank.li@vivo.com>
|
||||
Description: You can set the trial count limit for GC urgent and idle mode with this value.
|
||||
If GC thread gets to the limit, the mode will turn back to GC normal mode.
|
||||
By default, the value is zero, which means there is no limit like before.
|
||||
|
||||
@@ -634,3 +641,31 @@ Date: July 2022
|
||||
Contact: "Daeho Jeong" <daehojeong@google.com>
|
||||
Description: Show the accumulated total revoked atomic write block count after boot.
|
||||
If you write "0" here, you can initialize to "0".
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/gc_mode
|
||||
Date: October 2022
|
||||
Contact: "Yangtao Li" <frank.li@vivo.com>
|
||||
Description: Show the current gc_mode as a string.
|
||||
This is a read-only entry.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/discard_urgent_util
|
||||
Date: November 2022
|
||||
Contact: "Yangtao Li" <frank.li@vivo.com>
|
||||
Description: When space utilization exceeds this, do background DISCARD aggressively.
|
||||
Does DISCARD forcibly in a period of given min_discard_issue_time when the number
|
||||
of discards is not 0 and set discard granularity to 1.
|
||||
Default: 80
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/hot_data_age_threshold
|
||||
Date: November 2022
|
||||
Contact: "Ping Xiong" <xiongping1@xiaomi.com>
|
||||
Description: When DATA SEPARATION is on, it controls the age threshold to indicate
|
||||
the data blocks as hot. By default it was initialized as 262144 blocks
|
||||
(equals to 1GB).
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/warm_data_age_threshold
|
||||
Date: November 2022
|
||||
Contact: "Ping Xiong" <xiongping1@xiaomi.com>
|
||||
Description: When DATA SEPARATION is on, it controls the age threshold to indicate
|
||||
the data blocks as warm. By default it was initialized as 2621440 blocks
|
||||
(equals to 10GB).
|
||||
@@ -25,10 +25,14 @@ a consistency checking tool (fsck.f2fs), and a debugging tool (dump.f2fs).
|
||||
|
||||
- git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git
|
||||
|
||||
For reporting bugs and sending patches, please use the following mailing list:
|
||||
For sending patches, please use the following mailing list:
|
||||
|
||||
- linux-f2fs-devel@lists.sourceforge.net
|
||||
|
||||
For reporting bugs, please use the following f2fs bug tracker link:
|
||||
|
||||
- https://bugzilla.kernel.org/enter_bug.cgi?product=File%20System&component=f2fs
|
||||
|
||||
Background and Design issues
|
||||
============================
|
||||
|
||||
@@ -154,6 +158,8 @@ nobarrier This option can be used if underlying storage guarantees
|
||||
If this option is set, no cache_flush commands are issued
|
||||
but f2fs still guarantees the write ordering of all the
|
||||
data writes.
|
||||
barrier If this option is set, cache_flush commands are allowed to be
|
||||
issued.
|
||||
fastboot This option is used when a system wants to reduce mount
|
||||
time as much as possible, even though normal performance
|
||||
can be sacrificed.
|
||||
@@ -199,6 +205,7 @@ fault_type=%d Support configuring fault injection type, should be
|
||||
FAULT_SLAB_ALLOC 0x000008000
|
||||
FAULT_DQUOT_INIT 0x000010000
|
||||
FAULT_LOCK_OP 0x000020000
|
||||
FAULT_BLKADDR 0x000040000
|
||||
=================== ===========
|
||||
mode=%s Control block allocation mode which supports "adaptive"
|
||||
and "lfs". In "lfs" mode, there should be no random
|
||||
@@ -340,6 +347,10 @@ memory=%s Control memory mode. This supports "normal" and "low" modes.
|
||||
Because of the nature of low memory devices, in this mode, f2fs
|
||||
will try to save memory sometimes by sacrificing performance.
|
||||
"normal" mode is the default mode and same as before.
|
||||
age_extent_cache Enable an age extent cache based on rb-tree. It records
|
||||
data block update frequency of the extent per inode, in
|
||||
order to provide better temperature hints for data block
|
||||
allocation.
|
||||
======================== ============================================================
|
||||
|
||||
Debugfs Entries
|
||||
|
||||
@@ -7889,6 +7889,7 @@ M: Chao Yu <chao@kernel.org>
|
||||
L: linux-f2fs-devel@lists.sourceforge.net
|
||||
S: Maintained
|
||||
W: https://f2fs.wiki.kernel.org/
|
||||
B: https://bugzilla.kernel.org/enter_bug.cgi?product=File%20System&component=f2fs
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs.git
|
||||
F: Documentation/ABI/testing/sysfs-fs-f2fs
|
||||
F: Documentation/filesystems/f2fs.rst
|
||||
|
||||
@@ -171,6 +171,11 @@ static bool __is_bitmap_valid(struct f2fs_sb_info *sbi, block_t blkaddr,
|
||||
bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
|
||||
block_t blkaddr, int type)
|
||||
{
|
||||
if (time_to_inject(sbi, FAULT_BLKADDR)) {
|
||||
f2fs_show_injection_info(sbi, FAULT_BLKADDR);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case META_NAT:
|
||||
break;
|
||||
@@ -1897,8 +1902,10 @@ int f2fs_start_ckpt_thread(struct f2fs_sb_info *sbi)
|
||||
cprc->f2fs_issue_ckpt = kthread_run(issue_checkpoint_thread, sbi,
|
||||
"f2fs_ckpt-%u:%u", MAJOR(dev), MINOR(dev));
|
||||
if (IS_ERR(cprc->f2fs_issue_ckpt)) {
|
||||
int err = PTR_ERR(cprc->f2fs_issue_ckpt);
|
||||
|
||||
cprc->f2fs_issue_ckpt = NULL;
|
||||
return -ENOMEM;
|
||||
return err;
|
||||
}
|
||||
|
||||
set_task_ioprio(cprc->f2fs_issue_ckpt, cprc->ckpt_thread_ioprio);
|
||||
|
||||
+7
-41
@@ -346,7 +346,7 @@ static int zstd_init_compress_ctx(struct compress_ctx *cc)
|
||||
if (!level)
|
||||
level = F2FS_ZSTD_DEFAULT_CLEVEL;
|
||||
|
||||
params = zstd_get_params(F2FS_ZSTD_DEFAULT_CLEVEL, cc->rlen);
|
||||
params = zstd_get_params(level, cc->rlen);
|
||||
workspace_size = zstd_cstream_workspace_bound(¶ms.cParams);
|
||||
|
||||
workspace = f2fs_kvmalloc(F2FS_I_SB(cc->inode),
|
||||
@@ -567,10 +567,7 @@ MODULE_PARM_DESC(num_compress_pages,
|
||||
int f2fs_init_compress_mempool(void)
|
||||
{
|
||||
compress_page_pool = mempool_create_page_pool(num_compress_pages, 0);
|
||||
if (!compress_page_pool)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
return compress_page_pool ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void f2fs_destroy_compress_mempool(void)
|
||||
@@ -1981,9 +1978,7 @@ int f2fs_init_page_array_cache(struct f2fs_sb_info *sbi)
|
||||
|
||||
sbi->page_array_slab = f2fs_kmem_cache_create(slab_name,
|
||||
sbi->page_array_slab_size);
|
||||
if (!sbi->page_array_slab)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
return sbi->page_array_slab ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi)
|
||||
@@ -1991,53 +1986,24 @@ void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi)
|
||||
kmem_cache_destroy(sbi->page_array_slab);
|
||||
}
|
||||
|
||||
static int __init f2fs_init_cic_cache(void)
|
||||
int __init f2fs_init_compress_cache(void)
|
||||
{
|
||||
cic_entry_slab = f2fs_kmem_cache_create("f2fs_cic_entry",
|
||||
sizeof(struct compress_io_ctx));
|
||||
if (!cic_entry_slab)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void f2fs_destroy_cic_cache(void)
|
||||
{
|
||||
kmem_cache_destroy(cic_entry_slab);
|
||||
}
|
||||
|
||||
static int __init f2fs_init_dic_cache(void)
|
||||
{
|
||||
dic_entry_slab = f2fs_kmem_cache_create("f2fs_dic_entry",
|
||||
sizeof(struct decompress_io_ctx));
|
||||
if (!dic_entry_slab)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void f2fs_destroy_dic_cache(void)
|
||||
{
|
||||
kmem_cache_destroy(dic_entry_slab);
|
||||
}
|
||||
|
||||
int __init f2fs_init_compress_cache(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = f2fs_init_cic_cache();
|
||||
if (err)
|
||||
goto out;
|
||||
err = f2fs_init_dic_cache();
|
||||
if (err)
|
||||
goto free_cic;
|
||||
return 0;
|
||||
free_cic:
|
||||
f2fs_destroy_cic_cache();
|
||||
out:
|
||||
kmem_cache_destroy(cic_entry_slab);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void f2fs_destroy_compress_cache(void)
|
||||
{
|
||||
f2fs_destroy_dic_cache();
|
||||
f2fs_destroy_cic_cache();
|
||||
kmem_cache_destroy(dic_entry_slab);
|
||||
kmem_cache_destroy(cic_entry_slab);
|
||||
}
|
||||
+29
-25
@@ -39,10 +39,8 @@ static struct bio_set f2fs_bioset;
|
||||
|
||||
int __init f2fs_init_bioset(void)
|
||||
{
|
||||
if (bioset_init(&f2fs_bioset, F2FS_BIO_POOL_SIZE,
|
||||
0, BIOSET_NEED_BVECS))
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
return bioset_init(&f2fs_bioset, F2FS_BIO_POOL_SIZE,
|
||||
0, BIOSET_NEED_BVECS);
|
||||
}
|
||||
|
||||
void f2fs_destroy_bioset(void)
|
||||
@@ -1145,7 +1143,7 @@ void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr)
|
||||
{
|
||||
dn->data_blkaddr = blkaddr;
|
||||
f2fs_set_data_blkaddr(dn);
|
||||
f2fs_update_extent_cache(dn);
|
||||
f2fs_update_read_extent_cache(dn);
|
||||
}
|
||||
|
||||
/* dn->ofs_in_node will be returned with up-to-date last block pointer */
|
||||
@@ -1214,7 +1212,7 @@ int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
|
||||
struct extent_info ei = {0, };
|
||||
struct inode *inode = dn->inode;
|
||||
|
||||
if (f2fs_lookup_extent_cache(inode, index, &ei)) {
|
||||
if (f2fs_lookup_read_extent_cache(inode, index, &ei)) {
|
||||
dn->data_blkaddr = ei.blk + index - ei.fofs;
|
||||
return 0;
|
||||
}
|
||||
@@ -1223,7 +1221,8 @@ int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index)
|
||||
}
|
||||
|
||||
struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
|
||||
blk_opf_t op_flags, bool for_write)
|
||||
blk_opf_t op_flags, bool for_write,
|
||||
pgoff_t *next_pgofs)
|
||||
{
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct dnode_of_data dn;
|
||||
@@ -1235,7 +1234,7 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
|
||||
if (!page)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (f2fs_lookup_extent_cache(inode, index, &ei)) {
|
||||
if (f2fs_lookup_read_extent_cache(inode, index, &ei)) {
|
||||
dn.data_blkaddr = ei.blk + index - ei.fofs;
|
||||
if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), dn.data_blkaddr,
|
||||
DATA_GENERIC_ENHANCE_READ)) {
|
||||
@@ -1249,12 +1248,17 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
|
||||
if (err)
|
||||
if (err) {
|
||||
if (err == -ENOENT && next_pgofs)
|
||||
*next_pgofs = f2fs_get_next_page_offset(&dn, index);
|
||||
goto put_err;
|
||||
}
|
||||
f2fs_put_dnode(&dn);
|
||||
|
||||
if (unlikely(dn.data_blkaddr == NULL_ADDR)) {
|
||||
err = -ENOENT;
|
||||
if (next_pgofs)
|
||||
*next_pgofs = index + 1;
|
||||
goto put_err;
|
||||
}
|
||||
if (dn.data_blkaddr != NEW_ADDR &&
|
||||
@@ -1298,7 +1302,8 @@ put_err:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index)
|
||||
struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index,
|
||||
pgoff_t *next_pgofs)
|
||||
{
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct page *page;
|
||||
@@ -1308,7 +1313,7 @@ struct page *f2fs_find_data_page(struct inode *inode, pgoff_t index)
|
||||
return page;
|
||||
f2fs_put_page(page, 0);
|
||||
|
||||
page = f2fs_get_read_data_page(inode, index, 0, false);
|
||||
page = f2fs_get_read_data_page(inode, index, 0, false, next_pgofs);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
|
||||
@@ -1334,7 +1339,7 @@ struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index,
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct page *page;
|
||||
repeat:
|
||||
page = f2fs_get_read_data_page(inode, index, 0, for_write);
|
||||
page = f2fs_get_read_data_page(inode, index, 0, for_write, NULL);
|
||||
if (IS_ERR(page))
|
||||
return page;
|
||||
|
||||
@@ -1497,7 +1502,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map,
|
||||
pgofs = (pgoff_t)map->m_lblk;
|
||||
end = pgofs + maxblocks;
|
||||
|
||||
if (!create && f2fs_lookup_extent_cache(inode, pgofs, &ei)) {
|
||||
if (!create && f2fs_lookup_read_extent_cache(inode, pgofs, &ei)) {
|
||||
if (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO &&
|
||||
map->m_may_create)
|
||||
goto next_dnode;
|
||||
@@ -1707,7 +1712,7 @@ skip:
|
||||
if (map->m_flags & F2FS_MAP_MAPPED) {
|
||||
unsigned int ofs = start_pgofs - map->m_lblk;
|
||||
|
||||
f2fs_update_extent_cache_range(&dn,
|
||||
f2fs_update_read_extent_cache_range(&dn,
|
||||
start_pgofs, map->m_pblk + ofs,
|
||||
map->m_len - ofs);
|
||||
}
|
||||
@@ -1752,7 +1757,7 @@ sync_out:
|
||||
if (map->m_flags & F2FS_MAP_MAPPED) {
|
||||
unsigned int ofs = start_pgofs - map->m_lblk;
|
||||
|
||||
f2fs_update_extent_cache_range(&dn,
|
||||
f2fs_update_read_extent_cache_range(&dn,
|
||||
start_pgofs, map->m_pblk + ofs,
|
||||
map->m_len - ofs);
|
||||
}
|
||||
@@ -2212,7 +2217,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
|
||||
if (f2fs_cluster_is_empty(cc))
|
||||
goto out;
|
||||
|
||||
if (f2fs_lookup_extent_cache(inode, start_idx, &ei))
|
||||
if (f2fs_lookup_read_extent_cache(inode, start_idx, &ei))
|
||||
from_dnode = false;
|
||||
|
||||
if (!from_dnode)
|
||||
@@ -2643,7 +2648,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
|
||||
if (need_inplace_update(fio) &&
|
||||
f2fs_lookup_extent_cache(inode, page->index, &ei)) {
|
||||
f2fs_lookup_read_extent_cache(inode, page->index, &ei)) {
|
||||
fio->old_blkaddr = ei.blk + page->index - ei.fofs;
|
||||
|
||||
if (!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
|
||||
@@ -3367,7 +3372,7 @@ restart:
|
||||
} else if (locked) {
|
||||
err = f2fs_get_block(&dn, index);
|
||||
} else {
|
||||
if (f2fs_lookup_extent_cache(inode, index, &ei)) {
|
||||
if (f2fs_lookup_read_extent_cache(inode, index, &ei)) {
|
||||
dn.data_blkaddr = ei.blk + index - ei.fofs;
|
||||
} else {
|
||||
/* hole case */
|
||||
@@ -3408,7 +3413,7 @@ static int __find_data_block(struct inode *inode, pgoff_t index,
|
||||
|
||||
set_new_dnode(&dn, inode, ipage, ipage, 0);
|
||||
|
||||
if (f2fs_lookup_extent_cache(inode, index, &ei)) {
|
||||
if (f2fs_lookup_read_extent_cache(inode, index, &ei)) {
|
||||
dn.data_blkaddr = ei.blk + index - ei.fofs;
|
||||
} else {
|
||||
/* hole case */
|
||||
@@ -3472,6 +3477,9 @@ static int prepare_atomic_write_begin(struct f2fs_sb_info *sbi,
|
||||
else if (*blk_addr != NULL_ADDR)
|
||||
return 0;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_ATOMIC_REPLACE))
|
||||
goto reserve_block;
|
||||
|
||||
/* Look for the block in the original inode */
|
||||
err = __find_data_block(inode, index, &ori_blk_addr);
|
||||
if (err)
|
||||
@@ -4093,9 +4101,7 @@ int f2fs_init_post_read_wq(struct f2fs_sb_info *sbi)
|
||||
sbi->post_read_wq = alloc_workqueue("f2fs_post_read_wq",
|
||||
WQ_UNBOUND | WQ_HIGHPRI,
|
||||
num_online_cpus());
|
||||
if (!sbi->post_read_wq)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
return sbi->post_read_wq ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void f2fs_destroy_post_read_wq(struct f2fs_sb_info *sbi)
|
||||
@@ -4108,9 +4114,7 @@ int __init f2fs_init_bio_entry_cache(void)
|
||||
{
|
||||
bio_entry_slab = f2fs_kmem_cache_create("f2fs_bio_entry_slab",
|
||||
sizeof(struct bio_entry));
|
||||
if (!bio_entry_slab)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
return bio_entry_slab ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void f2fs_destroy_bio_entry_cache(void)
|
||||
|
||||
+88
-43
@@ -72,15 +72,26 @@ static void update_general_status(struct f2fs_sb_info *sbi)
|
||||
si->main_area_zones = si->main_area_sections /
|
||||
le32_to_cpu(raw_super->secs_per_zone);
|
||||
|
||||
/* validation check of the segment numbers */
|
||||
/* general extent cache stats */
|
||||
for (i = 0; i < NR_EXTENT_CACHES; i++) {
|
||||
struct extent_tree_info *eti = &sbi->extent_tree[i];
|
||||
|
||||
si->hit_cached[i] = atomic64_read(&sbi->read_hit_cached[i]);
|
||||
si->hit_rbtree[i] = atomic64_read(&sbi->read_hit_rbtree[i]);
|
||||
si->total_ext[i] = atomic64_read(&sbi->total_hit_ext[i]);
|
||||
si->hit_total[i] = si->hit_cached[i] + si->hit_rbtree[i];
|
||||
si->ext_tree[i] = atomic_read(&eti->total_ext_tree);
|
||||
si->zombie_tree[i] = atomic_read(&eti->total_zombie_tree);
|
||||
si->ext_node[i] = atomic_read(&eti->total_ext_node);
|
||||
}
|
||||
/* read extent_cache only */
|
||||
si->hit_largest = atomic64_read(&sbi->read_hit_largest);
|
||||
si->hit_cached = atomic64_read(&sbi->read_hit_cached);
|
||||
si->hit_rbtree = atomic64_read(&sbi->read_hit_rbtree);
|
||||
si->hit_total = si->hit_largest + si->hit_cached + si->hit_rbtree;
|
||||
si->total_ext = atomic64_read(&sbi->total_hit_ext);
|
||||
si->ext_tree = atomic_read(&sbi->total_ext_tree);
|
||||
si->zombie_tree = atomic_read(&sbi->total_zombie_tree);
|
||||
si->ext_node = atomic_read(&sbi->total_ext_node);
|
||||
si->hit_total[EX_READ] += si->hit_largest;
|
||||
|
||||
/* block age extent_cache only */
|
||||
si->allocated_data_blocks = atomic64_read(&sbi->allocated_data_blocks);
|
||||
|
||||
/* validation check of the segment numbers */
|
||||
si->ndirty_node = get_pages(sbi, F2FS_DIRTY_NODES);
|
||||
si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
|
||||
si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
|
||||
@@ -294,25 +305,32 @@ get_cache:
|
||||
sizeof(struct nat_entry_set);
|
||||
for (i = 0; i < MAX_INO_ENTRY; i++)
|
||||
si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry);
|
||||
si->cache_mem += atomic_read(&sbi->total_ext_tree) *
|
||||
|
||||
for (i = 0; i < NR_EXTENT_CACHES; i++) {
|
||||
struct extent_tree_info *eti = &sbi->extent_tree[i];
|
||||
|
||||
si->ext_mem[i] = atomic_read(&eti->total_ext_tree) *
|
||||
sizeof(struct extent_tree);
|
||||
si->cache_mem += atomic_read(&sbi->total_ext_node) *
|
||||
si->ext_mem[i] += atomic_read(&eti->total_ext_node) *
|
||||
sizeof(struct extent_node);
|
||||
si->cache_mem += si->ext_mem[i];
|
||||
}
|
||||
|
||||
si->page_mem = 0;
|
||||
if (sbi->node_inode) {
|
||||
unsigned npages = NODE_MAPPING(sbi)->nrpages;
|
||||
unsigned long npages = NODE_MAPPING(sbi)->nrpages;
|
||||
|
||||
si->page_mem += (unsigned long long)npages << PAGE_SHIFT;
|
||||
}
|
||||
if (sbi->meta_inode) {
|
||||
unsigned npages = META_MAPPING(sbi)->nrpages;
|
||||
unsigned long npages = META_MAPPING(sbi)->nrpages;
|
||||
|
||||
si->page_mem += (unsigned long long)npages << PAGE_SHIFT;
|
||||
}
|
||||
#ifdef CONFIG_F2FS_FS_COMPRESSION
|
||||
if (sbi->compress_inode) {
|
||||
unsigned npages = COMPRESS_MAPPING(sbi)->nrpages;
|
||||
unsigned long npages = COMPRESS_MAPPING(sbi)->nrpages;
|
||||
|
||||
si->page_mem += (unsigned long long)npages << PAGE_SHIFT;
|
||||
}
|
||||
#endif
|
||||
@@ -460,28 +478,28 @@ static int stat_show(struct seq_file *s, void *v)
|
||||
si->meta_count[META_NAT]);
|
||||
seq_printf(s, " - ssa blocks : %u\n",
|
||||
si->meta_count[META_SSA]);
|
||||
seq_printf(s, "CP merge (Queued: %4d, Issued: %4d, Total: %4d, "
|
||||
"Cur time: %4d(ms), Peak time: %4d(ms))\n",
|
||||
si->nr_queued_ckpt, si->nr_issued_ckpt,
|
||||
si->nr_total_ckpt, si->cur_ckpt_time,
|
||||
si->peak_ckpt_time);
|
||||
seq_puts(s, "CP merge:\n");
|
||||
seq_printf(s, " - Queued : %4d\n", si->nr_queued_ckpt);
|
||||
seq_printf(s, " - Issued : %4d\n", si->nr_issued_ckpt);
|
||||
seq_printf(s, " - Total : %4d\n", si->nr_total_ckpt);
|
||||
seq_printf(s, " - Cur time : %4d(ms)\n", si->cur_ckpt_time);
|
||||
seq_printf(s, " - Peak time : %4d(ms)\n", si->peak_ckpt_time);
|
||||
seq_printf(s, "GC calls: %d (BG: %d)\n",
|
||||
si->call_count, si->bg_gc);
|
||||
seq_printf(s, " - data segments : %d (%d)\n",
|
||||
si->data_segs, si->bg_data_segs);
|
||||
seq_printf(s, " - node segments : %d (%d)\n",
|
||||
si->node_segs, si->bg_node_segs);
|
||||
seq_printf(s, " - Reclaimed segs : Normal (%d), Idle CB (%d), "
|
||||
"Idle Greedy (%d), Idle AT (%d), "
|
||||
"Urgent High (%d), Urgent Mid (%d), "
|
||||
"Urgent Low (%d)\n",
|
||||
si->sbi->gc_reclaimed_segs[GC_NORMAL],
|
||||
si->sbi->gc_reclaimed_segs[GC_IDLE_CB],
|
||||
si->sbi->gc_reclaimed_segs[GC_IDLE_GREEDY],
|
||||
si->sbi->gc_reclaimed_segs[GC_IDLE_AT],
|
||||
si->sbi->gc_reclaimed_segs[GC_URGENT_HIGH],
|
||||
si->sbi->gc_reclaimed_segs[GC_URGENT_MID],
|
||||
si->sbi->gc_reclaimed_segs[GC_URGENT_LOW]);
|
||||
seq_puts(s, " - Reclaimed segs :\n");
|
||||
seq_printf(s, " - Normal : %d\n", si->sbi->gc_reclaimed_segs[GC_NORMAL]);
|
||||
seq_printf(s, " - Idle CB : %d\n", si->sbi->gc_reclaimed_segs[GC_IDLE_CB]);
|
||||
seq_printf(s, " - Idle Greedy : %d\n",
|
||||
si->sbi->gc_reclaimed_segs[GC_IDLE_GREEDY]);
|
||||
seq_printf(s, " - Idle AT : %d\n", si->sbi->gc_reclaimed_segs[GC_IDLE_AT]);
|
||||
seq_printf(s, " - Urgent High : %d\n",
|
||||
si->sbi->gc_reclaimed_segs[GC_URGENT_HIGH]);
|
||||
seq_printf(s, " - Urgent Mid : %d\n", si->sbi->gc_reclaimed_segs[GC_URGENT_MID]);
|
||||
seq_printf(s, " - Urgent Low : %d\n", si->sbi->gc_reclaimed_segs[GC_URGENT_LOW]);
|
||||
seq_printf(s, "Try to move %d blocks (BG: %d)\n", si->tot_blks,
|
||||
si->bg_data_blks + si->bg_node_blks);
|
||||
seq_printf(s, " - data blocks : %d (%d)\n", si->data_blks,
|
||||
@@ -490,26 +508,44 @@ static int stat_show(struct seq_file *s, void *v)
|
||||
si->bg_node_blks);
|
||||
seq_printf(s, "BG skip : IO: %u, Other: %u\n",
|
||||
si->io_skip_bggc, si->other_skip_bggc);
|
||||
seq_puts(s, "\nExtent Cache:\n");
|
||||
seq_puts(s, "\nExtent Cache (Read):\n");
|
||||
seq_printf(s, " - Hit Count: L1-1:%llu L1-2:%llu L2:%llu\n",
|
||||
si->hit_largest, si->hit_cached,
|
||||
si->hit_rbtree);
|
||||
si->hit_largest, si->hit_cached[EX_READ],
|
||||
si->hit_rbtree[EX_READ]);
|
||||
seq_printf(s, " - Hit Ratio: %llu%% (%llu / %llu)\n",
|
||||
!si->total_ext ? 0 :
|
||||
div64_u64(si->hit_total * 100, si->total_ext),
|
||||
si->hit_total, si->total_ext);
|
||||
!si->total_ext[EX_READ] ? 0 :
|
||||
div64_u64(si->hit_total[EX_READ] * 100,
|
||||
si->total_ext[EX_READ]),
|
||||
si->hit_total[EX_READ], si->total_ext[EX_READ]);
|
||||
seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n",
|
||||
si->ext_tree, si->zombie_tree, si->ext_node);
|
||||
si->ext_tree[EX_READ], si->zombie_tree[EX_READ],
|
||||
si->ext_node[EX_READ]);
|
||||
seq_puts(s, "\nExtent Cache (Block Age):\n");
|
||||
seq_printf(s, " - Allocated Data Blocks: %llu\n",
|
||||
si->allocated_data_blocks);
|
||||
seq_printf(s, " - Hit Count: L1:%llu L2:%llu\n",
|
||||
si->hit_cached[EX_BLOCK_AGE],
|
||||
si->hit_rbtree[EX_BLOCK_AGE]);
|
||||
seq_printf(s, " - Hit Ratio: %llu%% (%llu / %llu)\n",
|
||||
!si->total_ext[EX_BLOCK_AGE] ? 0 :
|
||||
div64_u64(si->hit_total[EX_BLOCK_AGE] * 100,
|
||||
si->total_ext[EX_BLOCK_AGE]),
|
||||
si->hit_total[EX_BLOCK_AGE],
|
||||
si->total_ext[EX_BLOCK_AGE]);
|
||||
seq_printf(s, " - Inner Struct Count: tree: %d(%d), node: %d\n",
|
||||
si->ext_tree[EX_BLOCK_AGE],
|
||||
si->zombie_tree[EX_BLOCK_AGE],
|
||||
si->ext_node[EX_BLOCK_AGE]);
|
||||
seq_puts(s, "\nBalancing F2FS Async:\n");
|
||||
seq_printf(s, " - DIO (R: %4d, W: %4d)\n",
|
||||
si->nr_dio_read, si->nr_dio_write);
|
||||
seq_printf(s, " - IO_R (Data: %4d, Node: %4d, Meta: %4d\n",
|
||||
si->nr_rd_data, si->nr_rd_node, si->nr_rd_meta);
|
||||
seq_printf(s, " - IO_W (CP: %4d, Data: %4d, Flush: (%4d %4d %4d), "
|
||||
"Discard: (%4d %4d)) cmd: %4d undiscard:%4u\n",
|
||||
seq_printf(s, " - IO_W (CP: %4d, Data: %4d, Flush: (%4d %4d %4d), ",
|
||||
si->nr_wb_cp_data, si->nr_wb_data,
|
||||
si->nr_flushing, si->nr_flushed,
|
||||
si->flush_list_empty,
|
||||
si->flush_list_empty);
|
||||
seq_printf(s, "Discard: (%4d %4d)) cmd: %4d undiscard:%4u\n",
|
||||
si->nr_discarding, si->nr_discarded,
|
||||
si->nr_discard_cmd, si->undiscard_blks);
|
||||
seq_printf(s, " - atomic IO: %4d (Max. %4d)\n",
|
||||
@@ -566,8 +602,12 @@ static int stat_show(struct seq_file *s, void *v)
|
||||
(si->base_mem + si->cache_mem + si->page_mem) >> 10);
|
||||
seq_printf(s, " - static: %llu KB\n",
|
||||
si->base_mem >> 10);
|
||||
seq_printf(s, " - cached: %llu KB\n",
|
||||
seq_printf(s, " - cached all: %llu KB\n",
|
||||
si->cache_mem >> 10);
|
||||
seq_printf(s, " - read extent cache: %llu KB\n",
|
||||
si->ext_mem[EX_READ] >> 10);
|
||||
seq_printf(s, " - block age extent cache: %llu KB\n",
|
||||
si->ext_mem[EX_BLOCK_AGE] >> 10);
|
||||
seq_printf(s, " - paged : %llu KB\n",
|
||||
si->page_mem >> 10);
|
||||
}
|
||||
@@ -600,10 +640,15 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
|
||||
si->sbi = sbi;
|
||||
sbi->stat_info = si;
|
||||
|
||||
atomic64_set(&sbi->total_hit_ext, 0);
|
||||
atomic64_set(&sbi->read_hit_rbtree, 0);
|
||||
/* general extent cache stats */
|
||||
for (i = 0; i < NR_EXTENT_CACHES; i++) {
|
||||
atomic64_set(&sbi->total_hit_ext[i], 0);
|
||||
atomic64_set(&sbi->read_hit_rbtree[i], 0);
|
||||
atomic64_set(&sbi->read_hit_cached[i], 0);
|
||||
}
|
||||
|
||||
/* read extent_cache only */
|
||||
atomic64_set(&sbi->read_hit_largest, 0);
|
||||
atomic64_set(&sbi->read_hit_cached, 0);
|
||||
|
||||
atomic_set(&sbi->inline_xattr, 0);
|
||||
atomic_set(&sbi->inline_inode, 0);
|
||||
|
||||
+25
-11
@@ -340,6 +340,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
|
||||
unsigned int bidx, end_block;
|
||||
struct page *dentry_page;
|
||||
struct f2fs_dir_entry *de = NULL;
|
||||
pgoff_t next_pgofs;
|
||||
bool room = false;
|
||||
int max_slots;
|
||||
|
||||
@@ -350,12 +351,13 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
|
||||
le32_to_cpu(fname->hash) % nbucket);
|
||||
end_block = bidx + nblock;
|
||||
|
||||
for (; bidx < end_block; bidx++) {
|
||||
while (bidx < end_block) {
|
||||
/* no need to allocate new dentry pages to all the indices */
|
||||
dentry_page = f2fs_find_data_page(dir, bidx);
|
||||
dentry_page = f2fs_find_data_page(dir, bidx, &next_pgofs);
|
||||
if (IS_ERR(dentry_page)) {
|
||||
if (PTR_ERR(dentry_page) == -ENOENT) {
|
||||
room = true;
|
||||
bidx = next_pgofs;
|
||||
continue;
|
||||
} else {
|
||||
*res_page = dentry_page;
|
||||
@@ -376,6 +378,8 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
|
||||
if (max_slots >= s)
|
||||
room = true;
|
||||
f2fs_put_page(dentry_page, 0);
|
||||
|
||||
bidx++;
|
||||
}
|
||||
|
||||
if (!de && room && F2FS_I(dir)->chash != fname->hash) {
|
||||
@@ -956,7 +960,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
|
||||
bool f2fs_empty_dir(struct inode *dir)
|
||||
{
|
||||
unsigned long bidx;
|
||||
unsigned long bidx = 0;
|
||||
struct page *dentry_page;
|
||||
unsigned int bit_pos;
|
||||
struct f2fs_dentry_block *dentry_blk;
|
||||
@@ -965,13 +969,17 @@ bool f2fs_empty_dir(struct inode *dir)
|
||||
if (f2fs_has_inline_dentry(dir))
|
||||
return f2fs_empty_inline_dir(dir);
|
||||
|
||||
for (bidx = 0; bidx < nblock; bidx++) {
|
||||
dentry_page = f2fs_get_lock_data_page(dir, bidx, false);
|
||||
while (bidx < nblock) {
|
||||
pgoff_t next_pgofs;
|
||||
|
||||
dentry_page = f2fs_find_data_page(dir, bidx, &next_pgofs);
|
||||
if (IS_ERR(dentry_page)) {
|
||||
if (PTR_ERR(dentry_page) == -ENOENT)
|
||||
if (PTR_ERR(dentry_page) == -ENOENT) {
|
||||
bidx = next_pgofs;
|
||||
continue;
|
||||
else
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
dentry_blk = page_address(dentry_page);
|
||||
@@ -983,10 +991,12 @@ bool f2fs_empty_dir(struct inode *dir)
|
||||
NR_DENTRY_IN_BLOCK,
|
||||
bit_pos);
|
||||
|
||||
f2fs_put_page(dentry_page, 1);
|
||||
f2fs_put_page(dentry_page, 0);
|
||||
|
||||
if (bit_pos < NR_DENTRY_IN_BLOCK)
|
||||
return false;
|
||||
|
||||
bidx++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1000,7 +1010,7 @@ int f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
|
||||
struct fscrypt_str de_name = FSTR_INIT(NULL, 0);
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(d->inode);
|
||||
struct blk_plug plug;
|
||||
bool readdir_ra = sbi->readdir_ra == 1;
|
||||
bool readdir_ra = sbi->readdir_ra;
|
||||
bool found_valid_dirent = false;
|
||||
int err = 0;
|
||||
|
||||
@@ -1104,7 +1114,8 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
for (; n < npages; n++, ctx->pos = n * NR_DENTRY_IN_BLOCK) {
|
||||
for (; n < npages; ctx->pos = n * NR_DENTRY_IN_BLOCK) {
|
||||
pgoff_t next_pgofs;
|
||||
|
||||
/* allow readdir() to be interrupted */
|
||||
if (fatal_signal_pending(current)) {
|
||||
@@ -1118,11 +1129,12 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
|
||||
page_cache_sync_readahead(inode->i_mapping, ra, file, n,
|
||||
min(npages - n, (pgoff_t)MAX_DIR_RA_PAGES));
|
||||
|
||||
dentry_page = f2fs_find_data_page(inode, n);
|
||||
dentry_page = f2fs_find_data_page(inode, n, &next_pgofs);
|
||||
if (IS_ERR(dentry_page)) {
|
||||
err = PTR_ERR(dentry_page);
|
||||
if (err == -ENOENT) {
|
||||
err = 0;
|
||||
n = next_pgofs;
|
||||
continue;
|
||||
} else {
|
||||
goto out_free;
|
||||
@@ -1141,6 +1153,8 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
|
||||
}
|
||||
|
||||
f2fs_put_page(dentry_page, 0);
|
||||
|
||||
n++;
|
||||
}
|
||||
out_free:
|
||||
fscrypt_fname_free_buffer(&fstr);
|
||||
|
||||
+514
-187
File diff suppressed because it is too large.
Load diff
+154
-128
File diff suppressed because it is too large.
Load diff
+32
-14
@@ -571,7 +571,7 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
|
||||
raw_node = F2FS_NODE(dn->node_page);
|
||||
addr = blkaddr_in_node(raw_node) + base + ofs;
|
||||
|
||||
/* Assumption: truncateion starts with cluster */
|
||||
/* Assumption: truncation starts with cluster */
|
||||
for (; count > 0; count--, addr++, dn->ofs_in_node++, cluster_index++) {
|
||||
block_t blkaddr = le32_to_cpu(*addr);
|
||||
|
||||
@@ -618,7 +618,8 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count)
|
||||
*/
|
||||
fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page),
|
||||
dn->inode) + ofs;
|
||||
f2fs_update_extent_cache_range(dn, fofs, 0, len);
|
||||
f2fs_update_read_extent_cache_range(dn, fofs, 0, len);
|
||||
f2fs_update_age_extent_cache_range(dn, fofs, nr_free);
|
||||
dec_valid_block_count(sbi, dn->inode, nr_free);
|
||||
}
|
||||
dn->ofs_in_node = ofs;
|
||||
@@ -1496,7 +1497,7 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start,
|
||||
f2fs_set_data_blkaddr(dn);
|
||||
}
|
||||
|
||||
f2fs_update_extent_cache_range(dn, start, 0, index - start);
|
||||
f2fs_update_read_extent_cache_range(dn, start, 0, index - start);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1915,6 +1916,10 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
|
||||
if (!f2fs_disable_compressed_file(inode))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
/* try to convert inline_data to support compression */
|
||||
int err = f2fs_convert_inline_inode(inode);
|
||||
if (err)
|
||||
return err;
|
||||
if (!f2fs_may_compress(inode))
|
||||
return -EINVAL;
|
||||
if (S_ISREG(inode->i_mode) && F2FS_HAS_BLOCKS(inode))
|
||||
@@ -2030,13 +2035,14 @@ static int f2fs_ioc_getversion(struct file *filp, unsigned long arg)
|
||||
return put_user(inode->i_generation, (int __user *)arg);
|
||||
}
|
||||
|
||||
static int f2fs_ioc_start_atomic_write(struct file *filp)
|
||||
static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
|
||||
{
|
||||
struct inode *inode = file_inode(filp);
|
||||
struct user_namespace *mnt_userns = file_mnt_user_ns(filp);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct inode *pinode;
|
||||
loff_t isize;
|
||||
int ret;
|
||||
|
||||
if (!inode_owner_or_capable(mnt_userns, inode))
|
||||
@@ -2095,13 +2101,25 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
|
||||
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
||||
goto out;
|
||||
}
|
||||
f2fs_i_size_write(fi->cow_inode, i_size_read(inode));
|
||||
|
||||
f2fs_write_inode(inode, NULL);
|
||||
|
||||
stat_inc_atomic_inode(inode);
|
||||
|
||||
set_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
set_inode_flag(fi->cow_inode, FI_COW_FILE);
|
||||
clear_inode_flag(fi->cow_inode, FI_INLINE_DATA);
|
||||
|
||||
isize = i_size_read(inode);
|
||||
fi->original_i_size = isize;
|
||||
if (truncate) {
|
||||
set_inode_flag(inode, FI_ATOMIC_REPLACE);
|
||||
truncate_inode_pages_final(inode->i_mapping);
|
||||
f2fs_i_size_write(inode, 0);
|
||||
isize = 0;
|
||||
}
|
||||
f2fs_i_size_write(fi->cow_inode, isize);
|
||||
|
||||
f2fs_up_write(&fi->i_gc_rwsem[WRITE]);
|
||||
|
||||
f2fs_update_time(sbi, REQ_TIME);
|
||||
@@ -2133,16 +2151,14 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp)
|
||||
|
||||
if (f2fs_is_atomic_file(inode)) {
|
||||
ret = f2fs_commit_atomic_write(inode);
|
||||
if (ret)
|
||||
goto unlock_out;
|
||||
|
||||
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
|
||||
if (!ret)
|
||||
f2fs_abort_atomic_write(inode, false);
|
||||
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 0, true);
|
||||
|
||||
f2fs_abort_atomic_write(inode, ret);
|
||||
} else {
|
||||
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
|
||||
}
|
||||
unlock_out:
|
||||
|
||||
inode_unlock(inode);
|
||||
mnt_drop_write_file(filp);
|
||||
return ret;
|
||||
@@ -2543,7 +2559,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
|
||||
struct f2fs_map_blocks map = { .m_next_extent = NULL,
|
||||
.m_seg_type = NO_CHECK_TYPE,
|
||||
.m_may_create = false };
|
||||
struct extent_info ei = {0, 0, 0};
|
||||
struct extent_info ei = {0, };
|
||||
pgoff_t pg_start, pg_end, next_pgofs;
|
||||
unsigned int blk_per_seg = sbi->blocks_per_seg;
|
||||
unsigned int total = 0, sec_num;
|
||||
@@ -2575,7 +2591,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
|
||||
* lookup mapping info in extent cache, skip defragmenting if physical
|
||||
* block addresses are continuous.
|
||||
*/
|
||||
if (f2fs_lookup_extent_cache(inode, pg_start, &ei)) {
|
||||
if (f2fs_lookup_read_extent_cache(inode, pg_start, &ei)) {
|
||||
if (ei.fofs + ei.len >= pg_end)
|
||||
goto out;
|
||||
}
|
||||
@@ -4131,7 +4147,9 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
case FS_IOC_GETVERSION:
|
||||
return f2fs_ioc_getversion(filp, arg);
|
||||
case F2FS_IOC_START_ATOMIC_WRITE:
|
||||
return f2fs_ioc_start_atomic_write(filp);
|
||||
return f2fs_ioc_start_atomic_write(filp, false);
|
||||
case F2FS_IOC_START_ATOMIC_REPLACE:
|
||||
return f2fs_ioc_start_atomic_write(filp, true);
|
||||
case F2FS_IOC_COMMIT_ATOMIC_WRITE:
|
||||
return f2fs_ioc_commit_atomic_write(filp);
|
||||
case F2FS_IOC_ABORT_ATOMIC_WRITE:
|
||||
|
||||
+43
-36
@@ -96,16 +96,6 @@ static int gc_thread_func(void *data)
|
||||
* invalidated soon after by user update or deletion.
|
||||
* So, I'd like to wait some time to collect dirty segments.
|
||||
*/
|
||||
if (sbi->gc_mode == GC_URGENT_HIGH) {
|
||||
spin_lock(&sbi->gc_urgent_high_lock);
|
||||
if (sbi->gc_urgent_high_remaining) {
|
||||
sbi->gc_urgent_high_remaining--;
|
||||
if (!sbi->gc_urgent_high_remaining)
|
||||
sbi->gc_mode = GC_NORMAL;
|
||||
}
|
||||
spin_unlock(&sbi->gc_urgent_high_lock);
|
||||
}
|
||||
|
||||
if (sbi->gc_mode == GC_URGENT_HIGH ||
|
||||
sbi->gc_mode == GC_URGENT_MID) {
|
||||
wait_ms = gc_th->urgent_sleep_time;
|
||||
@@ -151,6 +141,10 @@ do_gc:
|
||||
/* don't bother wait_ms by foreground gc */
|
||||
if (!foreground)
|
||||
wait_ms = gc_th->no_gc_sleep_time;
|
||||
} else {
|
||||
/* reset wait_ms to default sleep time */
|
||||
if (wait_ms == gc_th->no_gc_sleep_time)
|
||||
wait_ms = gc_th->min_sleep_time;
|
||||
}
|
||||
|
||||
if (foreground)
|
||||
@@ -162,6 +156,15 @@ do_gc:
|
||||
/* balancing f2fs's metadata periodically */
|
||||
f2fs_balance_fs_bg(sbi, true);
|
||||
next:
|
||||
if (sbi->gc_mode != GC_NORMAL) {
|
||||
spin_lock(&sbi->gc_remaining_trials_lock);
|
||||
if (sbi->gc_remaining_trials) {
|
||||
sbi->gc_remaining_trials--;
|
||||
if (!sbi->gc_remaining_trials)
|
||||
sbi->gc_mode = GC_NORMAL;
|
||||
}
|
||||
spin_unlock(&sbi->gc_remaining_trials_lock);
|
||||
}
|
||||
sb_end_write(sbi->sb);
|
||||
|
||||
} while (!kthread_should_stop());
|
||||
@@ -172,13 +175,10 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
struct f2fs_gc_kthread *gc_th;
|
||||
dev_t dev = sbi->sb->s_bdev->bd_dev;
|
||||
int err = 0;
|
||||
|
||||
gc_th = f2fs_kmalloc(sbi, sizeof(struct f2fs_gc_kthread), GFP_KERNEL);
|
||||
if (!gc_th) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (!gc_th)
|
||||
return -ENOMEM;
|
||||
|
||||
gc_th->urgent_sleep_time = DEF_GC_THREAD_URGENT_SLEEP_TIME;
|
||||
gc_th->min_sleep_time = DEF_GC_THREAD_MIN_SLEEP_TIME;
|
||||
@@ -193,12 +193,14 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi)
|
||||
sbi->gc_thread->f2fs_gc_task = kthread_run(gc_thread_func, sbi,
|
||||
"f2fs_gc-%u:%u", MAJOR(dev), MINOR(dev));
|
||||
if (IS_ERR(gc_th->f2fs_gc_task)) {
|
||||
err = PTR_ERR(gc_th->f2fs_gc_task);
|
||||
int err = PTR_ERR(gc_th->f2fs_gc_task);
|
||||
|
||||
kfree(gc_th);
|
||||
sbi->gc_thread = NULL;
|
||||
return err;
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void f2fs_stop_gc_thread(struct f2fs_sb_info *sbi)
|
||||
@@ -1079,7 +1081,7 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
{
|
||||
struct page *node_page;
|
||||
nid_t nid;
|
||||
unsigned int ofs_in_node, max_addrs;
|
||||
unsigned int ofs_in_node, max_addrs, base;
|
||||
block_t source_blkaddr;
|
||||
|
||||
nid = le32_to_cpu(sum->nid);
|
||||
@@ -1105,11 +1107,18 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
return false;
|
||||
}
|
||||
|
||||
max_addrs = IS_INODE(node_page) ? DEF_ADDRS_PER_INODE :
|
||||
DEF_ADDRS_PER_BLOCK;
|
||||
if (ofs_in_node >= max_addrs) {
|
||||
f2fs_err(sbi, "Inconsistent ofs_in_node:%u in summary, ino:%u, nid:%u, max:%u",
|
||||
ofs_in_node, dni->ino, dni->nid, max_addrs);
|
||||
if (IS_INODE(node_page)) {
|
||||
base = offset_in_addr(F2FS_INODE(node_page));
|
||||
max_addrs = DEF_ADDRS_PER_INODE;
|
||||
} else {
|
||||
base = 0;
|
||||
max_addrs = DEF_ADDRS_PER_BLOCK;
|
||||
}
|
||||
|
||||
if (base + ofs_in_node >= max_addrs) {
|
||||
f2fs_err(sbi, "Inconsistent blkaddr offset: base:%u, ofs_in_node:%u, max:%u, ino:%u, nid:%u",
|
||||
base, ofs_in_node, max_addrs, dni->ino, dni->nid);
|
||||
f2fs_put_page(node_page, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1141,7 +1150,7 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct dnode_of_data dn;
|
||||
struct page *page;
|
||||
struct extent_info ei = {0, 0, 0};
|
||||
struct extent_info ei = {0, };
|
||||
struct f2fs_io_info fio = {
|
||||
.sbi = sbi,
|
||||
.ino = inode->i_ino,
|
||||
@@ -1159,7 +1168,7 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
if (f2fs_lookup_extent_cache(inode, index, &ei)) {
|
||||
if (f2fs_lookup_read_extent_cache(inode, index, &ei)) {
|
||||
dn.data_blkaddr = ei.blk + index - ei.fofs;
|
||||
if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr,
|
||||
DATA_GENERIC_ENHANCE_READ))) {
|
||||
@@ -1563,8 +1572,8 @@ next_step:
|
||||
continue;
|
||||
}
|
||||
|
||||
data_page = f2fs_get_read_data_page(inode,
|
||||
start_bidx, REQ_RAHEAD, true);
|
||||
data_page = f2fs_get_read_data_page(inode, start_bidx,
|
||||
REQ_RAHEAD, true, NULL);
|
||||
f2fs_up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
if (IS_ERR(data_page)) {
|
||||
iput(inode);
|
||||
@@ -1744,8 +1753,9 @@ freed:
|
||||
get_valid_blocks(sbi, segno, false) == 0)
|
||||
seg_freed++;
|
||||
|
||||
if (__is_large_section(sbi) && segno + 1 < end_segno)
|
||||
sbi->next_victim_seg[gc_type] = segno + 1;
|
||||
if (__is_large_section(sbi))
|
||||
sbi->next_victim_seg[gc_type] =
|
||||
(segno + 1 < end_segno) ? segno + 1 : NULL_SEGNO;
|
||||
skip:
|
||||
f2fs_put_page(sum_page, 0);
|
||||
}
|
||||
@@ -1898,9 +1908,7 @@ int __init f2fs_create_garbage_collection_cache(void)
|
||||
{
|
||||
victim_entry_slab = f2fs_kmem_cache_create("f2fs_victim_entry",
|
||||
sizeof(struct victim_entry));
|
||||
if (!victim_entry_slab)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
return victim_entry_slab ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void f2fs_destroy_garbage_collection_cache(void)
|
||||
@@ -2133,8 +2141,6 @@ out_unlock:
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
set_sbi_flag(sbi, SBI_IS_RESIZEFS);
|
||||
|
||||
freeze_super(sbi->sb);
|
||||
f2fs_down_write(&sbi->gc_lock);
|
||||
f2fs_down_write(&sbi->cp_global_sem);
|
||||
@@ -2150,6 +2156,7 @@ out_unlock:
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
set_sbi_flag(sbi, SBI_IS_RESIZEFS);
|
||||
err = free_segment_range(sbi, secs, false);
|
||||
if (err)
|
||||
goto recover_out;
|
||||
@@ -2173,6 +2180,7 @@ out_unlock:
|
||||
f2fs_commit_super(sbi, false);
|
||||
}
|
||||
recover_out:
|
||||
clear_sbi_flag(sbi, SBI_IS_RESIZEFS);
|
||||
if (err) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_err(sbi, "resize_fs failed, should run fsck to repair!");
|
||||
@@ -2185,6 +2193,5 @@ out_err:
|
||||
f2fs_up_write(&sbi->cp_global_sem);
|
||||
f2fs_up_write(&sbi->gc_lock);
|
||||
thaw_super(sbi->sb);
|
||||
clear_sbi_flag(sbi, SBI_IS_RESIZEFS);
|
||||
return err;
|
||||
}
|
||||
+13
-7
@@ -262,8 +262,8 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fi->extent_tree) {
|
||||
struct extent_info *ei = &fi->extent_tree->largest;
|
||||
if (fi->extent_tree[EX_READ]) {
|
||||
struct extent_info *ei = &fi->extent_tree[EX_READ]->largest;
|
||||
|
||||
if (ei->len &&
|
||||
(!f2fs_is_valid_blkaddr(sbi, ei->blk,
|
||||
@@ -392,8 +392,6 @@ static int do_read_inode(struct inode *inode)
|
||||
fi->i_pino = le32_to_cpu(ri->i_pino);
|
||||
fi->i_dir_level = ri->i_dir_level;
|
||||
|
||||
f2fs_init_extent_tree(inode, node_page);
|
||||
|
||||
get_inline_info(inode, ri);
|
||||
|
||||
fi->i_extra_isize = f2fs_has_extra_attr(inode) ?
|
||||
@@ -479,6 +477,11 @@ static int do_read_inode(struct inode *inode)
|
||||
}
|
||||
|
||||
init_idisk_time(inode);
|
||||
|
||||
/* Need all the flag bits */
|
||||
f2fs_init_read_extent_tree(inode, node_page);
|
||||
f2fs_init_age_extent_tree(inode);
|
||||
|
||||
f2fs_put_page(node_page, 1);
|
||||
|
||||
stat_inc_inline_xattr(inode);
|
||||
@@ -607,7 +610,7 @@ retry:
|
||||
void f2fs_update_inode(struct inode *inode, struct page *node_page)
|
||||
{
|
||||
struct f2fs_inode *ri;
|
||||
struct extent_tree *et = F2FS_I(inode)->extent_tree;
|
||||
struct extent_tree *et = F2FS_I(inode)->extent_tree[EX_READ];
|
||||
|
||||
f2fs_wait_on_page_writeback(node_page, NODE, true, true);
|
||||
set_page_dirty(node_page);
|
||||
@@ -621,12 +624,15 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page)
|
||||
ri->i_uid = cpu_to_le32(i_uid_read(inode));
|
||||
ri->i_gid = cpu_to_le32(i_gid_read(inode));
|
||||
ri->i_links = cpu_to_le32(inode->i_nlink);
|
||||
ri->i_size = cpu_to_le64(i_size_read(inode));
|
||||
ri->i_blocks = cpu_to_le64(SECTOR_TO_BLOCK(inode->i_blocks) + 1);
|
||||
|
||||
if (!f2fs_is_atomic_file(inode) ||
|
||||
is_inode_flag_set(inode, FI_ATOMIC_COMMITTED))
|
||||
ri->i_size = cpu_to_le64(i_size_read(inode));
|
||||
|
||||
if (et) {
|
||||
read_lock(&et->lock);
|
||||
set_raw_extent(&et->largest, &ri->i_ext);
|
||||
set_raw_read_extent(&et->largest, &ri->i_ext);
|
||||
read_unlock(&et->lock);
|
||||
} else {
|
||||
memset(&ri->i_ext, 0, sizeof(ri->i_ext));
|
||||
|
||||
+196
-203
@@ -22,8 +22,189 @@
|
||||
#include "acl.h"
|
||||
#include <trace/events/f2fs.h>
|
||||
|
||||
static inline int is_extension_exist(const unsigned char *s, const char *sub,
|
||||
bool tmp_ext)
|
||||
{
|
||||
size_t slen = strlen(s);
|
||||
size_t sublen = strlen(sub);
|
||||
int i;
|
||||
|
||||
if (sublen == 1 && *sub == '*')
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* filename format of multimedia file should be defined as:
|
||||
* "filename + '.' + extension + (optional: '.' + temp extension)".
|
||||
*/
|
||||
if (slen < sublen + 2)
|
||||
return 0;
|
||||
|
||||
if (!tmp_ext) {
|
||||
/* file has no temp extension */
|
||||
if (s[slen - sublen - 1] != '.')
|
||||
return 0;
|
||||
return !strncasecmp(s + slen - sublen, sub, sublen);
|
||||
}
|
||||
|
||||
for (i = 1; i < slen - sublen; i++) {
|
||||
if (s[i] != '.')
|
||||
continue;
|
||||
if (!strncasecmp(s + i + 1, sub, sublen))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
|
||||
bool hot, bool set)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
int hot_count = sbi->raw_super->hot_ext_count;
|
||||
int total_count = cold_count + hot_count;
|
||||
int start, count;
|
||||
int i;
|
||||
|
||||
if (set) {
|
||||
if (total_count == F2FS_MAX_EXTENSION)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (!hot && !cold_count)
|
||||
return -EINVAL;
|
||||
if (hot && !hot_count)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hot) {
|
||||
start = cold_count;
|
||||
count = total_count;
|
||||
} else {
|
||||
start = 0;
|
||||
count = cold_count;
|
||||
}
|
||||
|
||||
for (i = start; i < count; i++) {
|
||||
if (strcmp(name, extlist[i]))
|
||||
continue;
|
||||
|
||||
if (set)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(extlist[i], extlist[i + 1],
|
||||
F2FS_EXTENSION_LEN * (total_count - i - 1));
|
||||
memset(extlist[total_count - 1], 0, F2FS_EXTENSION_LEN);
|
||||
if (hot)
|
||||
sbi->raw_super->hot_ext_count = hot_count - 1;
|
||||
else
|
||||
sbi->raw_super->extension_count =
|
||||
cpu_to_le32(cold_count - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!set)
|
||||
return -EINVAL;
|
||||
|
||||
if (hot) {
|
||||
memcpy(extlist[count], name, strlen(name));
|
||||
sbi->raw_super->hot_ext_count = hot_count + 1;
|
||||
} else {
|
||||
char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];
|
||||
|
||||
memcpy(buf, &extlist[cold_count],
|
||||
F2FS_EXTENSION_LEN * hot_count);
|
||||
memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN);
|
||||
memcpy(extlist[cold_count], name, strlen(name));
|
||||
memcpy(&extlist[cold_count + 1], buf,
|
||||
F2FS_EXTENSION_LEN * hot_count);
|
||||
sbi->raw_super->extension_count = cpu_to_le32(cold_count + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_compress_new_inode(struct f2fs_sb_info *sbi, struct inode *dir,
|
||||
struct inode *inode, const unsigned char *name)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
unsigned char (*noext)[F2FS_EXTENSION_LEN] =
|
||||
F2FS_OPTION(sbi).noextensions;
|
||||
unsigned char (*ext)[F2FS_EXTENSION_LEN] = F2FS_OPTION(sbi).extensions;
|
||||
unsigned char ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
|
||||
unsigned char noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
|
||||
int i, cold_count, hot_count;
|
||||
|
||||
if (!f2fs_sb_has_compression(sbi))
|
||||
return;
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
goto inherit_comp;
|
||||
|
||||
/* This name comes only from normal files. */
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
/* Don't compress hot files. */
|
||||
f2fs_down_read(&sbi->sb_lock);
|
||||
cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
hot_count = sbi->raw_super->hot_ext_count;
|
||||
for (i = cold_count; i < cold_count + hot_count; i++)
|
||||
if (is_extension_exist(name, extlist[i], false))
|
||||
break;
|
||||
f2fs_up_read(&sbi->sb_lock);
|
||||
if (i < (cold_count + hot_count))
|
||||
return;
|
||||
|
||||
/* Don't compress unallowed extension. */
|
||||
for (i = 0; i < noext_cnt; i++)
|
||||
if (is_extension_exist(name, noext[i], false))
|
||||
return;
|
||||
|
||||
/* Compress wanting extension. */
|
||||
for (i = 0; i < ext_cnt; i++) {
|
||||
if (is_extension_exist(name, ext[i], false)) {
|
||||
set_compress_context(inode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
inherit_comp:
|
||||
/* Inherit the {no-}compression flag in directory */
|
||||
if (F2FS_I(dir)->i_flags & F2FS_NOCOMP_FL) {
|
||||
F2FS_I(inode)->i_flags |= F2FS_NOCOMP_FL;
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
} else if (F2FS_I(dir)->i_flags & F2FS_COMPR_FL) {
|
||||
set_compress_context(inode);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set file's temperature for hot/cold data separation
|
||||
*/
|
||||
static void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
const unsigned char *name)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
int i, cold_count, hot_count;
|
||||
|
||||
f2fs_down_read(&sbi->sb_lock);
|
||||
cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
hot_count = sbi->raw_super->hot_ext_count;
|
||||
for (i = 0; i < cold_count + hot_count; i++)
|
||||
if (is_extension_exist(name, extlist[i], true))
|
||||
break;
|
||||
f2fs_up_read(&sbi->sb_lock);
|
||||
|
||||
if (i == cold_count + hot_count)
|
||||
return;
|
||||
|
||||
if (i < cold_count)
|
||||
file_set_cold(inode);
|
||||
else
|
||||
file_set_hot(inode);
|
||||
}
|
||||
|
||||
static struct inode *f2fs_new_inode(struct user_namespace *mnt_userns,
|
||||
struct inode *dir, umode_t mode)
|
||||
struct inode *dir, umode_t mode,
|
||||
const char *name)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
|
||||
nid_t ino;
|
||||
@@ -103,8 +284,6 @@ static struct inode *f2fs_new_inode(struct user_namespace *mnt_userns,
|
||||
}
|
||||
F2FS_I(inode)->i_inline_xattr_size = xattr_size;
|
||||
|
||||
f2fs_init_extent_tree(inode, NULL);
|
||||
|
||||
F2FS_I(inode)->i_flags =
|
||||
f2fs_mask_flags(mode, F2FS_I(dir)->i_flags & F2FS_FL_INHERITED);
|
||||
|
||||
@@ -114,23 +293,24 @@ static struct inode *f2fs_new_inode(struct user_namespace *mnt_userns,
|
||||
if (F2FS_I(inode)->i_flags & F2FS_PROJINHERIT_FL)
|
||||
set_inode_flag(inode, FI_PROJ_INHERIT);
|
||||
|
||||
if (f2fs_sb_has_compression(sbi)) {
|
||||
/* Inherit the compression flag in directory */
|
||||
if ((F2FS_I(dir)->i_flags & F2FS_COMPR_FL) &&
|
||||
f2fs_may_compress(inode))
|
||||
set_compress_context(inode);
|
||||
}
|
||||
/* Check compression first. */
|
||||
set_compress_new_inode(sbi, dir, inode, name);
|
||||
|
||||
/* Should enable inline_data after compression set */
|
||||
if (test_opt(sbi, INLINE_DATA) && f2fs_may_inline_data(inode))
|
||||
set_inode_flag(inode, FI_INLINE_DATA);
|
||||
|
||||
if (name && !test_opt(sbi, DISABLE_EXT_IDENTIFY))
|
||||
set_file_temperature(sbi, inode, name);
|
||||
|
||||
stat_inc_inline_xattr(inode);
|
||||
stat_inc_inline_inode(inode);
|
||||
stat_inc_inline_dir(inode);
|
||||
|
||||
f2fs_set_inode_flags(inode);
|
||||
|
||||
f2fs_init_extent_tree(inode);
|
||||
|
||||
trace_f2fs_new_inode(inode, 0);
|
||||
return inode;
|
||||
|
||||
@@ -153,188 +333,6 @@ fail_drop:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static inline int is_extension_exist(const unsigned char *s, const char *sub,
|
||||
bool tmp_ext)
|
||||
{
|
||||
size_t slen = strlen(s);
|
||||
size_t sublen = strlen(sub);
|
||||
int i;
|
||||
|
||||
if (sublen == 1 && *sub == '*')
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* filename format of multimedia file should be defined as:
|
||||
* "filename + '.' + extension + (optional: '.' + temp extension)".
|
||||
*/
|
||||
if (slen < sublen + 2)
|
||||
return 0;
|
||||
|
||||
if (!tmp_ext) {
|
||||
/* file has no temp extension */
|
||||
if (s[slen - sublen - 1] != '.')
|
||||
return 0;
|
||||
return !strncasecmp(s + slen - sublen, sub, sublen);
|
||||
}
|
||||
|
||||
for (i = 1; i < slen - sublen; i++) {
|
||||
if (s[i] != '.')
|
||||
continue;
|
||||
if (!strncasecmp(s + i + 1, sub, sublen))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set file's temperature for hot/cold data separation
|
||||
*/
|
||||
static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
const unsigned char *name)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
int i, cold_count, hot_count;
|
||||
|
||||
f2fs_down_read(&sbi->sb_lock);
|
||||
|
||||
cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
hot_count = sbi->raw_super->hot_ext_count;
|
||||
|
||||
for (i = 0; i < cold_count + hot_count; i++) {
|
||||
if (is_extension_exist(name, extlist[i], true))
|
||||
break;
|
||||
}
|
||||
|
||||
f2fs_up_read(&sbi->sb_lock);
|
||||
|
||||
if (i == cold_count + hot_count)
|
||||
return;
|
||||
|
||||
if (i < cold_count)
|
||||
file_set_cold(inode);
|
||||
else
|
||||
file_set_hot(inode);
|
||||
}
|
||||
|
||||
int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
|
||||
bool hot, bool set)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
int hot_count = sbi->raw_super->hot_ext_count;
|
||||
int total_count = cold_count + hot_count;
|
||||
int start, count;
|
||||
int i;
|
||||
|
||||
if (set) {
|
||||
if (total_count == F2FS_MAX_EXTENSION)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (!hot && !cold_count)
|
||||
return -EINVAL;
|
||||
if (hot && !hot_count)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hot) {
|
||||
start = cold_count;
|
||||
count = total_count;
|
||||
} else {
|
||||
start = 0;
|
||||
count = cold_count;
|
||||
}
|
||||
|
||||
for (i = start; i < count; i++) {
|
||||
if (strcmp(name, extlist[i]))
|
||||
continue;
|
||||
|
||||
if (set)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(extlist[i], extlist[i + 1],
|
||||
F2FS_EXTENSION_LEN * (total_count - i - 1));
|
||||
memset(extlist[total_count - 1], 0, F2FS_EXTENSION_LEN);
|
||||
if (hot)
|
||||
sbi->raw_super->hot_ext_count = hot_count - 1;
|
||||
else
|
||||
sbi->raw_super->extension_count =
|
||||
cpu_to_le32(cold_count - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!set)
|
||||
return -EINVAL;
|
||||
|
||||
if (hot) {
|
||||
memcpy(extlist[count], name, strlen(name));
|
||||
sbi->raw_super->hot_ext_count = hot_count + 1;
|
||||
} else {
|
||||
char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];
|
||||
|
||||
memcpy(buf, &extlist[cold_count],
|
||||
F2FS_EXTENSION_LEN * hot_count);
|
||||
memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN);
|
||||
memcpy(extlist[cold_count], name, strlen(name));
|
||||
memcpy(&extlist[cold_count + 1], buf,
|
||||
F2FS_EXTENSION_LEN * hot_count);
|
||||
sbi->raw_super->extension_count = cpu_to_le32(cold_count + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_compress_inode(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
const unsigned char *name)
|
||||
{
|
||||
__u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
|
||||
unsigned char (*noext)[F2FS_EXTENSION_LEN] = F2FS_OPTION(sbi).noextensions;
|
||||
unsigned char (*ext)[F2FS_EXTENSION_LEN] = F2FS_OPTION(sbi).extensions;
|
||||
unsigned char ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
|
||||
unsigned char noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
|
||||
int i, cold_count, hot_count;
|
||||
|
||||
if (!f2fs_sb_has_compression(sbi) ||
|
||||
F2FS_I(inode)->i_flags & F2FS_NOCOMP_FL ||
|
||||
!f2fs_may_compress(inode) ||
|
||||
(!ext_cnt && !noext_cnt))
|
||||
return;
|
||||
|
||||
f2fs_down_read(&sbi->sb_lock);
|
||||
|
||||
cold_count = le32_to_cpu(sbi->raw_super->extension_count);
|
||||
hot_count = sbi->raw_super->hot_ext_count;
|
||||
|
||||
for (i = cold_count; i < cold_count + hot_count; i++) {
|
||||
if (is_extension_exist(name, extlist[i], false)) {
|
||||
f2fs_up_read(&sbi->sb_lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
f2fs_up_read(&sbi->sb_lock);
|
||||
|
||||
for (i = 0; i < noext_cnt; i++) {
|
||||
if (is_extension_exist(name, noext[i], false)) {
|
||||
f2fs_disable_compressed_file(inode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_inode_flag_set(inode, FI_COMPRESSED_FILE))
|
||||
return;
|
||||
|
||||
for (i = 0; i < ext_cnt; i++) {
|
||||
if (!is_extension_exist(name, ext[i], false))
|
||||
continue;
|
||||
|
||||
/* Do not use inline_data with compression */
|
||||
stat_dec_inline_inode(inode);
|
||||
clear_inode_flag(inode, FI_INLINE_DATA);
|
||||
set_compress_context(inode);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int f2fs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl)
|
||||
{
|
||||
@@ -352,15 +350,10 @@ static int f2fs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode = f2fs_new_inode(mnt_userns, dir, mode);
|
||||
inode = f2fs_new_inode(mnt_userns, dir, mode, dentry->d_name.name);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
if (!test_opt(sbi, DISABLE_EXT_IDENTIFY))
|
||||
set_file_temperature(sbi, inode, dentry->d_name.name);
|
||||
|
||||
set_compress_inode(sbi, inode, dentry->d_name.name);
|
||||
|
||||
inode->i_op = &f2fs_file_inode_operations;
|
||||
inode->i_fop = &f2fs_file_operations;
|
||||
inode->i_mapping->a_ops = &f2fs_dblock_aops;
|
||||
@@ -632,6 +625,8 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
goto fail;
|
||||
}
|
||||
f2fs_delete_entry(de, page, dir, inode);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
#if IS_ENABLED(CONFIG_UNICODE)
|
||||
/* VFS negative dentries are incompatible with Encoding and
|
||||
* Case-insensitiveness. Eventually we'll want avoid
|
||||
@@ -642,8 +637,6 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
if (IS_CASEFOLDED(dir))
|
||||
d_invalidate(dentry);
|
||||
#endif
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
if (IS_DIRSYNC(dir))
|
||||
f2fs_sync_fs(sbi->sb, 1);
|
||||
fail:
|
||||
@@ -689,7 +682,7 @@ static int f2fs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode = f2fs_new_inode(mnt_userns, dir, S_IFLNK | S_IRWXUGO);
|
||||
inode = f2fs_new_inode(mnt_userns, dir, S_IFLNK | S_IRWXUGO, NULL);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
@@ -760,7 +753,7 @@ static int f2fs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode = f2fs_new_inode(mnt_userns, dir, S_IFDIR | mode);
|
||||
inode = f2fs_new_inode(mnt_userns, dir, S_IFDIR | mode, NULL);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
@@ -817,7 +810,7 @@ static int f2fs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode = f2fs_new_inode(mnt_userns, dir, mode);
|
||||
inode = f2fs_new_inode(mnt_userns, dir, mode, NULL);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
@@ -856,7 +849,7 @@ static int __f2fs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
inode = f2fs_new_inode(mnt_userns, dir, mode);
|
||||
inode = f2fs_new_inode(mnt_userns, dir, mode, NULL);
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
|
||||
+11
-8
@@ -60,7 +60,7 @@ bool f2fs_available_free_memory(struct f2fs_sb_info *sbi, int type)
|
||||
avail_ram = val.totalram - val.totalhigh;
|
||||
|
||||
/*
|
||||
* give 25%, 25%, 50%, 50%, 50% memory for each components respectively
|
||||
* give 25%, 25%, 50%, 50%, 25%, 25% memory for each components respectively
|
||||
*/
|
||||
if (type == FREE_NIDS) {
|
||||
mem_size = (nm_i->nid_cnt[FREE_NID] *
|
||||
@@ -85,12 +85,16 @@ bool f2fs_available_free_memory(struct f2fs_sb_info *sbi, int type)
|
||||
sizeof(struct ino_entry);
|
||||
mem_size >>= PAGE_SHIFT;
|
||||
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
|
||||
} else if (type == EXTENT_CACHE) {
|
||||
mem_size = (atomic_read(&sbi->total_ext_tree) *
|
||||
} else if (type == READ_EXTENT_CACHE || type == AGE_EXTENT_CACHE) {
|
||||
enum extent_type etype = type == READ_EXTENT_CACHE ?
|
||||
EX_READ : EX_BLOCK_AGE;
|
||||
struct extent_tree_info *eti = &sbi->extent_tree[etype];
|
||||
|
||||
mem_size = (atomic_read(&eti->total_ext_tree) *
|
||||
sizeof(struct extent_tree) +
|
||||
atomic_read(&sbi->total_ext_node) *
|
||||
atomic_read(&eti->total_ext_node) *
|
||||
sizeof(struct extent_node)) >> PAGE_SHIFT;
|
||||
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
|
||||
res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);
|
||||
} else if (type == DISCARD_CACHE) {
|
||||
mem_size = (atomic_read(&dcc->discard_cmd_cnt) *
|
||||
sizeof(struct discard_cmd)) >> PAGE_SHIFT;
|
||||
@@ -859,7 +863,7 @@ int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode)
|
||||
blkaddr = data_blkaddr(dn->inode, dn->node_page,
|
||||
dn->ofs_in_node + 1);
|
||||
|
||||
f2fs_update_extent_tree_range_compressed(dn->inode,
|
||||
f2fs_update_read_extent_tree_range_compressed(dn->inode,
|
||||
index, blkaddr,
|
||||
F2FS_I(dn->inode)->i_cluster_size,
|
||||
c_len);
|
||||
@@ -1360,8 +1364,7 @@ static int read_node_page(struct page *page, blk_opf_t op_flags)
|
||||
return err;
|
||||
|
||||
/* NEW_ADDR can be seen, after cp_error drops some dirty node pages */
|
||||
if (unlikely(ni.blk_addr == NULL_ADDR || ni.blk_addr == NEW_ADDR) ||
|
||||
is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN)) {
|
||||
if (unlikely(ni.blk_addr == NULL_ADDR || ni.blk_addr == NEW_ADDR)) {
|
||||
ClearPageUptodate(page);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
+2
-1
@@ -146,7 +146,8 @@ enum mem_type {
|
||||
NAT_ENTRIES, /* indicates the cached nat entry */
|
||||
DIRTY_DENTS, /* indicates dirty dentry pages */
|
||||
INO_ENTRIES, /* indicates inode entries */
|
||||
EXTENT_CACHE, /* indicates extent cache */
|
||||
READ_EXTENT_CACHE, /* indicates read extent cache */
|
||||
AGE_EXTENT_CACHE, /* indicates age extent cache */
|
||||
DISCARD_CACHE, /* indicates memory of cached discard cmds */
|
||||
COMPRESS_PAGE, /* indicates memory of cached compressed pages */
|
||||
BASE_CHECK, /* check kernel status */
|
||||
|
||||
+1
-3
@@ -923,9 +923,7 @@ int __init f2fs_create_recovery_cache(void)
|
||||
{
|
||||
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
|
||||
sizeof(struct fsync_inode_entry));
|
||||
if (!fsync_entry_slab)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
return fsync_entry_slab ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void f2fs_destroy_recovery_cache(void)
|
||||
|
||||
+120
-81
@@ -192,14 +192,19 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean)
|
||||
if (!f2fs_is_atomic_file(inode))
|
||||
return;
|
||||
|
||||
if (clean)
|
||||
truncate_inode_pages_final(inode->i_mapping);
|
||||
clear_inode_flag(fi->cow_inode, FI_COW_FILE);
|
||||
iput(fi->cow_inode);
|
||||
fi->cow_inode = NULL;
|
||||
release_atomic_write_cnt(inode);
|
||||
clear_inode_flag(inode, FI_ATOMIC_COMMITTED);
|
||||
clear_inode_flag(inode, FI_ATOMIC_REPLACE);
|
||||
clear_inode_flag(inode, FI_ATOMIC_FILE);
|
||||
stat_dec_atomic_inode(inode);
|
||||
|
||||
if (clean) {
|
||||
truncate_inode_pages_final(inode->i_mapping);
|
||||
f2fs_i_size_write(inode, fi->original_i_size);
|
||||
}
|
||||
}
|
||||
|
||||
static int __replace_atomic_write_block(struct inode *inode, pgoff_t index,
|
||||
@@ -257,14 +262,19 @@ static void __complete_revoke_list(struct inode *inode, struct list_head *head,
|
||||
bool revoke)
|
||||
{
|
||||
struct revoke_entry *cur, *tmp;
|
||||
bool truncate = is_inode_flag_set(inode, FI_ATOMIC_REPLACE);
|
||||
|
||||
list_for_each_entry_safe(cur, tmp, head, list) {
|
||||
if (revoke)
|
||||
__replace_atomic_write_block(inode, cur->index,
|
||||
cur->old_addr, NULL, true);
|
||||
|
||||
list_del(&cur->list);
|
||||
kmem_cache_free(revoke_entry_slab, cur);
|
||||
}
|
||||
|
||||
if (!revoke && truncate)
|
||||
f2fs_do_truncate_blocks(inode, 0, false);
|
||||
}
|
||||
|
||||
static int __f2fs_commit_atomic_write(struct inode *inode)
|
||||
@@ -335,10 +345,12 @@ next:
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
if (ret) {
|
||||
sbi->revoked_atomic_block += fi->atomic_write_cnt;
|
||||
else
|
||||
} else {
|
||||
sbi->committed_atomic_block += fi->atomic_write_cnt;
|
||||
set_inode_flag(inode, FI_ATOMIC_COMMITTED);
|
||||
}
|
||||
|
||||
__complete_revoke_list(inode, &revoke_list, ret ? true : false);
|
||||
|
||||
@@ -437,8 +449,14 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi, bool from_bg)
|
||||
return;
|
||||
|
||||
/* try to shrink extent cache when there is no enough memory */
|
||||
if (!f2fs_available_free_memory(sbi, EXTENT_CACHE))
|
||||
f2fs_shrink_extent_tree(sbi, EXTENT_CACHE_SHRINK_NUMBER);
|
||||
if (!f2fs_available_free_memory(sbi, READ_EXTENT_CACHE))
|
||||
f2fs_shrink_read_extent_tree(sbi,
|
||||
READ_EXTENT_CACHE_SHRINK_NUMBER);
|
||||
|
||||
/* try to shrink age extent cache when there is no enough memory */
|
||||
if (!f2fs_available_free_memory(sbi, AGE_EXTENT_CACHE))
|
||||
f2fs_shrink_age_extent_tree(sbi,
|
||||
AGE_EXTENT_CACHE_SHRINK_NUMBER);
|
||||
|
||||
/* check the # of cached NAT entries */
|
||||
if (!f2fs_available_free_memory(sbi, NAT_ENTRIES))
|
||||
@@ -620,12 +638,11 @@ int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
dev_t dev = sbi->sb->s_bdev->bd_dev;
|
||||
struct flush_cmd_control *fcc;
|
||||
int err = 0;
|
||||
|
||||
if (SM_I(sbi)->fcc_info) {
|
||||
fcc = SM_I(sbi)->fcc_info;
|
||||
if (fcc->f2fs_issue_flush)
|
||||
return err;
|
||||
return 0;
|
||||
goto init_thread;
|
||||
}
|
||||
|
||||
@@ -638,19 +655,20 @@ int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi)
|
||||
init_llist_head(&fcc->issue_list);
|
||||
SM_I(sbi)->fcc_info = fcc;
|
||||
if (!test_opt(sbi, FLUSH_MERGE))
|
||||
return err;
|
||||
return 0;
|
||||
|
||||
init_thread:
|
||||
fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
|
||||
"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
|
||||
if (IS_ERR(fcc->f2fs_issue_flush)) {
|
||||
err = PTR_ERR(fcc->f2fs_issue_flush);
|
||||
int err = PTR_ERR(fcc->f2fs_issue_flush);
|
||||
|
||||
kfree(fcc);
|
||||
SM_I(sbi)->fcc_info = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void f2fs_destroy_flush_cmd_control(struct f2fs_sb_info *sbi, bool free)
|
||||
@@ -856,7 +874,7 @@ block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi)
|
||||
}
|
||||
mutex_unlock(&dirty_i->seglist_lock);
|
||||
|
||||
unusable = holes[DATA] > holes[NODE] ? holes[DATA] : holes[NODE];
|
||||
unusable = max(holes[DATA], holes[NODE]);
|
||||
if (unusable > ovp_holes)
|
||||
return unusable - ovp_holes;
|
||||
return 0;
|
||||
@@ -1052,8 +1070,8 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
|
||||
dpolicy->io_aware = true;
|
||||
dpolicy->sync = false;
|
||||
dpolicy->ordered = true;
|
||||
if (utilization(sbi) > DEF_DISCARD_URGENT_UTIL) {
|
||||
dpolicy->granularity = 1;
|
||||
if (utilization(sbi) > dcc->discard_urgent_util) {
|
||||
dpolicy->granularity = MIN_DISCARD_GRANULARITY;
|
||||
if (atomic_read(&dcc->discard_cmd_cnt))
|
||||
dpolicy->max_interval =
|
||||
dcc->min_discard_issue_time;
|
||||
@@ -1068,7 +1086,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi,
|
||||
} else if (discard_type == DPOLICY_UMOUNT) {
|
||||
dpolicy->io_aware = false;
|
||||
/* we need to issue all to keep CP_TRIMMED_FLAG */
|
||||
dpolicy->granularity = 1;
|
||||
dpolicy->granularity = MIN_DISCARD_GRANULARITY;
|
||||
dpolicy->timeout = true;
|
||||
}
|
||||
}
|
||||
@@ -1126,13 +1144,12 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,
|
||||
if (time_to_inject(sbi, FAULT_DISCARD)) {
|
||||
f2fs_show_injection_info(sbi, FAULT_DISCARD);
|
||||
err = -EIO;
|
||||
goto submit;
|
||||
}
|
||||
err = __blkdev_issue_discard(bdev,
|
||||
} else {
|
||||
err = __blkdev_issue_discard(bdev,
|
||||
SECTOR_FROM_BLOCK(start),
|
||||
SECTOR_FROM_BLOCK(len),
|
||||
GFP_NOFS, &bio);
|
||||
submit:
|
||||
}
|
||||
if (err) {
|
||||
spin_lock_irqsave(&dc->lock, flags);
|
||||
if (dc->state == D_PARTIAL)
|
||||
@@ -1170,7 +1187,7 @@ submit:
|
||||
|
||||
atomic_inc(&dcc->issued_discard);
|
||||
|
||||
f2fs_update_iostat(sbi, NULL, FS_DISCARD, 1);
|
||||
f2fs_update_iostat(sbi, NULL, FS_DISCARD, len * F2FS_BLKSIZE);
|
||||
|
||||
lstart += len;
|
||||
start += len;
|
||||
@@ -1342,13 +1359,13 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi,
|
||||
}
|
||||
}
|
||||
|
||||
static int __queue_discard_cmd(struct f2fs_sb_info *sbi,
|
||||
static void __queue_discard_cmd(struct f2fs_sb_info *sbi,
|
||||
struct block_device *bdev, block_t blkstart, block_t blklen)
|
||||
{
|
||||
block_t lblkstart = blkstart;
|
||||
|
||||
if (!f2fs_bdev_support_discard(bdev))
|
||||
return 0;
|
||||
return;
|
||||
|
||||
trace_f2fs_queue_discard(bdev, blkstart, blklen);
|
||||
|
||||
@@ -1360,7 +1377,6 @@ static int __queue_discard_cmd(struct f2fs_sb_info *sbi,
|
||||
mutex_lock(&SM_I(sbi)->dcc_info->cmd_lock);
|
||||
__update_discard_tree_range(sbi, bdev, lblkstart, blkstart, blklen);
|
||||
mutex_unlock(&SM_I(sbi)->dcc_info->cmd_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi,
|
||||
@@ -1448,7 +1464,7 @@ retry:
|
||||
if (i + 1 < dpolicy->granularity)
|
||||
break;
|
||||
|
||||
if (i < DEFAULT_DISCARD_GRANULARITY && dpolicy->ordered)
|
||||
if (i + 1 < dcc->max_ordered_discard && dpolicy->ordered)
|
||||
return __issue_discard_cmd_orderly(sbi, dpolicy);
|
||||
|
||||
pend_list = &dcc->pend_list[i];
|
||||
@@ -1645,6 +1661,9 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi)
|
||||
struct discard_policy dpolicy;
|
||||
bool dropped;
|
||||
|
||||
if (!atomic_read(&dcc->discard_cmd_cnt))
|
||||
return false;
|
||||
|
||||
__init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT,
|
||||
dcc->discard_granularity);
|
||||
__issue_discard_cmd(sbi, &dpolicy);
|
||||
@@ -1669,6 +1688,11 @@ static int issue_discard_thread(void *data)
|
||||
set_freezable();
|
||||
|
||||
do {
|
||||
wait_event_interruptible_timeout(*q,
|
||||
kthread_should_stop() || freezing(current) ||
|
||||
dcc->discard_wake,
|
||||
msecs_to_jiffies(wait_ms));
|
||||
|
||||
if (sbi->gc_mode == GC_URGENT_HIGH ||
|
||||
!f2fs_available_free_memory(sbi, DISCARD_CACHE))
|
||||
__init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE, 1);
|
||||
@@ -1676,14 +1700,6 @@ static int issue_discard_thread(void *data)
|
||||
__init_discard_policy(sbi, &dpolicy, DPOLICY_BG,
|
||||
dcc->discard_granularity);
|
||||
|
||||
if (!atomic_read(&dcc->discard_cmd_cnt))
|
||||
wait_ms = dpolicy.max_interval;
|
||||
|
||||
wait_event_interruptible_timeout(*q,
|
||||
kthread_should_stop() || freezing(current) ||
|
||||
dcc->discard_wake,
|
||||
msecs_to_jiffies(wait_ms));
|
||||
|
||||
if (dcc->discard_wake)
|
||||
dcc->discard_wake = 0;
|
||||
|
||||
@@ -1697,12 +1713,11 @@ static int issue_discard_thread(void *data)
|
||||
continue;
|
||||
if (kthread_should_stop())
|
||||
return 0;
|
||||
if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) {
|
||||
if (is_sbi_flag_set(sbi, SBI_NEED_FSCK) ||
|
||||
!atomic_read(&dcc->discard_cmd_cnt)) {
|
||||
wait_ms = dpolicy.max_interval;
|
||||
continue;
|
||||
}
|
||||
if (!atomic_read(&dcc->discard_cmd_cnt))
|
||||
continue;
|
||||
|
||||
sb_start_intwrite(sbi->sb);
|
||||
|
||||
@@ -1717,6 +1732,8 @@ static int issue_discard_thread(void *data)
|
||||
} else {
|
||||
wait_ms = dpolicy.max_interval;
|
||||
}
|
||||
if (!atomic_read(&dcc->discard_cmd_cnt))
|
||||
wait_ms = dpolicy.max_interval;
|
||||
|
||||
sb_end_intwrite(sbi->sb);
|
||||
|
||||
@@ -1760,7 +1777,8 @@ static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
|
||||
}
|
||||
|
||||
/* For conventional zones, use regular discard if supported */
|
||||
return __queue_discard_cmd(sbi, bdev, lblkstart, blklen);
|
||||
__queue_discard_cmd(sbi, bdev, lblkstart, blklen);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1771,7 +1789,8 @@ static int __issue_discard_async(struct f2fs_sb_info *sbi,
|
||||
if (f2fs_sb_has_blkzoned(sbi) && bdev_is_zoned(bdev))
|
||||
return __f2fs_issue_discard_zone(sbi, bdev, blkstart, blklen);
|
||||
#endif
|
||||
return __queue_discard_cmd(sbi, bdev, blkstart, blklen);
|
||||
__queue_discard_cmd(sbi, bdev, blkstart, blklen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
|
||||
@@ -2025,8 +2044,10 @@ int f2fs_start_discard_thread(struct f2fs_sb_info *sbi)
|
||||
|
||||
dcc->f2fs_issue_discard = kthread_run(issue_discard_thread, sbi,
|
||||
"f2fs_discard-%u:%u", MAJOR(dev), MINOR(dev));
|
||||
if (IS_ERR(dcc->f2fs_issue_discard))
|
||||
if (IS_ERR(dcc->f2fs_issue_discard)) {
|
||||
err = PTR_ERR(dcc->f2fs_issue_discard);
|
||||
dcc->f2fs_issue_discard = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -2046,6 +2067,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
|
||||
return -ENOMEM;
|
||||
|
||||
dcc->discard_granularity = DEFAULT_DISCARD_GRANULARITY;
|
||||
dcc->max_ordered_discard = DEFAULT_MAX_ORDERED_DISCARD_GRANULARITY;
|
||||
if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT)
|
||||
dcc->discard_granularity = sbi->blocks_per_seg;
|
||||
else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION)
|
||||
@@ -2066,6 +2088,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
|
||||
dcc->min_discard_issue_time = DEF_MIN_DISCARD_ISSUE_TIME;
|
||||
dcc->mid_discard_issue_time = DEF_MID_DISCARD_ISSUE_TIME;
|
||||
dcc->max_discard_issue_time = DEF_MAX_DISCARD_ISSUE_TIME;
|
||||
dcc->discard_urgent_util = DEF_DISCARD_URGENT_UTIL;
|
||||
dcc->undiscard_blks = 0;
|
||||
dcc->next_pos = 0;
|
||||
dcc->root = RB_ROOT_CACHED;
|
||||
@@ -2096,8 +2119,7 @@ static void destroy_discard_cmd_control(struct f2fs_sb_info *sbi)
|
||||
* Recovery can cache discard commands, so in error path of
|
||||
* fill_super(), it needs to give a chance to handle them.
|
||||
*/
|
||||
if (unlikely(atomic_read(&dcc->discard_cmd_cnt)))
|
||||
f2fs_issue_discard_timeout(sbi);
|
||||
f2fs_issue_discard_timeout(sbi);
|
||||
|
||||
kfree(dcc);
|
||||
SM_I(sbi)->dcc_info = NULL;
|
||||
@@ -2642,7 +2664,7 @@ bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno)
|
||||
* This function always allocates a used segment(from dirty seglist) by SSR
|
||||
* manner, so it should recover the existing segment information of valid blocks
|
||||
*/
|
||||
static void change_curseg(struct f2fs_sb_info *sbi, int type, bool flush)
|
||||
static void change_curseg(struct f2fs_sb_info *sbi, int type)
|
||||
{
|
||||
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
|
||||
struct curseg_info *curseg = CURSEG_I(sbi, type);
|
||||
@@ -2650,9 +2672,7 @@ static void change_curseg(struct f2fs_sb_info *sbi, int type, bool flush)
|
||||
struct f2fs_summary_block *sum_node;
|
||||
struct page *sum_page;
|
||||
|
||||
if (flush)
|
||||
write_sum_page(sbi, curseg->sum_blk,
|
||||
GET_SUM_BLOCK(sbi, curseg->segno));
|
||||
write_sum_page(sbi, curseg->sum_blk, GET_SUM_BLOCK(sbi, curseg->segno));
|
||||
|
||||
__set_test_and_inuse(sbi, new_segno);
|
||||
|
||||
@@ -2691,7 +2711,7 @@ static void get_atssr_segment(struct f2fs_sb_info *sbi, int type,
|
||||
struct seg_entry *se = get_seg_entry(sbi, curseg->next_segno);
|
||||
|
||||
curseg->seg_type = se->type;
|
||||
change_curseg(sbi, type, true);
|
||||
change_curseg(sbi, type);
|
||||
} else {
|
||||
/* allocate cold segment by default */
|
||||
curseg->seg_type = CURSEG_COLD_DATA;
|
||||
@@ -2835,31 +2855,20 @@ static int get_ssr_segment(struct f2fs_sb_info *sbi, int type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* flush out current segment and replace it with new segment
|
||||
* This function should be returned with success, otherwise BUG
|
||||
*/
|
||||
static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
|
||||
int type, bool force)
|
||||
static bool need_new_seg(struct f2fs_sb_info *sbi, int type)
|
||||
{
|
||||
struct curseg_info *curseg = CURSEG_I(sbi, type);
|
||||
|
||||
if (force)
|
||||
new_curseg(sbi, type, true);
|
||||
else if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) &&
|
||||
curseg->seg_type == CURSEG_WARM_NODE)
|
||||
new_curseg(sbi, type, false);
|
||||
else if (curseg->alloc_type == LFS &&
|
||||
is_next_segment_free(sbi, curseg, type) &&
|
||||
likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
|
||||
new_curseg(sbi, type, false);
|
||||
else if (f2fs_need_SSR(sbi) &&
|
||||
get_ssr_segment(sbi, type, SSR, 0))
|
||||
change_curseg(sbi, type, true);
|
||||
else
|
||||
new_curseg(sbi, type, false);
|
||||
|
||||
stat_inc_seg_type(sbi, curseg);
|
||||
if (!is_set_ckpt_flags(sbi, CP_CRC_RECOVERY_FLAG) &&
|
||||
curseg->seg_type == CURSEG_WARM_NODE)
|
||||
return true;
|
||||
if (curseg->alloc_type == LFS &&
|
||||
is_next_segment_free(sbi, curseg, type) &&
|
||||
likely(!is_sbi_flag_set(sbi, SBI_CP_DISABLED)))
|
||||
return true;
|
||||
if (!f2fs_need_SSR(sbi) || !get_ssr_segment(sbi, type, SSR, 0))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
|
||||
@@ -2877,7 +2886,7 @@ void f2fs_allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
|
||||
goto unlock;
|
||||
|
||||
if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type, SSR, 0))
|
||||
change_curseg(sbi, type, true);
|
||||
change_curseg(sbi, type);
|
||||
else
|
||||
new_curseg(sbi, type, true);
|
||||
|
||||
@@ -2912,7 +2921,8 @@ static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type,
|
||||
return;
|
||||
alloc:
|
||||
old_segno = curseg->segno;
|
||||
SIT_I(sbi)->s_ops->allocate_segment(sbi, type, true);
|
||||
new_curseg(sbi, type, true);
|
||||
stat_inc_seg_type(sbi, curseg);
|
||||
locate_dirty_segment(sbi, old_segno);
|
||||
}
|
||||
|
||||
@@ -2943,10 +2953,6 @@ void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi)
|
||||
f2fs_up_read(&SM_I(sbi)->curseg_lock);
|
||||
}
|
||||
|
||||
static const struct segment_allocation default_salloc_ops = {
|
||||
.allocate_segment = allocate_segment_by_default,
|
||||
};
|
||||
|
||||
bool f2fs_exist_trim_candidates(struct f2fs_sb_info *sbi,
|
||||
struct cp_control *cpc)
|
||||
{
|
||||
@@ -3152,10 +3158,28 @@ static int __get_segment_type_4(struct f2fs_io_info *fio)
|
||||
}
|
||||
}
|
||||
|
||||
static int __get_age_segment_type(struct inode *inode, pgoff_t pgofs)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct extent_info ei;
|
||||
|
||||
if (f2fs_lookup_age_extent_cache(inode, pgofs, &ei)) {
|
||||
if (!ei.age)
|
||||
return NO_CHECK_TYPE;
|
||||
if (ei.age <= sbi->hot_data_age_threshold)
|
||||
return CURSEG_HOT_DATA;
|
||||
if (ei.age <= sbi->warm_data_age_threshold)
|
||||
return CURSEG_WARM_DATA;
|
||||
return CURSEG_COLD_DATA;
|
||||
}
|
||||
return NO_CHECK_TYPE;
|
||||
}
|
||||
|
||||
static int __get_segment_type_6(struct f2fs_io_info *fio)
|
||||
{
|
||||
if (fio->type == DATA) {
|
||||
struct inode *inode = fio->page->mapping->host;
|
||||
int type;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_ALIGNED_WRITE))
|
||||
return CURSEG_COLD_DATA_PINNED;
|
||||
@@ -3170,6 +3194,11 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
|
||||
}
|
||||
if (file_is_cold(inode) || f2fs_need_compress_data(inode))
|
||||
return CURSEG_COLD_DATA;
|
||||
|
||||
type = __get_age_segment_type(inode, fio->page->index);
|
||||
if (type != NO_CHECK_TYPE)
|
||||
return type;
|
||||
|
||||
if (file_is_hot(inode) ||
|
||||
is_inode_flag_set(inode, FI_HOT_DATA) ||
|
||||
f2fs_is_cow_file(inode))
|
||||
@@ -3266,11 +3295,19 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
update_sit_entry(sbi, old_blkaddr, -1);
|
||||
|
||||
if (!__has_curseg_space(sbi, curseg)) {
|
||||
if (from_gc)
|
||||
/*
|
||||
* Flush out current segment and replace it with new segment.
|
||||
*/
|
||||
if (from_gc) {
|
||||
get_atssr_segment(sbi, type, se->type,
|
||||
AT_SSR, se->mtime);
|
||||
else
|
||||
sit_i->s_ops->allocate_segment(sbi, type, false);
|
||||
} else {
|
||||
if (need_new_seg(sbi, type))
|
||||
new_curseg(sbi, type, false);
|
||||
else
|
||||
change_curseg(sbi, type);
|
||||
stat_inc_seg_type(sbi, curseg);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* segment dirty status should be updated after segment allocation,
|
||||
@@ -3280,6 +3317,9 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
|
||||
locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
|
||||
locate_dirty_segment(sbi, GET_SEGNO(sbi, *new_blkaddr));
|
||||
|
||||
if (IS_DATASEG(type))
|
||||
atomic64_inc(&sbi->allocated_data_blocks);
|
||||
|
||||
up_write(&sit_i->sentry_lock);
|
||||
|
||||
if (page && IS_NODESEG(type)) {
|
||||
@@ -3407,6 +3447,8 @@ void f2fs_outplace_write_data(struct dnode_of_data *dn,
|
||||
struct f2fs_summary sum;
|
||||
|
||||
f2fs_bug_on(sbi, dn->data_blkaddr == NULL_ADDR);
|
||||
if (fio->io_type == FS_DATA_IO || fio->io_type == FS_CP_DATA_IO)
|
||||
f2fs_update_age_extent_cache(dn);
|
||||
set_summary(&sum, dn->nid, dn->ofs_in_node, fio->version);
|
||||
do_write_page(&sum, fio);
|
||||
f2fs_update_data_blkaddr(dn, fio->new_blkaddr);
|
||||
@@ -3531,7 +3573,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
/* change the current segment */
|
||||
if (segno != curseg->segno) {
|
||||
curseg->next_segno = segno;
|
||||
change_curseg(sbi, type, true);
|
||||
change_curseg(sbi, type);
|
||||
}
|
||||
|
||||
curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr);
|
||||
@@ -3559,7 +3601,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
if (recover_curseg) {
|
||||
if (old_cursegno != curseg->segno) {
|
||||
curseg->next_segno = old_cursegno;
|
||||
change_curseg(sbi, type, true);
|
||||
change_curseg(sbi, type);
|
||||
}
|
||||
curseg->next_blkoff = old_blkoff;
|
||||
curseg->alloc_type = old_alloc_type;
|
||||
@@ -4256,9 +4298,6 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
|
||||
/* init SIT information */
|
||||
sit_i->s_ops = &default_salloc_ops;
|
||||
|
||||
sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr);
|
||||
sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg;
|
||||
sit_i->written_valid_blocks = 0;
|
||||
|
||||
@@ -222,10 +222,6 @@ struct sec_entry {
|
||||
unsigned int valid_blocks; /* # of valid blocks in a section */
|
||||
};
|
||||
|
||||
struct segment_allocation {
|
||||
void (*allocate_segment)(struct f2fs_sb_info *, int, bool);
|
||||
};
|
||||
|
||||
#define MAX_SKIP_GC_COUNT 16
|
||||
|
||||
struct revoke_entry {
|
||||
@@ -235,8 +231,6 @@ struct revoke_entry {
|
||||
};
|
||||
|
||||
struct sit_info {
|
||||
const struct segment_allocation *s_ops;
|
||||
|
||||
block_t sit_base_addr; /* start block address of SIT area */
|
||||
block_t sit_blocks; /* # of blocks used by SIT area */
|
||||
block_t written_valid_blocks; /* # of valid blocks in main area */
|
||||
|
||||
+18
-7
@@ -28,10 +28,13 @@ static unsigned long __count_free_nids(struct f2fs_sb_info *sbi)
|
||||
return count > 0 ? count : 0;
|
||||
}
|
||||
|
||||
static unsigned long __count_extent_cache(struct f2fs_sb_info *sbi)
|
||||
static unsigned long __count_extent_cache(struct f2fs_sb_info *sbi,
|
||||
enum extent_type type)
|
||||
{
|
||||
return atomic_read(&sbi->total_zombie_tree) +
|
||||
atomic_read(&sbi->total_ext_node);
|
||||
struct extent_tree_info *eti = &sbi->extent_tree[type];
|
||||
|
||||
return atomic_read(&eti->total_zombie_tree) +
|
||||
atomic_read(&eti->total_ext_node);
|
||||
}
|
||||
|
||||
unsigned long f2fs_shrink_count(struct shrinker *shrink,
|
||||
@@ -53,8 +56,11 @@ unsigned long f2fs_shrink_count(struct shrinker *shrink,
|
||||
}
|
||||
spin_unlock(&f2fs_list_lock);
|
||||
|
||||
/* count extent cache entries */
|
||||
count += __count_extent_cache(sbi);
|
||||
/* count read extent cache entries */
|
||||
count += __count_extent_cache(sbi, EX_READ);
|
||||
|
||||
/* count block age extent cache entries */
|
||||
count += __count_extent_cache(sbi, EX_BLOCK_AGE);
|
||||
|
||||
/* count clean nat cache entries */
|
||||
count += __count_nat_entries(sbi);
|
||||
@@ -100,7 +106,10 @@ unsigned long f2fs_shrink_scan(struct shrinker *shrink,
|
||||
sbi->shrinker_run_no = run_no;
|
||||
|
||||
/* shrink extent cache entries */
|
||||
freed += f2fs_shrink_extent_tree(sbi, nr >> 1);
|
||||
freed += f2fs_shrink_age_extent_tree(sbi, nr >> 2);
|
||||
|
||||
/* shrink read extent cache entries */
|
||||
freed += f2fs_shrink_read_extent_tree(sbi, nr >> 2);
|
||||
|
||||
/* shrink clean nat cache entries */
|
||||
if (freed < nr)
|
||||
@@ -130,7 +139,9 @@ void f2fs_join_shrinker(struct f2fs_sb_info *sbi)
|
||||
|
||||
void f2fs_leave_shrinker(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
f2fs_shrink_extent_tree(sbi, __count_extent_cache(sbi));
|
||||
f2fs_shrink_read_extent_tree(sbi, __count_extent_cache(sbi, EX_READ));
|
||||
f2fs_shrink_age_extent_tree(sbi,
|
||||
__count_extent_cache(sbi, EX_BLOCK_AGE));
|
||||
|
||||
spin_lock(&f2fs_list_lock);
|
||||
list_del_init(&sbi->s_list);
|
||||
|
||||
Loaded 20 of 24 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user