mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-25 20:10:23 +09:00
Merge remote-tracking branch 'aosp/upstream-f2fs-stable-linux-5.10.y' into android12-5.10
Early merge to fix bugs and address compression issues. * aosp/upstream-f2fs-stable-linux-5.10.y: f2fs: introduce FI_COMPRESS_RELEASED instead of using IMMUTABLE bit f2fs: compress: remove unneeded preallocation f2fs: avoid attaching SB_ACTIVE flag during mount/remount f2fs: atgc: export entries for better tunability via sysfs f2fs: compress: fix to disallow temp extension f2fs: let's allow compression for mmap files f2fs: add MODULE_SOFTDEP to ensure crc32 is included in the initramfs f2fs: return success if there is no work to do f2fs: compress: clean up parameter of __f2fs_cluster_blocks() f2fs: compress: remove unneeded f2fs_put_dnode() f2fs: atgc: fix to set default age threshold f2fs: Prevent swap file in LFS mode f2fs: fix to avoid racing on fsync_entry_slab by multi filesystem instances f2fs: restructure f2fs page.private layout f2fs: add cp_error check in f2fs_write_compressed_pages f2fs: compress: rename __cluster_may_compress Bug: 188928405 Signed-off-by: Jaegeuk Kim <jaegeuk@google.com> Change-Id: I73c670648e352dc783731e4d80c1df9069c61d0c
This commit is contained in:
@@ -438,3 +438,31 @@ Description: Show the count of inode newly enabled for compression since mount.
|
||||
Note that when the compression is disabled for the files, this count
|
||||
doesn't decrease. If you write "0" here, you can initialize
|
||||
compr_new_inode to "0".
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/atgc_candidate_ratio
|
||||
Date: May 2021
|
||||
Contact: "Chao Yu" <yuchao0@huawei.com>
|
||||
Description: When ATGC is on, it controls candidate ratio in order to limit total
|
||||
number of potential victim in all candidates, the value should be in
|
||||
range of [0, 100], by default it was initialized as 20(%).
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/atgc_candidate_count
|
||||
Date: May 2021
|
||||
Contact: "Chao Yu" <yuchao0@huawei.com>
|
||||
Description: When ATGC is on, it controls candidate count in order to limit total
|
||||
number of potential victim in all candidates, by default it was
|
||||
initialized as 10 (sections).
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/atgc_age_weight
|
||||
Date: May 2021
|
||||
Contact: "Chao Yu" <yuchao0@huawei.com>
|
||||
Description: When ATGC is on, it controls age weight to balance weight proportion
|
||||
in between aging and valid blocks, the value should be in range of
|
||||
[0, 100], by default it was initialized as 60(%).
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/atgc_age_threshold
|
||||
Date: May 2021
|
||||
Contact: "Chao Yu" <yuchao0@huawei.com>
|
||||
Description: When ATGC is on, it controls age threshold to bypass GCing young
|
||||
candidates whose age is not beyond the threshold, by default it was
|
||||
initialized as 604800 seconds (equals to 7 days).
|
||||
|
||||
@@ -444,7 +444,7 @@ static int f2fs_set_meta_page_dirty(struct page *page)
|
||||
if (!PageDirty(page)) {
|
||||
__set_page_dirty_nobuffers(page);
|
||||
inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META);
|
||||
f2fs_set_page_private(page, 0);
|
||||
set_page_private_reference(page);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -691,9 +691,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.
|
||||
@@ -1018,7 +1015,7 @@ void f2fs_update_dirty_page(struct inode *inode, struct page *page)
|
||||
inode_inc_dirty_pages(inode);
|
||||
spin_unlock(&sbi->inode_lock[type]);
|
||||
|
||||
f2fs_set_page_private(page, 0);
|
||||
set_page_private_reference(page);
|
||||
}
|
||||
|
||||
void f2fs_remove_dirty_inode(struct inode *inode)
|
||||
|
||||
@@ -74,7 +74,7 @@ bool f2fs_is_compressed_page(struct page *page)
|
||||
return false;
|
||||
if (!page_private(page))
|
||||
return false;
|
||||
if (IS_ATOMIC_WRITTEN_PAGE(page) || IS_DUMMY_WRITTEN_PAGE(page))
|
||||
if (page_private_nonpointer(page))
|
||||
return false;
|
||||
|
||||
f2fs_bug_on(F2FS_M_SB(page->mapping),
|
||||
@@ -85,8 +85,7 @@ bool f2fs_is_compressed_page(struct page *page)
|
||||
static void f2fs_set_compressed_page(struct page *page,
|
||||
struct inode *inode, pgoff_t index, void *data)
|
||||
{
|
||||
SetPagePrivate(page);
|
||||
set_page_private(page, (unsigned long)data);
|
||||
attach_page_private(page, (void *)data);
|
||||
|
||||
/* i_crypto_info and iv index */
|
||||
page->index = index;
|
||||
@@ -589,8 +588,7 @@ static void f2fs_compress_free_page(struct page *page)
|
||||
{
|
||||
if (!page)
|
||||
return;
|
||||
set_page_private(page, (unsigned long)NULL);
|
||||
ClearPagePrivate(page);
|
||||
detach_page_private(page);
|
||||
page->mapping = NULL;
|
||||
unlock_page(page);
|
||||
mempool_free(page, compress_page_pool);
|
||||
@@ -876,7 +874,7 @@ bool f2fs_cluster_can_merge_page(struct compress_ctx *cc, pgoff_t index)
|
||||
return is_page_in_cluster(cc, index);
|
||||
}
|
||||
|
||||
static bool __cluster_may_compress(struct compress_ctx *cc)
|
||||
static bool cluster_has_invalid_data(struct compress_ctx *cc)
|
||||
{
|
||||
loff_t i_size = i_size_read(cc->inode);
|
||||
unsigned nr_pages = DIV_ROUND_UP(i_size, PAGE_SIZE);
|
||||
@@ -889,19 +887,22 @@ static bool __cluster_may_compress(struct compress_ctx *cc)
|
||||
|
||||
/* beyond EOF */
|
||||
if (page->index >= nr_pages)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __f2fs_cluster_blocks(struct compress_ctx *cc, bool compr)
|
||||
static int __f2fs_cluster_blocks(struct inode *inode,
|
||||
unsigned int cluster_idx, bool compr)
|
||||
{
|
||||
struct dnode_of_data dn;
|
||||
unsigned int cluster_size = F2FS_I(inode)->i_cluster_size;
|
||||
unsigned int start_idx = cluster_idx <<
|
||||
F2FS_I(inode)->i_log_cluster_size;
|
||||
int ret;
|
||||
|
||||
set_new_dnode(&dn, cc->inode, NULL, NULL, 0);
|
||||
ret = f2fs_get_dnode_of_data(&dn, start_idx_of_cluster(cc),
|
||||
LOOKUP_NODE);
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
ret = f2fs_get_dnode_of_data(&dn, start_idx, LOOKUP_NODE);
|
||||
if (ret) {
|
||||
if (ret == -ENOENT)
|
||||
ret = 0;
|
||||
@@ -912,7 +913,7 @@ static int __f2fs_cluster_blocks(struct compress_ctx *cc, bool compr)
|
||||
int i;
|
||||
|
||||
ret = 1;
|
||||
for (i = 1; i < cc->cluster_size; i++) {
|
||||
for (i = 1; i < cluster_size; i++) {
|
||||
block_t blkaddr;
|
||||
|
||||
blkaddr = data_blkaddr(dn.inode,
|
||||
@@ -925,6 +926,10 @@ static int __f2fs_cluster_blocks(struct compress_ctx *cc, bool compr)
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
|
||||
f2fs_bug_on(F2FS_I_SB(inode),
|
||||
!compr && ret != cluster_size &&
|
||||
!is_inode_flag_set(inode, FI_COMPRESS_RELEASED));
|
||||
}
|
||||
fail:
|
||||
f2fs_put_dnode(&dn);
|
||||
@@ -934,25 +939,15 @@ fail:
|
||||
/* return # of compressed blocks in compressed cluster */
|
||||
static int f2fs_compressed_blocks(struct compress_ctx *cc)
|
||||
{
|
||||
return __f2fs_cluster_blocks(cc, true);
|
||||
return __f2fs_cluster_blocks(cc->inode, cc->cluster_idx, true);
|
||||
}
|
||||
|
||||
/* return # of valid blocks in compressed cluster */
|
||||
static int f2fs_cluster_blocks(struct compress_ctx *cc)
|
||||
{
|
||||
return __f2fs_cluster_blocks(cc, false);
|
||||
}
|
||||
|
||||
int f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index)
|
||||
{
|
||||
struct compress_ctx cc = {
|
||||
.inode = inode,
|
||||
.log_cluster_size = F2FS_I(inode)->i_log_cluster_size,
|
||||
.cluster_size = F2FS_I(inode)->i_cluster_size,
|
||||
.cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size,
|
||||
};
|
||||
|
||||
return f2fs_cluster_blocks(&cc);
|
||||
return __f2fs_cluster_blocks(inode,
|
||||
index >> F2FS_I(inode)->i_log_cluster_size,
|
||||
false);
|
||||
}
|
||||
|
||||
static bool cluster_may_compress(struct compress_ctx *cc)
|
||||
@@ -961,13 +956,11 @@ static bool cluster_may_compress(struct compress_ctx *cc)
|
||||
return false;
|
||||
if (f2fs_is_atomic_file(cc->inode))
|
||||
return false;
|
||||
if (f2fs_is_mmap_file(cc->inode))
|
||||
return false;
|
||||
if (!f2fs_cluster_is_full(cc))
|
||||
return false;
|
||||
if (unlikely(f2fs_cp_error(F2FS_I_SB(cc->inode))))
|
||||
return false;
|
||||
return __cluster_may_compress(cc);
|
||||
return !cluster_has_invalid_data(cc);
|
||||
}
|
||||
|
||||
static void set_cluster_writeback(struct compress_ctx *cc)
|
||||
@@ -995,21 +988,16 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode);
|
||||
struct address_space *mapping = cc->inode->i_mapping;
|
||||
struct page *page;
|
||||
struct dnode_of_data dn;
|
||||
sector_t last_block_in_bio;
|
||||
unsigned fgp_flag = FGP_LOCK | FGP_WRITE | FGP_CREAT;
|
||||
pgoff_t start_idx = start_idx_of_cluster(cc);
|
||||
int i, ret;
|
||||
bool prealloc;
|
||||
|
||||
retry:
|
||||
ret = f2fs_cluster_blocks(cc);
|
||||
ret = f2fs_is_compressed_cluster(cc->inode, start_idx);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
/* compressed case */
|
||||
prealloc = (ret < cc->cluster_size);
|
||||
|
||||
ret = f2fs_init_compress_ctx(cc);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -1067,25 +1055,6 @@ release_and_retry:
|
||||
}
|
||||
}
|
||||
|
||||
if (prealloc) {
|
||||
f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
|
||||
|
||||
set_new_dnode(&dn, cc->inode, NULL, NULL, 0);
|
||||
|
||||
for (i = cc->cluster_size - 1; i > 0; i--) {
|
||||
ret = f2fs_get_block(&dn, start_idx + i);
|
||||
if (ret) {
|
||||
i = cc->cluster_size;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dn.data_blkaddr != NEW_ADDR)
|
||||
break;
|
||||
}
|
||||
|
||||
f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
|
||||
}
|
||||
|
||||
if (likely(!ret)) {
|
||||
*fsdata = cc->rpages;
|
||||
*pagep = cc->rpages[offset_in_cluster(cc, index)];
|
||||
@@ -1216,6 +1185,12 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
|
||||
loff_t psize;
|
||||
int i, err;
|
||||
|
||||
/* we should bypass data pages to proceed the kworkder jobs */
|
||||
if (unlikely(f2fs_cp_error(sbi))) {
|
||||
mapping_set_error(cc->rpages[0]->mapping, -EIO);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
if (IS_NOQUOTA(inode)) {
|
||||
/*
|
||||
* We need to wait for node_write to avoid block allocation during
|
||||
@@ -1399,7 +1374,7 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page)
|
||||
|
||||
for (i = 0; i < cic->nr_rpages; i++) {
|
||||
WARN_ON(!cic->rpages[i]);
|
||||
clear_cold_data(cic->rpages[i]);
|
||||
clear_page_private_gcing(cic->rpages[i]);
|
||||
end_page_writeback(cic->rpages[i]);
|
||||
}
|
||||
|
||||
|
||||
@@ -59,18 +59,19 @@ static bool __is_cp_guaranteed(struct page *page)
|
||||
if (!mapping)
|
||||
return false;
|
||||
|
||||
if (f2fs_is_compressed_page(page))
|
||||
return false;
|
||||
|
||||
inode = mapping->host;
|
||||
sbi = F2FS_I_SB(inode);
|
||||
|
||||
if (inode->i_ino == F2FS_META_INO(sbi) ||
|
||||
inode->i_ino == F2FS_NODE_INO(sbi) ||
|
||||
S_ISDIR(inode->i_mode) ||
|
||||
(S_ISREG(inode->i_mode) &&
|
||||
S_ISDIR(inode->i_mode))
|
||||
return true;
|
||||
|
||||
if (f2fs_is_compressed_page(page))
|
||||
return false;
|
||||
if ((S_ISREG(inode->i_mode) &&
|
||||
(f2fs_is_atomic_file(inode) || IS_NOQUOTA(inode))) ||
|
||||
is_cold_data(page))
|
||||
page_private_gcing(page))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -300,9 +301,8 @@ static void f2fs_write_end_io(struct bio *bio)
|
||||
struct page *page = bvec->bv_page;
|
||||
enum count_type type = WB_DATA_TYPE(page);
|
||||
|
||||
if (IS_DUMMY_WRITTEN_PAGE(page)) {
|
||||
set_page_private(page, (unsigned long)NULL);
|
||||
ClearPagePrivate(page);
|
||||
if (page_private_dummy(page)) {
|
||||
clear_page_private_dummy(page);
|
||||
unlock_page(page);
|
||||
mempool_free(page, sbi->write_io_dummy);
|
||||
|
||||
@@ -332,7 +332,7 @@ static void f2fs_write_end_io(struct bio *bio)
|
||||
dec_page_count(sbi, type);
|
||||
if (f2fs_in_warm_node_list(sbi, page))
|
||||
f2fs_del_fsync_node_entry(sbi, page);
|
||||
clear_cold_data(page);
|
||||
clear_page_private_gcing(page);
|
||||
end_page_writeback(page);
|
||||
}
|
||||
if (!get_pages(sbi, F2FS_WB_CP_DATA) &&
|
||||
@@ -470,10 +470,11 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi,
|
||||
GFP_NOIO | __GFP_NOFAIL);
|
||||
f2fs_bug_on(sbi, !page);
|
||||
|
||||
zero_user_segment(page, 0, PAGE_SIZE);
|
||||
SetPagePrivate(page);
|
||||
set_page_private(page, DUMMY_WRITTEN_PAGE);
|
||||
lock_page(page);
|
||||
|
||||
zero_user_segment(page, 0, PAGE_SIZE);
|
||||
set_page_private_dummy(page);
|
||||
|
||||
if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE)
|
||||
f2fs_bug_on(sbi, 1);
|
||||
}
|
||||
@@ -2498,9 +2499,9 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
|
||||
if (f2fs_is_atomic_file(inode))
|
||||
return true;
|
||||
if (fio) {
|
||||
if (is_cold_data(fio->page))
|
||||
if (page_private_gcing(fio->page))
|
||||
return true;
|
||||
if (IS_ATOMIC_WRITTEN_PAGE(fio->page))
|
||||
if (page_private_dummy(fio->page))
|
||||
return true;
|
||||
if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) &&
|
||||
f2fs_is_checkpointed_data(sbi, fio->old_blkaddr)))
|
||||
@@ -2556,7 +2557,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
|
||||
/* This page is already truncated */
|
||||
if (fio->old_blkaddr == NULL_ADDR) {
|
||||
ClearPageUptodate(page);
|
||||
clear_cold_data(page);
|
||||
clear_page_private_gcing(page);
|
||||
goto out_writepage;
|
||||
}
|
||||
got_it:
|
||||
@@ -2766,7 +2767,7 @@ out:
|
||||
inode_dec_dirty_pages(inode);
|
||||
if (err) {
|
||||
ClearPageUptodate(page);
|
||||
clear_cold_data(page);
|
||||
clear_page_private_gcing(page);
|
||||
}
|
||||
|
||||
if (wbc->for_reclaim) {
|
||||
@@ -3240,7 +3241,7 @@ restart:
|
||||
f2fs_do_read_inline_data(page, ipage);
|
||||
set_inode_flag(inode, FI_DATA_EXIST);
|
||||
if (inode->i_nlink)
|
||||
set_inline_node(ipage);
|
||||
set_page_private_inline(ipage);
|
||||
} else {
|
||||
err = f2fs_convert_inline_page(&dn, page);
|
||||
if (err)
|
||||
@@ -3672,12 +3673,13 @@ void f2fs_invalidate_page(struct page *page, unsigned int offset,
|
||||
}
|
||||
}
|
||||
|
||||
clear_cold_data(page);
|
||||
clear_page_private_gcing(page);
|
||||
|
||||
if (IS_ATOMIC_WRITTEN_PAGE(page))
|
||||
if (page_private_atomic(page))
|
||||
return f2fs_drop_inmem_page(inode, page);
|
||||
|
||||
f2fs_clear_page_private(page);
|
||||
detach_page_private(page);
|
||||
set_page_private(page, 0);
|
||||
}
|
||||
|
||||
int f2fs_release_page(struct page *page, gfp_t wait)
|
||||
@@ -3687,11 +3689,13 @@ int f2fs_release_page(struct page *page, gfp_t wait)
|
||||
return 0;
|
||||
|
||||
/* This is atomic written page, keep Private */
|
||||
if (IS_ATOMIC_WRITTEN_PAGE(page))
|
||||
if (page_private_atomic(page))
|
||||
return 0;
|
||||
|
||||
clear_cold_data(page);
|
||||
f2fs_clear_page_private(page);
|
||||
clear_page_private_gcing(page);
|
||||
|
||||
detach_page_private(page);
|
||||
set_page_private(page, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -3707,7 +3711,7 @@ static int f2fs_set_data_page_dirty(struct page *page)
|
||||
return __set_page_dirty_nobuffers(page);
|
||||
|
||||
if (f2fs_is_atomic_file(inode) && !f2fs_is_commit_atomic_write(inode)) {
|
||||
if (!IS_ATOMIC_WRITTEN_PAGE(page)) {
|
||||
if (!page_private_atomic(page)) {
|
||||
f2fs_register_inmem_page(inode, page);
|
||||
return 1;
|
||||
}
|
||||
@@ -3799,7 +3803,7 @@ int f2fs_migrate_page(struct address_space *mapping,
|
||||
{
|
||||
int rc, extra_count;
|
||||
struct f2fs_inode_info *fi = F2FS_I(mapping->host);
|
||||
bool atomic_written = IS_ATOMIC_WRITTEN_PAGE(page);
|
||||
bool atomic_written = page_private_atomic(page);
|
||||
|
||||
BUG_ON(PageWriteback(page));
|
||||
|
||||
@@ -3835,8 +3839,13 @@ int f2fs_migrate_page(struct address_space *mapping,
|
||||
}
|
||||
|
||||
if (PagePrivate(page)) {
|
||||
f2fs_set_page_private(newpage, page_private(page));
|
||||
f2fs_clear_page_private(page);
|
||||
set_page_private(newpage, page_private(page));
|
||||
SetPagePrivate(newpage);
|
||||
get_page(newpage);
|
||||
|
||||
set_page_private(page, 0);
|
||||
ClearPagePrivate(page);
|
||||
put_page(page);
|
||||
}
|
||||
|
||||
if (mode != MIGRATE_SYNC_NO_COPY)
|
||||
@@ -4124,6 +4133,12 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
|
||||
if (f2fs_readonly(F2FS_I_SB(inode)->sb))
|
||||
return -EROFS;
|
||||
|
||||
if (f2fs_lfs_mode(F2FS_I_SB(inode))) {
|
||||
f2fs_err(F2FS_I_SB(inode),
|
||||
"Swapfile not supported in LFS mode");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = f2fs_convert_inline_inode(inode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -931,11 +931,15 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
!f2fs_truncate_hole(dir, page->index, page->index + 1)) {
|
||||
f2fs_clear_page_cache_dirty_tag(page);
|
||||
clear_page_dirty_for_io(page);
|
||||
f2fs_clear_page_private(page);
|
||||
ClearPageUptodate(page);
|
||||
clear_cold_data(page);
|
||||
|
||||
clear_page_private_gcing(page);
|
||||
|
||||
inode_dec_dirty_pages(dir);
|
||||
f2fs_remove_dirty_inode(dir);
|
||||
|
||||
detach_page_private(page);
|
||||
set_page_private(page, 0);
|
||||
}
|
||||
f2fs_put_page(page, 1);
|
||||
|
||||
|
||||
110
fs/f2fs/f2fs.h
110
fs/f2fs/f2fs.h
@@ -706,6 +706,7 @@ enum {
|
||||
FI_COMPRESS_CORRUPT, /* indicate compressed cluster is corrupted */
|
||||
FI_MMAP_FILE, /* indicate file was mmapped */
|
||||
FI_ENABLE_COMPRESS, /* enable compression in "user" compression mode */
|
||||
FI_COMPRESS_RELEASED, /* compressed blocks were released */
|
||||
FI_MAX, /* max flag, never be used */
|
||||
};
|
||||
|
||||
@@ -1291,17 +1292,85 @@ enum {
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* this value is set in page as a private data which indicate that
|
||||
* the page is atomically written, and it is in inmem_pages list.
|
||||
*/
|
||||
#define ATOMIC_WRITTEN_PAGE ((unsigned long)-1)
|
||||
#define DUMMY_WRITTEN_PAGE ((unsigned long)-2)
|
||||
static inline int f2fs_test_bit(unsigned int nr, char *addr);
|
||||
static inline void f2fs_set_bit(unsigned int nr, char *addr);
|
||||
static inline void f2fs_clear_bit(unsigned int nr, char *addr);
|
||||
|
||||
#define IS_ATOMIC_WRITTEN_PAGE(page) \
|
||||
(page_private(page) == ATOMIC_WRITTEN_PAGE)
|
||||
#define IS_DUMMY_WRITTEN_PAGE(page) \
|
||||
(page_private(page) == DUMMY_WRITTEN_PAGE)
|
||||
/*
|
||||
* Layout of f2fs page.private:
|
||||
*
|
||||
* Layout A: lowest bit should be 1
|
||||
* | bit0 = 1 | bit1 | bit2 | ... | bit MAX | private data .... |
|
||||
* bit 0 PAGE_PRIVATE_NOT_POINTER
|
||||
* bit 1 PAGE_PRIVATE_ATOMIC_WRITE
|
||||
* bit 2 PAGE_PRIVATE_DUMMY_WRITE
|
||||
* bit 3 PAGE_PRIVATE_ONGOING_MIGRATION
|
||||
* bit 4 PAGE_PRIVATE_INLINE_INODE
|
||||
* bit 5 PAGE_PRIVATE_REF_RESOURCE
|
||||
* bit 6- f2fs private data
|
||||
*
|
||||
* Layout B: lowest bit should be 0
|
||||
* page.private is a wrapped pointer.
|
||||
*/
|
||||
enum {
|
||||
PAGE_PRIVATE_NOT_POINTER, /* private contains non-pointer data */
|
||||
PAGE_PRIVATE_ATOMIC_WRITE, /* data page from atomic write path */
|
||||
PAGE_PRIVATE_DUMMY_WRITE, /* data page for padding aligned IO */
|
||||
PAGE_PRIVATE_ONGOING_MIGRATION, /* data page which is on-going migrating */
|
||||
PAGE_PRIVATE_INLINE_INODE, /* inode page contains inline data */
|
||||
PAGE_PRIVATE_REF_RESOURCE, /* dirty page has referenced resources */
|
||||
PAGE_PRIVATE_MAX
|
||||
};
|
||||
|
||||
#define PAGE_PRIVATE_GET_FUNC(name, flagname) \
|
||||
static inline bool page_private_##name(struct page *page) \
|
||||
{ \
|
||||
return test_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)) && \
|
||||
test_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \
|
||||
}
|
||||
|
||||
#define PAGE_PRIVATE_SET_FUNC(name, flagname) \
|
||||
static inline void set_page_private_##name(struct page *page) \
|
||||
{ \
|
||||
if (!PagePrivate(page)) { \
|
||||
get_page(page); \
|
||||
SetPagePrivate(page); \
|
||||
} \
|
||||
set_bit(PAGE_PRIVATE_NOT_POINTER, &page_private(page)); \
|
||||
set_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \
|
||||
}
|
||||
|
||||
#define PAGE_PRIVATE_CLEAR_FUNC(name, flagname) \
|
||||
static inline void clear_page_private_##name(struct page *page) \
|
||||
{ \
|
||||
clear_bit(PAGE_PRIVATE_##flagname, &page_private(page)); \
|
||||
if (page_private(page) == 1 << PAGE_PRIVATE_NOT_POINTER) { \
|
||||
set_page_private(page, 0); \
|
||||
if (PagePrivate(page)) { \
|
||||
ClearPagePrivate(page); \
|
||||
put_page(page); \
|
||||
}\
|
||||
} \
|
||||
}
|
||||
|
||||
PAGE_PRIVATE_GET_FUNC(nonpointer, NOT_POINTER);
|
||||
PAGE_PRIVATE_GET_FUNC(reference, REF_RESOURCE);
|
||||
PAGE_PRIVATE_GET_FUNC(inline, INLINE_INODE);
|
||||
PAGE_PRIVATE_GET_FUNC(gcing, ONGOING_MIGRATION);
|
||||
PAGE_PRIVATE_GET_FUNC(atomic, ATOMIC_WRITE);
|
||||
PAGE_PRIVATE_GET_FUNC(dummy, DUMMY_WRITE);
|
||||
|
||||
PAGE_PRIVATE_SET_FUNC(reference, REF_RESOURCE);
|
||||
PAGE_PRIVATE_SET_FUNC(inline, INLINE_INODE);
|
||||
PAGE_PRIVATE_SET_FUNC(gcing, ONGOING_MIGRATION);
|
||||
PAGE_PRIVATE_SET_FUNC(atomic, ATOMIC_WRITE);
|
||||
PAGE_PRIVATE_SET_FUNC(dummy, DUMMY_WRITE);
|
||||
|
||||
PAGE_PRIVATE_CLEAR_FUNC(reference, REF_RESOURCE);
|
||||
PAGE_PRIVATE_CLEAR_FUNC(inline, INLINE_INODE);
|
||||
PAGE_PRIVATE_CLEAR_FUNC(gcing, ONGOING_MIGRATION);
|
||||
PAGE_PRIVATE_CLEAR_FUNC(atomic, ATOMIC_WRITE);
|
||||
PAGE_PRIVATE_CLEAR_FUNC(dummy, DUMMY_WRITE);
|
||||
|
||||
/* For compression */
|
||||
enum compress_algorithm_type {
|
||||
@@ -2678,6 +2747,7 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,
|
||||
case FI_DATA_EXIST:
|
||||
case FI_INLINE_DOTS:
|
||||
case FI_PIN_FILE:
|
||||
case FI_COMPRESS_RELEASED:
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
}
|
||||
}
|
||||
@@ -2799,6 +2869,8 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)
|
||||
set_bit(FI_EXTRA_ATTR, fi->flags);
|
||||
if (ri->i_inline & F2FS_PIN_FILE)
|
||||
set_bit(FI_PIN_FILE, fi->flags);
|
||||
if (ri->i_inline & F2FS_COMPRESS_RELEASED)
|
||||
set_bit(FI_COMPRESS_RELEASED, fi->flags);
|
||||
}
|
||||
|
||||
static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri)
|
||||
@@ -2819,6 +2891,8 @@ static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri)
|
||||
ri->i_inline |= F2FS_EXTRA_ATTR;
|
||||
if (is_inode_flag_set(inode, FI_PIN_FILE))
|
||||
ri->i_inline |= F2FS_PIN_FILE;
|
||||
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
|
||||
ri->i_inline |= F2FS_COMPRESS_RELEASED;
|
||||
}
|
||||
|
||||
static inline int f2fs_has_extra_attr(struct inode *inode)
|
||||
@@ -3169,20 +3243,6 @@ static inline bool __is_valid_data_blkaddr(block_t blkaddr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void f2fs_set_page_private(struct page *page,
|
||||
unsigned long data)
|
||||
{
|
||||
if (PagePrivate(page))
|
||||
return;
|
||||
|
||||
attach_page_private(page, (void *)data);
|
||||
}
|
||||
|
||||
static inline void f2fs_clear_page_private(struct page *page)
|
||||
{
|
||||
detach_page_private(page);
|
||||
}
|
||||
|
||||
/*
|
||||
* file.c
|
||||
*/
|
||||
@@ -3562,6 +3622,8 @@ void f2fs_destroy_garbage_collection_cache(void);
|
||||
*/
|
||||
int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only);
|
||||
bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi);
|
||||
int __init f2fs_create_recovery_cache(void);
|
||||
void f2fs_destroy_recovery_cache(void);
|
||||
|
||||
/*
|
||||
* debug.c
|
||||
|
||||
@@ -62,6 +62,9 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
|
||||
if (unlikely(IS_IMMUTABLE(inode)))
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED))
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
if (unlikely(f2fs_cp_error(sbi))) {
|
||||
err = -EIO;
|
||||
goto err;
|
||||
@@ -84,10 +87,6 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
|
||||
err = ret;
|
||||
goto err;
|
||||
} else if (ret) {
|
||||
if (ret < F2FS_I(inode)->i_cluster_size) {
|
||||
err = -EAGAIN;
|
||||
goto err;
|
||||
}
|
||||
need_alloc = false;
|
||||
}
|
||||
}
|
||||
@@ -116,7 +115,6 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf)
|
||||
f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true);
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = f2fs_get_block(&dn, page->index);
|
||||
f2fs_put_dnode(&dn);
|
||||
f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false);
|
||||
}
|
||||
|
||||
@@ -3328,7 +3326,7 @@ int f2fs_precache_extents(struct inode *inode)
|
||||
map.m_lblk = m_next_extent;
|
||||
}
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int f2fs_ioc_precache_extents(struct file *filp, unsigned long arg)
|
||||
@@ -3550,7 +3548,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (IS_IMMUTABLE(inode)) {
|
||||
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
@@ -3559,8 +3557,7 @@ static int f2fs_release_compress_blocks(struct file *filp, unsigned long arg)
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
F2FS_I(inode)->i_flags |= F2FS_IMMUTABLE_FL;
|
||||
f2fs_set_inode_flags(inode);
|
||||
set_inode_flag(inode, FI_COMPRESS_RELEASED);
|
||||
inode->i_ctime = current_time(inode);
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
|
||||
@@ -3715,7 +3712,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
|
||||
|
||||
inode_lock(inode);
|
||||
|
||||
if (!IS_IMMUTABLE(inode)) {
|
||||
if (!is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
|
||||
ret = -EINVAL;
|
||||
goto unlock_inode;
|
||||
}
|
||||
@@ -3760,8 +3757,7 @@ static int f2fs_reserve_compress_blocks(struct file *filp, unsigned long arg)
|
||||
up_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
|
||||
if (ret >= 0) {
|
||||
F2FS_I(inode)->i_flags &= ~F2FS_IMMUTABLE_FL;
|
||||
f2fs_set_inode_flags(inode);
|
||||
clear_inode_flag(inode, FI_COMPRESS_RELEASED);
|
||||
inode->i_ctime = current_time(inode);
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
}
|
||||
@@ -4387,6 +4383,11 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (is_inode_flag_set(inode, FI_COMPRESS_RELEASED)) {
|
||||
ret = -EPERM;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret = generic_write_checks(iocb, from);
|
||||
if (ret > 0) {
|
||||
bool preallocated = false;
|
||||
|
||||
@@ -1336,7 +1336,7 @@ static int move_data_page(struct inode *inode, block_t bidx, int gc_type,
|
||||
goto out;
|
||||
}
|
||||
set_page_dirty(page);
|
||||
set_cold_data(page);
|
||||
set_page_private_gcing(page);
|
||||
} else {
|
||||
struct f2fs_io_info fio = {
|
||||
.sbi = F2FS_I_SB(inode),
|
||||
@@ -1362,11 +1362,11 @@ retry:
|
||||
f2fs_remove_dirty_inode(inode);
|
||||
}
|
||||
|
||||
set_cold_data(page);
|
||||
set_page_private_gcing(page);
|
||||
|
||||
err = f2fs_do_write_data_page(&fio);
|
||||
if (err) {
|
||||
clear_cold_data(page);
|
||||
clear_page_private_gcing(page);
|
||||
if (err == -ENOMEM) {
|
||||
congestion_wait(BLK_RW_ASYNC,
|
||||
DEFAULT_IO_TIMEOUT);
|
||||
@@ -1822,6 +1822,7 @@ static void init_atgc_management(struct f2fs_sb_info *sbi)
|
||||
am->candidate_ratio = DEF_GC_THREAD_CANDIDATE_RATIO;
|
||||
am->max_candidate_count = DEF_GC_THREAD_MAX_CANDIDATE_COUNT;
|
||||
am->age_weight = DEF_GC_THREAD_AGE_WEIGHT;
|
||||
am->age_threshold = DEF_GC_THREAD_AGE_THRESHOLD;
|
||||
}
|
||||
|
||||
void f2fs_build_gc_manager(struct f2fs_sb_info *sbi)
|
||||
|
||||
@@ -191,7 +191,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
|
||||
|
||||
/* clear inline data and flag after data writeback */
|
||||
f2fs_truncate_inline_inode(dn->inode, dn->inode_page, 0);
|
||||
clear_inline_node(dn->inode_page);
|
||||
clear_page_private_inline(dn->inode_page);
|
||||
clear_out:
|
||||
stat_dec_inline_inode(dn->inode);
|
||||
clear_inode_flag(dn->inode, FI_INLINE_DATA);
|
||||
@@ -273,7 +273,7 @@ int f2fs_write_inline_data(struct inode *inode, struct page *page)
|
||||
set_inode_flag(inode, FI_APPEND_WRITE);
|
||||
set_inode_flag(inode, FI_DATA_EXIST);
|
||||
|
||||
clear_inline_node(dn.inode_page);
|
||||
clear_page_private_inline(dn.inode_page);
|
||||
f2fs_put_dnode(&dn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -646,7 +646,7 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page)
|
||||
|
||||
/* deleted inode */
|
||||
if (inode->i_nlink == 0)
|
||||
clear_inline_node(node_page);
|
||||
clear_page_private_inline(node_page);
|
||||
|
||||
F2FS_I(inode)->i_disk_time[0] = inode->i_atime;
|
||||
F2FS_I(inode)->i_disk_time[1] = inode->i_ctime;
|
||||
|
||||
@@ -153,7 +153,8 @@ fail_drop:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static inline int is_extension_exist(const unsigned char *s, const char *sub)
|
||||
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);
|
||||
@@ -169,6 +170,13 @@ static inline int is_extension_exist(const unsigned char *s, const char *sub)
|
||||
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;
|
||||
@@ -194,7 +202,7 @@ static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *
|
||||
hot_count = sbi->raw_super->hot_ext_count;
|
||||
|
||||
for (i = 0; i < cold_count + hot_count; i++) {
|
||||
if (is_extension_exist(name, extlist[i]))
|
||||
if (is_extension_exist(name, extlist[i], true))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -295,7 +303,7 @@ static void set_compress_inode(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
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])) {
|
||||
if (is_extension_exist(name, extlist[i], false)) {
|
||||
up_read(&sbi->sb_lock);
|
||||
return;
|
||||
}
|
||||
@@ -306,7 +314,7 @@ static void set_compress_inode(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
ext = F2FS_OPTION(sbi).extensions;
|
||||
|
||||
for (i = 0; i < ext_cnt; i++) {
|
||||
if (!is_extension_exist(name, ext[i]))
|
||||
if (!is_extension_exist(name, ext[i], false))
|
||||
continue;
|
||||
|
||||
set_compress_context(inode);
|
||||
|
||||
@@ -1860,8 +1860,8 @@ continue_unlock:
|
||||
}
|
||||
|
||||
/* flush inline_data, if it's async context. */
|
||||
if (is_inline_node(page)) {
|
||||
clear_inline_node(page);
|
||||
if (page_private_inline(page)) {
|
||||
clear_page_private_inline(page);
|
||||
unlock_page(page);
|
||||
flush_inline_data(sbi, ino_of_node(page));
|
||||
continue;
|
||||
@@ -1941,8 +1941,8 @@ continue_unlock:
|
||||
goto write_node;
|
||||
|
||||
/* flush inline_data */
|
||||
if (is_inline_node(page)) {
|
||||
clear_inline_node(page);
|
||||
if (page_private_inline(page)) {
|
||||
clear_page_private_inline(page);
|
||||
unlock_page(page);
|
||||
flush_inline_data(sbi, ino_of_node(page));
|
||||
goto lock_node;
|
||||
@@ -2096,7 +2096,7 @@ static int f2fs_set_node_page_dirty(struct page *page)
|
||||
if (!PageDirty(page)) {
|
||||
__set_page_dirty_nobuffers(page);
|
||||
inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES);
|
||||
f2fs_set_page_private(page, 0);
|
||||
set_page_private_reference(page);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -389,20 +389,6 @@ static inline nid_t get_nid(struct page *p, int off, bool i)
|
||||
* - Mark cold node blocks in their node footer
|
||||
* - Mark cold data pages in page cache
|
||||
*/
|
||||
static inline int is_cold_data(struct page *page)
|
||||
{
|
||||
return PageChecked(page);
|
||||
}
|
||||
|
||||
static inline void set_cold_data(struct page *page)
|
||||
{
|
||||
SetPageChecked(page);
|
||||
}
|
||||
|
||||
static inline void clear_cold_data(struct page *page)
|
||||
{
|
||||
ClearPageChecked(page);
|
||||
}
|
||||
|
||||
static inline int is_node(struct page *page, int type)
|
||||
{
|
||||
@@ -414,21 +400,6 @@ static inline int is_node(struct page *page, int type)
|
||||
#define is_fsync_dnode(page) is_node(page, FSYNC_BIT_SHIFT)
|
||||
#define is_dent_dnode(page) is_node(page, DENT_BIT_SHIFT)
|
||||
|
||||
static inline int is_inline_node(struct page *page)
|
||||
{
|
||||
return PageChecked(page);
|
||||
}
|
||||
|
||||
static inline void set_inline_node(struct page *page)
|
||||
{
|
||||
SetPageChecked(page);
|
||||
}
|
||||
|
||||
static inline void clear_inline_node(struct page *page)
|
||||
{
|
||||
ClearPageChecked(page);
|
||||
}
|
||||
|
||||
static inline void set_cold_node(struct page *page, bool is_dir)
|
||||
{
|
||||
struct f2fs_node *rn = F2FS_NODE(page);
|
||||
|
||||
@@ -782,19 +782,10 @@ 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
|
||||
|
||||
fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
|
||||
sizeof(struct fsync_inode_entry));
|
||||
if (!fsync_entry_slab) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&inode_list);
|
||||
INIT_LIST_HEAD(&tmp_inode_list);
|
||||
INIT_LIST_HEAD(&dir_list);
|
||||
@@ -818,10 +809,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);
|
||||
|
||||
@@ -867,8 +856,6 @@ skip:
|
||||
}
|
||||
}
|
||||
|
||||
kmem_cache_destroy(fsync_entry_slab);
|
||||
out:
|
||||
#ifdef CONFIG_QUOTA
|
||||
/* Turn quotas off */
|
||||
if (quota_enabled)
|
||||
@@ -878,3 +865,17 @@ out:
|
||||
|
||||
return ret ? ret : err;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void f2fs_destroy_recovery_cache(void)
|
||||
{
|
||||
kmem_cache_destroy(fsync_entry_slab);
|
||||
}
|
||||
|
||||
@@ -186,10 +186,7 @@ void f2fs_register_inmem_page(struct inode *inode, struct page *page)
|
||||
{
|
||||
struct inmem_pages *new;
|
||||
|
||||
if (PagePrivate(page))
|
||||
set_page_private(page, (unsigned long)ATOMIC_WRITTEN_PAGE);
|
||||
else
|
||||
f2fs_set_page_private(page, ATOMIC_WRITTEN_PAGE);
|
||||
set_page_private_atomic(page);
|
||||
|
||||
new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS);
|
||||
|
||||
@@ -272,9 +269,10 @@ next:
|
||||
/* we don't need to invalidate this in the sccessful status */
|
||||
if (drop || recover) {
|
||||
ClearPageUptodate(page);
|
||||
clear_cold_data(page);
|
||||
clear_page_private_gcing(page);
|
||||
}
|
||||
f2fs_clear_page_private(page);
|
||||
detach_page_private(page);
|
||||
set_page_private(page, 0);
|
||||
f2fs_put_page(page, 1);
|
||||
|
||||
list_del(&cur->list);
|
||||
@@ -357,7 +355,7 @@ void f2fs_drop_inmem_page(struct inode *inode, struct page *page)
|
||||
struct list_head *head = &fi->inmem_pages;
|
||||
struct inmem_pages *cur = NULL;
|
||||
|
||||
f2fs_bug_on(sbi, !IS_ATOMIC_WRITTEN_PAGE(page));
|
||||
f2fs_bug_on(sbi, !page_private_atomic(page));
|
||||
|
||||
mutex_lock(&fi->inmem_lock);
|
||||
list_for_each_entry(cur, head, list) {
|
||||
@@ -373,9 +371,12 @@ void f2fs_drop_inmem_page(struct inode *inode, struct page *page)
|
||||
kmem_cache_free(inmem_entry_slab, cur);
|
||||
|
||||
ClearPageUptodate(page);
|
||||
f2fs_clear_page_private(page);
|
||||
clear_page_private_atomic(page);
|
||||
f2fs_put_page(page, 0);
|
||||
|
||||
detach_page_private(page);
|
||||
set_page_private(page, 0);
|
||||
|
||||
trace_f2fs_commit_inmem_page(page, INMEM_INVALIDATE);
|
||||
}
|
||||
|
||||
@@ -3289,7 +3290,7 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
|
||||
if (fio->type == DATA) {
|
||||
struct inode *inode = fio->page->mapping->host;
|
||||
|
||||
if (is_cold_data(fio->page)) {
|
||||
if (page_private_gcing(fio->page)) {
|
||||
if (fio->sbi->am.atgc_enabled &&
|
||||
(fio->io_type == FS_DATA_IO) &&
|
||||
(fio->sbi->gc_mode != GC_URGENT_HIGH))
|
||||
|
||||
@@ -1869,17 +1869,15 @@ static int f2fs_enable_quotas(struct super_block *sb);
|
||||
|
||||
static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
unsigned int s_flags = sbi->sb->s_flags;
|
||||
struct cp_control cpc;
|
||||
int err = 0;
|
||||
int ret;
|
||||
block_t unusable;
|
||||
|
||||
if (s_flags & SB_RDONLY) {
|
||||
if (sbi->sb->s_flags & SB_RDONLY) {
|
||||
f2fs_err(sbi, "checkpoint=disable on readonly fs");
|
||||
return -EINVAL;
|
||||
}
|
||||
sbi->sb->s_flags |= SB_ACTIVE;
|
||||
|
||||
f2fs_update_time(sbi, DISABLE_TIME);
|
||||
|
||||
@@ -1897,13 +1895,13 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
|
||||
ret = sync_filesystem(sbi->sb);
|
||||
if (ret || err) {
|
||||
err = ret ? ret : err;
|
||||
goto restore_flag;
|
||||
goto out;
|
||||
}
|
||||
|
||||
unusable = f2fs_get_unusable_blocks(sbi);
|
||||
if (f2fs_disable_cp_again(sbi, unusable)) {
|
||||
err = -EAGAIN;
|
||||
goto restore_flag;
|
||||
goto out;
|
||||
}
|
||||
|
||||
down_write(&sbi->gc_lock);
|
||||
@@ -1919,8 +1917,7 @@ static int f2fs_disable_checkpoint(struct f2fs_sb_info *sbi)
|
||||
|
||||
out_unlock:
|
||||
up_write(&sbi->gc_lock);
|
||||
restore_flag:
|
||||
sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -4230,9 +4227,12 @@ static int __init init_f2fs_fs(void)
|
||||
err = f2fs_create_checkpoint_caches();
|
||||
if (err)
|
||||
goto free_segment_manager_caches;
|
||||
err = f2fs_create_extent_cache();
|
||||
err = f2fs_create_recovery_cache();
|
||||
if (err)
|
||||
goto free_checkpoint_caches;
|
||||
err = f2fs_create_extent_cache();
|
||||
if (err)
|
||||
goto free_recovery_cache;
|
||||
err = f2fs_create_garbage_collection_cache();
|
||||
if (err)
|
||||
goto free_extent_cache;
|
||||
@@ -4281,6 +4281,8 @@ free_garbage_collection_cache:
|
||||
f2fs_destroy_garbage_collection_cache();
|
||||
free_extent_cache:
|
||||
f2fs_destroy_extent_cache();
|
||||
free_recovery_cache:
|
||||
f2fs_destroy_recovery_cache();
|
||||
free_checkpoint_caches:
|
||||
f2fs_destroy_checkpoint_caches();
|
||||
free_segment_manager_caches:
|
||||
@@ -4306,6 +4308,7 @@ static void __exit exit_f2fs_fs(void)
|
||||
f2fs_exit_sysfs();
|
||||
f2fs_destroy_garbage_collection_cache();
|
||||
f2fs_destroy_extent_cache();
|
||||
f2fs_destroy_recovery_cache();
|
||||
f2fs_destroy_checkpoint_caches();
|
||||
f2fs_destroy_segment_manager_caches();
|
||||
f2fs_destroy_node_manager_caches();
|
||||
@@ -4318,4 +4321,5 @@ module_exit(exit_f2fs_fs)
|
||||
MODULE_AUTHOR("Samsung Electronics's Praesto Team");
|
||||
MODULE_DESCRIPTION("Flash Friendly File System");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_SOFTDEP("pre: crc32");
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ enum {
|
||||
#endif
|
||||
RESERVED_BLOCKS, /* struct f2fs_sb_info */
|
||||
CPRC_INFO, /* struct ckpt_req_control */
|
||||
ATGC_INFO, /* struct atgc_management */
|
||||
};
|
||||
|
||||
struct f2fs_attr {
|
||||
@@ -75,6 +76,8 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
|
||||
#endif
|
||||
else if (struct_type == CPRC_INFO)
|
||||
return (unsigned char *)&sbi->cprc_info;
|
||||
else if (struct_type == ATGC_INFO)
|
||||
return (unsigned char *)&sbi->am;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -495,6 +498,20 @@ out:
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!strcmp(a->attr.name, "atgc_candidate_ratio")) {
|
||||
if (t > 100)
|
||||
return -EINVAL;
|
||||
sbi->am.candidate_ratio = t;
|
||||
return count;
|
||||
}
|
||||
|
||||
if (!strcmp(a->attr.name, "atgc_age_weight")) {
|
||||
if (t > 100)
|
||||
return -EINVAL;
|
||||
sbi->am.age_weight = t;
|
||||
return count;
|
||||
}
|
||||
|
||||
*ui = (unsigned int)t;
|
||||
|
||||
return count;
|
||||
@@ -710,6 +727,11 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_written_block, compr_written_block);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_saved_block, compr_saved_block);
|
||||
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, compr_new_inode, compr_new_inode);
|
||||
#endif
|
||||
/* For ATGC */
|
||||
F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_candidate_ratio, candidate_ratio);
|
||||
F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_candidate_count, max_candidate_count);
|
||||
F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_age_weight, age_weight);
|
||||
F2FS_RW_ATTR(ATGC_INFO, atgc_management, atgc_age_threshold, age_threshold);
|
||||
|
||||
#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
|
||||
static struct attribute *f2fs_attrs[] = {
|
||||
@@ -778,6 +800,11 @@ static struct attribute *f2fs_attrs[] = {
|
||||
ATTR_LIST(compr_saved_block),
|
||||
ATTR_LIST(compr_new_inode),
|
||||
#endif
|
||||
/* For ATGC */
|
||||
ATTR_LIST(atgc_candidate_ratio),
|
||||
ATTR_LIST(atgc_candidate_count),
|
||||
ATTR_LIST(atgc_age_weight),
|
||||
ATTR_LIST(atgc_age_threshold),
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(f2fs);
|
||||
|
||||
@@ -229,6 +229,7 @@ struct f2fs_extent {
|
||||
#define F2FS_INLINE_DOTS 0x10 /* file having implicit dot dentries */
|
||||
#define F2FS_EXTRA_ATTR 0x20 /* file having extra attribute */
|
||||
#define F2FS_PIN_FILE 0x40 /* file should not be gced */
|
||||
#define F2FS_COMPRESS_RELEASED 0x80 /* file released compressed blocks */
|
||||
|
||||
struct f2fs_inode {
|
||||
__le16 i_mode; /* file mode */
|
||||
|
||||
Reference in New Issue
Block a user