summaryrefslogtreecommitdiff
path: root/fs/f2fs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/f2fs/inode.c')
-rw-r--r--fs/f2fs/inode.c311
1 files changed, 219 insertions, 92 deletions
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index e0f850b3f0c3..96cc0e777567 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -9,8 +9,10 @@
#include <linux/f2fs_fs.h>
#include <linux/writeback.h>
#include <linux/sched/mm.h>
+#include <linux/swap.h>
#include <linux/lz4.h>
#include <linux/zstd.h>
+#include <linux/fserror.h>
#include "f2fs.h"
#include "node.h"
@@ -23,6 +25,18 @@
extern const struct address_space_operations f2fs_compress_aops;
#endif
+#define NUM_PREALLOC_EVICT_INODE_WORK 8
+
+static struct kmem_cache *evict_inode_work_cache;
+static mempool_t *evict_inode_work_pool;
+
+struct evict_inode_work {
+ struct work_struct work;
+ struct f2fs_sb_info *sbi;
+ nid_t ino;
+ unsigned int add_ino_entry_bits;
+};
+
void f2fs_mark_inode_dirty_sync(struct inode *inode, bool sync)
{
if (is_inode_flag_set(inode, FI_NEW_INODE))
@@ -203,14 +217,14 @@ static bool sanity_check_compress_inode(struct inode *inode,
if (ri->i_compress_algorithm >= COMPRESS_MAX) {
f2fs_warn(sbi,
- "%s: inode (ino=%lx) has unsupported compress algorithm: %u, run fsck to fix",
+ "%s: inode (ino=%llx) has unsupported compress algorithm: %u, run fsck to fix",
__func__, inode->i_ino, ri->i_compress_algorithm);
return false;
}
if (le64_to_cpu(ri->i_compr_blocks) >
SECTOR_TO_BLOCK(inode->i_blocks)) {
f2fs_warn(sbi,
- "%s: inode (ino=%lx) has inconsistent i_compr_blocks:%llu, i_blocks:%llu, run fsck to fix",
+ "%s: inode (ino=%llx) has inconsistent i_compr_blocks:%llu, i_blocks:%llu, run fsck to fix",
__func__, inode->i_ino, le64_to_cpu(ri->i_compr_blocks),
SECTOR_TO_BLOCK(inode->i_blocks));
return false;
@@ -218,7 +232,7 @@ static bool sanity_check_compress_inode(struct inode *inode,
if (ri->i_log_cluster_size < MIN_COMPRESS_LOG_SIZE ||
ri->i_log_cluster_size > MAX_COMPRESS_LOG_SIZE) {
f2fs_warn(sbi,
- "%s: inode (ino=%lx) has unsupported log cluster size: %u, run fsck to fix",
+ "%s: inode (ino=%llx) has unsupported log cluster size: %u, run fsck to fix",
__func__, inode->i_ino, ri->i_log_cluster_size);
return false;
}
@@ -262,7 +276,7 @@ static bool sanity_check_compress_inode(struct inode *inode,
return true;
err_level:
- f2fs_warn(sbi, "%s: inode (ino=%lx) has unsupported compress level: %u, run fsck to fix",
+ f2fs_warn(sbi, "%s: inode (ino=%llx) has unsupported compress level: %u, run fsck to fix",
__func__, inode->i_ino, clevel);
return false;
}
@@ -276,40 +290,40 @@ static bool sanity_check_inode(struct inode *inode, struct folio *node_folio)
iblocks = le64_to_cpu(F2FS_INODE(node_folio)->i_blocks);
if (!iblocks) {
- f2fs_warn(sbi, "%s: corrupted inode i_blocks i_ino=%lx iblocks=%llu, run fsck to fix.",
+ f2fs_warn(sbi, "%s: corrupted inode i_blocks i_ino=%llx iblocks=%llu, run fsck to fix.",
__func__, inode->i_ino, iblocks);
return false;
}
if (ino_of_node(node_folio) != nid_of_node(node_folio)) {
- f2fs_warn(sbi, "%s: corrupted inode footer i_ino=%lx, ino,nid: [%u, %u] run fsck to fix.",
+ f2fs_warn(sbi, "%s: corrupted inode footer i_ino=%llx, ino,nid: [%u, %u] run fsck to fix.",
__func__, inode->i_ino,
ino_of_node(node_folio), nid_of_node(node_folio));
return false;
}
if (ino_of_node(node_folio) == fi->i_xattr_nid) {
- f2fs_warn(sbi, "%s: corrupted inode i_ino=%lx, xnid=%x, run fsck to fix.",
+ f2fs_warn(sbi, "%s: corrupted inode i_ino=%llx, xnid=%x, run fsck to fix.",
__func__, inode->i_ino, fi->i_xattr_nid);
return false;
}
if (S_ISDIR(inode->i_mode) && unlikely(inode->i_nlink == 1)) {
- f2fs_warn(sbi, "%s: directory inode (ino=%lx) has a single i_nlink",
+ f2fs_warn(sbi, "%s: directory inode (ino=%llx) has a single i_nlink",
__func__, inode->i_ino);
return false;
}
if (f2fs_has_extra_attr(inode)) {
if (!f2fs_sb_has_extra_attr(sbi)) {
- f2fs_warn(sbi, "%s: inode (ino=%lx) is with extra_attr, but extra_attr feature is off",
+ f2fs_warn(sbi, "%s: inode (ino=%llx) is with extra_attr, but extra_attr feature is off",
__func__, inode->i_ino);
return false;
}
if (fi->i_extra_isize > F2FS_TOTAL_EXTRA_ATTR_SIZE ||
fi->i_extra_isize < F2FS_MIN_EXTRA_ATTR_SIZE ||
fi->i_extra_isize % sizeof(__le32)) {
- f2fs_warn(sbi, "%s: inode (ino=%lx) has corrupted i_extra_isize: %d, max: %zu",
+ f2fs_warn(sbi, "%s: inode (ino=%llx) has corrupted i_extra_isize: %d, max: %zu",
__func__, inode->i_ino, fi->i_extra_isize,
F2FS_TOTAL_EXTRA_ATTR_SIZE);
return false;
@@ -324,10 +338,10 @@ static bool sanity_check_inode(struct inode *inode, struct folio *node_folio)
}
if (f2fs_sb_has_flexible_inline_xattr(sbi) &&
- f2fs_has_inline_xattr(inode) &&
- (fi->i_inline_xattr_size < MIN_INLINE_XATTR_SIZE ||
- fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE)) {
- f2fs_warn(sbi, "%s: inode (ino=%lx) has corrupted i_inline_xattr_size: %d, min: %zu, max: %lu",
+ (fi->i_inline_xattr_size > MAX_INLINE_XATTR_SIZE ||
+ (f2fs_has_inline_xattr(inode) &&
+ fi->i_inline_xattr_size < MIN_INLINE_XATTR_SIZE))) {
+ f2fs_warn(sbi, "%s: inode (ino=%llx) has corrupted i_inline_xattr_size: %d, min: %zu, max: %lu",
__func__, inode->i_ino, fi->i_inline_xattr_size,
MIN_INLINE_XATTR_SIZE, MAX_INLINE_XATTR_SIZE);
return false;
@@ -335,64 +349,64 @@ static bool sanity_check_inode(struct inode *inode, struct folio *node_folio)
if (!f2fs_sb_has_extra_attr(sbi)) {
if (f2fs_sb_has_project_quota(sbi)) {
- f2fs_warn(sbi, "%s: corrupted inode ino=%lx, wrong feature flag: %u, run fsck to fix.",
+ f2fs_warn(sbi, "%s: corrupted inode ino=%llx, wrong feature flag: %u, run fsck to fix.",
__func__, inode->i_ino, F2FS_FEATURE_PRJQUOTA);
return false;
}
if (f2fs_sb_has_inode_chksum(sbi)) {
- f2fs_warn(sbi, "%s: corrupted inode ino=%lx, wrong feature flag: %u, run fsck to fix.",
+ f2fs_warn(sbi, "%s: corrupted inode ino=%llx, wrong feature flag: %u, run fsck to fix.",
__func__, inode->i_ino, F2FS_FEATURE_INODE_CHKSUM);
return false;
}
if (f2fs_sb_has_flexible_inline_xattr(sbi)) {
- f2fs_warn(sbi, "%s: corrupted inode ino=%lx, wrong feature flag: %u, run fsck to fix.",
+ f2fs_warn(sbi, "%s: corrupted inode ino=%llx, wrong feature flag: %u, run fsck to fix.",
__func__, inode->i_ino, F2FS_FEATURE_FLEXIBLE_INLINE_XATTR);
return false;
}
if (f2fs_sb_has_inode_crtime(sbi)) {
- f2fs_warn(sbi, "%s: corrupted inode ino=%lx, wrong feature flag: %u, run fsck to fix.",
+ f2fs_warn(sbi, "%s: corrupted inode ino=%llx, wrong feature flag: %u, run fsck to fix.",
__func__, inode->i_ino, F2FS_FEATURE_INODE_CRTIME);
return false;
}
if (f2fs_sb_has_compression(sbi)) {
- f2fs_warn(sbi, "%s: corrupted inode ino=%lx, wrong feature flag: %u, run fsck to fix.",
+ f2fs_warn(sbi, "%s: corrupted inode ino=%llx, wrong feature flag: %u, run fsck to fix.",
__func__, inode->i_ino, F2FS_FEATURE_COMPRESSION);
return false;
}
}
if (f2fs_sanity_check_inline_data(inode, node_folio)) {
- f2fs_warn(sbi, "%s: inode (ino=%lx, mode=%u) should not have inline_data, run fsck to fix",
+ f2fs_warn(sbi, "%s: inode (ino=%llx, mode=%u) should not have inline_data, run fsck to fix",
__func__, inode->i_ino, inode->i_mode);
return false;
}
if (f2fs_has_inline_dentry(inode) && !S_ISDIR(inode->i_mode)) {
- f2fs_warn(sbi, "%s: inode (ino=%lx, mode=%u) should not have inline_dentry, run fsck to fix",
+ f2fs_warn(sbi, "%s: inode (ino=%llx, mode=%u) should not have inline_dentry, run fsck to fix",
__func__, inode->i_ino, inode->i_mode);
return false;
}
if ((fi->i_flags & F2FS_CASEFOLD_FL) && !f2fs_sb_has_casefold(sbi)) {
- f2fs_warn(sbi, "%s: inode (ino=%lx) has casefold flag, but casefold feature is off",
+ f2fs_warn(sbi, "%s: inode (ino=%llx) has casefold flag, but casefold feature is off",
__func__, inode->i_ino);
return false;
}
if (fi->i_xattr_nid && f2fs_check_nid_range(sbi, fi->i_xattr_nid)) {
- f2fs_warn(sbi, "%s: inode (ino=%lx) has corrupted i_xattr_nid: %u, run fsck to fix.",
+ f2fs_warn(sbi, "%s: inode (ino=%llx) has corrupted i_xattr_nid: %u, run fsck to fix.",
__func__, inode->i_ino, fi->i_xattr_nid);
return false;
}
if (IS_DEVICE_ALIASING(inode)) {
if (!f2fs_sb_has_device_alias(sbi)) {
- f2fs_warn(sbi, "%s: inode (ino=%lx) has device alias flag, but the feature is off",
+ f2fs_warn(sbi, "%s: inode (ino=%llx) has device alias flag, but the feature is off",
__func__, inode->i_ino);
return false;
}
if (!f2fs_is_pinned_file(inode)) {
- f2fs_warn(sbi, "%s: inode (ino=%lx) has device alias flag, but is not pinned",
+ f2fs_warn(sbi, "%s: inode (ino=%llx) has device alias flag, but is not pinned",
__func__, inode->i_ino);
return false;
}
@@ -480,6 +494,7 @@ static int do_read_inode(struct inode *inode)
f2fs_folio_put(node_folio, true);
set_sbi_flag(sbi, SBI_NEED_FSCK);
f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE);
+ fserror_report_file_metadata(inode, -EFSCORRUPTED, GFP_NOFS);
return -EFSCORRUPTED;
}
@@ -541,6 +556,7 @@ static int do_read_inode(struct inode *inode)
if (!sanity_check_extent_cache(inode, node_folio)) {
f2fs_folio_put(node_folio, true);
f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE);
+ fserror_report_file_metadata(inode, -EFSCORRUPTED, GFP_NOFS);
return -EFSCORRUPTED;
}
@@ -561,8 +577,13 @@ static int do_read_inode(struct inode *inode)
static bool is_meta_ino(struct f2fs_sb_info *sbi, unsigned int ino)
{
- return ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi) ||
- ino == F2FS_COMPRESS_INO(sbi);
+ if (ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi))
+ return true;
+#ifdef CONFIG_F2FS_FS_COMPRESSION
+ if (test_opt(sbi, COMPRESS_CACHE) && ino == F2FS_COMPRESS_INO(sbi))
+ return true;
+#endif
+ return false;
}
struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
@@ -583,6 +604,7 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
trace_f2fs_iget_exit(inode, ret);
iput(inode);
f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE);
+ fserror_report_file_metadata(inode, ret, GFP_NOFS);
return ERR_PTR(ret);
}
@@ -628,6 +650,9 @@ make_now:
inode->i_fop = &f2fs_dir_operations;
inode->i_mapping->a_ops = &f2fs_dblock_aops;
mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
+
+ /* Let's prepare APPEND/UPDATE_INO before future access. */
+ flush_workqueue(sbi->evict_wq);
} else if (S_ISLNK(inode->i_mode)) {
if (file_is_encrypt(inode))
inode->i_op = &f2fs_encrypted_symlink_inode_operations;
@@ -687,7 +712,7 @@ void f2fs_update_inode(struct inode *inode, struct folio *node_folio)
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_blocks = cpu_to_le64(SECTOR_TO_BLOCK(inode->i_blocks) + 1);
+ ri->i_blocks = cpu_to_le64(SECTOR_TO_BLOCK(READ_ONCE(inode->i_blocks)) + 1);
if (!f2fs_is_atomic_file(inode) ||
is_inode_flag_set(inode, FI_ATOMIC_COMMITTED))
@@ -787,6 +812,7 @@ retry:
if (err == -ENOMEM || ++count <= DEFAULT_RETRY_IO_COUNT)
goto retry;
stop_checkpoint:
+ fserror_report_file_metadata(inode, -EFSCORRUPTED, GFP_NOFS);
f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_UPDATE_INODE);
return;
}
@@ -844,37 +870,58 @@ void f2fs_remove_donate_inode(struct inode *inode)
spin_unlock(&sbi->inode_lock[DONATE_INODE]);
}
+static void f2fs_record_inode_state(struct f2fs_sb_info *sbi, nid_t ino,
+ unsigned int bits)
+{
+ if (bits & BIT(APPEND_INO))
+ f2fs_add_ino_entry(sbi, ino, APPEND_INO);
+ if (bits & BIT(UPDATE_INO))
+ f2fs_add_ino_entry(sbi, ino, UPDATE_INO);
+}
+
+static void f2fs_evict_inode_work(struct work_struct *work)
+{
+ struct evict_inode_work *ew =
+ container_of(work, struct evict_inode_work, work);
+
+ f2fs_record_inode_state(ew->sbi, ew->ino, ew->add_ino_entry_bits);
+
+ mempool_free(ew, evict_inode_work_pool);
+}
+
/*
- * Called at the last iput() if i_nlink is zero
+ * Return true, if we shouldn't go through post_evict_inode.
*/
-void f2fs_evict_inode(struct inode *inode)
+static bool f2fs_pre_evict_inode(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_inode_info *fi = F2FS_I(inode);
- nid_t xnid = fi->i_xattr_nid;
- int err = 0;
- bool freeze_protected = false;
f2fs_abort_atomic_write(inode, true);
if (fi->cow_inode && f2fs_is_cow_file(fi->cow_inode)) {
- clear_inode_flag(fi->cow_inode, FI_COW_FILE);
- F2FS_I(fi->cow_inode)->atomic_inode = NULL;
- iput(fi->cow_inode);
+ struct inode *cow_inode = fi->cow_inode;
+
+ f2fs_down_write(&F2FS_I(cow_inode)->i_sem);
+ clear_inode_flag(cow_inode, FI_COW_FILE);
+ F2FS_I(cow_inode)->atomic_inode = NULL;
fi->cow_inode = NULL;
+ f2fs_up_write(&F2FS_I(cow_inode)->i_sem);
+
+ iput(cow_inode);
}
trace_f2fs_evict_inode(inode);
truncate_inode_pages_final(&inode->i_data);
if ((inode->i_nlink || is_bad_inode(inode)) &&
- test_opt(sbi, COMPRESS_CACHE) && f2fs_compressed_file(inode))
+ test_opt(sbi, COMPRESS_CACHE) && f2fs_compressed_file(inode))
f2fs_invalidate_compress_pages(sbi, inode->i_ino);
if (inode->i_ino == F2FS_NODE_INO(sbi) ||
- inode->i_ino == F2FS_META_INO(sbi) ||
- inode->i_ino == F2FS_COMPRESS_INO(sbi))
- goto out_clear;
+ inode->i_ino == F2FS_META_INO(sbi) ||
+ inode->i_ino == F2FS_COMPRESS_INO(sbi))
+ return true;
f2fs_bug_on(sbi, get_dirty_pages(inode));
f2fs_remove_dirty_inode(inode);
@@ -883,14 +930,18 @@ void f2fs_evict_inode(struct inode *inode)
if (!IS_DEVICE_ALIASING(inode))
f2fs_destroy_extent_tree(inode);
- if (inode->i_nlink || is_bad_inode(inode))
- goto no_delete;
+ return false;
+}
- err = f2fs_dquot_initialize(inode);
- if (err) {
- err = 0;
+static void f2fs_delete_inode(struct inode *inode)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ bool freeze_protected = false;
+ struct f2fs_lock_context lc;
+ int err = 0;
+
+ if (f2fs_dquot_initialize(inode))
set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
- }
f2fs_remove_ino_entry(sbi, inode->i_ino, APPEND_INO);
f2fs_remove_ino_entry(sbi, inode->i_ino, UPDATE_INO);
@@ -909,30 +960,30 @@ retry:
if (time_to_inject(sbi, FAULT_EVICT_INODE))
err = -EIO;
- if (!err) {
- struct f2fs_lock_context lc;
-
- f2fs_lock_op(sbi, &lc);
- err = f2fs_remove_inode_page(inode);
- f2fs_unlock_op(sbi, &lc);
- if (err == -ENOENT) {
- err = 0;
-
- /*
- * in fuzzed image, another node may has the same
- * block address as inode's, if it was truncated
- * previously, truncation of inode node will fail.
- */
- if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
- f2fs_warn(F2FS_I_SB(inode),
- "f2fs_evict_inode: inconsistent node id, ino:%lu",
- inode->i_ino);
- f2fs_inode_synced(inode);
- set_sbi_flag(sbi, SBI_NEED_FSCK);
- }
+ if (err)
+ goto error_check;
+
+ f2fs_lock_op(sbi, &lc);
+ err = f2fs_remove_inode_page(inode);
+ f2fs_unlock_op(sbi, &lc);
+
+ if (err == -ENOENT) {
+ err = 0;
+
+ /*
+ * in fuzzed image, another node may has the same
+ * block address as inode's, if it was truncated
+ * previously, truncation of inode node will fail.
+ */
+ if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
+ f2fs_warn(F2FS_I_SB(inode),
+ "f2fs_evict_inode: inconsistent node id, ino:%llu",
+ inode->i_ino);
+ f2fs_inode_synced(inode);
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
}
}
-
+error_check:
/* give more chances, if ENOMEM case */
if (err == -ENOMEM) {
err = 0;
@@ -942,27 +993,38 @@ retry:
if (IS_DEVICE_ALIASING(inode))
f2fs_destroy_extent_tree(inode);
- if (err) {
- f2fs_update_inode_page(inode);
- if (dquot_initialize_needed(inode))
- set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
+ if (!err)
+ goto unfreeze_out;
- /*
- * If both f2fs_truncate() and f2fs_update_inode_page() failed
- * due to fuzzed corrupted inode, call f2fs_inode_synced() to
- * avoid triggering later f2fs_bug_on().
- */
- if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
- f2fs_warn(sbi,
- "f2fs_evict_inode: inode is dirty, ino:%lu",
- inode->i_ino);
- f2fs_inode_synced(inode);
- set_sbi_flag(sbi, SBI_NEED_FSCK);
- }
+ f2fs_update_inode_page(inode);
+
+ if (dquot_initialize_needed(inode))
+ set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
+
+ /*
+ * If both f2fs_truncate() and f2fs_update_inode_page() failed
+ * due to fuzzed corrupted inode, call f2fs_inode_synced() to
+ * avoid triggering later f2fs_bug_on().
+ */
+ if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
+ f2fs_warn(sbi,
+ "f2fs_evict_inode: inode is dirty, ino:%llu",
+ inode->i_ino);
+ f2fs_inode_synced(inode);
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
}
+unfreeze_out:
if (freeze_protected)
sb_end_intwrite(inode->i_sb);
-no_delete:
+}
+
+static void f2fs_post_evict_inode(struct inode *inode)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ nid_t xnid = fi->i_xattr_nid;
+ unsigned int record_bits = 0;
+
dquot_drop(inode);
stat_dec_inline_xattr(inode);
@@ -988,12 +1050,32 @@ no_delete:
inode->i_ino);
if (xnid)
invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid);
- if (inode->i_nlink) {
- if (is_inode_flag_set(inode, FI_APPEND_WRITE))
- f2fs_add_ino_entry(sbi, inode->i_ino, APPEND_INO);
- if (is_inode_flag_set(inode, FI_UPDATE_WRITE))
- f2fs_add_ino_entry(sbi, inode->i_ino, UPDATE_INO);
+
+ if (!inode->i_nlink)
+ goto skip_record;
+
+ if (is_inode_flag_set(inode, FI_APPEND_WRITE))
+ record_bits = BIT(APPEND_INO);
+ if (is_inode_flag_set(inode, FI_UPDATE_WRITE))
+ record_bits = BIT(UPDATE_INO);
+
+ if (!record_bits)
+ goto skip_record;
+
+ /* Let's do this in workqueue out of the direct reclaim path. */
+ if (current_is_kswapd()) {
+ f2fs_record_inode_state(sbi, inode->i_ino, record_bits);
+ } else {
+ struct evict_inode_work *ew =
+ mempool_alloc(evict_inode_work_pool, GFP_NOFS);
+
+ ew->sbi = sbi;
+ ew->ino = inode->i_ino;
+ ew->add_ino_entry_bits = record_bits;
+ INIT_WORK(&ew->work, f2fs_evict_inode_work);
+ queue_work(sbi->evict_wq, &ew->work);
}
+skip_record:
if (is_inode_flag_set(inode, FI_FREE_NID)) {
f2fs_alloc_nid_failed(sbi, inode->i_ino);
clear_inode_flag(inode, FI_FREE_NID);
@@ -1004,13 +1086,29 @@ no_delete:
* In that case, f2fs_check_nid_range() is enough to give a clue.
*/
}
-out_clear:
+}
+
+/*
+ * Called at the last iput() if i_nlink is zero
+ */
+void f2fs_evict_inode(struct inode *inode)
+{
+ if (f2fs_pre_evict_inode(inode))
+ goto clear_out;
+
+ if (!inode->i_nlink && !is_bad_inode(inode))
+ f2fs_delete_inode(inode);
+
+ f2fs_post_evict_inode(inode);
+
+clear_out:
fscrypt_put_encryption_info(inode);
clear_inode(inode);
}
/* caller should call f2fs_lock_op() */
-void f2fs_handle_failed_inode(struct inode *inode, struct f2fs_lock_context *lc)
+void f2fs_handle_failed_inode(struct inode *inode,
+ struct f2fs_lock_context *lc, bool orphan_free)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct node_info ni;
@@ -1032,6 +1130,9 @@ void f2fs_handle_failed_inode(struct inode *inode, struct f2fs_lock_context *lc)
/* don't make bad inode, since it becomes a regular file. */
unlock_new_inode(inode);
+ if (!orphan_free)
+ goto out;
+
/*
* Note: we should add inode to orphan list before f2fs_unlock_op()
* so we can prevent losing this orphan when encoutering checkpoint
@@ -1064,3 +1165,29 @@ out:
/* iput will drop the inode object */
iput(inode);
}
+
+int __init f2fs_init_evict_inode_work(void)
+{
+ evict_inode_work_cache =
+ kmem_cache_create("f2fs_evict_inode_work",
+ sizeof(struct evict_inode_work), 0, 0, NULL);
+ if (!evict_inode_work_cache)
+ goto fail;
+ evict_inode_work_pool =
+ mempool_create_slab_pool(NUM_PREALLOC_EVICT_INODE_WORK,
+ evict_inode_work_cache);
+ if (!evict_inode_work_pool)
+ goto fail_free_cache;
+ return 0;
+
+fail_free_cache:
+ kmem_cache_destroy(evict_inode_work_cache);
+fail:
+ return -ENOMEM;
+}
+
+void f2fs_destroy_evict_inode_work(void)
+{
+ mempool_destroy(evict_inode_work_pool);
+ kmem_cache_destroy(evict_inode_work_cache);
+}