mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
f2fs: Sync code with branch upstream-linux-4.9.y
This commit is contained in:
@@ -352,12 +352,14 @@ static int f2fs_acl_create(struct inode *dir, umode_t *mode,
|
||||
return PTR_ERR(p);
|
||||
|
||||
clone = f2fs_acl_clone(p, GFP_NOFS);
|
||||
if (!clone)
|
||||
goto no_mem;
|
||||
if (!clone) {
|
||||
ret = -ENOMEM;
|
||||
goto release_acl;
|
||||
}
|
||||
|
||||
ret = f2fs_acl_create_masq(clone, mode);
|
||||
if (ret < 0)
|
||||
goto no_mem_clone;
|
||||
goto release_clone;
|
||||
|
||||
if (ret == 0)
|
||||
posix_acl_release(clone);
|
||||
@@ -371,11 +373,11 @@ static int f2fs_acl_create(struct inode *dir, umode_t *mode,
|
||||
|
||||
return 0;
|
||||
|
||||
no_mem_clone:
|
||||
release_clone:
|
||||
posix_acl_release(clone);
|
||||
no_mem:
|
||||
release_acl:
|
||||
posix_acl_release(p);
|
||||
return -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,
|
||||
|
||||
@@ -85,8 +85,10 @@ repeat:
|
||||
fio.page = page;
|
||||
|
||||
if (f2fs_submit_page_bio(&fio)) {
|
||||
f2fs_put_page(page, 1);
|
||||
goto repeat;
|
||||
memset(page_address(page), 0, PAGE_SIZE);
|
||||
f2fs_stop_checkpoint(sbi, false);
|
||||
f2fs_bug_on(sbi, 1);
|
||||
return page;
|
||||
}
|
||||
|
||||
lock_page(page);
|
||||
@@ -117,7 +119,8 @@ struct page *get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index)
|
||||
return __get_meta_page(sbi, index, false);
|
||||
}
|
||||
|
||||
bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
|
||||
bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
|
||||
block_t blkaddr, int type)
|
||||
{
|
||||
switch (type) {
|
||||
case META_NAT:
|
||||
@@ -137,8 +140,20 @@ bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type)
|
||||
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:
|
||||
@@ -173,7 +188,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
|
||||
blk_start_plug(&plug);
|
||||
for (; nrpages-- > 0; blkno++) {
|
||||
|
||||
if (!is_valid_blkaddr(sbi, blkno, type))
|
||||
if (!f2fs_is_valid_blkaddr(sbi, blkno, type))
|
||||
goto out;
|
||||
|
||||
switch (type) {
|
||||
@@ -745,7 +760,7 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
|
||||
|
||||
crc_offset = le32_to_cpu((*cp_block)->checksum_offset);
|
||||
if (crc_offset > (blk_size - sizeof(__le32))) {
|
||||
f2fs_put_page(*cp_page, 1);
|
||||
f2fs_put_page(*cp_page, 1);
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"invalid crc_offset: %zu", crc_offset);
|
||||
return -EINVAL;
|
||||
@@ -774,6 +789,14 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
|
||||
&cp_page_1, version);
|
||||
if (err)
|
||||
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;
|
||||
@@ -837,15 +860,15 @@ int 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 (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 (sanity_check_ckpt(sbi))
|
||||
goto free_fail_no_cp;
|
||||
|
||||
if (cp_blks <= 1)
|
||||
goto done;
|
||||
|
||||
|
||||
@@ -438,7 +438,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);
|
||||
|
||||
@@ -483,7 +486,7 @@ next:
|
||||
spin_unlock(&io->io_lock);
|
||||
}
|
||||
|
||||
if (fio->old_blkaddr != NEW_ADDR)
|
||||
if (__is_valid_data_blkaddr(fio->old_blkaddr))
|
||||
verify_block_addr(fio, fio->old_blkaddr);
|
||||
verify_block_addr(fio, fio->new_blkaddr);
|
||||
|
||||
@@ -1043,7 +1046,13 @@ next_dnode:
|
||||
next_block:
|
||||
blkaddr = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
|
||||
|
||||
if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR) {
|
||||
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;
|
||||
@@ -1493,6 +1502,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))
|
||||
@@ -1721,6 +1734,7 @@ int do_write_data_page(struct f2fs_io_info *fio)
|
||||
/* This page is already truncated */
|
||||
if (fio->old_blkaddr == NULL_ADDR) {
|
||||
ClearPageUptodate(page);
|
||||
clear_cold_data(page);
|
||||
goto out_writepage;
|
||||
}
|
||||
got_it:
|
||||
@@ -1756,6 +1770,12 @@ got_it:
|
||||
if (err)
|
||||
goto out_writepage;
|
||||
|
||||
if (__is_valid_data_blkaddr(fio->old_blkaddr) &&
|
||||
!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
|
||||
DATA_GENERIC)) {
|
||||
err = -EFAULT;
|
||||
goto out_writepage;
|
||||
}
|
||||
set_page_writeback(page);
|
||||
ClearPageError(page);
|
||||
|
||||
@@ -1782,7 +1802,7 @@ static int __write_data_page(struct page *page, bool *submitted,
|
||||
loff_t i_size = i_size_read(inode);
|
||||
const pgoff_t end_index = ((unsigned long long) i_size)
|
||||
>> PAGE_SHIFT;
|
||||
loff_t psize = (page->index + 1) << PAGE_SHIFT;
|
||||
loff_t psize = (loff_t)(page->index + 1) << PAGE_SHIFT;
|
||||
unsigned offset = 0;
|
||||
bool need_balance_fs = false;
|
||||
int err = 0;
|
||||
@@ -1877,8 +1897,10 @@ done:
|
||||
|
||||
out:
|
||||
inode_dec_dirty_pages(inode);
|
||||
if (err)
|
||||
if (err) {
|
||||
ClearPageUptodate(page);
|
||||
clear_cold_data(page);
|
||||
}
|
||||
|
||||
if (wbc->for_reclaim) {
|
||||
f2fs_submit_merged_write_cond(sbi, inode, 0, page->index, DATA);
|
||||
@@ -2243,9 +2265,6 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||
block_t blkaddr = NULL_ADDR;
|
||||
int err = 0;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_VMAP
|
||||
trace_android_fs_datawrite_wrap(inode, pos, len);
|
||||
#else
|
||||
if (trace_android_fs_datawrite_start_enabled()) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
@@ -2256,7 +2275,6 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
|
||||
current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
#endif
|
||||
trace_f2fs_write_begin(inode, pos, len, flags);
|
||||
|
||||
if (f2fs_is_atomic_file(inode) &&
|
||||
@@ -2417,12 +2435,6 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
|
||||
trace_f2fs_direct_IO_enter(inode, offset, count, rw);
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_VMAP
|
||||
if (rw == READ)
|
||||
trace_android_fs_dataread_wrap(inode, offset, count);
|
||||
if (rw == WRITE)
|
||||
trace_android_fs_datawrite_wrap(inode, offset, count);
|
||||
#else
|
||||
if (trace_android_fs_dataread_start_enabled() &&
|
||||
(rw == READ)) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
@@ -2445,7 +2457,6 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
||||
current->pid, path,
|
||||
current->comm);
|
||||
}
|
||||
#endif
|
||||
if (rw == WRITE && whint_mode == WHINT_MODE_OFF)
|
||||
iocb->ki_hint = WRITE_LIFE_NOT_SET;
|
||||
|
||||
@@ -2506,6 +2517,8 @@ void f2fs_invalidate_page(struct page *page, unsigned int offset,
|
||||
}
|
||||
}
|
||||
|
||||
clear_cold_data(page);
|
||||
|
||||
/* This is atomic written page, keep Private */
|
||||
if (IS_ATOMIC_WRITTEN_PAGE(page))
|
||||
return drop_inmem_page(inode, page);
|
||||
@@ -2524,6 +2537,7 @@ int f2fs_release_page(struct page *page, gfp_t wait)
|
||||
if (IS_ATOMIC_WRITTEN_PAGE(page))
|
||||
return 0;
|
||||
|
||||
clear_cold_data(page);
|
||||
set_page_private(page, 0);
|
||||
ClearPagePrivate(page);
|
||||
return 1;
|
||||
|
||||
@@ -740,6 +740,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
|
||||
clear_page_dirty_for_io(page);
|
||||
ClearPagePrivate(page);
|
||||
ClearPageUptodate(page);
|
||||
clear_cold_data(page);
|
||||
inode_dec_dirty_pages(dir);
|
||||
remove_dirty_inode(dir);
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ struct cp_control {
|
||||
};
|
||||
|
||||
/*
|
||||
* For CP/NAT/SIT/SSA readahead
|
||||
* indicate meta/data type
|
||||
*/
|
||||
enum {
|
||||
META_CP,
|
||||
@@ -202,6 +202,8 @@ enum {
|
||||
META_SIT,
|
||||
META_SSA,
|
||||
META_POR,
|
||||
DATA_GENERIC,
|
||||
META_GENERIC,
|
||||
};
|
||||
|
||||
/* for the list of ino */
|
||||
@@ -2512,10 +2514,19 @@ static inline bool is_dot_dotdot(const struct qstr *str)
|
||||
|
||||
static inline bool f2fs_may_extent_tree(struct inode *inode)
|
||||
{
|
||||
if (!test_opt(F2FS_I_SB(inode), EXTENT_CACHE) ||
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
|
||||
if (!test_opt(sbi, EXTENT_CACHE) ||
|
||||
is_inode_flag_set(inode, FI_NO_EXTENT))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* for recovered files during mount do not create extents
|
||||
* if shrinker is not registered.
|
||||
*/
|
||||
if (list_empty(&sbi->s_list))
|
||||
return false;
|
||||
|
||||
return S_ISREG(inode->i_mode);
|
||||
}
|
||||
|
||||
@@ -2634,6 +2645,39 @@ static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi,
|
||||
spin_unlock(&sbi->iostat_lock);
|
||||
}
|
||||
|
||||
#define __is_meta_io(fio) (PAGE_TYPE_OF_BIO(fio->type) == META && \
|
||||
(!is_read_io(fio->op) || fio->is_meta))
|
||||
|
||||
bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
|
||||
block_t blkaddr, int type);
|
||||
void f2fs_msg(struct super_block *sb, const char *level, const char *fmt, ...);
|
||||
static inline void verify_blkaddr(struct f2fs_sb_info *sbi,
|
||||
block_t blkaddr, int type)
|
||||
{
|
||||
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, type)) {
|
||||
f2fs_msg(sbi->sb, KERN_ERR,
|
||||
"invalid blkaddr: %u, type: %d, run fsck to fix.",
|
||||
blkaddr, type);
|
||||
f2fs_bug_on(sbi, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool __is_valid_data_blkaddr(block_t blkaddr)
|
||||
{
|
||||
if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool is_valid_data_blkaddr(struct f2fs_sb_info *sbi,
|
||||
block_t blkaddr)
|
||||
{
|
||||
if (!__is_valid_data_blkaddr(blkaddr))
|
||||
return false;
|
||||
verify_blkaddr(sbi, blkaddr, DATA_GENERIC);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* file.c
|
||||
*/
|
||||
@@ -2851,6 +2895,8 @@ void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io);
|
||||
struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
struct page *get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index);
|
||||
bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
|
||||
block_t blkaddr, int type);
|
||||
bool is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type);
|
||||
int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages,
|
||||
int type, bool sync);
|
||||
|
||||
@@ -219,6 +219,9 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end,
|
||||
|
||||
trace_f2fs_sync_file_enter(inode);
|
||||
|
||||
if (S_ISDIR(inode->i_mode))
|
||||
goto go_write;
|
||||
|
||||
/* if fdatasync is triggered, let's do in-place-update */
|
||||
if (datasync || get_dirty_pages(inode) <= SM_I(sbi)->min_fsync_blocks)
|
||||
set_inode_flag(inode, FI_NEED_IPU);
|
||||
@@ -347,13 +350,13 @@ static pgoff_t __get_first_dirty_index(struct address_space *mapping,
|
||||
return pgofs;
|
||||
}
|
||||
|
||||
static bool __found_offset(block_t blkaddr, pgoff_t dirty, pgoff_t pgofs,
|
||||
int whence)
|
||||
static bool __found_offset(struct f2fs_sb_info *sbi, block_t blkaddr,
|
||||
pgoff_t dirty, pgoff_t pgofs, int whence)
|
||||
{
|
||||
switch (whence) {
|
||||
case SEEK_DATA:
|
||||
if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
|
||||
(blkaddr != NEW_ADDR && blkaddr != NULL_ADDR))
|
||||
is_valid_data_blkaddr(sbi, blkaddr))
|
||||
return true;
|
||||
break;
|
||||
case SEEK_HOLE:
|
||||
@@ -416,7 +419,15 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
|
||||
blkaddr = datablock_addr(dn.inode,
|
||||
dn.node_page, dn.ofs_in_node);
|
||||
|
||||
if (__found_offset(blkaddr, dirty, pgofs, whence)) {
|
||||
if (__is_valid_data_blkaddr(blkaddr) &&
|
||||
!f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
|
||||
blkaddr, DATA_GENERIC)) {
|
||||
f2fs_put_dnode(&dn);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (__found_offset(F2FS_I_SB(inode), blkaddr, dirty,
|
||||
pgofs, whence)) {
|
||||
f2fs_put_dnode(&dn);
|
||||
goto found;
|
||||
}
|
||||
@@ -508,6 +519,11 @@ void truncate_data_blocks_range(struct dnode_of_data *dn, int count)
|
||||
|
||||
dn->data_blkaddr = NULL_ADDR;
|
||||
set_data_blkaddr(dn);
|
||||
|
||||
if (__is_valid_data_blkaddr(blkaddr) &&
|
||||
!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
|
||||
continue;
|
||||
|
||||
invalidate_blocks(sbi, blkaddr);
|
||||
if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page))
|
||||
clear_inode_flag(dn->inode, FI_FIRST_BLOCK_WRITTEN);
|
||||
@@ -1070,7 +1086,7 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
|
||||
}
|
||||
dn.ofs_in_node++;
|
||||
i++;
|
||||
new_size = (dst + i) << PAGE_SHIFT;
|
||||
new_size = (loff_t)(dst + i) << PAGE_SHIFT;
|
||||
if (dst_inode->i_size < new_size)
|
||||
f2fs_i_size_write(dst_inode, new_size);
|
||||
} while (--ilen && (do_replace[i] || blkaddr[i] == NULL_ADDR));
|
||||
|
||||
@@ -1109,7 +1109,7 @@ stop:
|
||||
|
||||
put_gc_inode(&gc_list);
|
||||
|
||||
if (sync)
|
||||
if (sync && !ret)
|
||||
ret = sec_freed ? 0 : -EAGAIN;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -86,9 +86,6 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
|
||||
{
|
||||
struct page *ipage;
|
||||
|
||||
#ifdef CONFIG_AMLOGIC_VMAP
|
||||
trace_android_fs_dataread_wrap(inode, page_offset(page), PAGE_SIZE);
|
||||
#else
|
||||
if (trace_android_fs_dataread_start_enabled()) {
|
||||
char *path, pathbuf[MAX_TRACE_PATHBUF_LEN];
|
||||
|
||||
@@ -99,7 +96,6 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
|
||||
PAGE_SIZE, current->pid,
|
||||
path, current->comm);
|
||||
}
|
||||
#endif
|
||||
|
||||
ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
|
||||
if (IS_ERR(ipage)) {
|
||||
|
||||
@@ -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 (addr != NEW_ADDR && addr != NULL_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)
|
||||
@@ -185,6 +188,50 @@ 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, struct page *node_page)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(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_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;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int do_read_inode(struct inode *inode)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
|
||||
@@ -192,6 +239,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 (check_nid_range(sbi, inode->i_ino)) {
|
||||
@@ -235,6 +283,11 @@ static int do_read_inode(struct inode *inode)
|
||||
|
||||
get_inline_info(inode, ri);
|
||||
|
||||
if (!sanity_check_inode(inode, node_page)) {
|
||||
f2fs_put_page(node_page, 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fi->i_extra_isize = f2fs_has_extra_attr(inode) ?
|
||||
le16_to_cpu(ri->i_extra_isize) : 0;
|
||||
|
||||
@@ -262,7 +315,12 @@ static int do_read_inode(struct inode *inode)
|
||||
/* get rdev by using inline_info */
|
||||
__get_inode_rdev(inode, ri);
|
||||
|
||||
if (__written_first_block(ri))
|
||||
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 (!need_inode_block_update(sbi, inode->i_ino))
|
||||
@@ -354,6 +412,7 @@ make_now:
|
||||
return inode;
|
||||
|
||||
bad_inode:
|
||||
f2fs_inode_synced(inode);
|
||||
iget_failed(inode);
|
||||
trace_f2fs_iget_exit(inode, ret);
|
||||
return ERR_PTR(ret);
|
||||
|
||||
@@ -364,8 +364,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||
new_blkaddr == NULL_ADDR);
|
||||
f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR &&
|
||||
new_blkaddr == NEW_ADDR);
|
||||
f2fs_bug_on(sbi, nat_get_blkaddr(e) != NEW_ADDR &&
|
||||
nat_get_blkaddr(e) != NULL_ADDR &&
|
||||
f2fs_bug_on(sbi, is_valid_data_blkaddr(sbi, nat_get_blkaddr(e)) &&
|
||||
new_blkaddr == NEW_ADDR);
|
||||
|
||||
/* increment version no as node is removed */
|
||||
@@ -376,7 +375,7 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
|
||||
|
||||
/* change address */
|
||||
nat_set_blkaddr(e, new_blkaddr);
|
||||
if (new_blkaddr == NEW_ADDR || new_blkaddr == NULL_ADDR)
|
||||
if (!is_valid_data_blkaddr(sbi, new_blkaddr))
|
||||
set_nat_flag(e, IS_CHECKPOINTED, false);
|
||||
__set_nat_cache_dirty(nm_i, e);
|
||||
|
||||
@@ -719,6 +718,7 @@ static void truncate_node(struct dnode_of_data *dn)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
|
||||
struct node_info ni;
|
||||
pgoff_t index;
|
||||
|
||||
get_node_info(sbi, dn->nid, &ni);
|
||||
|
||||
@@ -736,10 +736,11 @@ static void truncate_node(struct dnode_of_data *dn)
|
||||
clear_node_page_dirty(dn->node_page);
|
||||
set_sbi_flag(sbi, SBI_IS_DIRTY);
|
||||
|
||||
index = dn->node_page->index;
|
||||
f2fs_put_page(dn->node_page, 1);
|
||||
|
||||
invalidate_mapping_pages(NODE_MAPPING(sbi),
|
||||
dn->node_page->index, dn->node_page->index);
|
||||
index, index);
|
||||
|
||||
dn->node_page = NULL;
|
||||
trace_f2fs_truncate_node(dn->inode, dn->nid, ni.blk_addr);
|
||||
@@ -1394,6 +1395,12 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (__is_valid_data_blkaddr(ni.blk_addr) &&
|
||||
!f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) {
|
||||
up_read(&sbi->node_write);
|
||||
goto redirty_out;
|
||||
}
|
||||
|
||||
if (atomic && !test_opt(sbi, NOBARRIER))
|
||||
fio.op_flags |= REQ_PREFLUSH | REQ_FUA;
|
||||
|
||||
|
||||
@@ -214,6 +214,8 @@ static void recover_inode(struct inode *inode, struct page *page)
|
||||
char *name;
|
||||
|
||||
inode->i_mode = le16_to_cpu(raw->i_mode);
|
||||
i_uid_write(inode, le32_to_cpu(raw->i_uid));
|
||||
i_gid_write(inode, le32_to_cpu(raw->i_gid));
|
||||
f2fs_i_size_write(inode, le64_to_cpu(raw->i_size));
|
||||
inode->i_atime.tv_sec = le64_to_cpu(raw->i_atime);
|
||||
inode->i_ctime.tv_sec = le64_to_cpu(raw->i_ctime);
|
||||
@@ -254,7 +256,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
|
||||
while (1) {
|
||||
struct fsync_inode_entry *entry;
|
||||
|
||||
if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
|
||||
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
|
||||
return 0;
|
||||
|
||||
page = get_tmp_page(sbi, blkaddr);
|
||||
@@ -474,7 +476,15 @@ retry_dn:
|
||||
|
||||
get_node_info(sbi, dn.nid, &ni);
|
||||
f2fs_bug_on(sbi, ni.ino != ino_of_node(page));
|
||||
f2fs_bug_on(sbi, ofs_of_node(dn.node_page) != ofs_of_node(page));
|
||||
|
||||
if (ofs_of_node(dn.node_page) != ofs_of_node(page)) {
|
||||
f2fs_msg(sbi->sb, KERN_WARNING,
|
||||
"Inconsistent ofs_of_node, ino:%lu, ofs:%u, %u",
|
||||
inode->i_ino, ofs_of_node(dn.node_page),
|
||||
ofs_of_node(page));
|
||||
err = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (; start < end; start++, dn.ofs_in_node++) {
|
||||
block_t src, dest;
|
||||
@@ -508,7 +518,7 @@ retry_dn:
|
||||
}
|
||||
|
||||
/* dest is valid block, try to recover from src to dest */
|
||||
if (is_valid_blkaddr(sbi, dest, META_POR)) {
|
||||
if (f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
|
||||
|
||||
if (src == NULL_ADDR) {
|
||||
err = reserve_new_block(&dn);
|
||||
@@ -569,7 +579,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
||||
while (1) {
|
||||
struct fsync_inode_entry *entry;
|
||||
|
||||
if (!is_valid_blkaddr(sbi, blkaddr, META_POR))
|
||||
if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR))
|
||||
break;
|
||||
|
||||
ra_meta_pages_cond(sbi, blkaddr);
|
||||
|
||||
@@ -260,8 +260,10 @@ retry:
|
||||
}
|
||||
next:
|
||||
/* we don't need to invalidate this in the sccessful status */
|
||||
if (drop || recover)
|
||||
if (drop || recover) {
|
||||
ClearPageUptodate(page);
|
||||
clear_cold_data(page);
|
||||
}
|
||||
set_page_private(page, 0);
|
||||
ClearPagePrivate(page);
|
||||
f2fs_put_page(page, 1);
|
||||
@@ -1892,7 +1894,7 @@ bool is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
|
||||
struct seg_entry *se;
|
||||
bool is_cp = false;
|
||||
|
||||
if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
|
||||
if (!is_valid_data_blkaddr(sbi, blkaddr))
|
||||
return true;
|
||||
|
||||
down_read(&sit_i->sentry_lock);
|
||||
@@ -2954,7 +2956,7 @@ void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr)
|
||||
{
|
||||
struct page *cpage;
|
||||
|
||||
if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
|
||||
if (!is_valid_data_blkaddr(sbi, blkaddr))
|
||||
return;
|
||||
|
||||
cpage = find_lock_page(META_MAPPING(sbi), blkaddr);
|
||||
@@ -3669,6 +3671,15 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
|
||||
unsigned int old_valid_blocks;
|
||||
|
||||
start = le32_to_cpu(segno_in_journal(journal, i));
|
||||
if (start >= MAIN_SEGS(sbi)) {
|
||||
f2fs_msg(sbi->sb, KERN_ERR,
|
||||
"Wrong journal entry on segno %u",
|
||||
start);
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
se = &sit_i->sentries[start];
|
||||
sit = sit_in_journal(journal, i);
|
||||
|
||||
@@ -3784,6 +3795,41 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi)
|
||||
return init_victim_secmap(sbi);
|
||||
}
|
||||
|
||||
static int sanity_check_curseg(struct f2fs_sb_info *sbi)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* In LFS/SSR curseg, .next_blkoff should point to an unused blkaddr;
|
||||
* In LFS curseg, all blkaddr after .next_blkoff should be unused.
|
||||
*/
|
||||
for (i = 0; i < NO_CHECK_TYPE; i++) {
|
||||
struct curseg_info *curseg = CURSEG_I(sbi, i);
|
||||
struct seg_entry *se = get_seg_entry(sbi, curseg->segno);
|
||||
unsigned int blkofs = curseg->next_blkoff;
|
||||
|
||||
if (f2fs_test_bit(blkofs, se->cur_valid_map))
|
||||
goto out;
|
||||
|
||||
if (curseg->alloc_type == SSR)
|
||||
continue;
|
||||
|
||||
for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) {
|
||||
if (!f2fs_test_bit(blkofs, se->cur_valid_map))
|
||||
continue;
|
||||
out:
|
||||
f2fs_msg(sbi->sb, KERN_ERR,
|
||||
"Current segment's next free block offset is "
|
||||
"inconsistent with bitmap, logtype:%u, "
|
||||
"segno:%u, type:%u, next_blkoff:%u, blkofs:%u",
|
||||
i, curseg->segno, curseg->alloc_type,
|
||||
curseg->next_blkoff, blkofs);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update min, max modified time for cost-benefit GC algorithm
|
||||
*/
|
||||
@@ -3878,6 +3924,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = sanity_check_curseg(sbi);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
init_min_max_mtime(sbi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -40,18 +40,18 @@
|
||||
((seg) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno))
|
||||
|
||||
#define IS_CURSEC(sbi, secno) \
|
||||
(((secno) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno / \
|
||||
(sbi)->segs_per_sec) || \
|
||||
((secno) == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno / \
|
||||
(sbi)->segs_per_sec) || \
|
||||
((secno) == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno / \
|
||||
(sbi)->segs_per_sec) || \
|
||||
((secno) == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno / \
|
||||
(sbi)->segs_per_sec) || \
|
||||
((secno) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno / \
|
||||
(sbi)->segs_per_sec) || \
|
||||
((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \
|
||||
(sbi)->segs_per_sec)) \
|
||||
((secno == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno / \
|
||||
sbi->segs_per_sec) || \
|
||||
(secno == CURSEG_I(sbi, CURSEG_WARM_DATA)->segno / \
|
||||
sbi->segs_per_sec) || \
|
||||
(secno == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno / \
|
||||
sbi->segs_per_sec) || \
|
||||
(secno == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno / \
|
||||
sbi->segs_per_sec) || \
|
||||
(secno == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno / \
|
||||
sbi->segs_per_sec) || \
|
||||
(secno == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \
|
||||
sbi->segs_per_sec)) \
|
||||
|
||||
#define MAIN_BLKADDR(sbi) \
|
||||
(SM_I(sbi) ? SM_I(sbi)->main_blkaddr : \
|
||||
@@ -66,7 +66,7 @@
|
||||
#define TOTAL_SEGS(sbi) \
|
||||
(SM_I(sbi) ? SM_I(sbi)->segment_count : \
|
||||
le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count))
|
||||
#define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << (sbi)->log_blocks_per_seg)
|
||||
#define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << sbi->log_blocks_per_seg)
|
||||
|
||||
#define MAX_BLKADDR(sbi) (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi))
|
||||
#define SEGMENT_SIZE(sbi) (1ULL << ((sbi)->log_blocksize + \
|
||||
@@ -85,7 +85,7 @@
|
||||
(GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1))
|
||||
|
||||
#define GET_SEGNO(sbi, blk_addr) \
|
||||
((((blk_addr) == NULL_ADDR) || ((blk_addr) == NEW_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) \
|
||||
@@ -645,13 +645,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -660,7 +657,6 @@ static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
|
||||
static inline int check_block_count(struct f2fs_sb_info *sbi,
|
||||
int segno, struct f2fs_sit_entry *raw_sit)
|
||||
{
|
||||
#ifdef CONFIG_F2FS_CHECK_FS
|
||||
bool is_valid = test_bit_le(0, raw_sit->valid_map) ? true : false;
|
||||
int valid_blocks = 0;
|
||||
int cur_pos = 0, next_pos;
|
||||
@@ -687,7 +683,7 @@ static inline int check_block_count(struct f2fs_sb_info *sbi,
|
||||
set_sbi_flag(sbi, SBI_NEED_FSCK);
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check segment usage, and check boundary of a given segment number */
|
||||
if (unlikely(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg
|
||||
|| segno > TOTAL_SEGS(sbi) - 1)) {
|
||||
|
||||
@@ -138,6 +138,6 @@ void f2fs_leave_shrinker(struct f2fs_sb_info *sbi)
|
||||
f2fs_shrink_extent_tree(sbi, __count_extent_cache(sbi));
|
||||
|
||||
spin_lock(&f2fs_list_lock);
|
||||
list_del(&sbi->s_list);
|
||||
list_del_init(&sbi->s_list);
|
||||
spin_unlock(&f2fs_list_lock);
|
||||
}
|
||||
|
||||
136
fs/f2fs/super.c
136
fs/f2fs/super.c
@@ -2139,6 +2139,8 @@ static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi,
|
||||
static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
|
||||
struct buffer_head *bh)
|
||||
{
|
||||
block_t segment_count, segs_per_sec, secs_per_zone;
|
||||
block_t total_sections, blocks_per_seg;
|
||||
struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
|
||||
(bh->b_data + F2FS_SUPER_OFFSET);
|
||||
struct super_block *sb = sbi->sb;
|
||||
@@ -2195,6 +2197,68 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
|
||||
return 1;
|
||||
}
|
||||
|
||||
segment_count = le32_to_cpu(raw_super->segment_count);
|
||||
segs_per_sec = le32_to_cpu(raw_super->segs_per_sec);
|
||||
secs_per_zone = le32_to_cpu(raw_super->secs_per_zone);
|
||||
total_sections = le32_to_cpu(raw_super->section_count);
|
||||
|
||||
/* blocks_per_seg should be 512, given the above check */
|
||||
blocks_per_seg = 1 << le32_to_cpu(raw_super->log_blocks_per_seg);
|
||||
|
||||
if (segment_count > F2FS_MAX_SEGMENT ||
|
||||
segment_count < F2FS_MIN_SEGMENTS) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"Invalid segment count (%u)",
|
||||
segment_count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (total_sections > segment_count ||
|
||||
total_sections < F2FS_MIN_SEGMENTS ||
|
||||
segs_per_sec > segment_count || !segs_per_sec) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"Invalid segment/section count (%u, %u x %u)",
|
||||
segment_count, total_sections, segs_per_sec);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((segment_count / segs_per_sec) < total_sections) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"Small segment_count (%u < %u * %u)",
|
||||
segment_count, segs_per_sec, total_sections);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (segment_count > (le64_to_cpu(raw_super->block_count) >> 9)) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"Wrong segment_count / block_count (%u > %llu)",
|
||||
segment_count, le64_to_cpu(raw_super->block_count));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (secs_per_zone > total_sections || !secs_per_zone) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"Wrong secs_per_zone / total_sections (%u, %u)",
|
||||
secs_per_zone, total_sections);
|
||||
return 1;
|
||||
}
|
||||
if (le32_to_cpu(raw_super->extension_count) > F2FS_MAX_EXTENSION) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"Corrupted extension count (%u > %u)",
|
||||
le32_to_cpu(raw_super->extension_count),
|
||||
F2FS_MAX_EXTENSION);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(raw_super->cp_payload) >
|
||||
(blocks_per_seg - F2FS_CP_PACKS)) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"Insane cp_payload (%u > %u)",
|
||||
le32_to_cpu(raw_super->cp_payload),
|
||||
blocks_per_seg - F2FS_CP_PACKS);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check reserved ino info */
|
||||
if (le32_to_cpu(raw_super->node_ino) != 1 ||
|
||||
le32_to_cpu(raw_super->meta_ino) != 2 ||
|
||||
@@ -2207,13 +2271,6 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (le32_to_cpu(raw_super->segment_count) > F2FS_MAX_SEGMENT) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
"Invalid segment count (%u)",
|
||||
le32_to_cpu(raw_super->segment_count));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check CP/SIT/NAT/SSA/MAIN_AREA area boundary */
|
||||
if (sanity_check_area_boundary(sbi, bh))
|
||||
return 1;
|
||||
@@ -2231,7 +2288,10 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi)
|
||||
unsigned int sit_segs, nat_segs;
|
||||
unsigned int sit_bitmap_size, nat_bitmap_size;
|
||||
unsigned int log_blocks_per_seg;
|
||||
int i;
|
||||
unsigned int segment_count_main;
|
||||
unsigned int cp_pack_start_sum, cp_payload;
|
||||
block_t user_block_count;
|
||||
int i, j;
|
||||
|
||||
total = le32_to_cpu(raw_super->segment_count);
|
||||
fsmeta = le32_to_cpu(raw_super->segment_count_ckpt);
|
||||
@@ -2255,6 +2315,16 @@ int 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;
|
||||
|
||||
@@ -2262,16 +2332,47 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi)
|
||||
if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs ||
|
||||
le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg)
|
||||
return 1;
|
||||
for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) {
|
||||
if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
|
||||
le32_to_cpu(ckpt->cur_node_segno[j])) {
|
||||
f2fs_msg(sbi->sb, KERN_ERR,
|
||||
"Node segment (%u, %u) has the same "
|
||||
"segno: %u", i, j,
|
||||
le32_to_cpu(ckpt->cur_node_segno[i]));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) {
|
||||
if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs ||
|
||||
le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg)
|
||||
return 1;
|
||||
for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) {
|
||||
if (le32_to_cpu(ckpt->cur_data_segno[i]) ==
|
||||
le32_to_cpu(ckpt->cur_data_segno[j])) {
|
||||
f2fs_msg(sbi->sb, KERN_ERR,
|
||||
"Data segment (%u, %u) has the same "
|
||||
"segno: %u", i, j,
|
||||
le32_to_cpu(ckpt->cur_data_segno[i]));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) {
|
||||
for (j = 0; j < NR_CURSEG_DATA_TYPE; j++) {
|
||||
if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
|
||||
le32_to_cpu(ckpt->cur_data_segno[j])) {
|
||||
f2fs_msg(sbi->sb, KERN_ERR,
|
||||
"Node segment (%u) and Data segment (%u)"
|
||||
" has the same segno: %u", i, j,
|
||||
le32_to_cpu(ckpt->cur_node_segno[i]));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize);
|
||||
nat_bitmap_size = le32_to_cpu(ckpt->nat_ver_bitmap_bytesize);
|
||||
log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
|
||||
|
||||
if (sit_bitmap_size != ((sit_segs / 2) << log_blocks_per_seg) / 8 ||
|
||||
nat_bitmap_size != ((nat_segs / 2) << log_blocks_per_seg) / 8) {
|
||||
@@ -2281,6 +2382,17 @@ int sanity_check_ckpt(struct f2fs_sb_info *sbi)
|
||||
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;
|
||||
@@ -2342,8 +2454,12 @@ static int init_percpu_info(struct f2fs_sb_info *sbi)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return percpu_counter_init(&sbi->total_valid_inode_count, 0,
|
||||
err = percpu_counter_init(&sbi->total_valid_inode_count, 0,
|
||||
GFP_KERNEL);
|
||||
if (err)
|
||||
percpu_counter_destroy(&sbi->alloc_valid_block_count);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLK_DEV_ZONED
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "trace.h"
|
||||
|
||||
static RADIX_TREE(pids, GFP_ATOMIC);
|
||||
static struct mutex pids_lock;
|
||||
static spinlock_t pids_lock;
|
||||
static struct last_io_info last_io;
|
||||
|
||||
static inline void __print_last_io(void)
|
||||
@@ -61,23 +61,29 @@ void f2fs_trace_pid(struct page *page)
|
||||
|
||||
set_page_private(page, (unsigned long)pid);
|
||||
|
||||
retry:
|
||||
if (radix_tree_preload(GFP_NOFS))
|
||||
return;
|
||||
|
||||
mutex_lock(&pids_lock);
|
||||
spin_lock(&pids_lock);
|
||||
p = radix_tree_lookup(&pids, pid);
|
||||
if (p == current)
|
||||
goto out;
|
||||
if (p)
|
||||
radix_tree_delete(&pids, pid);
|
||||
|
||||
f2fs_radix_tree_insert(&pids, pid, current);
|
||||
if (radix_tree_insert(&pids, pid, current)) {
|
||||
spin_unlock(&pids_lock);
|
||||
radix_tree_preload_end();
|
||||
cond_resched();
|
||||
goto retry;
|
||||
}
|
||||
|
||||
trace_printk("%3x:%3x %4x %-16s\n",
|
||||
MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev),
|
||||
pid, current->comm);
|
||||
out:
|
||||
mutex_unlock(&pids_lock);
|
||||
spin_unlock(&pids_lock);
|
||||
radix_tree_preload_end();
|
||||
}
|
||||
|
||||
@@ -122,7 +128,7 @@ void f2fs_trace_ios(struct f2fs_io_info *fio, int flush)
|
||||
|
||||
void f2fs_build_trace_ios(void)
|
||||
{
|
||||
mutex_init(&pids_lock);
|
||||
spin_lock_init(&pids_lock);
|
||||
}
|
||||
|
||||
#define PIDVEC_SIZE 128
|
||||
@@ -150,7 +156,7 @@ void f2fs_destroy_trace_ios(void)
|
||||
pid_t next_pid = 0;
|
||||
unsigned int found;
|
||||
|
||||
mutex_lock(&pids_lock);
|
||||
spin_lock(&pids_lock);
|
||||
while ((found = gang_lookup_pids(pid, next_pid, PIDVEC_SIZE))) {
|
||||
unsigned idx;
|
||||
|
||||
@@ -158,5 +164,5 @@ void f2fs_destroy_trace_ios(void)
|
||||
for (idx = 0; idx < found; idx++)
|
||||
radix_tree_delete(&pids, pid[idx]);
|
||||
}
|
||||
mutex_unlock(&pids_lock);
|
||||
spin_unlock(&pids_lock);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user