diff options
| author | Ryusuke Konishi <[email protected]> | 2023-01-27 13:22:02 +0000 |
|---|---|---|
| committer | Andrew Morton <[email protected]> | 2023-02-03 06:50:10 +0000 |
| commit | 602ce7b8e1343b19c0cf93a3dd1926838ac5a1cc (patch) | |
| tree | e9daaa4d0ac597159dd733d2f39cad33a3e99885 | |
| parent | lib/zlib: remove redundation assignement of avail_in dfltcc_gdht() (diff) | |
| download | kernel-602ce7b8e1343b19c0cf93a3dd1926838ac5a1cc.tar.gz kernel-602ce7b8e1343b19c0cf93a3dd1926838ac5a1cc.zip | |
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/[email protected]
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Ryusuke Konishi <[email protected]>
Reported-by: <[email protected]>
Tested-by: Ryusuke Konishi <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
| -rw-r--r-- | fs/nilfs2/dat.c | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index 1e7f653c1df7..9cf6ba58f585 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c @@ -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) { struct nilfs_dat_entry *entry; + __u64 start; sector_t blocknr; void *kaddr; 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); entry = nilfs_palloc_block_get_entry(dat, req->pr_entry_nr, req->pr_entry_bh, kaddr); + start = le64_to_cpu(entry->de_start); blocknr = le64_to_cpu(entry->de_blocknr); kunmap_atomic(kaddr); @@ -179,6 +181,15 @@ int nilfs_dat_prepare_end(struct inode *dat, struct nilfs_palloc_req *req) 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; } |
