summaryrefslogtreecommitdiff
path: root/fs/f2fs/node.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/f2fs/node.c')
-rw-r--r--fs/f2fs/node.c99
1 files changed, 72 insertions, 27 deletions
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 482a362f2625..74992fd9c9b6 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -606,7 +606,7 @@ retry:
goto retry;
}
- i = f2fs_lookup_journal_in_cursum(journal, NAT_JOURNAL, nid, 0);
+ i = f2fs_lookup_journal_in_cursum(sbi, journal, NAT_JOURNAL, nid, 0);
if (i >= 0) {
ne = nat_in_journal(journal, i);
node_info_from_raw_nat(ni, &ne);
@@ -643,6 +643,17 @@ sanity_check:
return -EFSCORRUPTED;
}
+ if (unlikely(f2fs_quota_file(sbi, ni->nid) &&
+ !__is_valid_data_blkaddr(ni->blk_addr))) {
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ f2fs_err_ratelimited(sbi,
+ "f2fs_get_node_info of %pS: inconsistent nat entry from qf_ino, "
+ "ino:%u, nid:%u, blkaddr:%u, ver:%u, flag:%u",
+ __builtin_return_address(0),
+ ni->ino, ni->nid, ni->blk_addr, ni->version, ni->flag);
+ f2fs_handle_error(sbi, ERROR_INCONSISTENT_NAT);
+ }
+
/* cache nat entry */
if (need_cache)
cache_nat_entry(sbi, nid, &ne);
@@ -1500,24 +1511,33 @@ void f2fs_ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
f2fs_folio_put(afolio, err ? true : false);
}
-static int sanity_check_node_footer(struct f2fs_sb_info *sbi,
+int f2fs_sanity_check_node_footer(struct f2fs_sb_info *sbi,
struct folio *folio, pgoff_t nid,
- enum node_type ntype)
+ enum node_type ntype, bool in_irq)
{
+ bool is_inode, is_xnode;
+
if (unlikely(nid != nid_of_node(folio)))
goto out_err;
+ is_inode = IS_INODE(folio);
+ is_xnode = f2fs_has_xattr_block(ofs_of_node(folio));
+
switch (ntype) {
+ case NODE_TYPE_REGULAR:
+ if (is_inode && is_xnode)
+ goto out_err;
+ break;
case NODE_TYPE_INODE:
- if (!IS_INODE(folio))
+ if (!is_inode || is_xnode)
goto out_err;
break;
case NODE_TYPE_XATTR:
- if (!f2fs_has_xattr_block(ofs_of_node(folio)))
+ if (is_inode || !is_xnode)
goto out_err;
break;
case NODE_TYPE_NON_INODE:
- if (IS_INODE(folio))
+ if (is_inode)
goto out_err;
break;
default:
@@ -1527,12 +1547,13 @@ static int sanity_check_node_footer(struct f2fs_sb_info *sbi,
goto out_err;
return 0;
out_err:
- f2fs_warn(sbi, "inconsistent node block, node_type:%d, nid:%lu, "
- "node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]",
- ntype, nid, nid_of_node(folio), ino_of_node(folio),
- ofs_of_node(folio), cpver_of_node(folio),
- next_blkaddr_of_node(folio));
set_sbi_flag(sbi, SBI_NEED_FSCK);
+ f2fs_warn_ratelimited(sbi, "inconsistent node block, node_type:%d, nid:%lu, "
+ "node_footer[nid:%u,ino:%u,ofs:%u,cpver:%llu,blkaddr:%u]",
+ ntype, nid, nid_of_node(folio), ino_of_node(folio),
+ ofs_of_node(folio), cpver_of_node(folio),
+ next_blkaddr_of_node(folio));
+
f2fs_handle_error(sbi, ERROR_INCONSISTENT_FOOTER);
return -EFSCORRUPTED;
}
@@ -1578,7 +1599,7 @@ repeat:
goto out_err;
}
page_hit:
- err = sanity_check_node_footer(sbi, folio, nid, ntype);
+ err = f2fs_sanity_check_node_footer(sbi, folio, nid, ntype, false);
if (!err)
return folio;
out_err:
@@ -1727,6 +1748,7 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted
.io_type = io_type,
.io_wbc = wbc,
};
+ struct f2fs_lock_context lc;
unsigned int seq;
trace_f2fs_writepage(folio, NODE);
@@ -1751,18 +1773,23 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted
/* get old block addr of this node page */
nid = nid_of_node(folio);
- f2fs_bug_on(sbi, folio->index != nid);
+
+ if (f2fs_sanity_check_node_footer(sbi, folio, nid,
+ NODE_TYPE_REGULAR, false)) {
+ f2fs_handle_critical_error(sbi, STOP_CP_REASON_CORRUPTED_NID);
+ goto redirty_out;
+ }
if (f2fs_get_node_info(sbi, nid, &ni, !do_balance))
goto redirty_out;
- f2fs_down_read(&sbi->node_write);
+ f2fs_down_read_trace(&sbi->node_write, &lc);
/* This page is already truncated */
if (unlikely(ni.blk_addr == NULL_ADDR)) {
folio_clear_uptodate(folio);
dec_page_count(sbi, F2FS_DIRTY_NODES);
- f2fs_up_read(&sbi->node_write);
+ f2fs_up_read_trace(&sbi->node_write, &lc);
folio_unlock(folio);
return true;
}
@@ -1770,12 +1797,17 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted
if (__is_valid_data_blkaddr(ni.blk_addr) &&
!f2fs_is_valid_blkaddr(sbi, ni.blk_addr,
DATA_GENERIC_ENHANCE)) {
- f2fs_up_read(&sbi->node_write);
+ f2fs_up_read_trace(&sbi->node_write, &lc);
goto redirty_out;
}
- if (atomic && !test_opt(sbi, NOBARRIER))
- fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
+ if (atomic) {
+ if (!test_opt(sbi, NOBARRIER))
+ fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
+ if (IS_INODE(folio))
+ set_dentry_mark(folio,
+ f2fs_need_dentry_mark(sbi, ino_of_node(folio)));
+ }
/* should add to global list before clearing PAGECACHE status */
if (f2fs_in_warm_node_list(sbi, folio)) {
@@ -1790,7 +1822,7 @@ static bool __write_node_folio(struct folio *folio, bool atomic, bool *submitted
f2fs_do_write_node_page(nid, &fio);
set_node_addr(sbi, &ni, fio.new_blkaddr, is_fsync_dnode(folio));
dec_page_count(sbi, F2FS_DIRTY_NODES);
- f2fs_up_read(&sbi->node_write);
+ f2fs_up_read_trace(&sbi->node_write, &lc);
folio_unlock(folio);
@@ -1916,8 +1948,9 @@ continue_unlock:
if (is_inode_flag_set(inode,
FI_DIRTY_INODE))
f2fs_update_inode(inode, folio);
- set_dentry_mark(folio,
- f2fs_need_dentry_mark(sbi, ino));
+ if (!atomic)
+ set_dentry_mark(folio,
+ f2fs_need_dentry_mark(sbi, ino));
}
/* may be written by other thread */
if (!folio_test_dirty(folio))
@@ -2937,7 +2970,7 @@ int f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
/* scan the node segment */
last_offset = BLKS_PER_SEG(sbi);
addr = START_BLOCK(sbi, segno);
- sum_entry = &sum->entries[0];
+ sum_entry = sum_entries(sum);
for (i = 0; i < last_offset; i += nrpages, addr += nrpages) {
nrpages = bio_max_segs(last_offset - i);
@@ -3078,7 +3111,7 @@ static int __flush_nat_entry_set(struct f2fs_sb_info *sbi,
* #2, flush nat entries to nat page.
*/
if (enabled_nat_bits(sbi, cpc) ||
- !__has_cursum_space(journal, set->entry_cnt, NAT_JOURNAL))
+ !__has_cursum_space(sbi, journal, set->entry_cnt, NAT_JOURNAL))
to_journal = false;
if (to_journal) {
@@ -3101,7 +3134,7 @@ static int __flush_nat_entry_set(struct f2fs_sb_info *sbi,
f2fs_bug_on(sbi, nat_get_blkaddr(ne) == NEW_ADDR);
if (to_journal) {
- offset = f2fs_lookup_journal_in_cursum(journal,
+ offset = f2fs_lookup_journal_in_cursum(sbi, journal,
NAT_JOURNAL, nid, 1);
f2fs_bug_on(sbi, offset < 0);
raw_ne = &nat_in_journal(journal, offset);
@@ -3146,7 +3179,7 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
struct f2fs_journal *journal = curseg->journal;
struct nat_entry_set *setvec[NAT_VEC_SIZE];
struct nat_entry_set *set, *tmp;
- unsigned int found;
+ unsigned int found, entry_count = 0;
nid_t set_idx = 0;
LIST_HEAD(sets);
int err = 0;
@@ -3172,7 +3205,7 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
* into nat entry set.
*/
if (enabled_nat_bits(sbi, cpc) ||
- !__has_cursum_space(journal,
+ !__has_cursum_space(sbi, journal,
nm_i->nat_cnt[DIRTY_NAT], NAT_JOURNAL))
remove_nats_in_journal(sbi);
@@ -3183,9 +3216,21 @@ int f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
set_idx = setvec[found - 1]->set + 1;
for (idx = 0; idx < found; idx++)
__adjust_nat_entry_set(setvec[idx], &sets,
- MAX_NAT_JENTRIES(journal));
+ MAX_NAT_JENTRIES(sbi, journal));
}
+ /*
+ * Readahead the current NAT block to prevent read requests from
+ * being issued and waited on one by one.
+ */
+ list_for_each_entry(set, &sets, set_list) {
+ entry_count += set->entry_cnt;
+ if (!enabled_nat_bits(sbi, cpc) &&
+ __has_cursum_space(sbi, journal,
+ entry_count, NAT_JOURNAL))
+ continue;
+ f2fs_ra_meta_pages(sbi, set->set, 1, META_NAT, true);
+ }
/* flush dirty nats in nat entry set */
list_for_each_entry_safe(set, tmp, &sets, set_list) {
err = __flush_nat_entry_set(sbi, set, cpc);