mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
nilfs2: prevent WARNING in nilfs_dat_commit_end()
If nilfs2 reads a corrupted disk image and its DAT metadata file contains invalid lifetime data for a virtual block number, a kernel warning can be generated by the WARN_ON check in nilfs_dat_commit_end() and can panic if the kernel is booted with panic_on_warn. This patch avoids the issue with a sanity check that treats it as an error. Since error return is not allowed in the execution phase of nilfs_dat_commit_end(), this inserts that sanity check in nilfs_dat_prepare_end(), which prepares for nilfs_dat_commit_end(). As the error code, -EINVAL is returned to notify bmap layer of the metadata corruption. When the bmap layer sees this code, it handles the abnormal situation and replaces the return code with -EIO as it should. Link: https://lkml.kernel.org/r/000000000000154d2c05e9ec7df6@google.com Link: https://lkml.kernel.org/r/20230127132202.6083-1-konishi.ryusuke@gmail.com Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com> Reported-by: <syzbot+cbff7a52b6f99059e67f@syzkaller.appspotmail.com> Tested-by: Ryusuke Konishi <konishi.ryusuke@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
committed by
Andrew Morton
parent
e89bd9e7d8
commit
602ce7b8e1
@@ -158,6 +158,7 @@ void nilfs_dat_commit_start(struct inode *dat, struct nilfs_palloc_req *req,
|
|||||||
int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req)
|
int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req)
|
||||||
{
|
{
|
||||||
struct nilfs_dat_entry *entry;
|
struct nilfs_dat_entry *entry;
|
||||||
|
__u64 start;
|
||||||
sector_t blocknr;
|
sector_t blocknr;
|
||||||
void *kaddr;
|
void *kaddr;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -169,6 +170,7 @@ int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req)
|
|||||||
kaddr = kmap_atomic(req->pr_entry_bh->b_page);
|
kaddr = kmap_atomic(req->pr_entry_bh->b_page);
|
||||||
entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
|
entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr,
|
||||||
req->pr_entry_bh, kaddr);
|
req->pr_entry_bh, kaddr);
|
||||||
|
start = le64_to_cpu(entry->de_start);
|
||||||
blocknr = le64_to_cpu(entry->de_blocknr);
|
blocknr = le64_to_cpu(entry->de_blocknr);
|
||||||
kunmap_atomic(kaddr);
|
kunmap_atomic(kaddr);
|
||||||
|
|
||||||
@@ -179,6 +181,15 @@ int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (unlikely(start > nilfs_mdt_cno(dat))) {
|
||||||
|
nilfs_err(dat->i_sb,
|
||||||
|
"vblocknr = %llu has abnormal lifetime: start cno (= %llu) > current cno (= %llu)",
|
||||||
|
(unsigned long long)req->pr_entry_nr,
|
||||||
|
(unsigned long long)start,
|
||||||
|
(unsigned long long)nilfs_mdt_cno(dat));
|
||||||
|
nilfs_dat_abort_entry(dat, req);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user