You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'f2fs-for-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim:
"In this round, we've tuned f2fs to improve general performance by
serializing block allocation and enhancing discard flows like fstrim
which avoids user IO contention. And we've added fsync_mode=nobarrier
which gives an option to user where it skips issuing cache_flush
commands to underlying flash storage. And there are many bug fixes
related to fuzzed images, revoked atomic writes, quota ops, and minor
direct IO.
Enhancements:
- add fsync_mode=nobarrier which bypasses cache_flush command
- enhance the discarding flow which avoids user IOs and issues in
LBA order
- readahead some encrypted blocks during GC
- enable in-memory inode checksum to verify the blocks if
F2FS_CHECK_FS is set
- enhance nat_bits behavior
- set -o discard by default
- set REQ_RAHEAD to bio in ->readpages
Bug fixes:
- fix a corner case to corrupt atomic_writes revoking flow
- revisit i_gc_rwsem to fix race conditions
- fix some dio behaviors captured by xfstests
- correct handling errors given by quota-related failures
- add many sanity check flows to avoid fuzz test failures
- add more error number propagation to their callers
- fix several corner cases to continue fault injection w/ shutdown
loop"
* tag 'f2fs-for-4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (89 commits)
f2fs: readahead encrypted block during GC
f2fs: avoid fi->i_gc_rwsem[WRITE] lock in f2fs_gc
f2fs: fix performance issue observed with multi-thread sequential read
f2fs: fix to skip verifying block address for non-regular inode
f2fs: rework fault injection handling to avoid a warning
f2fs: support fault_type mount option
f2fs: fix to return success when trimming meta area
f2fs: fix use-after-free of dicard command entry
f2fs: support discard submission error injection
f2fs: split discard command in prior to block layer
f2fs: wake up gc thread immediately when gc_urgent is set
f2fs: fix incorrect range->len in f2fs_trim_fs()
f2fs: refresh recent accessed nat entry in lru list
f2fs: fix avoid race between truncate and background GC
f2fs: avoid race between zero_range and background GC
f2fs: fix to do sanity check with block address in main area v2
f2fs: fix to do sanity check with inline flags
f2fs: fix to reset i_gc_failures correctly
f2fs: fix invalid memory access
f2fs: fix to avoid broken of dnode block list
...
This commit is contained in:
@@ -51,6 +51,14 @@ Description:
|
||||
Controls the dirty page count condition for the in-place-update
|
||||
policies.
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/min_seq_blocks
|
||||
Date: August 2018
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
Description:
|
||||
Controls the dirty page count condition for batched sequential
|
||||
writes in ->writepages.
|
||||
|
||||
|
||||
What: /sys/fs/f2fs/<disk>/min_hot_blocks
|
||||
Date: March 2017
|
||||
Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
|
||||
|
||||
@@ -157,6 +157,24 @@ data_flush Enable data flushing before checkpoint in order to
|
||||
persist data of regular and symlink.
|
||||
fault_injection=%d Enable fault injection in all supported types with
|
||||
specified injection rate.
|
||||
fault_type=%d Support configuring fault injection type, should be
|
||||
enabled with fault_injection option, fault type value
|
||||
is shown below, it supports single or combined type.
|
||||
Type_Name Type_Value
|
||||
FAULT_KMALLOC 0x000000001
|
||||
FAULT_KVMALLOC 0x000000002
|
||||
FAULT_PAGE_ALLOC 0x000000004
|
||||
FAULT_PAGE_GET 0x000000008
|
||||
FAULT_ALLOC_BIO 0x000000010
|
||||
FAULT_ALLOC_NID 0x000000020
|
||||
FAULT_ORPHAN 0x000000040
|
||||
FAULT_BLOCK 0x000000080
|
||||
FAULT_DIR_DEPTH 0x000000100
|
||||
FAULT_EVICT_INODE 0x000000200
|
||||
FAULT_TRUNCATE 0x000000400
|
||||
FAULT_IO 0x000000800
|
||||
FAULT_CHECKPOINT 0x000001000
|
||||
FAULT_DISCARD 0x000002000
|
||||
mode=%s Control block allocation mode which supports "adaptive"
|
||||
and "lfs". In "lfs" mode, there should be no random
|
||||
writes towards main area.
|
||||
|
||||
+106
-53
@@ -28,6 +28,7 @@ struct kmem_cache *f2fs_inode_entry_slab;
|
||||
|
||||
void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io)
|
||||
{
|
||||
f2fs_build_fault_attr(sbi, 0, 0);
|
||||
set_ckpt_flags(sbi, CP_ERROR_FLAG);
|
||||
if (!end_io)
|
||||
f2fs_flush_merged_writes(sbi);
|
||||
@@ -70,6 +71,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
|
||||
.encrypted_page = NULL,
|
||||
.is_meta = is_meta,
|
||||
};
|
||||
int err;
|
||||
|
||||
if (unlikely(!is_meta))
|
||||
fio.op_flags &= ~REQ_META;
|
||||
@@ -84,9 +86,10 @@ repeat:
|
||||
|
||||
fio.page = page;
|
||||
|
||||
if (f2fs_submit_page_bio(&fio)) {
|
||||
err = f2fs_submit_page_bio(&fio);
|
||||
if (err) {
|
||||
f2fs_put_page(page, 1);
|
||||
goto repeat;
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
lock_page(page);
|
||||
@@ -95,14 +98,9 @@ repeat:
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
/*
|
||||
* if there is any IO error when accessing device, make our filesystem
|
||||
* readonly and make sure do not write checkpoint with non-uptodate
|
||||
* meta page.
|
||||
*/
|
||||
if (unlikely(!PageUptodate(page))) {
|
||||
memset(page_address(page), 0, PAGE_SIZE);
|
||||
f2fs_stop_checkpoint(sbi, false);
|
||||
f2fs_put_page(page, 1);
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
out:
|
||||
return page;
|
||||
@@ -113,13 +111,32 @@ struct page *f2fs_get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
return __get_meta_page(sbi, index, true);
|
||||
}
|
||||
|
||||
struct page *f2fs_get_meta_page_nofail(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
{
|
||||
struct page *page;
|
||||
int count = 0;
|
||||
|
||||
retry:
|
||||
page = __get_meta_page(sbi, index, true);
|
||||
if (IS_ERR(page)) {
|
||||
if (PTR_ERR(page) == -EIO &&
|
||||
++count <= DEFAULT_RETRY_IO_COUNT)
|
||||
goto retry;
|
||||
|
||||
f2fs_stop_checkpoint(sbi, false);
|
||||
f2fs_bug_on(sbi, 1);
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
/* for POR only */
|
||||
struct page *f2fs_get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
{
|
||||
return __get_meta_page(sbi, index, false);
|
||||
}
|
||||
|
||||
bool f2fs_is_valid_meta_blkaddr(struct f2fs_sb_info *sbi,
|
||||
bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
|
||||
block_t blkaddr, int type)
|
||||
{
|
||||
switch (type) {
|
||||
@@ -140,8 +157,20 @@ bool f2fs_is_valid_meta_blkaddr(struct f2fs_sb_info *sbi,
|
||||
return false;
|
||||
break;
|
||||
case META_POR:
|
||||
case DATA_GENERIC:
|
||||
if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
|
||||
blkaddr < MAIN_BLKADDR(sbi)))
|
||||
blkaddr < MAIN_BLKADDR(sbi))) {
|
||||
if (type == DATA_GENERIC) {
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"access invalid blkaddr:%u", blkaddr);
|
||||
WARN_ON(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case META_GENERIC:
|
||||
if (unlikely(blkaddr < SEG0_BLKADDR(sbi) ||
|
||||
blkaddr >= MAIN_BLKADDR(sbi)))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
@@ -176,7 +205,7 @@ int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
|
||||
blk_start_plug(&plug);
|
||||
for (; nrpages-- > 0; blkno++) {
|
||||
|
||||
if (!f2fs_is_valid_meta_blkaddr(sbi, blkno, type))
|
||||
if (!f2fs_is_valid_blkaddr(sbi, blkno, type))
|
||||
goto out;
|
||||
|
||||
switch (type) {
|
||||
@@ -242,11 +271,8 @@ static int __f2fs_write_meta_page(struct page *page,
|
||||
|
||||
trace_f2fs_writepage(page, META);
|
||||
|
||||
if (unlikely(f2fs_cp_error(sbi))) {
|
||||
dec_page_count(sbi, F2FS_DIRTY_META);
|
||||
unlock_page(page);
|
||||
return 0;
|
||||
}
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
goto redirty_out;
|
||||
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
|
||||
goto redirty_out;
|
||||
if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0))
|
||||
@@ -529,13 +555,12 @@ int f2fs_acquire_orphan_inode(struct f2fs_sb_info *sbi)
|
||||
|
||||
spin_lock(&im->ino_lock);
|
||||
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
if (time_to_inject(sbi, FAULT_ORPHAN)) {
|
||||
spin_unlock(&im->ino_lock);
|
||||
f2fs_show_injection_info(FAULT_ORPHAN);
|
||||
return -ENOSPC;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (unlikely(im->ino_num >= sbi->max_orphans))
|
||||
err = -ENOSPC;
|
||||
else
|
||||
@@ -572,12 +597,7 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct node_info ni;
|
||||
int err = f2fs_acquire_orphan_inode(sbi);
|
||||
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
__add_ino_entry(sbi, ino, 0, ORPHAN_INO);
|
||||
int err;
|
||||
|
||||
inode = f2fs_iget_retry(sbi->sb, ino);
|
||||
if (IS_ERR(inode)) {
|
||||
@@ -600,14 +620,15 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
|
||||
/* truncate all the data during iput */
|
||||
iput(inode);
|
||||
|
||||
f2fs_get_node_info(sbi, ino, &ni);
|
||||
err = f2fs_get_node_info(sbi, ino, &ni);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
/* ENOMEM was fully retried in f2fs_evict_inode. */
|
||||
if (ni.blk_addr != NULL_ADDR) {
|
||||
err = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
__remove_ino_entry(sbi, ino, ORPHAN_INO);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
@@ -639,7 +660,10 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
|
||||
/* 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 */
|
||||
/*
|
||||
* Turn on quotas which were not enabled for read-only mounts if
|
||||
* filesystem has quota feature, so that they are updated correctly.
|
||||
*/
|
||||
quota_enabled = f2fs_enable_quota_files(sbi, s_flags & SB_RDONLY);
|
||||
#endif
|
||||
|
||||
@@ -649,9 +673,15 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
|
||||
f2fs_ra_meta_pages(sbi, start_blk, orphan_blocks, META_CP, true);
|
||||
|
||||
for (i = 0; i < orphan_blocks; i++) {
|
||||
struct page *page = f2fs_get_meta_page(sbi, start_blk + i);
|
||||
struct page *page;
|
||||
struct f2fs_orphan_block *orphan_blk;
|
||||
|
||||
page = f2fs_get_meta_page(sbi, start_blk + i);
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
goto out;
|
||||
}
|
||||
|
||||
orphan_blk = (struct f2fs_orphan_block *)page_address(page);
|
||||
for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) {
|
||||
nid_t ino = le32_to_cpu(orphan_blk->ino[j]);
|
||||
@@ -742,10 +772,14 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
|
||||
__u32 crc = 0;
|
||||
|
||||
*cp_page = f2fs_get_meta_page(sbi, cp_addr);
|
||||
if (IS_ERR(*cp_page))
|
||||
return PTR_ERR(*cp_page);
|
||||
|
||||
*cp_block = (struct f2fs_checkpoint *)page_address(*cp_page);
|
||||
|
||||
crc_offset = le32_to_cpu((*cp_block)->checksum_offset);
|
||||
if (crc_offset > (blk_size - sizeof(__le32))) {
|
||||
f2fs_put_page(*cp_page, 1);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"invalid crc_offset: %zu", crc_offset);
|
||||
return -EINVAL;
|
||||
@@ -753,6 +787,7 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
|
||||
|
||||
crc = cur_cp_crc(*cp_block);
|
||||
if (!f2fs_crc_valid(sbi, crc, *cp_block, crc_offset)) {
|
||||
f2fs_put_page(*cp_page, 1);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -772,14 +807,22 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
|
||||
err = get_checkpoint_version(sbi, cp_addr, &cp_block,
|
||||
&cp_page_1, version);
|
||||
if (err)
|
||||
goto invalid_cp1;
|
||||
return NULL;
|
||||
|
||||
if (le32_to_cpu(cp_block->cp_pack_total_block_count) >
|
||||
sbi->blocks_per_seg) {
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"invalid cp_pack_total_block_count:%u",
|
||||
le32_to_cpu(cp_block->cp_pack_total_block_count));
|
||||
goto invalid_cp;
|
||||
}
|
||||
pre_version = *version;
|
||||
|
||||
cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
|
||||
err = get_checkpoint_version(sbi, cp_addr, &cp_block,
|
||||
&cp_page_2, version);
|
||||
if (err)
|
||||
goto invalid_cp2;
|
||||
goto invalid_cp;
|
||||
cur_version = *version;
|
||||
|
||||
if (cur_version == pre_version) {
|
||||
@@ -787,9 +830,8 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
|
||||
f2fs_put_page(cp_page_2, 1);
|
||||
return cp_page_1;
|
||||
}
|
||||
invalid_cp2:
|
||||
f2fs_put_page(cp_page_2, 1);
|
||||
invalid_cp1:
|
||||
invalid_cp:
|
||||
f2fs_put_page(cp_page_1, 1);
|
||||
return NULL;
|
||||
}
|
||||
@@ -838,15 +880,15 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi)
|
||||
cp_block = (struct f2fs_checkpoint *)page_address(cur_page);
|
||||
memcpy(sbi->ckpt, cp_block, blk_size);
|
||||
|
||||
/* Sanity checking of checkpoint */
|
||||
if (f2fs_sanity_check_ckpt(sbi))
|
||||
goto free_fail_no_cp;
|
||||
|
||||
if (cur_page == cp1)
|
||||
sbi->cur_cp_pack = 1;
|
||||
else
|
||||
sbi->cur_cp_pack = 2;
|
||||
|
||||
/* Sanity checking of checkpoint */
|
||||
if (f2fs_sanity_check_ckpt(sbi))
|
||||
goto free_fail_no_cp;
|
||||
|
||||
if (cp_blks <= 1)
|
||||
goto done;
|
||||
|
||||
@@ -859,6 +901,8 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi)
|
||||
unsigned char *ckpt = (unsigned char *)sbi->ckpt;
|
||||
|
||||
cur_page = f2fs_get_meta_page(sbi, cp_blk_no + i);
|
||||
if (IS_ERR(cur_page))
|
||||
goto free_fail_no_cp;
|
||||
sit_bitmap_ptr = page_address(cur_page);
|
||||
memcpy(ckpt + i * blk_size, sit_bitmap_ptr, blk_size);
|
||||
f2fs_put_page(cur_page, 1);
|
||||
@@ -980,12 +1024,10 @@ retry:
|
||||
|
||||
iput(inode);
|
||||
/* We need to give cpu to another writers. */
|
||||
if (ino == cur_ino) {
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
if (ino == cur_ino)
|
||||
cond_resched();
|
||||
} else {
|
||||
else
|
||||
ino = cur_ino;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We should submit bio, since it exists several
|
||||
@@ -1119,7 +1161,7 @@ static void unblock_operations(struct f2fs_sb_info *sbi)
|
||||
f2fs_unlock_all(sbi);
|
||||
}
|
||||
|
||||
static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
|
||||
void f2fs_wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
@@ -1129,6 +1171,9 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
|
||||
if (!get_pages(sbi, F2FS_WB_CP_DATA))
|
||||
break;
|
||||
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
break;
|
||||
|
||||
io_schedule_timeout(5*HZ);
|
||||
}
|
||||
finish_wait(&sbi->cp_wait, &wait);
|
||||
@@ -1202,8 +1247,12 @@ static void commit_checkpoint(struct f2fs_sb_info *sbi,
|
||||
|
||||
/* writeout cp pack 2 page */
|
||||
err = __f2fs_write_meta_page(page, &wbc, FS_CP_META_IO);
|
||||
f2fs_bug_on(sbi, err);
|
||||
if (unlikely(err && f2fs_cp_error(sbi))) {
|
||||
f2fs_put_page(page, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
f2fs_bug_on(sbi, err);
|
||||
f2fs_put_page(page, 0);
|
||||
|
||||
/* submit checkpoint (with barrier if NOBARRIER is not set) */
|
||||
@@ -1229,7 +1278,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
while (get_pages(sbi, F2FS_DIRTY_META)) {
|
||||
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
return -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1309,7 +1358,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
f2fs_sync_meta_pages(sbi, META, LONG_MAX,
|
||||
FS_CP_META_IO);
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
return -EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1348,10 +1397,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
f2fs_sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
|
||||
|
||||
/* wait for previous submitted meta pages writeback */
|
||||
wait_on_all_pages_writeback(sbi);
|
||||
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
return -EIO;
|
||||
f2fs_wait_on_all_pages_writeback(sbi);
|
||||
|
||||
/* flush all device cache */
|
||||
err = f2fs_flush_device_cache(sbi);
|
||||
@@ -1360,12 +1406,19 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
|
||||
/* barrier and flush checkpoint cp pack 2 page if it can */
|
||||
commit_checkpoint(sbi, ckpt, start_blk);
|
||||
wait_on_all_pages_writeback(sbi);
|
||||
f2fs_wait_on_all_pages_writeback(sbi);
|
||||
|
||||
/*
|
||||
* invalidate intermediate page cache borrowed from meta inode
|
||||
* which are used for migration of encrypted inode's blocks.
|
||||
*/
|
||||
if (f2fs_sb_has_encrypt(sbi->sb))
|
||||
invalidate_mapping_pages(META_MAPPING(sbi),
|
||||
MAIN_BLKADDR(sbi), MAX_BLKADDR(sbi) - 1);
|
||||
|
||||
f2fs_release_ino_entry(sbi, false);
|
||||
|
||||
if (unlikely(f2fs_cp_error(sbi)))
|
||||
return -EIO;
|
||||
f2fs_reset_fsync_node_info(sbi);
|
||||
|
||||
clear_sbi_flag(sbi, SBI_IS_DIRTY);
|
||||
clear_sbi_flag(sbi, SBI_NEED_CP);
|
||||
@@ -1381,7 +1434,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
||||
|
||||
f2fs_bug_on(sbi, get_pages(sbi, F2FS_DIRTY_DENTS));
|
||||
|
||||
return 0;
|
||||
return unlikely(f2fs_cp_error(sbi)) ? -EIO : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+137
-45
@@ -126,12 +126,10 @@ static bool f2fs_bio_post_read_required(struct bio *bio)
|
||||
|
||||
static void f2fs_read_end_io(struct bio *bio)
|
||||
{
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
if (time_to_inject(F2FS_P_SB(bio_first_page_all(bio)), FAULT_IO)) {
|
||||
f2fs_show_injection_info(FAULT_IO);
|
||||
bio->bi_status = BLK_STS_IOERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (f2fs_bio_post_read_required(bio)) {
|
||||
struct bio_post_read_ctx *ctx = bio->bi_private;
|
||||
@@ -177,6 +175,8 @@ static void f2fs_write_end_io(struct bio *bio)
|
||||
page->index != nid_of_node(page));
|
||||
|
||||
dec_page_count(sbi, type);
|
||||
if (f2fs_in_warm_node_list(sbi, page))
|
||||
f2fs_del_fsync_node_entry(sbi, page);
|
||||
clear_cold_data(page);
|
||||
end_page_writeback(page);
|
||||
}
|
||||
@@ -264,7 +264,7 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi,
|
||||
if (type != DATA && type != NODE)
|
||||
goto submit_io;
|
||||
|
||||
if (f2fs_sb_has_blkzoned(sbi->sb) && current->plug)
|
||||
if (test_opt(sbi, LFS) && current->plug)
|
||||
blk_finish_plug(current->plug);
|
||||
|
||||
start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS;
|
||||
@@ -441,7 +441,10 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
|
||||
struct page *page = fio->encrypted_page ?
|
||||
fio->encrypted_page : fio->page;
|
||||
|
||||
verify_block_addr(fio, fio->new_blkaddr);
|
||||
if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
|
||||
__is_meta_io(fio) ? META_GENERIC : DATA_GENERIC))
|
||||
return -EFAULT;
|
||||
|
||||
trace_f2fs_submit_page_bio(page, fio);
|
||||
f2fs_trace_ios(fio, 0);
|
||||
|
||||
@@ -485,7 +488,7 @@ next:
|
||||
spin_unlock(&io->io_lock);
|
||||
}
|
||||
|
||||
if (is_valid_blkaddr(fio->old_blkaddr))
|
||||
if (__is_valid_data_blkaddr(fio->old_blkaddr))
|
||||
verify_block_addr(fio, fio->old_blkaddr);
|
||||
verify_block_addr(fio, fio->new_blkaddr);
|
||||
|
||||
@@ -534,19 +537,22 @@ out:
|
||||
}
|
||||
|
||||
static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
|
||||
unsigned nr_pages)
|
||||
unsigned nr_pages, unsigned op_flag)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct bio *bio;
|
||||
struct bio_post_read_ctx *ctx;
|
||||
unsigned int post_read_steps = 0;
|
||||
|
||||
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
|
||||
return ERR_PTR(-EFAULT);
|
||||
|
||||
bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
|
||||
if (!bio)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
f2fs_target_device(sbi, blkaddr, bio);
|
||||
bio->bi_end_io = f2fs_read_end_io;
|
||||
bio_set_op_attrs(bio, REQ_OP_READ, 0);
|
||||
bio_set_op_attrs(bio, REQ_OP_READ, op_flag);
|
||||
|
||||
if (f2fs_encrypted_file(inode))
|
||||
post_read_steps |= 1 << STEP_DECRYPT;
|
||||
@@ -571,7 +577,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
|
||||
static int f2fs_submit_page_read(struct inode *inode, struct page *page,
|
||||
block_t blkaddr)
|
||||
{
|
||||
struct bio *bio = f2fs_grab_read_bio(inode, blkaddr, 1);
|
||||
struct bio *bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0);
|
||||
|
||||
if (IS_ERR(bio))
|
||||
return PTR_ERR(bio);
|
||||
@@ -869,6 +875,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
|
||||
struct f2fs_summary sum;
|
||||
struct node_info ni;
|
||||
block_t old_blkaddr;
|
||||
pgoff_t fofs;
|
||||
blkcnt_t count = 1;
|
||||
int err;
|
||||
@@ -876,6 +883,10 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
|
||||
if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
|
||||
return -EPERM;
|
||||
|
||||
err = f2fs_get_node_info(sbi, dn->nid, &ni);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dn->data_blkaddr = datablock_addr(dn->inode,
|
||||
dn->node_page, dn->ofs_in_node);
|
||||
if (dn->data_blkaddr == NEW_ADDR)
|
||||
@@ -885,11 +896,13 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
|
||||
return err;
|
||||
|
||||
alloc:
|
||||
f2fs_get_node_info(sbi, dn->nid, &ni);
|
||||
set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
|
||||
|
||||
f2fs_allocate_data_block(sbi, NULL, dn->data_blkaddr, &dn->data_blkaddr,
|
||||
old_blkaddr = dn->data_blkaddr;
|
||||
f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr,
|
||||
&sum, seg_type, NULL, false);
|
||||
if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
|
||||
invalidate_mapping_pages(META_MAPPING(sbi),
|
||||
old_blkaddr, old_blkaddr);
|
||||
f2fs_set_data_blkaddr(dn);
|
||||
|
||||
/* update i_size */
|
||||
@@ -1045,7 +1058,13 @@ next_dnode:
|
||||
next_block:
|
||||
blkaddr = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
|
||||
|
||||
if (!is_valid_blkaddr(blkaddr)) {
|
||||
if (__is_valid_data_blkaddr(blkaddr) &&
|
||||
!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC)) {
|
||||
err = -EFAULT;
|
||||
goto sync_out;
|
||||
}
|
||||
|
||||
if (!is_valid_data_blkaddr(sbi, blkaddr)) {
|
||||
if (create) {
|
||||
if (unlikely(f2fs_cp_error(sbi))) {
|
||||
err = -EIO;
|
||||
@@ -1282,7 +1301,11 @@ static int f2fs_xattr_fiemap(struct inode *inode,
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
f2fs_get_node_info(sbi, inode->i_ino, &ni);
|
||||
err = f2fs_get_node_info(sbi, inode->i_ino, &ni);
|
||||
if (err) {
|
||||
f2fs_put_page(page, 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
phys = (__u64)blk_to_logical(inode, ni.blk_addr);
|
||||
offset = offsetof(struct f2fs_inode, i_addr) +
|
||||
@@ -1309,7 +1332,11 @@ static int f2fs_xattr_fiemap(struct inode *inode,
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
f2fs_get_node_info(sbi, xnid, &ni);
|
||||
err = f2fs_get_node_info(sbi, xnid, &ni);
|
||||
if (err) {
|
||||
f2fs_put_page(page, 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
phys = (__u64)blk_to_logical(inode, ni.blk_addr);
|
||||
len = inode->i_sb->s_blocksize;
|
||||
@@ -1425,11 +1452,11 @@ out:
|
||||
* Note that the aops->readpages() function is ONLY used for read-ahead. If
|
||||
* this function ever deviates from doing just read-ahead, it should either
|
||||
* use ->readpage() or do the necessary surgery to decouple ->readpages()
|
||||
* readom read-ahead.
|
||||
* from read-ahead.
|
||||
*/
|
||||
static int f2fs_mpage_readpages(struct address_space *mapping,
|
||||
struct list_head *pages, struct page *page,
|
||||
unsigned nr_pages)
|
||||
unsigned nr_pages, bool is_readahead)
|
||||
{
|
||||
struct bio *bio = NULL;
|
||||
sector_t last_block_in_bio = 0;
|
||||
@@ -1500,6 +1527,10 @@ got_it:
|
||||
SetPageUptodate(page);
|
||||
goto confused;
|
||||
}
|
||||
|
||||
if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr,
|
||||
DATA_GENERIC))
|
||||
goto set_error_page;
|
||||
} else {
|
||||
zero_user_segment(page, 0, PAGE_SIZE);
|
||||
if (!PageUptodate(page))
|
||||
@@ -1519,7 +1550,8 @@ submit_and_realloc:
|
||||
bio = NULL;
|
||||
}
|
||||
if (bio == NULL) {
|
||||
bio = f2fs_grab_read_bio(inode, block_nr, nr_pages);
|
||||
bio = f2fs_grab_read_bio(inode, block_nr, nr_pages,
|
||||
is_readahead ? REQ_RAHEAD : 0);
|
||||
if (IS_ERR(bio)) {
|
||||
bio = NULL;
|
||||
goto set_error_page;
|
||||
@@ -1563,7 +1595,7 @@ static int f2fs_read_data_page(struct file *file, struct page *page)
|
||||
if (f2fs_has_inline_data(inode))
|
||||
ret = f2fs_read_inline_data(inode, page);
|
||||
if (ret == -EAGAIN)
|
||||
ret = f2fs_mpage_readpages(page->mapping, NULL, page, 1);
|
||||
ret = f2fs_mpage_readpages(page->mapping, NULL, page, 1, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1580,12 +1612,13 @@ static int f2fs_read_data_pages(struct file *file,
|
||||
if (f2fs_has_inline_data(inode))
|
||||
return 0;
|
||||
|
||||
return f2fs_mpage_readpages(mapping, pages, NULL, nr_pages);
|
||||
return f2fs_mpage_readpages(mapping, pages, NULL, nr_pages, true);
|
||||
}
|
||||
|
||||
static int encrypt_one_page(struct f2fs_io_info *fio)
|
||||
{
|
||||
struct inode *inode = fio->page->mapping->host;
|
||||
struct page *mpage;
|
||||
gfp_t gfp_flags = GFP_NOFS;
|
||||
|
||||
if (!f2fs_encrypted_file(inode))
|
||||
@@ -1597,17 +1630,25 @@ static int encrypt_one_page(struct f2fs_io_info *fio)
|
||||
retry_encrypt:
|
||||
fio->encrypted_page = fscrypt_encrypt_page(inode, fio->page,
|
||||
PAGE_SIZE, 0, fio->page->index, gfp_flags);
|
||||
if (!IS_ERR(fio->encrypted_page))
|
||||
return 0;
|
||||
|
||||
/* flush pending IOs and wait for a while in the ENOMEM case */
|
||||
if (PTR_ERR(fio->encrypted_page) == -ENOMEM) {
|
||||
f2fs_flush_merged_writes(fio->sbi);
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
gfp_flags |= __GFP_NOFAIL;
|
||||
goto retry_encrypt;
|
||||
if (IS_ERR(fio->encrypted_page)) {
|
||||
/* flush pending IOs and wait for a while in the ENOMEM case */
|
||||
if (PTR_ERR(fio->encrypted_page) == -ENOMEM) {
|
||||
f2fs_flush_merged_writes(fio->sbi);
|
||||
congestion_wait(BLK_RW_ASYNC, HZ/50);
|
||||
gfp_flags |= __GFP_NOFAIL;
|
||||
goto retry_encrypt;
|
||||
}
|
||||
return PTR_ERR(fio->encrypted_page);
|
||||
}
|
||||
return PTR_ERR(fio->encrypted_page);
|
||||
|
||||
mpage = find_lock_page(META_MAPPING(fio->sbi), fio->old_blkaddr);
|
||||
if (mpage) {
|
||||
if (PageUptodate(mpage))
|
||||
memcpy(page_address(mpage),
|
||||
page_address(fio->encrypted_page), PAGE_SIZE);
|
||||
f2fs_put_page(mpage, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool check_inplace_update_policy(struct inode *inode,
|
||||
@@ -1691,6 +1732,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
|
||||
struct inode *inode = page->mapping->host;
|
||||
struct dnode_of_data dn;
|
||||
struct extent_info ei = {0,0,0};
|
||||
struct node_info ni;
|
||||
bool ipu_force = false;
|
||||
int err = 0;
|
||||
|
||||
@@ -1699,11 +1741,13 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
|
||||
f2fs_lookup_extent_cache(inode, page->index, &ei)) {
|
||||
fio->old_blkaddr = ei.blk + page->index - ei.fofs;
|
||||
|
||||
if (is_valid_blkaddr(fio->old_blkaddr)) {
|
||||
ipu_force = true;
|
||||
fio->need_lock = LOCK_DONE;
|
||||
goto got_it;
|
||||
}
|
||||
if (!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
|
||||
DATA_GENERIC))
|
||||
return -EFAULT;
|
||||
|
||||
ipu_force = true;
|
||||
fio->need_lock = LOCK_DONE;
|
||||
goto got_it;
|
||||
}
|
||||
|
||||
/* Deadlock due to between page->lock and f2fs_lock_op */
|
||||
@@ -1722,11 +1766,17 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
|
||||
goto out_writepage;
|
||||
}
|
||||
got_it:
|
||||
if (__is_valid_data_blkaddr(fio->old_blkaddr) &&
|
||||
!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
|
||||
DATA_GENERIC)) {
|
||||
err = -EFAULT;
|
||||
goto out_writepage;
|
||||
}
|
||||
/*
|
||||
* If current allocation needs SSR,
|
||||
* it had better in-place writes for updated data.
|
||||
*/
|
||||
if (ipu_force || (is_valid_blkaddr(fio->old_blkaddr) &&
|
||||
if (ipu_force || (is_valid_data_blkaddr(fio->sbi, fio->old_blkaddr) &&
|
||||
need_inplace_update(fio))) {
|
||||
err = encrypt_one_page(fio);
|
||||
if (err)
|
||||
@@ -1751,6 +1801,12 @@ got_it:
|
||||
fio->need_lock = LOCK_REQ;
|
||||
}
|
||||
|
||||
err = f2fs_get_node_info(fio->sbi, dn.nid, &ni);
|
||||
if (err)
|
||||
goto out_writepage;
|
||||
|
||||
fio->version = ni.version;
|
||||
|
||||
err = encrypt_one_page(fio);
|
||||
if (err)
|
||||
goto out_writepage;
|
||||
@@ -2079,6 +2135,18 @@ continue_unlock:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline bool __should_serialize_io(struct inode *inode,
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
if (!S_ISREG(inode->i_mode))
|
||||
return false;
|
||||
if (wbc->sync_mode != WB_SYNC_ALL)
|
||||
return true;
|
||||
if (get_dirty_pages(inode) >= SM_I(F2FS_I_SB(inode))->min_seq_blocks)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __f2fs_write_data_pages(struct address_space *mapping,
|
||||
struct writeback_control *wbc,
|
||||
enum iostat_type io_type)
|
||||
@@ -2087,6 +2155,7 @@ static int __f2fs_write_data_pages(struct address_space *mapping,
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct blk_plug plug;
|
||||
int ret;
|
||||
bool locked = false;
|
||||
|
||||
/* deal with chardevs and other special file */
|
||||
if (!mapping->a_ops->writepage)
|
||||
@@ -2117,10 +2186,18 @@ static int __f2fs_write_data_pages(struct address_space *mapping,
|
||||
else if (atomic_read(&sbi->wb_sync_req[DATA]))
|
||||
goto skip_write;
|
||||
|
||||
if (__should_serialize_io(inode, wbc)) {
|
||||
mutex_lock(&sbi->writepages);
|
||||
locked = true;
|
||||
}
|
||||
|
||||
blk_start_plug(&plug);
|
||||
ret = f2fs_write_cache_pages(mapping, wbc, io_type);
|
||||
blk_finish_plug(&plug);
|
||||
|
||||
if (locked)
|
||||
mutex_unlock(&sbi->writepages);
|
||||
|
||||
if (wbc->sync_mode == WB_SYNC_ALL)
|
||||
atomic_dec(&sbi->wb_sync_req[DATA]);
|
||||
/*
|
||||
@@ -2153,10 +2230,14 @@ static void f2fs_write_failed(struct address_space *mapping, loff_t to)
|
||||
loff_t i_size = i_size_read(inode);
|
||||
|
||||
if (to > i_size) {
|
||||
down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
down_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
|
||||
truncate_pagecache(inode, i_size);
|
||||
f2fs_truncate_blocks(inode, i_size, true);
|
||||
|
||||
up_write(&F2FS_I(inode)->i_mmap_sem);
|
||||
up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2251,8 +2332,9 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||
|
||||
trace_f2fs_write_begin(inode, pos, len, flags);
|
||||
|
||||
if (f2fs_is_atomic_file(inode) &&
|
||||
!f2fs_available_free_memory(sbi, INMEM_PAGES)) {
|
||||
if ((f2fs_is_atomic_file(inode) &&
|
||||
!f2fs_available_free_memory(sbi, INMEM_PAGES)) ||
|
||||
is_inode_flag_set(inode, FI_ATOMIC_REVOKE_REQUEST)) {
|
||||
err = -ENOMEM;
|
||||
drop_atomic = true;
|
||||
goto fail;
|
||||
@@ -2376,14 +2458,20 @@ unlock_out:
|
||||
static int check_direct_IO(struct inode *inode, struct iov_iter *iter,
|
||||
loff_t offset)
|
||||
{
|
||||
unsigned blocksize_mask = inode->i_sb->s_blocksize - 1;
|
||||
|
||||
if (offset & blocksize_mask)
|
||||
return -EINVAL;
|
||||
|
||||
if (iov_iter_alignment(iter) & blocksize_mask)
|
||||
return -EINVAL;
|
||||
unsigned i_blkbits = READ_ONCE(inode->i_blkbits);
|
||||
unsigned blkbits = i_blkbits;
|
||||
unsigned blocksize_mask = (1 << blkbits) - 1;
|
||||
unsigned long align = offset | iov_iter_alignment(iter);
|
||||
struct block_device *bdev = inode->i_sb->s_bdev;
|
||||
|
||||
if (align & blocksize_mask) {
|
||||
if (bdev)
|
||||
blkbits = blksize_bits(bdev_logical_block_size(bdev));
|
||||
blocksize_mask = (1 << blkbits) - 1;
|
||||
if (align & blocksize_mask)
|
||||
return -EINVAL;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2401,7 +2489,7 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
|
||||
err = check_direct_IO(inode, iter, offset);
|
||||
if (err)
|
||||
return err;
|
||||
return err < 0 ? err : 0;
|
||||
|
||||
if (f2fs_force_buffered_io(inode, rw))
|
||||
return 0;
|
||||
@@ -2495,6 +2583,10 @@ static int f2fs_set_data_page_dirty(struct page *page)
|
||||
if (!PageUptodate(page))
|
||||
SetPageUptodate(page);
|
||||
|
||||
/* don't remain PG_checked flag which was set during GC */
|
||||
if (is_cold_data(page))
|
||||
clear_cold_data(page);
|
||||
|
||||
if (f2fs_is_atomic_file(inode) && !f2fs_is_commit_atomic_write(inode)) {
|
||||
if (!IS_ATOMIC_WRITTEN_PAGE(page)) {
|
||||
f2fs_register_inmem_page(inode, page);
|
||||
|
||||
+2
-1
@@ -215,7 +215,8 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
|
||||
si->base_mem += sizeof(struct f2fs_nm_info);
|
||||
si->base_mem += __bitmap_size(sbi, NAT_BITMAP);
|
||||
si->base_mem += (NM_I(sbi)->nat_bits_blocks << F2FS_BLKSIZE_BITS);
|
||||
si->base_mem += NM_I(sbi)->nat_blocks * NAT_ENTRY_BITMAP_SIZE;
|
||||
si->base_mem += NM_I(sbi)->nat_blocks *
|
||||
f2fs_bitmap_size(NAT_ENTRY_PER_BLOCK);
|
||||
si->base_mem += NM_I(sbi)->nat_blocks / 8;
|
||||
si->base_mem += NM_I(sbi)->nat_blocks * sizeof(unsigned short);
|
||||
|
||||
|
||||
+1
-2
@@ -517,12 +517,11 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name,
|
||||
}
|
||||
|
||||
start:
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
if (time_to_inject(F2FS_I_SB(dir), FAULT_DIR_DEPTH)) {
|
||||
f2fs_show_injection_info(FAULT_DIR_DEPTH);
|
||||
return -ENOSPC;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (unlikely(current_depth == MAX_DIR_HASH_DEPTH))
|
||||
return -ENOSPC;
|
||||
|
||||
|
||||
+132
-59
File diff suppressed because it is too large
Load Diff
+134
-86
File diff suppressed because it is too large
Load Diff
+142
-23
@@ -53,12 +53,10 @@ static int gc_thread_func(void *data)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
if (time_to_inject(sbi, FAULT_CHECKPOINT)) {
|
||||
f2fs_show_injection_info(FAULT_CHECKPOINT);
|
||||
f2fs_stop_checkpoint(sbi, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!sb_start_write_trylock(sbi->sb))
|
||||
continue;
|
||||
@@ -517,7 +515,11 @@ next_step:
|
||||
continue;
|
||||
}
|
||||
|
||||
f2fs_get_node_info(sbi, nid, &ni);
|
||||
if (f2fs_get_node_info(sbi, nid, &ni)) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ni.blk_addr != start_addr + off) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
continue;
|
||||
@@ -576,7 +578,10 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
if (IS_ERR(node_page))
|
||||
return false;
|
||||
|
||||
f2fs_get_node_info(sbi, nid, dni);
|
||||
if (f2fs_get_node_info(sbi, nid, dni)) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sum->version != dni->version) {
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
@@ -594,6 +599,72 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ra_data_block(struct inode *inode, pgoff_t index)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
struct dnode_of_data dn;
|
||||
struct page *page;
|
||||
struct extent_info ei = {0, 0, 0};
|
||||
struct f2fs_io_info fio = {
|
||||
.sbi = sbi,
|
||||
.ino = inode->i_ino,
|
||||
.type = DATA,
|
||||
.temp = COLD,
|
||||
.op = REQ_OP_READ,
|
||||
.op_flags = 0,
|
||||
.encrypted_page = NULL,
|
||||
.in_list = false,
|
||||
.retry = false,
|
||||
};
|
||||
int err;
|
||||
|
||||
page = f2fs_grab_cache_page(mapping, index, true);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
|
||||
if (f2fs_lookup_extent_cache(inode, index, &ei)) {
|
||||
dn.data_blkaddr = ei.blk + index - ei.fofs;
|
||||
goto got_it;
|
||||
}
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE);
|
||||
if (err)
|
||||
goto put_page;
|
||||
f2fs_put_dnode(&dn);
|
||||
|
||||
if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr,
|
||||
DATA_GENERIC))) {
|
||||
err = -EFAULT;
|
||||
goto put_page;
|
||||
}
|
||||
got_it:
|
||||
/* read page */
|
||||
fio.page = page;
|
||||
fio.new_blkaddr = fio.old_blkaddr = dn.data_blkaddr;
|
||||
|
||||
fio.encrypted_page = f2fs_pagecache_get_page(META_MAPPING(sbi),
|
||||
dn.data_blkaddr,
|
||||
FGP_LOCK | FGP_CREAT, GFP_NOFS);
|
||||
if (!fio.encrypted_page) {
|
||||
err = -ENOMEM;
|
||||
goto put_page;
|
||||
}
|
||||
|
||||
err = f2fs_submit_page_bio(&fio);
|
||||
if (err)
|
||||
goto put_encrypted_page;
|
||||
f2fs_put_page(fio.encrypted_page, 0);
|
||||
f2fs_put_page(page, 1);
|
||||
return 0;
|
||||
put_encrypted_page:
|
||||
f2fs_put_page(fio.encrypted_page, 1);
|
||||
put_page:
|
||||
f2fs_put_page(page, 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Move data block via META_MAPPING while keeping locked data page.
|
||||
* This can be used to move blocks, aka LBAs, directly on disk.
|
||||
@@ -615,7 +686,7 @@ static void move_data_block(struct inode *inode, block_t bidx,
|
||||
struct dnode_of_data dn;
|
||||
struct f2fs_summary sum;
|
||||
struct node_info ni;
|
||||
struct page *page;
|
||||
struct page *page, *mpage;
|
||||
block_t newaddr;
|
||||
int err;
|
||||
bool lfs_mode = test_opt(fio.sbi, LFS);
|
||||
@@ -655,7 +726,10 @@ static void move_data_block(struct inode *inode, block_t bidx,
|
||||
*/
|
||||
f2fs_wait_on_page_writeback(page, DATA, true);
|
||||
|
||||
f2fs_get_node_info(fio.sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(fio.sbi, dn.nid, &ni);
|
||||
if (err)
|
||||
goto put_out;
|
||||
|
||||
set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version);
|
||||
|
||||
/* read page */
|
||||
@@ -675,6 +749,23 @@ static void move_data_block(struct inode *inode, block_t bidx,
|
||||
goto recover_block;
|
||||
}
|
||||
|
||||
mpage = f2fs_pagecache_get_page(META_MAPPING(fio.sbi),
|
||||
fio.old_blkaddr, FGP_LOCK, GFP_NOFS);
|
||||
if (mpage) {
|
||||
bool updated = false;
|
||||
|
||||
if (PageUptodate(mpage)) {
|
||||
memcpy(page_address(fio.encrypted_page),
|
||||
page_address(mpage), PAGE_SIZE);
|
||||
updated = true;
|
||||
}
|
||||
f2fs_put_page(mpage, 1);
|
||||
invalidate_mapping_pages(META_MAPPING(fio.sbi),
|
||||
fio.old_blkaddr, fio.old_blkaddr);
|
||||
if (updated)
|
||||
goto write_page;
|
||||
}
|
||||
|
||||
err = f2fs_submit_page_bio(&fio);
|
||||
if (err)
|
||||
goto put_page_out;
|
||||
@@ -691,6 +782,7 @@ static void move_data_block(struct inode *inode, block_t bidx,
|
||||
goto put_page_out;
|
||||
}
|
||||
|
||||
write_page:
|
||||
set_page_dirty(fio.encrypted_page);
|
||||
f2fs_wait_on_page_writeback(fio.encrypted_page, DATA, true);
|
||||
if (clear_page_dirty_for_io(fio.encrypted_page))
|
||||
@@ -865,22 +957,30 @@ next_step:
|
||||
if (IS_ERR(inode) || is_bad_inode(inode))
|
||||
continue;
|
||||
|
||||
/* if inode uses special I/O path, let's go phase 3 */
|
||||
if (!down_write_trylock(
|
||||
&F2FS_I(inode)->i_gc_rwsem[WRITE])) {
|
||||
iput(inode);
|
||||
sbi->skipped_gc_rwsem++;
|
||||
continue;
|
||||
}
|
||||
|
||||
start_bidx = f2fs_start_bidx_of_node(nofs, inode) +
|
||||
ofs_in_node;
|
||||
|
||||
if (f2fs_post_read_required(inode)) {
|
||||
int err = ra_data_block(inode, start_bidx);
|
||||
|
||||
up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
if (err) {
|
||||
iput(inode);
|
||||
continue;
|
||||
}
|
||||
add_gc_inode(gc_list, inode);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!down_write_trylock(
|
||||
&F2FS_I(inode)->i_gc_rwsem[WRITE])) {
|
||||
iput(inode);
|
||||
continue;
|
||||
}
|
||||
|
||||
start_bidx = f2fs_start_bidx_of_node(nofs, inode);
|
||||
data_page = f2fs_get_read_data_page(inode,
|
||||
start_bidx + ofs_in_node, REQ_RAHEAD,
|
||||
true);
|
||||
start_bidx, REQ_RAHEAD, true);
|
||||
up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
|
||||
if (IS_ERR(data_page)) {
|
||||
iput(inode);
|
||||
@@ -903,6 +1003,7 @@ next_step:
|
||||
continue;
|
||||
if (!down_write_trylock(
|
||||
&fi->i_gc_rwsem[WRITE])) {
|
||||
sbi->skipped_gc_rwsem++;
|
||||
up_write(&fi->i_gc_rwsem[READ]);
|
||||
continue;
|
||||
}
|
||||
@@ -986,7 +1087,13 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
|
||||
goto next;
|
||||
|
||||
sum = page_address(sum_page);
|
||||
f2fs_bug_on(sbi, type != GET_SUM_TYPE((&sum->footer)));
|
||||
if (type != GET_SUM_TYPE((&sum->footer))) {
|
||||
f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent segment (%u) "
|
||||
"type [%d, %d] in SSA and SIT",
|
||||
segno, type, GET_SUM_TYPE((&sum->footer)));
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
goto next;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is to avoid deadlock:
|
||||
@@ -1034,6 +1141,7 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
|
||||
.iroot = RADIX_TREE_INIT(gc_list.iroot, GFP_NOFS),
|
||||
};
|
||||
unsigned long long last_skipped = sbi->skipped_atomic_files[FG_GC];
|
||||
unsigned long long first_skipped;
|
||||
unsigned int skipped_round = 0, round = 0;
|
||||
|
||||
trace_f2fs_gc_begin(sbi->sb, sync, background,
|
||||
@@ -1046,6 +1154,8 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
|
||||
prefree_segments(sbi));
|
||||
|
||||
cpc.reason = __get_cp_reason(sbi);
|
||||
sbi->skipped_gc_rwsem = 0;
|
||||
first_skipped = last_skipped;
|
||||
gc_more:
|
||||
if (unlikely(!(sbi->sb->s_flags & SB_ACTIVE))) {
|
||||
ret = -EINVAL;
|
||||
@@ -1087,7 +1197,8 @@ gc_more:
|
||||
total_freed += seg_freed;
|
||||
|
||||
if (gc_type == FG_GC) {
|
||||
if (sbi->skipped_atomic_files[FG_GC] > last_skipped)
|
||||
if (sbi->skipped_atomic_files[FG_GC] > last_skipped ||
|
||||
sbi->skipped_gc_rwsem)
|
||||
skipped_round++;
|
||||
last_skipped = sbi->skipped_atomic_files[FG_GC];
|
||||
round++;
|
||||
@@ -1096,15 +1207,23 @@ gc_more:
|
||||
if (gc_type == FG_GC)
|
||||
sbi->cur_victim_sec = NULL_SEGNO;
|
||||
|
||||
if (!sync) {
|
||||
if (has_not_enough_free_secs(sbi, sec_freed, 0)) {
|
||||
if (skipped_round > MAX_SKIP_ATOMIC_COUNT &&
|
||||
skipped_round * 2 >= round)
|
||||
f2fs_drop_inmem_pages_all(sbi, true);
|
||||
if (sync)
|
||||
goto stop;
|
||||
|
||||
if (has_not_enough_free_secs(sbi, sec_freed, 0)) {
|
||||
if (skipped_round <= MAX_SKIP_GC_COUNT ||
|
||||
skipped_round * 2 < round) {
|
||||
segno = NULL_SEGNO;
|
||||
goto gc_more;
|
||||
}
|
||||
|
||||
if (first_skipped < last_skipped &&
|
||||
(last_skipped - first_skipped) >
|
||||
sbi->skipped_gc_rwsem) {
|
||||
f2fs_drop_inmem_pages_all(sbi, true);
|
||||
segno = NULL_SEGNO;
|
||||
goto gc_more;
|
||||
}
|
||||
if (gc_type == FG_GC)
|
||||
ret = f2fs_write_checkpoint(sbi, &cpc);
|
||||
}
|
||||
|
||||
+35
-1
@@ -121,6 +121,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
|
||||
.encrypted_page = NULL,
|
||||
.io_type = FS_DATA_IO,
|
||||
};
|
||||
struct node_info ni;
|
||||
int dirty, err;
|
||||
|
||||
if (!f2fs_exist_data(dn->inode))
|
||||
@@ -130,6 +131,24 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = f2fs_get_node_info(fio.sbi, dn->nid, &ni);
|
||||
if (err) {
|
||||
f2fs_put_dnode(dn);
|
||||
return err;
|
||||
}
|
||||
|
||||
fio.version = ni.version;
|
||||
|
||||
if (unlikely(dn->data_blkaddr != NEW_ADDR)) {
|
||||
f2fs_put_dnode(dn);
|
||||
set_sbi_flag(fio.sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(fio.sbi->sb, KERN_WARNING,
|
||||
"%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, "
|
||||
"run fsck to fix.",
|
||||
__func__, dn->inode->i_ino, dn->data_blkaddr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
f2fs_bug_on(F2FS_P_SB(page), PageWriteback(page));
|
||||
|
||||
f2fs_do_read_inline_data(page, dn->inode_page);
|
||||
@@ -363,6 +382,17 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage,
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (unlikely(dn.data_blkaddr != NEW_ADDR)) {
|
||||
f2fs_put_dnode(&dn);
|
||||
set_sbi_flag(F2FS_P_SB(page), SBI_NEED_FSCK);
|
||||
f2fs_msg(F2FS_P_SB(page)->sb, KERN_WARNING,
|
||||
"%s: corrupted inline inode ino=%lx, i_addr[0]:0x%x, "
|
||||
"run fsck to fix.",
|
||||
__func__, dir->i_ino, dn.data_blkaddr);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
f2fs_wait_on_page_writeback(page, DATA, true);
|
||||
|
||||
dentry_blk = page_address(page);
|
||||
@@ -477,6 +507,7 @@ static int f2fs_move_rehashed_dirents(struct inode *dir, struct page *ipage,
|
||||
return 0;
|
||||
recover:
|
||||
lock_page(ipage);
|
||||
f2fs_wait_on_page_writeback(ipage, NODE, true);
|
||||
memcpy(inline_dentry, backup_dentry, MAX_INLINE_DATA(dir));
|
||||
f2fs_i_depth_write(dir, 0);
|
||||
f2fs_i_size_write(dir, MAX_INLINE_DATA(dir));
|
||||
@@ -668,7 +699,10 @@ int f2fs_inline_data_fiemap(struct inode *inode,
|
||||
ilen = start + len;
|
||||
ilen -= start;
|
||||
|
||||
f2fs_get_node_info(F2FS_I_SB(inode), inode->i_ino, &ni);
|
||||
err = f2fs_get_node_info(F2FS_I_SB(inode), inode->i_ino, &ni);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits;
|
||||
byteaddr += (char *)inline_data_addr(inode, ipage) -
|
||||
(char *)F2FS_INODE(ipage);
|
||||
|
||||
+132
-22
@@ -68,13 +68,16 @@ static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
|
||||
}
|
||||
}
|
||||
|
||||
static bool __written_first_block(struct f2fs_inode *ri)
|
||||
static int __written_first_block(struct f2fs_sb_info *sbi,
|
||||
struct f2fs_inode *ri)
|
||||
{
|
||||
block_t addr = le32_to_cpu(ri->i_addr[offset_in_addr(ri)]);
|
||||
|
||||
if (is_valid_blkaddr(addr))
|
||||
return true;
|
||||
return false;
|
||||
if (!__is_valid_data_blkaddr(addr))
|
||||
return 1;
|
||||
if (!f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __set_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
|
||||
@@ -121,7 +124,7 @@ static bool f2fs_enable_inode_chksum(struct f2fs_sb_info *sbi, struct page *page
|
||||
if (!f2fs_sb_has_inode_chksum(sbi->sb))
|
||||
return false;
|
||||
|
||||
if (!RAW_IS_INODE(F2FS_NODE(page)) || !(ri->i_inline & F2FS_EXTRA_ATTR))
|
||||
if (!IS_INODE(page) || !(ri->i_inline & F2FS_EXTRA_ATTR))
|
||||
return false;
|
||||
|
||||
if (!F2FS_FITS_IN_INODE(ri, le16_to_cpu(ri->i_extra_isize),
|
||||
@@ -159,8 +162,15 @@ bool f2fs_inode_chksum_verify(struct f2fs_sb_info *sbi, struct page *page)
|
||||
struct f2fs_inode *ri;
|
||||
__u32 provided, calculated;
|
||||
|
||||
if (unlikely(is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN)))
|
||||
return true;
|
||||
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
if (!f2fs_enable_inode_chksum(sbi, page))
|
||||
#else
|
||||
if (!f2fs_enable_inode_chksum(sbi, page) ||
|
||||
PageDirty(page) || PageWriteback(page))
|
||||
#endif
|
||||
return true;
|
||||
|
||||
ri = &F2FS_NODE(page)->i;
|
||||
@@ -185,9 +195,31 @@ void f2fs_inode_chksum_set(struct f2fs_sb_info *sbi, struct page *page)
|
||||
ri->i_inode_checksum = cpu_to_le32(f2fs_inode_chksum(sbi, page));
|
||||
}
|
||||
|
||||
static bool sanity_check_inode(struct inode *inode)
|
||||
static bool sanity_check_inode(struct inode *inode, struct page *node_page)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct f2fs_inode_info *fi = F2FS_I(inode);
|
||||
unsigned long long iblocks;
|
||||
|
||||
iblocks = le64_to_cpu(F2FS_INODE(node_page)->i_blocks);
|
||||
if (!iblocks) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"%s: corrupted inode i_blocks i_ino=%lx iblocks=%llu, "
|
||||
"run fsck to fix.",
|
||||
__func__, inode->i_ino, iblocks);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ino_of_node(node_page) != nid_of_node(node_page)) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"%s: corrupted inode footer i_ino=%lx, ino,nid: "
|
||||
"[%u, %u] run fsck to fix.",
|
||||
__func__, inode->i_ino,
|
||||
ino_of_node(node_page), nid_of_node(node_page));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)
|
||||
&& !f2fs_has_extra_attr(inode)) {
|
||||
@@ -197,6 +229,64 @@ static bool sanity_check_inode(struct inode *inode)
|
||||
__func__, inode->i_ino);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (f2fs_has_extra_attr(inode) &&
|
||||
!f2fs_sb_has_extra_attr(sbi->sb)) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"%s: inode (ino=%lx) 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 % sizeof(__le32)) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"%s: inode (ino=%lx) has corrupted i_extra_isize: %d, "
|
||||
"max: %zu",
|
||||
__func__, inode->i_ino, fi->i_extra_isize,
|
||||
F2FS_TOTAL_EXTRA_ATTR_SIZE);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (F2FS_I(inode)->extent_tree) {
|
||||
struct extent_info *ei = &F2FS_I(inode)->extent_tree->largest;
|
||||
|
||||
if (ei->len &&
|
||||
(!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC) ||
|
||||
!f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1,
|
||||
DATA_GENERIC))) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"%s: inode (ino=%lx) extent info [%u, %u, %u] "
|
||||
"is incorrect, run fsck to fix",
|
||||
__func__, inode->i_ino,
|
||||
ei->blk, ei->fofs, ei->len);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (f2fs_has_inline_data(inode) &&
|
||||
(!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode))) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"%s: inode (ino=%lx, 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)) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"%s: inode (ino=%lx, mode=%u) should not have "
|
||||
"inline_dentry, run fsck to fix",
|
||||
__func__, inode->i_ino, inode->i_mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -207,6 +297,7 @@ static int do_read_inode(struct inode *inode)
|
||||
struct page *node_page;
|
||||
struct f2fs_inode *ri;
|
||||
projid_t i_projid;
|
||||
int err;
|
||||
|
||||
/* Check if ino is within scope */
|
||||
if (f2fs_check_nid_range(sbi, inode->i_ino))
|
||||
@@ -268,6 +359,11 @@ static int do_read_inode(struct inode *inode)
|
||||
fi->i_inline_xattr_size = 0;
|
||||
}
|
||||
|
||||
if (!sanity_check_inode(inode, node_page)) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* check data exist */
|
||||
if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode))
|
||||
__recover_inline_status(inode, node_page);
|
||||
@@ -275,8 +371,15 @@ static int do_read_inode(struct inode *inode)
|
||||
/* get rdev by using inline_info */
|
||||
__get_inode_rdev(inode, ri);
|
||||
|
||||
if (__written_first_block(ri))
|
||||
set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
err = __written_first_block(sbi, ri);
|
||||
if (err < 0) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
return err;
|
||||
}
|
||||
if (!err)
|
||||
set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN);
|
||||
}
|
||||
|
||||
if (!f2fs_need_inode_block_update(sbi, inode->i_ino))
|
||||
fi->last_disk_size = inode->i_size;
|
||||
@@ -297,9 +400,9 @@ static int do_read_inode(struct inode *inode)
|
||||
fi->i_crtime.tv_nsec = le32_to_cpu(ri->i_crtime_nsec);
|
||||
}
|
||||
|
||||
F2FS_I(inode)->i_disk_time[0] = timespec64_to_timespec(inode->i_atime);
|
||||
F2FS_I(inode)->i_disk_time[1] = timespec64_to_timespec(inode->i_ctime);
|
||||
F2FS_I(inode)->i_disk_time[2] = timespec64_to_timespec(inode->i_mtime);
|
||||
F2FS_I(inode)->i_disk_time[0] = inode->i_atime;
|
||||
F2FS_I(inode)->i_disk_time[1] = inode->i_ctime;
|
||||
F2FS_I(inode)->i_disk_time[2] = inode->i_mtime;
|
||||
F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime;
|
||||
f2fs_put_page(node_page, 1);
|
||||
|
||||
@@ -330,10 +433,6 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
|
||||
ret = do_read_inode(inode);
|
||||
if (ret)
|
||||
goto bad_inode;
|
||||
if (!sanity_check_inode(inode)) {
|
||||
ret = -EINVAL;
|
||||
goto bad_inode;
|
||||
}
|
||||
make_now:
|
||||
if (ino == F2FS_NODE_INO(sbi)) {
|
||||
inode->i_mapping->a_ops = &f2fs_node_aops;
|
||||
@@ -470,10 +569,14 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page)
|
||||
if (inode->i_nlink == 0)
|
||||
clear_inline_node(node_page);
|
||||
|
||||
F2FS_I(inode)->i_disk_time[0] = timespec64_to_timespec(inode->i_atime);
|
||||
F2FS_I(inode)->i_disk_time[1] = timespec64_to_timespec(inode->i_ctime);
|
||||
F2FS_I(inode)->i_disk_time[2] = timespec64_to_timespec(inode->i_mtime);
|
||||
F2FS_I(inode)->i_disk_time[0] = inode->i_atime;
|
||||
F2FS_I(inode)->i_disk_time[1] = inode->i_ctime;
|
||||
F2FS_I(inode)->i_disk_time[2] = inode->i_mtime;
|
||||
F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime;
|
||||
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
f2fs_inode_chksum_set(F2FS_I_SB(inode), node_page);
|
||||
#endif
|
||||
}
|
||||
|
||||
void f2fs_update_inode_page(struct inode *inode)
|
||||
@@ -558,12 +661,11 @@ retry:
|
||||
if (F2FS_HAS_BLOCKS(inode))
|
||||
err = f2fs_truncate(inode);
|
||||
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
if (time_to_inject(sbi, FAULT_EVICT_INODE)) {
|
||||
f2fs_show_injection_info(FAULT_EVICT_INODE);
|
||||
err = -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!err) {
|
||||
f2fs_lock_op(sbi);
|
||||
err = f2fs_remove_inode_page(inode);
|
||||
@@ -626,6 +728,7 @@ void f2fs_handle_failed_inode(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
struct node_info ni;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* clear nlink of inode in order to release resource of inode
|
||||
@@ -648,10 +751,16 @@ void f2fs_handle_failed_inode(struct inode *inode)
|
||||
* so we can prevent losing this orphan when encoutering checkpoint
|
||||
* and following suddenly power-off.
|
||||
*/
|
||||
f2fs_get_node_info(sbi, inode->i_ino, &ni);
|
||||
err = f2fs_get_node_info(sbi, inode->i_ino, &ni);
|
||||
if (err) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"May loss orphan inode, run fsck to fix.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ni.blk_addr != NULL_ADDR) {
|
||||
int err = f2fs_acquire_orphan_inode(sbi);
|
||||
err = f2fs_acquire_orphan_inode(sbi);
|
||||
if (err) {
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
@@ -664,6 +773,7 @@ void f2fs_handle_failed_inode(struct inode *inode)
|
||||
set_inode_flag(inode, FI_FREE_NID);
|
||||
}
|
||||
|
||||
out:
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
/* iput will drop the inode object */
|
||||
|
||||
+3
-3
@@ -51,7 +51,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
|
||||
inode->i_ino = ino;
|
||||
inode->i_blocks = 0;
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
|
||||
F2FS_I(inode)->i_crtime = timespec64_to_timespec(inode->i_mtime);
|
||||
F2FS_I(inode)->i_crtime = inode->i_mtime;
|
||||
inode->i_generation = sbi->s_next_generation++;
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
@@ -246,7 +246,7 @@ int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
|
||||
return -EINVAL;
|
||||
|
||||
if (hot) {
|
||||
strncpy(extlist[count], name, strlen(name));
|
||||
memcpy(extlist[count], name, strlen(name));
|
||||
sbi->raw_super->hot_ext_count = hot_count + 1;
|
||||
} else {
|
||||
char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];
|
||||
@@ -254,7 +254,7 @@ int f2fs_update_extension_list(struct f2fs_sb_info *sbi, const char *name,
|
||||
memcpy(buf, &extlist[cold_count],
|
||||
F2FS_EXTENSION_LEN * hot_count);
|
||||
memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN);
|
||||
strncpy(extlist[cold_count], name, strlen(name));
|
||||
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);
|
||||
|
||||
+308
-76
File diff suppressed because it is too large
Load Diff
@@ -135,6 +135,11 @@ static inline bool excess_cached_nats(struct f2fs_sb_info *sbi)
|
||||
return NM_I(sbi)->nat_cnt >= DEF_NAT_CACHE_THRESHOLD;
|
||||
}
|
||||
|
||||
static inline bool excess_dirty_nodes(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
return get_pages(sbi, F2FS_DIRTY_NODES) >= sbi->blocks_per_seg * 8;
|
||||
}
|
||||
|
||||
enum mem_type {
|
||||
FREE_NIDS, /* indicates the free nid list */
|
||||
NAT_ENTRIES, /* indicates the cached nat entry */
|
||||
@@ -444,6 +449,10 @@ static inline void set_mark(struct page *page, int mark, int type)
|
||||
else
|
||||
flag &= ~(0x1 << type);
|
||||
rn->footer.flag = cpu_to_le32(flag);
|
||||
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
f2fs_inode_chksum_set(F2FS_P_SB(page), page);
|
||||
#endif
|
||||
}
|
||||
#define set_dentry_mark(page, mark) set_mark(page, mark, DENT_BIT_SHIFT)
|
||||
#define set_fsync_mark(page, mark) set_mark(page, mark, FSYNC_BIT_SHIFT)
|
||||
|
||||
+21
-10
@@ -241,8 +241,8 @@ 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 free_blocks = sbi->user_block_count -
|
||||
valid_user_blocks(sbi);
|
||||
unsigned int free_blocks = MAIN_SEGS(sbi) * sbi->blocks_per_seg -
|
||||
valid_user_blocks(sbi);
|
||||
int err = 0;
|
||||
|
||||
/* get node pages in the current segment */
|
||||
@@ -252,10 +252,14 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
|
||||
while (1) {
|
||||
struct fsync_inode_entry *entry;
|
||||
|
||||
if (!f2fs_is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
|
||||
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
|
||||
return 0;
|
||||
|
||||
page = f2fs_get_tmp_page(sbi, blkaddr);
|
||||
if (IS_ERR(page)) {
|
||||
err = PTR_ERR(page);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_recoverable_dnode(page))
|
||||
break;
|
||||
@@ -471,7 +475,10 @@ retry_dn:
|
||||
|
||||
f2fs_wait_on_page_writeback(dn.node_page, NODE, true);
|
||||
|
||||
f2fs_get_node_info(sbi, dn.nid, &ni);
|
||||
err = f2fs_get_node_info(sbi, dn.nid, &ni);
|
||||
if (err)
|
||||
goto err;
|
||||
|
||||
f2fs_bug_on(sbi, ni.ino != ino_of_node(page));
|
||||
f2fs_bug_on(sbi, ofs_of_node(dn.node_page) != ofs_of_node(page));
|
||||
|
||||
@@ -507,14 +514,13 @@ retry_dn:
|
||||
}
|
||||
|
||||
/* dest is valid block, try to recover from src to dest */
|
||||
if (f2fs_is_valid_meta_blkaddr(sbi, dest, META_POR)) {
|
||||
if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
|
||||
|
||||
if (src == NULL_ADDR) {
|
||||
err = f2fs_reserve_new_block(&dn);
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
while (err)
|
||||
while (err &&
|
||||
IS_ENABLED(CONFIG_F2FS_FAULT_INJECTION))
|
||||
err = f2fs_reserve_new_block(&dn);
|
||||
#endif
|
||||
/* We should not get -ENOSPC */
|
||||
f2fs_bug_on(sbi, err);
|
||||
if (err)
|
||||
@@ -568,12 +574,16 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
||||
while (1) {
|
||||
struct fsync_inode_entry *entry;
|
||||
|
||||
if (!f2fs_is_valid_meta_blkaddr(sbi, blkaddr, META_POR))
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_recoverable_dnode(page)) {
|
||||
f2fs_put_page(page, 1);
|
||||
@@ -628,7 +638,8 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
||||
#endif
|
||||
|
||||
if (s_flags & SB_RDONLY) {
|
||||
f2fs_msg(sbi->sb, KERN_INFO, "orphan cleanup on readonly fs");
|
||||
f2fs_msg(sbi->sb, KERN_INFO,
|
||||
"recover fsync data on readonly fs");
|
||||
sbi->sb->s_flags &= ~SB_RDONLY;
|
||||
}
|
||||
|
||||
|
||||
+307
-90
File diff suppressed because it is too large
Load Diff
+8
-8
@@ -85,7 +85,7 @@
|
||||
(GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1))
|
||||
|
||||
#define GET_SEGNO(sbi, blk_addr) \
|
||||
((!is_valid_blkaddr(blk_addr)) ? \
|
||||
((!is_valid_data_blkaddr(sbi, blk_addr)) ? \
|
||||
NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \
|
||||
GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
|
||||
#define BLKS_PER_SEC(sbi) \
|
||||
@@ -215,7 +215,7 @@ struct segment_allocation {
|
||||
#define IS_DUMMY_WRITTEN_PAGE(page) \
|
||||
(page_private(page) == (unsigned long)DUMMY_WRITTEN_PAGE)
|
||||
|
||||
#define MAX_SKIP_ATOMIC_COUNT 16
|
||||
#define MAX_SKIP_GC_COUNT 16
|
||||
|
||||
struct inmem_pages {
|
||||
struct list_head list;
|
||||
@@ -448,6 +448,8 @@ static inline void __set_test_and_free(struct f2fs_sb_info *sbi,
|
||||
if (test_and_clear_bit(segno, free_i->free_segmap)) {
|
||||
free_i->free_segments++;
|
||||
|
||||
if (IS_CURSEC(sbi, secno))
|
||||
goto skip_free;
|
||||
next = find_next_bit(free_i->free_segmap,
|
||||
start_segno + sbi->segs_per_sec, start_segno);
|
||||
if (next >= start_segno + sbi->segs_per_sec) {
|
||||
@@ -455,6 +457,7 @@ static inline void __set_test_and_free(struct f2fs_sb_info *sbi,
|
||||
free_i->free_sections++;
|
||||
}
|
||||
}
|
||||
skip_free:
|
||||
spin_unlock(&free_i->segmap_lock);
|
||||
}
|
||||
|
||||
@@ -645,13 +648,10 @@ static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = fio->sbi;
|
||||
|
||||
if (PAGE_TYPE_OF_BIO(fio->type) == META &&
|
||||
(!is_read_io(fio->op) || fio->is_meta))
|
||||
BUG_ON(blk_addr < SEG0_BLKADDR(sbi) ||
|
||||
blk_addr >= MAIN_BLKADDR(sbi));
|
||||
if (__is_meta_io(fio))
|
||||
verify_blkaddr(sbi, blk_addr, META_GENERIC);
|
||||
else
|
||||
BUG_ON(blk_addr < MAIN_BLKADDR(sbi) ||
|
||||
blk_addr >= MAX_BLKADDR(sbi));
|
||||
verify_blkaddr(sbi, blk_addr, DATA_GENERIC);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+122
-40
@@ -41,7 +41,7 @@ static struct kmem_cache *f2fs_inode_cachep;
|
||||
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
|
||||
char *fault_name[FAULT_MAX] = {
|
||||
char *f2fs_fault_name[FAULT_MAX] = {
|
||||
[FAULT_KMALLOC] = "kmalloc",
|
||||
[FAULT_KVMALLOC] = "kvmalloc",
|
||||
[FAULT_PAGE_ALLOC] = "page alloc",
|
||||
@@ -55,20 +55,24 @@ char *fault_name[FAULT_MAX] = {
|
||||
[FAULT_TRUNCATE] = "truncate fail",
|
||||
[FAULT_IO] = "IO error",
|
||||
[FAULT_CHECKPOINT] = "checkpoint error",
|
||||
[FAULT_DISCARD] = "discard error",
|
||||
};
|
||||
|
||||
static void f2fs_build_fault_attr(struct f2fs_sb_info *sbi,
|
||||
unsigned int rate)
|
||||
void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate,
|
||||
unsigned int type)
|
||||
{
|
||||
struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info;
|
||||
|
||||
if (rate) {
|
||||
atomic_set(&ffi->inject_ops, 0);
|
||||
ffi->inject_rate = rate;
|
||||
ffi->inject_type = (1 << FAULT_MAX) - 1;
|
||||
} else {
|
||||
memset(ffi, 0, sizeof(struct f2fs_fault_info));
|
||||
}
|
||||
|
||||
if (type)
|
||||
ffi->inject_type = type;
|
||||
|
||||
if (!rate && !type)
|
||||
memset(ffi, 0, sizeof(struct f2fs_fault_info));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -113,6 +117,7 @@ enum {
|
||||
Opt_mode,
|
||||
Opt_io_size_bits,
|
||||
Opt_fault_injection,
|
||||
Opt_fault_type,
|
||||
Opt_lazytime,
|
||||
Opt_nolazytime,
|
||||
Opt_quota,
|
||||
@@ -170,6 +175,7 @@ static match_table_t f2fs_tokens = {
|
||||
{Opt_mode, "mode=%s"},
|
||||
{Opt_io_size_bits, "io_bits=%u"},
|
||||
{Opt_fault_injection, "fault_injection=%u"},
|
||||
{Opt_fault_type, "fault_type=%u"},
|
||||
{Opt_lazytime, "lazytime"},
|
||||
{Opt_nolazytime, "nolazytime"},
|
||||
{Opt_quota, "quota"},
|
||||
@@ -347,12 +353,6 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi)
|
||||
"QUOTA feature is enabled, so ignore jquota_fmt");
|
||||
F2FS_OPTION(sbi).s_jquota_fmt = 0;
|
||||
}
|
||||
if (f2fs_sb_has_quota_ino(sbi->sb) && f2fs_readonly(sbi->sb)) {
|
||||
f2fs_msg(sbi->sb, KERN_INFO,
|
||||
"Filesystem with quota feature cannot be mounted RDWR "
|
||||
"without CONFIG_QUOTA");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -606,7 +606,18 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
if (args->from && match_int(args, &arg))
|
||||
return -EINVAL;
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
f2fs_build_fault_attr(sbi, arg);
|
||||
f2fs_build_fault_attr(sbi, arg, F2FS_ALL_FAULT_TYPE);
|
||||
set_opt(sbi, FAULT_INJECTION);
|
||||
#else
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"FAULT_INJECTION was not selected");
|
||||
#endif
|
||||
break;
|
||||
case Opt_fault_type:
|
||||
if (args->from && match_int(args, &arg))
|
||||
return -EINVAL;
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
f2fs_build_fault_attr(sbi, 0, arg);
|
||||
set_opt(sbi, FAULT_INJECTION);
|
||||
#else
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
@@ -775,6 +786,19 @@ static int parse_options(struct super_block *sb, char *options)
|
||||
#ifdef CONFIG_QUOTA
|
||||
if (f2fs_check_quota_options(sbi))
|
||||
return -EINVAL;
|
||||
#else
|
||||
if (f2fs_sb_has_quota_ino(sbi->sb) && !f2fs_readonly(sbi->sb)) {
|
||||
f2fs_msg(sbi->sb, KERN_INFO,
|
||||
"Filesystem with quota feature cannot be mounted RDWR "
|
||||
"without CONFIG_QUOTA");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (f2fs_sb_has_project_quota(sbi->sb) && !f2fs_readonly(sbi->sb)) {
|
||||
f2fs_msg(sb, KERN_ERR,
|
||||
"Filesystem with project quota feature cannot be "
|
||||
"mounted RDWR without CONFIG_QUOTA");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (F2FS_IO_SIZE_BITS(sbi) && !test_opt(sbi, LFS)) {
|
||||
@@ -1030,6 +1054,10 @@ static void f2fs_put_super(struct super_block *sb)
|
||||
/* our cp_error case, we can wait for any writeback page */
|
||||
f2fs_flush_merged_writes(sbi);
|
||||
|
||||
f2fs_wait_on_all_pages_writeback(sbi);
|
||||
|
||||
f2fs_bug_on(sbi, sbi->fsync_node_num);
|
||||
|
||||
iput(sbi->node_inode);
|
||||
iput(sbi->meta_inode);
|
||||
|
||||
@@ -1118,7 +1146,7 @@ static int f2fs_statfs_project(struct super_block *sb,
|
||||
dquot = dqget(sb, qid);
|
||||
if (IS_ERR(dquot))
|
||||
return PTR_ERR(dquot);
|
||||
spin_lock(&dq_data_lock);
|
||||
spin_lock(&dquot->dq_dqb_lock);
|
||||
|
||||
limit = (dquot->dq_dqb.dqb_bsoftlimit ?
|
||||
dquot->dq_dqb.dqb_bsoftlimit :
|
||||
@@ -1141,7 +1169,7 @@ static int f2fs_statfs_project(struct super_block *sb,
|
||||
(buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0;
|
||||
}
|
||||
|
||||
spin_unlock(&dq_data_lock);
|
||||
spin_unlock(&dquot->dq_dqb_lock);
|
||||
dqput(dquot);
|
||||
return 0;
|
||||
}
|
||||
@@ -1310,9 +1338,12 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
|
||||
if (F2FS_IO_SIZE_BITS(sbi))
|
||||
seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
if (test_opt(sbi, FAULT_INJECTION))
|
||||
if (test_opt(sbi, FAULT_INJECTION)) {
|
||||
seq_printf(seq, ",fault_injection=%u",
|
||||
F2FS_OPTION(sbi).fault_info.inject_rate);
|
||||
seq_printf(seq, ",fault_type=%u",
|
||||
F2FS_OPTION(sbi).fault_info.inject_type);
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_QUOTA
|
||||
if (test_opt(sbi, QUOTA))
|
||||
@@ -1343,6 +1374,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
|
||||
seq_printf(seq, ",fsync_mode=%s", "posix");
|
||||
else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT)
|
||||
seq_printf(seq, ",fsync_mode=%s", "strict");
|
||||
else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_NOBARRIER)
|
||||
seq_printf(seq, ",fsync_mode=%s", "nobarrier");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1355,7 +1388,8 @@ static void default_options(struct f2fs_sb_info *sbi)
|
||||
F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
|
||||
F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX;
|
||||
F2FS_OPTION(sbi).test_dummy_encryption = false;
|
||||
sbi->readdir_ra = 1;
|
||||
F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
|
||||
F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);
|
||||
|
||||
set_opt(sbi, BG_GC);
|
||||
set_opt(sbi, INLINE_XATTR);
|
||||
@@ -1365,12 +1399,12 @@ static void default_options(struct f2fs_sb_info *sbi)
|
||||
set_opt(sbi, NOHEAP);
|
||||
sbi->sb->s_flags |= SB_LAZYTIME;
|
||||
set_opt(sbi, FLUSH_MERGE);
|
||||
if (f2fs_sb_has_blkzoned(sbi->sb)) {
|
||||
set_opt_mode(sbi, F2FS_MOUNT_LFS);
|
||||
if (blk_queue_discard(bdev_get_queue(sbi->sb->s_bdev)))
|
||||
set_opt(sbi, DISCARD);
|
||||
} else {
|
||||
if (f2fs_sb_has_blkzoned(sbi->sb))
|
||||
set_opt_mode(sbi, F2FS_MOUNT_LFS);
|
||||
else
|
||||
set_opt_mode(sbi, F2FS_MOUNT_ADAPTIVE);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_F2FS_FS_XATTR
|
||||
set_opt(sbi, XATTR_USER);
|
||||
@@ -1379,9 +1413,7 @@ static void default_options(struct f2fs_sb_info *sbi)
|
||||
set_opt(sbi, POSIX_ACL);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_F2FS_FAULT_INJECTION
|
||||
f2fs_build_fault_attr(sbi, 0);
|
||||
#endif
|
||||
f2fs_build_fault_attr(sbi, 0, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
@@ -2229,9 +2261,9 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (secs_per_zone > total_sections) {
|
||||
if (secs_per_zone > total_sections || !secs_per_zone) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"Wrong secs_per_zone (%u > %u)",
|
||||
"Wrong secs_per_zone / total_sections (%u, %u)",
|
||||
secs_per_zone, total_sections);
|
||||
return 1;
|
||||
}
|
||||
@@ -2282,12 +2314,20 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
|
||||
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
|
||||
unsigned int ovp_segments, reserved_segments;
|
||||
unsigned int main_segs, blocks_per_seg;
|
||||
unsigned int sit_segs, nat_segs;
|
||||
unsigned int sit_bitmap_size, nat_bitmap_size;
|
||||
unsigned int log_blocks_per_seg;
|
||||
unsigned int segment_count_main;
|
||||
unsigned int cp_pack_start_sum, cp_payload;
|
||||
block_t user_block_count;
|
||||
int i;
|
||||
|
||||
total = le32_to_cpu(raw_super->segment_count);
|
||||
fsmeta = le32_to_cpu(raw_super->segment_count_ckpt);
|
||||
fsmeta += le32_to_cpu(raw_super->segment_count_sit);
|
||||
fsmeta += le32_to_cpu(raw_super->segment_count_nat);
|
||||
sit_segs = le32_to_cpu(raw_super->segment_count_sit);
|
||||
fsmeta += sit_segs;
|
||||
nat_segs = le32_to_cpu(raw_super->segment_count_nat);
|
||||
fsmeta += nat_segs;
|
||||
fsmeta += le32_to_cpu(ckpt->rsvd_segment_count);
|
||||
fsmeta += le32_to_cpu(raw_super->segment_count_ssa);
|
||||
|
||||
@@ -2304,6 +2344,16 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
|
||||
return 1;
|
||||
}
|
||||
|
||||
user_block_count = le64_to_cpu(ckpt->user_block_count);
|
||||
segment_count_main = le32_to_cpu(raw_super->segment_count_main);
|
||||
log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
|
||||
if (!user_block_count || user_block_count >=
|
||||
segment_count_main << log_blocks_per_seg) {
|
||||
f2fs_msg(sbi->sb, KERN_ERR,
|
||||
"Wrong user_block_count: %u", user_block_count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
main_segs = le32_to_cpu(raw_super->segment_count_main);
|
||||
blocks_per_seg = sbi->blocks_per_seg;
|
||||
|
||||
@@ -2318,6 +2368,28 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
|
||||
return 1;
|
||||
}
|
||||
|
||||
sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize);
|
||||
nat_bitmap_size = le32_to_cpu(ckpt->nat_ver_bitmap_bytesize);
|
||||
|
||||
if (sit_bitmap_size != ((sit_segs / 2) << log_blocks_per_seg) / 8 ||
|
||||
nat_bitmap_size != ((nat_segs / 2) << log_blocks_per_seg) / 8) {
|
||||
f2fs_msg(sbi->sb, KERN_ERR,
|
||||
"Wrong bitmap size: sit: %u, nat:%u",
|
||||
sit_bitmap_size, nat_bitmap_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
cp_pack_start_sum = __start_sum_addr(sbi);
|
||||
cp_payload = __cp_payload(sbi);
|
||||
if (cp_pack_start_sum < cp_payload + 1 ||
|
||||
cp_pack_start_sum > blocks_per_seg - 1 -
|
||||
NR_CURSEG_TYPE) {
|
||||
f2fs_msg(sbi->sb, KERN_ERR,
|
||||
"Wrong cp_pack_start_sum: %u",
|
||||
cp_pack_start_sum);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (unlikely(f2fs_cp_error(sbi))) {
|
||||
f2fs_msg(sbi->sb, KERN_ERR, "A bug case: need to run fsck");
|
||||
return 1;
|
||||
@@ -2651,6 +2723,8 @@ static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi)
|
||||
sm_i->dcc_info->discard_granularity = 1;
|
||||
sm_i->ipu_policy = 1 << F2FS_IPU_FORCE;
|
||||
}
|
||||
|
||||
sbi->readdir_ra = 1;
|
||||
}
|
||||
|
||||
static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
@@ -2700,9 +2774,6 @@ try_onemore:
|
||||
sb->s_fs_info = sbi;
|
||||
sbi->raw_super = raw_super;
|
||||
|
||||
F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
|
||||
F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);
|
||||
|
||||
/* precompute checksum seed for metadata */
|
||||
if (f2fs_sb_has_inode_chksum(sb))
|
||||
sbi->s_chksum_seed = f2fs_chksum(sbi, ~0, raw_super->uuid,
|
||||
@@ -2771,6 +2842,7 @@ try_onemore:
|
||||
/* init f2fs-specific super block info */
|
||||
sbi->valid_super_block = valid_super_block;
|
||||
mutex_init(&sbi->gc_mutex);
|
||||
mutex_init(&sbi->writepages);
|
||||
mutex_init(&sbi->cp_mutex);
|
||||
init_rwsem(&sbi->node_write);
|
||||
init_rwsem(&sbi->node_change);
|
||||
@@ -2865,6 +2937,8 @@ try_onemore:
|
||||
|
||||
f2fs_init_ino_entry_info(sbi);
|
||||
|
||||
f2fs_init_fsync_node_info(sbi);
|
||||
|
||||
/* setup f2fs internal modules */
|
||||
err = f2fs_build_segment_manager(sbi);
|
||||
if (err) {
|
||||
@@ -2912,10 +2986,11 @@ try_onemore:
|
||||
err = PTR_ERR(root);
|
||||
goto free_stats;
|
||||
}
|
||||
if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
|
||||
if (!S_ISDIR(root->i_mode) || !root->i_blocks ||
|
||||
!root->i_size || !root->i_nlink) {
|
||||
iput(root);
|
||||
err = -EINVAL;
|
||||
goto free_node_inode;
|
||||
goto free_stats;
|
||||
}
|
||||
|
||||
sb->s_root = d_make_root(root); /* allocate root dentry */
|
||||
@@ -2929,10 +3004,7 @@ try_onemore:
|
||||
goto free_root_inode;
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
/*
|
||||
* Turn on quotas which were not enabled for read-only mounts if
|
||||
* filesystem has quota feature, so that they are updated correctly.
|
||||
*/
|
||||
/* Enable quota usage during mount */
|
||||
if (f2fs_sb_has_quota_ino(sb) && !f2fs_readonly(sb)) {
|
||||
err = f2fs_enable_quotas(sb);
|
||||
if (err) {
|
||||
@@ -3090,9 +3162,19 @@ static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags,
|
||||
static void kill_f2fs_super(struct super_block *sb)
|
||||
{
|
||||
if (sb->s_root) {
|
||||
set_sbi_flag(F2FS_SB(sb), SBI_IS_CLOSE);
|
||||
f2fs_stop_gc_thread(F2FS_SB(sb));
|
||||
f2fs_stop_discard_thread(F2FS_SB(sb));
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
|
||||
set_sbi_flag(sbi, SBI_IS_CLOSE);
|
||||
f2fs_stop_gc_thread(sbi);
|
||||
f2fs_stop_discard_thread(sbi);
|
||||
|
||||
if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) ||
|
||||
!is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
|
||||
struct cp_control cpc = {
|
||||
.reason = CP_UMOUNT,
|
||||
};
|
||||
f2fs_write_checkpoint(sbi, &cpc);
|
||||
}
|
||||
}
|
||||
kill_block_super(sb);
|
||||
}
|
||||
|
||||
+39
-5
@@ -9,6 +9,7 @@
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/f2fs_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
@@ -252,6 +253,7 @@ out:
|
||||
if (t >= 1) {
|
||||
sbi->gc_mode = GC_URGENT;
|
||||
if (sbi->gc_thread) {
|
||||
sbi->gc_thread->gc_wake = 1;
|
||||
wake_up_interruptible_all(
|
||||
&sbi->gc_thread->gc_wait_queue_head);
|
||||
wake_up_discard_thread(sbi, true);
|
||||
@@ -286,8 +288,10 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a,
|
||||
bool gc_entry = (!strcmp(a->attr.name, "gc_urgent") ||
|
||||
a->struct_type == GC_THREAD);
|
||||
|
||||
if (gc_entry)
|
||||
down_read(&sbi->sb->s_umount);
|
||||
if (gc_entry) {
|
||||
if (!down_read_trylock(&sbi->sb->s_umount))
|
||||
return -EAGAIN;
|
||||
}
|
||||
ret = __sbi_store(a, sbi, buf, count);
|
||||
if (gc_entry)
|
||||
up_read(&sbi->sb->s_umount);
|
||||
@@ -393,6 +397,7 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_seq_blocks, min_seq_blocks);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_hot_blocks, min_hot_blocks);
|
||||
F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ssr_sections, min_ssr_sections);
|
||||
F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
|
||||
@@ -445,6 +450,7 @@ static struct attribute *f2fs_attrs[] = {
|
||||
ATTR_LIST(ipu_policy),
|
||||
ATTR_LIST(min_ipu_util),
|
||||
ATTR_LIST(min_fsync_blocks),
|
||||
ATTR_LIST(min_seq_blocks),
|
||||
ATTR_LIST(min_hot_blocks),
|
||||
ATTR_LIST(min_ssr_sections),
|
||||
ATTR_LIST(max_victim_search),
|
||||
@@ -516,7 +522,8 @@ static struct kobject f2fs_feat = {
|
||||
.kset = &f2fs_kset,
|
||||
};
|
||||
|
||||
static int segment_info_seq_show(struct seq_file *seq, void *offset)
|
||||
static int __maybe_unused segment_info_seq_show(struct seq_file *seq,
|
||||
void *offset)
|
||||
{
|
||||
struct super_block *sb = seq->private;
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
@@ -543,7 +550,8 @@ static int segment_info_seq_show(struct seq_file *seq, void *offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int segment_bits_seq_show(struct seq_file *seq, void *offset)
|
||||
static int __maybe_unused segment_bits_seq_show(struct seq_file *seq,
|
||||
void *offset)
|
||||
{
|
||||
struct super_block *sb = seq->private;
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
@@ -567,7 +575,8 @@ static int segment_bits_seq_show(struct seq_file *seq, void *offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iostat_info_seq_show(struct seq_file *seq, void *offset)
|
||||
static int __maybe_unused iostat_info_seq_show(struct seq_file *seq,
|
||||
void *offset)
|
||||
{
|
||||
struct super_block *sb = seq->private;
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
@@ -609,6 +618,28 @@ static int iostat_info_seq_show(struct seq_file *seq, void *offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused victim_bits_seq_show(struct seq_file *seq,
|
||||
void *offset)
|
||||
{
|
||||
struct super_block *sb = seq->private;
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
|
||||
int i;
|
||||
|
||||
seq_puts(seq, "format: victim_secmap bitmaps\n");
|
||||
|
||||
for (i = 0; i < MAIN_SECS(sbi); i++) {
|
||||
if ((i % 10) == 0)
|
||||
seq_printf(seq, "%-10d", i);
|
||||
seq_printf(seq, "%d", test_bit(i, dirty_i->victim_secmap) ? 1 : 0);
|
||||
if ((i % 10) == 9 || i == (MAIN_SECS(sbi) - 1))
|
||||
seq_putc(seq, '\n');
|
||||
else
|
||||
seq_putc(seq, ' ');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init f2fs_init_sysfs(void)
|
||||
{
|
||||
int ret;
|
||||
@@ -658,6 +689,8 @@ int f2fs_register_sysfs(struct f2fs_sb_info *sbi)
|
||||
segment_bits_seq_show, sb);
|
||||
proc_create_single_data("iostat_info", S_IRUGO, sbi->s_proc,
|
||||
iostat_info_seq_show, sb);
|
||||
proc_create_single_data("victim_bits", S_IRUGO, sbi->s_proc,
|
||||
victim_bits_seq_show, sb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -668,6 +701,7 @@ void f2fs_unregister_sysfs(struct f2fs_sb_info *sbi)
|
||||
remove_proc_entry("iostat_info", sbi->s_proc);
|
||||
remove_proc_entry("segment_info", sbi->s_proc);
|
||||
remove_proc_entry("segment_bits", sbi->s_proc);
|
||||
remove_proc_entry("victim_bits", sbi->s_proc);
|
||||
remove_proc_entry(sbi->sb->s_id, f2fs_proc_root);
|
||||
}
|
||||
kobject_del(&sbi->s_kobj);
|
||||
|
||||
+11
-7
@@ -37,9 +37,6 @@ static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
|
||||
return -EOPNOTSUPP;
|
||||
break;
|
||||
case F2FS_XATTR_INDEX_TRUSTED:
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
break;
|
||||
case F2FS_XATTR_INDEX_SECURITY:
|
||||
break;
|
||||
default:
|
||||
@@ -62,9 +59,6 @@ static int f2fs_xattr_generic_set(const struct xattr_handler *handler,
|
||||
return -EOPNOTSUPP;
|
||||
break;
|
||||
case F2FS_XATTR_INDEX_TRUSTED:
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
break;
|
||||
case F2FS_XATTR_INDEX_SECURITY:
|
||||
break;
|
||||
default:
|
||||
@@ -100,12 +94,22 @@ static int f2fs_xattr_advise_set(const struct xattr_handler *handler,
|
||||
const char *name, const void *value,
|
||||
size_t size, int flags)
|
||||
{
|
||||
unsigned char old_advise = F2FS_I(inode)->i_advise;
|
||||
unsigned char new_advise;
|
||||
|
||||
if (!inode_owner_or_capable(inode))
|
||||
return -EPERM;
|
||||
if (value == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
F2FS_I(inode)->i_advise |= *(char *)value;
|
||||
new_advise = *(char *)value;
|
||||
if (new_advise & ~FADVISE_MODIFIABLE_BITS)
|
||||
return -EINVAL;
|
||||
|
||||
new_advise = new_advise & FADVISE_MODIFIABLE_BITS;
|
||||
new_advise |= old_advise & ~FADVISE_MODIFIABLE_BITS;
|
||||
|
||||
F2FS_I(inode)->i_advise = new_advise;
|
||||
f2fs_mark_inode_dirty_sync(inode, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user