kernel: backport fix for non-regular inodes on f2fs
Upstream commit dda9f4b9ca ("f2fs: fix to skip verifying block address
for non-regular inode").
On 4.14, attempting to perform operations on a non-regular inode
residing on an f2fs filesystem, such rm-ing a device node, would fail
and lead to a warning / call trace in dmesg. This fix was already
applied to other kernels upstream - including 4.19, from which the patch
was taken.
More info at https://bugzilla.kernel.org/show_bug.cgi?id=202495.
Signed-off-by: Matt Merhar <mattmerhar@protonmail.com>
(cherry picked from commit ee500186a5)
			
			
This commit is contained in:
		 Matt Merhar
					Matt Merhar
				
			
				
					committed by
					
						 Hauke Mehrtens
						Hauke Mehrtens
					
				
			
			
				
	
			
			
			 Hauke Mehrtens
						Hauke Mehrtens
					
				
			
						parent
						
							f40947a8c0
						
					
				
				
					commit
					0974d59b5f
				
			| @@ -0,0 +1,69 @@ | |||||||
|  | From dda9f4b9cac6bdd2a96253b4444d7a6ce5132edb Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Chao Yu <yuchao0@huawei.com> | ||||||
|  | Date: Sat, 11 Aug 2018 23:42:09 +0800 | ||||||
|  | Subject: f2fs: fix to skip verifying block address for non-regular inode | ||||||
|  |  | ||||||
|  | generic/184 1s ... [failed, exit status 1]- output mismatch | ||||||
|  |     --- tests/generic/184.out	2015-01-11 16:52:27.643681072 +0800 | ||||||
|  |      QA output created by 184 - silence is golden | ||||||
|  |     +rm: cannot remove '/mnt/f2fs/null': Bad address | ||||||
|  |     +mknod: '/mnt/f2fs/null': Bad address | ||||||
|  |     +chmod: cannot access '/mnt/f2fs/null': Bad address | ||||||
|  |     +./tests/generic/184: line 36: /mnt/f2fs/null: Bad address | ||||||
|  |     ... | ||||||
|  |  | ||||||
|  | F2FS-fs (zram0): access invalid blkaddr:259 | ||||||
|  | EIP: f2fs_is_valid_blkaddr+0x14b/0x1b0 [f2fs] | ||||||
|  |  f2fs_iget+0x927/0x1010 [f2fs] | ||||||
|  |  f2fs_lookup+0x26e/0x630 [f2fs] | ||||||
|  |  __lookup_slow+0xb3/0x140 | ||||||
|  |  lookup_slow+0x31/0x50 | ||||||
|  |  walk_component+0x185/0x1f0 | ||||||
|  |  path_lookupat+0x51/0x190 | ||||||
|  |  filename_lookup+0x7f/0x140 | ||||||
|  |  user_path_at_empty+0x36/0x40 | ||||||
|  |  vfs_statx+0x61/0xc0 | ||||||
|  |  __do_sys_stat64+0x29/0x40 | ||||||
|  |  sys_stat64+0x13/0x20 | ||||||
|  |  do_fast_syscall_32+0xaa/0x22c | ||||||
|  |  entry_SYSENTER_32+0x53/0x86 | ||||||
|  |  | ||||||
|  | In f2fs_iget(), we will check inode's first block address, if it is valid, | ||||||
|  | we will set FI_FIRST_BLOCK_WRITTEN flag in inode. | ||||||
|  |  | ||||||
|  | But we should only do this for regular inode, otherwise, like special | ||||||
|  | inode, i_addr[0] is used for storing device info instead of block address, | ||||||
|  | it will fail checking flow obviously. | ||||||
|  |  | ||||||
|  | So for non-regular inode, let's skip verifying address and setting flag. | ||||||
|  |  | ||||||
|  | Signed-off-by: Chao Yu <yuchao0@huawei.com> | ||||||
|  | Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> | ||||||
|  | --- | ||||||
|  |  fs/f2fs/inode.c | 14 ++++++++------ | ||||||
|  |  1 file changed, 8 insertions(+), 6 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/fs/f2fs/inode.c | ||||||
|  | +++ b/fs/f2fs/inode.c | ||||||
|  | @@ -310,13 +310,15 @@ static int do_read_inode(struct inode *i | ||||||
|  |  	/* get rdev by using inline_info */ | ||||||
|  |  	__get_inode_rdev(inode, ri); | ||||||
|  |   | ||||||
|  | -	err = __written_first_block(sbi, ri); | ||||||
|  | -	if (err < 0) { | ||||||
|  | -		f2fs_put_page(node_page, 1); | ||||||
|  | -		return err; | ||||||
|  | +	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 (!err) | ||||||
|  | -		set_inode_flag(inode, FI_FIRST_BLOCK_WRITTEN); | ||||||
|  |   | ||||||
|  |  	if (!need_inode_block_update(sbi, inode->i_ino)) | ||||||
|  |  		fi->last_disk_size = inode->i_size; | ||||||
		Reference in New Issue
	
	Block a user