Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 191d385f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+18 −5
Original line number Diff line number Diff line
@@ -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)
+1 −1
Original line number Diff line number Diff line
@@ -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);
}
+2 −4
Original line number Diff line number Diff line
@@ -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;
+8 −4
Original line number Diff line number Diff line
@@ -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;
}
+1 −0
Original line number Diff line number Diff line
@@ -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;
	}

Loading