Merge branch 'upstream-f2fs-stable-linux-4.19.y' of https://android.googlesource.com/kernel/common into lineage-20
* 'upstream-f2fs-stable-linux-4.19.y' of https://android.googlesource.com/kernel/common: (560 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: avoid build warnining in extent_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 ... Conflicts: fs/crypto/hooks.c fs/ext4/ioctl.c fs/ext4/namei.c fs/f2fs/checkpoint.c fs/f2fs/data.c fs/f2fs/dir.c fs/f2fs/f2fs.h fs/f2fs/file.c fs/f2fs/gc.c fs/f2fs/hash.c fs/f2fs/inline.c fs/f2fs/namei.c fs/f2fs/node.c fs/f2fs/node.h fs/f2fs/recovery.c fs/f2fs/segment.c fs/f2fs/segment.h fs/f2fs/super.c fs/f2fs/sysfs.c fs/f2fs/xattr.c fs/libfs.c fs/ubifs/dir.c fs/unicode/utf8-core.c fs/verity/enable.c fs/verity/signature.c include/linux/fs.h include/linux/fscrypt.h include/uapi/linux/fsverity.h Change-Id: I555b2ac03d0bc864b8993a006994c68c0f4f8c41
This commit is contained in:
@@ -45,12 +45,20 @@
|
||||
|
||||
static struct kmem_cache *fsync_entry_slab;
|
||||
|
||||
#ifdef CONFIG_UNICODE
|
||||
extern struct kmem_cache *f2fs_cf_name_slab;
|
||||
#endif
|
||||
|
||||
bool f2fs_space_for_roll_forward(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
s64 nalloc = percpu_counter_sum_positive(&sbi->alloc_valid_block_count);
|
||||
|
||||
if (sbi->last_valid_block_count + nalloc > sbi->user_block_count)
|
||||
return false;
|
||||
if (NM_I(sbi)->max_rf_node_blocks &&
|
||||
percpu_counter_sum_positive(&sbi->rf_node_block_count) >=
|
||||
NM_I(sbi)->max_rf_node_blocks)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -77,7 +85,7 @@ static struct fsync_inode_entry *add_fsync_inode(struct f2fs_sb_info *sbi,
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
|
||||
err = dquot_initialize(inode);
|
||||
err = f2fs_dquot_initialize(inode);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
@@ -87,7 +95,8 @@ static struct fsync_inode_entry *add_fsync_inode(struct f2fs_sb_info *sbi,
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
entry = f2fs_kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO);
|
||||
entry = f2fs_kmem_cache_alloc(fsync_entry_slab,
|
||||
GFP_F2FS_ZERO, true, NULL);
|
||||
entry->inode = inode;
|
||||
list_add_tail(&entry->list, head);
|
||||
|
||||
@@ -145,7 +154,7 @@ static int init_recovered_filename(const struct inode *dir,
|
||||
f2fs_hash_filename(dir, fname);
|
||||
#ifdef CONFIG_UNICODE
|
||||
/* Case-sensitive match is fine for recovery */
|
||||
kfree(fname->cf_name.name);
|
||||
kmem_cache_free(f2fs_cf_name_slab, fname->cf_name.name);
|
||||
fname->cf_name.name = NULL;
|
||||
#endif
|
||||
} else {
|
||||
@@ -198,7 +207,7 @@ static int recover_dentry(struct inode *inode, struct page *ipage,
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
err = dquot_initialize(einode);
|
||||
err = f2fs_dquot_initialize(einode);
|
||||
if (err) {
|
||||
iput(einode);
|
||||
goto out_put;
|
||||
@@ -337,6 +346,19 @@ static int recover_inode(struct inode *inode, struct page *page)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int adjust_por_ra_blocks(struct f2fs_sb_info *sbi,
|
||||
unsigned int ra_blocks, unsigned int blkaddr,
|
||||
unsigned int next_blkaddr)
|
||||
{
|
||||
if (blkaddr + 1 == next_blkaddr)
|
||||
ra_blocks = min_t(unsigned int, RECOVERY_MAX_RA_BLOCKS,
|
||||
ra_blocks * 2);
|
||||
else if (next_blkaddr % sbi->blocks_per_seg)
|
||||
ra_blocks = max_t(unsigned int, RECOVERY_MIN_RA_BLOCKS,
|
||||
ra_blocks / 2);
|
||||
return ra_blocks;
|
||||
}
|
||||
|
||||
static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
|
||||
bool check_only)
|
||||
{
|
||||
@@ -344,6 +366,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
|
||||
struct page *page = NULL;
|
||||
block_t blkaddr;
|
||||
unsigned int loop_cnt = 0;
|
||||
unsigned int ra_blocks = RECOVERY_MAX_RA_BLOCKS;
|
||||
unsigned int free_blocks = MAIN_SEGS(sbi) * sbi->blocks_per_seg -
|
||||
valid_user_blocks(sbi);
|
||||
int err = 0;
|
||||
@@ -418,11 +441,14 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
|
||||
break;
|
||||
}
|
||||
|
||||
ra_blocks = adjust_por_ra_blocks(sbi, ra_blocks, blkaddr,
|
||||
next_blkaddr_of_node(page));
|
||||
|
||||
/* check next segment */
|
||||
blkaddr = next_blkaddr_of_node(page);
|
||||
f2fs_put_page(page, 1);
|
||||
|
||||
f2fs_ra_meta_pages_cond(sbi, blkaddr);
|
||||
f2fs_ra_meta_pages_cond(sbi, blkaddr, ra_blocks);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@@ -447,7 +473,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
|
||||
struct dnode_of_data tdn = *dn;
|
||||
nid_t ino, nid;
|
||||
struct inode *inode;
|
||||
unsigned int offset;
|
||||
unsigned int offset, ofs_in_node, max_addrs;
|
||||
block_t bidx;
|
||||
int i;
|
||||
|
||||
@@ -458,6 +484,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
|
||||
/* Get the previous summary */
|
||||
for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) {
|
||||
struct curseg_info *curseg = CURSEG_I(sbi, i);
|
||||
|
||||
if (curseg->segno == segno) {
|
||||
sum = curseg->sum_blk->entries[blkoff];
|
||||
goto got_it;
|
||||
@@ -473,15 +500,25 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
|
||||
got_it:
|
||||
/* Use the locked dnode page and inode */
|
||||
nid = le32_to_cpu(sum.nid);
|
||||
ofs_in_node = le16_to_cpu(sum.ofs_in_node);
|
||||
|
||||
max_addrs = ADDRS_PER_PAGE(dn->node_page, dn->inode);
|
||||
if (ofs_in_node >= max_addrs) {
|
||||
f2fs_err(sbi, "Inconsistent ofs_in_node:%u in summary, ino:%lu, nid:%u, max:%u",
|
||||
ofs_in_node, dn->inode->i_ino, nid, max_addrs);
|
||||
f2fs_handle_error(sbi, ERROR_INCONSISTENT_SUMMARY);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
|
||||
if (dn->inode->i_ino == nid) {
|
||||
tdn.nid = nid;
|
||||
if (!dn->inode_page_locked)
|
||||
lock_page(dn->inode_page);
|
||||
tdn.node_page = dn->inode_page;
|
||||
tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node);
|
||||
tdn.ofs_in_node = ofs_in_node;
|
||||
goto truncate_out;
|
||||
} else if (dn->nid == nid) {
|
||||
tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node);
|
||||
tdn.ofs_in_node = ofs_in_node;
|
||||
goto truncate_out;
|
||||
}
|
||||
|
||||
@@ -502,7 +539,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
ret = dquot_initialize(inode);
|
||||
ret = f2fs_dquot_initialize(inode);
|
||||
if (ret) {
|
||||
iput(inode);
|
||||
return ret;
|
||||
@@ -589,7 +626,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
|
||||
f2fs_wait_on_page_writeback(dn.node_page, NODE, true, true);
|
||||
|
||||
err = f2fs_get_node_info(sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(sbi, dn.nid, &ni, false);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
@@ -600,6 +637,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
inode->i_ino, ofs_of_node(dn.node_page),
|
||||
ofs_of_node(page));
|
||||
err = -EFSCORRUPTED;
|
||||
f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -612,12 +650,14 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
if (__is_valid_data_blkaddr(src) &&
|
||||
!f2fs_is_valid_blkaddr(sbi, src, META_POR)) {
|
||||
err = -EFSCORRUPTED;
|
||||
f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (__is_valid_data_blkaddr(dest) &&
|
||||
!f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
|
||||
err = -EFSCORRUPTED;
|
||||
f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -682,6 +722,16 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (f2fs_is_valid_blkaddr(sbi, dest,
|
||||
DATA_GENERIC_ENHANCE_UPDATE)) {
|
||||
f2fs_err(sbi, "Inconsistent dest blkaddr:%u, ino:%lu, ofs:%u",
|
||||
dest, inode->i_ino, dn.ofs_in_node);
|
||||
err = -EFSCORRUPTED;
|
||||
f2fs_handle_error(sbi,
|
||||
ERROR_INVALID_BLKADDR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* write dummy data page */
|
||||
f2fs_replace_block(sbi, &dn, src, dest,
|
||||
ni.version, false, false);
|
||||
@@ -709,6 +759,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
||||
struct page *page = NULL;
|
||||
int err = 0;
|
||||
block_t blkaddr;
|
||||
unsigned int ra_blocks = RECOVERY_MAX_RA_BLOCKS;
|
||||
|
||||
/* get node pages in the current segment */
|
||||
curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
|
||||
@@ -720,8 +771,6 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
||||
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
|
||||
break;
|
||||
|
||||
f2fs_ra_meta_pages_cond(sbi, blkaddr);
|
||||
|
||||
page = f2fs_get_tmp_page(sbi, blkaddr);
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
@@ -764,12 +813,17 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
||||
if (entry->blkaddr == blkaddr)
|
||||
list_move_tail(&entry->list, tmp_inode_list);
|
||||
next:
|
||||
ra_blocks = adjust_por_ra_blocks(sbi, ra_blocks, blkaddr,
|
||||
next_blkaddr_of_node(page));
|
||||
|
||||
/* check next segment */
|
||||
blkaddr = next_blkaddr_of_node(page);
|
||||
f2fs_put_page(page, 1);
|
||||
|
||||
f2fs_ra_meta_pages_cond(sbi, blkaddr, ra_blocks);
|
||||
}
|
||||
if (!err)
|
||||
f2fs_allocate_new_segments(sbi, NO_CHECK_TYPE);
|
||||
f2fs_allocate_new_segments(sbi);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -791,25 +845,16 @@ 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);
|
||||
|
||||
/* prevent checkpoint */
|
||||
down_write(&sbi->cp_global_sem);
|
||||
f2fs_down_write(&sbi->cp_global_sem);
|
||||
|
||||
/* step #1: find fsynced inode numbers */
|
||||
err = find_fsync_dnodes(sbi, &inode_list, check_only);
|
||||
@@ -827,10 +872,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:
|
||||
destroy_fsync_dnodes(&inode_list, err);
|
||||
destroy_fsync_dnodes(&tmp_inode_list, err);
|
||||
@@ -845,8 +888,7 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
||||
} else {
|
||||
clear_sbi_flag(sbi, SBI_POR_DOING);
|
||||
}
|
||||
|
||||
up_write(&sbi->cp_global_sem);
|
||||
f2fs_up_write(&sbi->cp_global_sem);
|
||||
|
||||
/* let's drop all the directory inodes for clean checkpoint */
|
||||
destroy_fsync_dnodes(&dir_list, err);
|
||||
@@ -862,8 +904,6 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
||||
}
|
||||
}
|
||||
|
||||
kmem_cache_destroy(fsync_entry_slab);
|
||||
out:
|
||||
#ifdef CONFIG_QUOTA
|
||||
/* Turn quotas off */
|
||||
if (quota_enabled)
|
||||
@@ -871,5 +911,17 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
||||
#endif
|
||||
sbi->sb->s_flags = s_flags; /* Restore SB_RDONLY status */
|
||||
|
||||
return ret ? ret: err;
|
||||
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));
|
||||
return fsync_entry_slab ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
void f2fs_destroy_recovery_cache(void)
|
||||
{
|
||||
kmem_cache_destroy(fsync_entry_slab);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user