Commit 5124a0a5 authored by Ryusuke Konishi's avatar Ryusuke Konishi Committed by Andrew Morton
Browse files

nilfs2: replace WARN_ONs for invalid DAT metadata block requests

If DAT metadata file block access fails due to corruption of the DAT file
or abnormal virtual block numbers held by b-trees or inodes, a kernel
warning is generated.

This replaces the WARN_ONs by error output, so that a kernel, booted with
panic_on_warn, does not panic.  This patch also replaces the detected
return code -ENOENT with another internal code -EINVAL to notify the bmap
layer of metadata corruption.  When the bmap layer sees -EINVAL, it
handles the abnormal situation with nilfs_bmap_convert_error() and finally
returns code -EIO as it should.

Link: https://lkml.kernel.org/r/0000000000005cc3d205ea23ddcf@google.com
Link: https://lkml.kernel.org/r/20230126164114.6911-1-konishi.ryusuke@gmail.com


Signed-off-by: default avatarRyusuke Konishi <konishi.ryusuke@gmail.com>
Reported-by: default avatar <syzbot+5d5d25f90f195a3cfcb4@syzkaller.appspotmail.com>
Tested-by: default avatarRyusuke Konishi <konishi.ryusuke@gmail.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 1b381f6f
Loading
Loading
Loading
Loading
+17 −10
Original line number Diff line number Diff line
@@ -40,8 +40,21 @@ static inline struct nilfs_dat_info *NILFS_DAT_I(struct inode *dat)
static int nilfs_dat_prepare_entry(struct inode *dat,
				   struct nilfs_palloc_req *req, int create)
{
	return nilfs_palloc_get_entry_block(dat, req->pr_entry_nr,
	int ret;

	ret = nilfs_palloc_get_entry_block(dat, req->pr_entry_nr,
					   create, &req->pr_entry_bh);
	if (unlikely(ret == -ENOENT)) {
		nilfs_err(dat->i_sb,
			  "DAT doesn't have a block to manage vblocknr = %llu",
			  (unsigned long long)req->pr_entry_nr);
		/*
		 * Return internal code -EINVAL to notify bmap layer of
		 * metadata corruption.
		 */
		ret = -EINVAL;
	}
	return ret;
}

static void nilfs_dat_commit_entry(struct inode *dat,
@@ -123,11 +136,7 @@ static void nilfs_dat_commit_free(struct inode *dat,

int nilfs_dat_prepare_start(struct inode *dat, struct nilfs_palloc_req *req)
{
	int ret;

	ret = nilfs_dat_prepare_entry(dat, req, 0);
	WARN_ON(ret == -ENOENT);
	return ret;
	return nilfs_dat_prepare_entry(dat, req, 0);
}

void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req,
@@ -154,10 +163,8 @@ int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req)
	int ret;

	ret = nilfs_dat_prepare_entry(dat, req, 0);
	if (ret < 0) {
		WARN_ON(ret == -ENOENT);
	if (ret < 0)
		return ret;
	}

	kaddr = kmap_atomic(req->pr_entry_bh->b_page);
	entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,