mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
f2fs bugfixes for 3.16
o fix normal and recovery path for fallocated regions o fix error case mishandling o recover renamed fsync inodes correctly o fix to get out of infinite loops in balance_dirty_pages o fix kernel NULL pointer error -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJTvUA5AAoJEEAUqH6CSFDSSKgP/RQ6ryncwwSUilDswq95/VI1 qXwAlHLBgJkPquld6Klqw//4ot49sThCjBtusxdNqoyB5aSb/xqupJxRvCrJe1RQ dRDYP1Mq63phd0cWsjAokfwXuiJQ2Ys/1bq2HguzAhL+7qNVNJEoy27ISUgvh71J 3v9pTfOqFY/qMxAa1Y91kIat3/27QTCtVQdS1sQM7s8UXlZHIIGyxrSmYWPUGNar yVtMNtgMQcEtmekRAjstM0glj3IukosTP1jameXYumEw9bchfIeeLznvtDiEqxKA maXtEPA+yrEk5y+RhOiBgaHuV/9uNmrHHvTwoqhMl9Wl+I4RzxpOhD2agRAUFbdn rvPKU514tsjhkdelSYf0v2rXf0PxZcZ5XE27TZ+xyhCADKykBdN5ZzTH1OUWjEOA TNdPVKv2btpvEdGdmdGzjKIQpPfjLgJLAKqDNNTSQ3u4XlVioMn6IyzEGddz41By kSU0Hzj3iBHk+XlqBWSELOd34aCuvqXG/gcE7rWOj0qbJ5T6GKVRTQN5CbqMNutJ Udw0JDhImgYxNI5fsy7Stg/5IqOwhp/pDIpLOHXRnYpLb2rJ1kzvgz4B/eJAZCcc zmjxZBn1C2GLBJYFDbY1KeR5Tp6WZ9yok+wbXFiO1mpx5RsU7jIL64X/7+Zg0X84 p3LlN/vBn1nr2DiB3+n/ =pwxz -----END PGP SIGNATURE----- Merge tag 'f2fs-fixes-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs Pull f2fs bugfixes from Jaegeuk Kim: "This includes a couple of bug fixes found by xfstests. In addition, one critical bug was reported by Brian Chadwick, which is falling into the infinite loop in balance_dirty_pages. And it turned out due to the IO merging policy in f2fs, which was newly merged in 3.16. - fix normal and recovery path for fallocated regions - fix error case mishandling - recover renamed fsync inodes correctly - fix to get out of infinite loops in balance_dirty_pages - fix kernel NULL pointer error" * tag 'f2fs-fixes-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: f2fs: avoid to access NULL pointer in issue_flush_thread f2fs: check bdi->dirty_exceeded when trying to skip data writes f2fs: do checkpoint for the renamed inode f2fs: release new entry page correctly in error path of f2fs_rename f2fs: fix error path in init_inode_metadata f2fs: check lower bound nid value in check_nid_range f2fs: remove unused variables in f2fs_sm_info f2fs: fix not to allocate unnecessary blocks during fallocate f2fs: recover fallocated data and its i_size together f2fs: fix to report newly allocate region as extent
This commit is contained in:
commit
191d385f25
9 changed files with 41 additions and 27 deletions
|
@ -608,8 +608,8 @@ static int __allocate_data_block(struct dnode_of_data *dn)
|
|||
* b. do not use extent cache for better performance
|
||||
* c. give the block addresses to blockdev
|
||||
*/
|
||||
static int get_data_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
static int __get_data_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create, bool fiemap)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
unsigned int blkbits = inode->i_sb->s_blocksize_bits;
|
||||
|
@ -637,7 +637,7 @@ static int get_data_block(struct inode *inode, sector_t iblock,
|
|||
err = 0;
|
||||
goto unlock_out;
|
||||
}
|
||||
if (dn.data_blkaddr == NEW_ADDR)
|
||||
if (dn.data_blkaddr == NEW_ADDR && !fiemap)
|
||||
goto put_out;
|
||||
|
||||
if (dn.data_blkaddr != NULL_ADDR) {
|
||||
|
@ -671,7 +671,7 @@ static int get_data_block(struct inode *inode, sector_t iblock,
|
|||
err = 0;
|
||||
goto unlock_out;
|
||||
}
|
||||
if (dn.data_blkaddr == NEW_ADDR)
|
||||
if (dn.data_blkaddr == NEW_ADDR && !fiemap)
|
||||
goto put_out;
|
||||
|
||||
end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
|
||||
|
@ -708,10 +708,23 @@ static int get_data_block(struct inode *inode, sector_t iblock,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int get_data_block(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
return __get_data_block(inode, iblock, bh_result, create, false);
|
||||
}
|
||||
|
||||
static int get_data_block_fiemap(struct inode *inode, sector_t iblock,
|
||||
struct buffer_head *bh_result, int create)
|
||||
{
|
||||
return __get_data_block(inode, iblock, bh_result, create, true);
|
||||
}
|
||||
|
||||
int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
u64 start, u64 len)
|
||||
{
|
||||
return generic_block_fiemap(inode, fieinfo, start, len, get_data_block);
|
||||
return generic_block_fiemap(inode, fieinfo,
|
||||
start, len, get_data_block_fiemap);
|
||||
}
|
||||
|
||||
static int f2fs_read_data_page(struct file *file, struct page *page)
|
||||
|
|
|
@ -376,11 +376,11 @@ static struct page *init_inode_metadata(struct inode *inode,
|
|||
|
||||
put_error:
|
||||
f2fs_put_page(page, 1);
|
||||
error:
|
||||
/* once the failed inode becomes a bad inode, i_mode is S_IFREG */
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
truncate_blocks(inode, 0);
|
||||
remove_dirty_dir_inode(inode);
|
||||
error:
|
||||
remove_inode_page(inode);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
|
|
@ -342,9 +342,6 @@ struct f2fs_sm_info {
|
|||
struct dirty_seglist_info *dirty_info; /* dirty segment information */
|
||||
struct curseg_info *curseg_array; /* active segment information */
|
||||
|
||||
struct list_head wblist_head; /* list of under-writeback pages */
|
||||
spinlock_t wblist_lock; /* lock for checkpoint */
|
||||
|
||||
block_t seg0_blkaddr; /* block address of 0'th segment */
|
||||
block_t main_blkaddr; /* start block address of main area */
|
||||
block_t ssa_blkaddr; /* start block address of SSA area */
|
||||
|
@ -644,7 +641,8 @@ static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi)
|
|||
*/
|
||||
static inline int check_nid_range(struct f2fs_sb_info *sbi, nid_t nid)
|
||||
{
|
||||
WARN_ON((nid >= NM_I(sbi)->max_nid));
|
||||
if (unlikely(nid < F2FS_ROOT_INO(sbi)))
|
||||
return -EINVAL;
|
||||
if (unlikely(nid >= NM_I(sbi)->max_nid))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
|
|
@ -659,16 +659,19 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
|
|||
off_start = offset & (PAGE_CACHE_SIZE - 1);
|
||||
off_end = (offset + len) & (PAGE_CACHE_SIZE - 1);
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
|
||||
for (index = pg_start; index <= pg_end; index++) {
|
||||
struct dnode_of_data dn;
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
if (index == pg_end && !off_end)
|
||||
goto noalloc;
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
ret = f2fs_reserve_block(&dn, index);
|
||||
f2fs_unlock_op(sbi);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
noalloc:
|
||||
if (pg_start == pg_end)
|
||||
new_size = offset + len;
|
||||
else if (index == pg_start && off_start)
|
||||
|
@ -683,8 +686,9 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
|
|||
i_size_read(inode) < new_size) {
|
||||
i_size_write(inode, new_size);
|
||||
mark_inode_dirty(inode);
|
||||
f2fs_write_inode(inode, NULL);
|
||||
update_inode_page(inode);
|
||||
}
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ static int do_read_inode(struct inode *inode)
|
|||
if (check_nid_range(sbi, inode->i_ino)) {
|
||||
f2fs_msg(inode->i_sb, KERN_ERR, "bad inode number: %lu",
|
||||
(unsigned long) inode->i_ino);
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -417,9 +417,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
}
|
||||
|
||||
f2fs_set_link(new_dir, new_entry, new_page, old_inode);
|
||||
down_write(&F2FS_I(old_inode)->i_sem);
|
||||
F2FS_I(old_inode)->i_pino = new_dir->i_ino;
|
||||
up_write(&F2FS_I(old_inode)->i_sem);
|
||||
|
||||
new_inode->i_ctime = CURRENT_TIME;
|
||||
down_write(&F2FS_I(new_inode)->i_sem);
|
||||
|
@ -448,6 +445,10 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
}
|
||||
}
|
||||
|
||||
down_write(&F2FS_I(old_inode)->i_sem);
|
||||
file_lost_pino(old_inode);
|
||||
up_write(&F2FS_I(old_inode)->i_sem);
|
||||
|
||||
old_inode->i_ctime = CURRENT_TIME;
|
||||
mark_inode_dirty(old_inode);
|
||||
|
||||
|
@ -457,9 +458,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
if (old_dir != new_dir) {
|
||||
f2fs_set_link(old_inode, old_dir_entry,
|
||||
old_dir_page, new_dir);
|
||||
down_write(&F2FS_I(old_inode)->i_sem);
|
||||
F2FS_I(old_inode)->i_pino = new_dir->i_ino;
|
||||
up_write(&F2FS_I(old_inode)->i_sem);
|
||||
update_inode_page(old_inode);
|
||||
} else {
|
||||
kunmap(old_dir_page);
|
||||
|
@ -474,7 +472,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
return 0;
|
||||
|
||||
put_out_dir:
|
||||
f2fs_put_page(new_page, 1);
|
||||
kunmap(new_page);
|
||||
f2fs_put_page(new_page, 0);
|
||||
out_dir:
|
||||
if (old_dir_entry) {
|
||||
kunmap(old_dir_page);
|
||||
|
|
|
@ -42,6 +42,8 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type)
|
|||
mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >> 12;
|
||||
res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2);
|
||||
} else if (type == DIRTY_DENTS) {
|
||||
if (sbi->sb->s_bdi->dirty_exceeded)
|
||||
return false;
|
||||
mem_size = get_pages(sbi, F2FS_DIRTY_DENTS);
|
||||
res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 1);
|
||||
}
|
||||
|
|
|
@ -272,14 +272,15 @@ int create_flush_cmd_control(struct f2fs_sb_info *sbi)
|
|||
return -ENOMEM;
|
||||
spin_lock_init(&fcc->issue_lock);
|
||||
init_waitqueue_head(&fcc->flush_wait_queue);
|
||||
sbi->sm_info->cmd_control_info = fcc;
|
||||
fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
|
||||
"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
|
||||
if (IS_ERR(fcc->f2fs_issue_flush)) {
|
||||
err = PTR_ERR(fcc->f2fs_issue_flush);
|
||||
kfree(fcc);
|
||||
sbi->sm_info->cmd_control_info = NULL;
|
||||
return err;
|
||||
}
|
||||
sbi->sm_info->cmd_control_info = fcc;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -1885,8 +1886,6 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
|
|||
|
||||
/* init sm info */
|
||||
sbi->sm_info = sm_info;
|
||||
INIT_LIST_HEAD(&sm_info->wblist_head);
|
||||
spin_lock_init(&sm_info->wblist_lock);
|
||||
sm_info->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
|
||||
sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr);
|
||||
sm_info->segment_count = le32_to_cpu(raw_super->segment_count);
|
||||
|
|
|
@ -689,9 +689,7 @@ static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
|
|||
struct f2fs_sb_info *sbi = F2FS_SB(sb);
|
||||
struct inode *inode;
|
||||
|
||||
if (unlikely(ino < F2FS_ROOT_INO(sbi)))
|
||||
return ERR_PTR(-ESTALE);
|
||||
if (unlikely(ino >= NM_I(sbi)->max_nid))
|
||||
if (check_nid_range(sbi, ino))
|
||||
return ERR_PTR(-ESTALE);
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue