Commit 191d385f authored by Linus Torvalds's avatar Linus Torvalds

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
parents 163e4074 50e1f8d2
...@@ -608,8 +608,8 @@ static int __allocate_data_block(struct dnode_of_data *dn) ...@@ -608,8 +608,8 @@ static int __allocate_data_block(struct dnode_of_data *dn)
* b. do not use extent cache for better performance * b. do not use extent cache for better performance
* c. give the block addresses to blockdev * c. give the block addresses to blockdev
*/ */
static int get_data_block(struct inode *inode, sector_t iblock, static int __get_data_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create) struct buffer_head *bh_result, int create, bool fiemap)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb); struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
unsigned int blkbits = inode->i_sb->s_blocksize_bits; unsigned int blkbits = inode->i_sb->s_blocksize_bits;
...@@ -637,7 +637,7 @@ static int get_data_block(struct inode *inode, sector_t iblock, ...@@ -637,7 +637,7 @@ static int get_data_block(struct inode *inode, sector_t iblock,
err = 0; err = 0;
goto unlock_out; goto unlock_out;
} }
if (dn.data_blkaddr == NEW_ADDR) if (dn.data_blkaddr == NEW_ADDR && !fiemap)
goto put_out; goto put_out;
if (dn.data_blkaddr != NULL_ADDR) { if (dn.data_blkaddr != NULL_ADDR) {
...@@ -671,7 +671,7 @@ static int get_data_block(struct inode *inode, sector_t iblock, ...@@ -671,7 +671,7 @@ static int get_data_block(struct inode *inode, sector_t iblock,
err = 0; err = 0;
goto unlock_out; goto unlock_out;
} }
if (dn.data_blkaddr == NEW_ADDR) if (dn.data_blkaddr == NEW_ADDR && !fiemap)
goto put_out; goto put_out;
end_offset = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode)); 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, ...@@ -708,10 +708,23 @@ static int get_data_block(struct inode *inode, sector_t iblock,
return err; 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, int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u64 start, u64 len) 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) 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, ...@@ -376,11 +376,11 @@ static struct page *init_inode_metadata(struct inode *inode,
put_error: put_error:
f2fs_put_page(page, 1); f2fs_put_page(page, 1);
error:
/* once the failed inode becomes a bad inode, i_mode is S_IFREG */ /* once the failed inode becomes a bad inode, i_mode is S_IFREG */
truncate_inode_pages(&inode->i_data, 0); truncate_inode_pages(&inode->i_data, 0);
truncate_blocks(inode, 0); truncate_blocks(inode, 0);
remove_dirty_dir_inode(inode); remove_dirty_dir_inode(inode);
error:
remove_inode_page(inode); remove_inode_page(inode);
return ERR_PTR(err); return ERR_PTR(err);
} }
......
...@@ -342,9 +342,6 @@ struct f2fs_sm_info { ...@@ -342,9 +342,6 @@ struct f2fs_sm_info {
struct dirty_seglist_info *dirty_info; /* dirty segment information */ struct dirty_seglist_info *dirty_info; /* dirty segment information */
struct curseg_info *curseg_array; /* active 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 seg0_blkaddr; /* block address of 0'th segment */
block_t main_blkaddr; /* start block address of main area */ block_t main_blkaddr; /* start block address of main area */
block_t ssa_blkaddr; /* start block address of SSA 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) ...@@ -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) 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)) if (unlikely(nid >= NM_I(sbi)->max_nid))
return -EINVAL; return -EINVAL;
return 0; return 0;
......
...@@ -659,16 +659,19 @@ static int expand_inode_data(struct inode *inode, loff_t offset, ...@@ -659,16 +659,19 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
off_start = offset & (PAGE_CACHE_SIZE - 1); off_start = offset & (PAGE_CACHE_SIZE - 1);
off_end = (offset + len) & (PAGE_CACHE_SIZE - 1); off_end = (offset + len) & (PAGE_CACHE_SIZE - 1);
f2fs_lock_op(sbi);
for (index = pg_start; index <= pg_end; index++) { for (index = pg_start; index <= pg_end; index++) {
struct dnode_of_data dn; 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); set_new_dnode(&dn, inode, NULL, NULL, 0);
ret = f2fs_reserve_block(&dn, index); ret = f2fs_reserve_block(&dn, index);
f2fs_unlock_op(sbi);
if (ret) if (ret)
break; break;
noalloc:
if (pg_start == pg_end) if (pg_start == pg_end)
new_size = offset + len; new_size = offset + len;
else if (index == pg_start && off_start) else if (index == pg_start && off_start)
...@@ -683,8 +686,9 @@ static int expand_inode_data(struct inode *inode, loff_t offset, ...@@ -683,8 +686,9 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
i_size_read(inode) < new_size) { i_size_read(inode) < new_size) {
i_size_write(inode, new_size); i_size_write(inode, new_size);
mark_inode_dirty(inode); mark_inode_dirty(inode);
f2fs_write_inode(inode, NULL); update_inode_page(inode);
} }
f2fs_unlock_op(sbi);
return ret; return ret;
} }
......
...@@ -78,6 +78,7 @@ static int do_read_inode(struct inode *inode) ...@@ -78,6 +78,7 @@ static int do_read_inode(struct inode *inode)
if (check_nid_range(sbi, inode->i_ino)) { if (check_nid_range(sbi, inode->i_ino)) {
f2fs_msg(inode->i_sb, KERN_ERR, "bad inode number: %lu", f2fs_msg(inode->i_sb, KERN_ERR, "bad inode number: %lu",
(unsigned long) inode->i_ino); (unsigned long) inode->i_ino);
WARN_ON(1);
return -EINVAL; return -EINVAL;
} }
......
...@@ -417,9 +417,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -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); 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; new_inode->i_ctime = CURRENT_TIME;
down_write(&F2FS_I(new_inode)->i_sem); down_write(&F2FS_I(new_inode)->i_sem);
...@@ -448,6 +445,10 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -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; old_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(old_inode); mark_inode_dirty(old_inode);
...@@ -457,9 +458,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -457,9 +458,6 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (old_dir != new_dir) { if (old_dir != new_dir) {
f2fs_set_link(old_inode, old_dir_entry, f2fs_set_link(old_inode, old_dir_entry,
old_dir_page, new_dir); 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); update_inode_page(old_inode);
} else { } else {
kunmap(old_dir_page); kunmap(old_dir_page);
...@@ -474,7 +472,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -474,7 +472,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
return 0; return 0;
put_out_dir: put_out_dir:
f2fs_put_page(new_page, 1); kunmap(new_page);
f2fs_put_page(new_page, 0);
out_dir: out_dir:
if (old_dir_entry) { if (old_dir_entry) {
kunmap(old_dir_page); kunmap(old_dir_page);
......
...@@ -42,6 +42,8 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type) ...@@ -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; mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >> 12;
res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2); res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2);
} else if (type == DIRTY_DENTS) { } else if (type == DIRTY_DENTS) {
if (sbi->sb->s_bdi->dirty_exceeded)
return false;
mem_size = get_pages(sbi, F2FS_DIRTY_DENTS); mem_size = get_pages(sbi, F2FS_DIRTY_DENTS);
res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 1); 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) ...@@ -272,14 +272,15 @@ int create_flush_cmd_control(struct f2fs_sb_info *sbi)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&fcc->issue_lock); spin_lock_init(&fcc->issue_lock);
init_waitqueue_head(&fcc->flush_wait_queue); init_waitqueue_head(&fcc->flush_wait_queue);
sbi->sm_info->cmd_control_info = fcc;
fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi, fcc->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
"f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev)); "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
if (IS_ERR(fcc->f2fs_issue_flush)) { if (IS_ERR(fcc->f2fs_issue_flush)) {
err = PTR_ERR(fcc->f2fs_issue_flush); err = PTR_ERR(fcc->f2fs_issue_flush);
kfree(fcc); kfree(fcc);
sbi->sm_info->cmd_control_info = NULL;
return err; return err;
} }
sbi->sm_info->cmd_control_info = fcc;
return err; return err;
} }
...@@ -1885,8 +1886,6 @@ int build_segment_manager(struct f2fs_sb_info *sbi) ...@@ -1885,8 +1886,6 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
/* init sm info */ /* init sm info */
sbi->sm_info = 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->seg0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr); sm_info->main_blkaddr = le32_to_cpu(raw_super->main_blkaddr);
sm_info->segment_count = le32_to_cpu(raw_super->segment_count); 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, ...@@ -689,9 +689,7 @@ static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_sb_info *sbi = F2FS_SB(sb);
struct inode *inode; struct inode *inode;
if (unlikely(ino < F2FS_ROOT_INO(sbi))) if (check_nid_range(sbi, ino))
return ERR_PTR(-ESTALE);
if (unlikely(ino >= NM_I(sbi)->max_nid))
return ERR_PTR(-ESTALE); return ERR_PTR(-ESTALE);
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment