git: 5679656e09fb - main - Improve extents verification logic.
Fedor Uporov
fsu at FreeBSD.org
Fri May 7 07:28:30 UTC 2021
The branch main has been updated by fsu:
URL: https://cgit.FreeBSD.org/src/commit/?id=5679656e09fb58254da1613ebda75e368074c507
commit 5679656e09fb58254da1613ebda75e368074c507
Author: Fedor Uporov <fsu at FreeBSD.org>
AuthorDate: 2021-02-18 07:48:10 +0000
Commit: Fedor Uporov <fsu at FreeBSD.org>
CommitDate: 2021-05-07 07:27:28 +0000
Improve extents verification logic.
It is possible to walk thru inode extents if EXT2FS_PRINT_EXTENTS
macro is defined. The extents headers magics and physical blocks
ranges are checked during extents walk.
Reviewed by: pfg
MFC after: 2 weeks
Differential Revision: https://reviews.freebsd.org/D29932
---
sys/fs/ext2fs/ext2_extents.c | 130 ++++++++++++++++++++++++++++-------------
sys/fs/ext2fs/ext2_extents.h | 10 ++--
sys/fs/ext2fs/ext2_inode_cnv.c | 2 +-
sys/fs/ext2fs/ext2_vfsops.c | 11 +++-
sys/fs/ext2fs/fs.h | 2 +-
5 files changed, 104 insertions(+), 51 deletions(-)
diff --git a/sys/fs/ext2fs/ext2_extents.c b/sys/fs/ext2fs/ext2_extents.c
index 1a5dca66dd76..cc77107785a5 100644
--- a/sys/fs/ext2fs/ext2_extents.c
+++ b/sys/fs/ext2fs/ext2_extents.c
@@ -59,94 +59,140 @@ SDT_PROBE_DEFINE2(ext2fs, , trace, extents, "int", "char*");
static MALLOC_DEFINE(M_EXT2EXTENTS, "ext2_extents", "EXT2 extents");
#ifdef EXT2FS_PRINT_EXTENTS
-static void
-ext4_ext_print_extent(struct ext4_extent *ep)
+static const bool print_extents_walk = true;
+
+static int ext4_ext_check_header(struct inode *, struct ext4_extent_header *);
+static int ext4_ext_walk_header(struct inode *, struct ext4_extent_header *);
+static inline e4fs_daddr_t ext4_ext_index_pblock(struct ext4_extent_index *);
+static inline e4fs_daddr_t ext4_ext_extent_pblock(struct ext4_extent *);
+
+static int
+ext4_ext_blk_check(struct inode *ip, e4fs_daddr_t blk)
{
+ struct m_ext2fs *fs;
- printf(" ext %p => (blk %u len %u start %ju)\n",
- ep, le32toh(ep->e_blk), le16toh(ep->e_len),
- (uint64_t)le16toh(ep->e_start_hi) << 32 | le32toh(ep->e_start_lo));
-}
+ fs = ip->i_e2fs;
-static void ext4_ext_print_header(struct inode *ip, struct ext4_extent_header *ehp);
+ if (blk < fs->e2fs->e2fs_first_dblock || blk >= fs->e2fs_bcount)
+ return (EIO);
-static void
-ext4_ext_print_index(struct inode *ip, struct ext4_extent_index *ex, int do_walk)
+ return (0);
+}
+
+static int
+ext4_ext_walk_index(struct inode *ip, struct ext4_extent_index *ex, bool do_walk)
{
struct m_ext2fs *fs;
struct buf *bp;
+ e4fs_daddr_t blk;
int error;
fs = ip->i_e2fs;
- printf(" index %p => (blk %u pblk %ju)\n",
- ex, le32toh(ex->ei_blk), (uint64_t)le16toh(ex->ei_leaf_hi) << 32 |
- le32toh(ex->ei_leaf_lo));
+ if (print_extents_walk)
+ printf(" index %p => (blk %u pblk %ju)\n", ex,
+ le32toh(ex->ei_blk), (uint64_t)le16toh(ex->ei_leaf_hi) << 32 |
+ le32toh(ex->ei_leaf_lo));
if(!do_walk)
- return;
+ return (0);
+
+ blk = ext4_ext_index_pblock(ex);
+ error = ext4_ext_blk_check(ip, blk);
+ if (error)
+ return (error);
if ((error = bread(ip->i_devvp,
- fsbtodb(fs, ((uint64_t)le16toh(ex->ei_leaf_hi) << 32 |
- le32toh(ex->ei_leaf_lo))), (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
+ fsbtodb(fs, blk), (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) {
brelse(bp);
- return;
+ return (error);
}
- ext4_ext_print_header(ip, (struct ext4_extent_header *)bp->b_data);
+ error = ext4_ext_walk_header(ip, (struct ext4_extent_header *)bp->b_data);
brelse(bp);
+ return (error);
}
-static void
-ext4_ext_print_header(struct inode *ip, struct ext4_extent_header *ehp)
+static int
+ext4_ext_walk_extent(struct inode *ip, struct ext4_extent *ep)
+{
+ e4fs_daddr_t blk;
+ int error;
+
+ blk = ext4_ext_extent_pblock(ep);
+ error = ext4_ext_blk_check(ip, blk);
+ if (error)
+ return (error);
+
+ if (print_extents_walk)
+ printf(" ext %p => (blk %u len %u start %ju)\n",
+ ep, le32toh(ep->e_blk), le16toh(ep->e_len),
+ (uint64_t)blk);
+
+ return (0);
+}
+
+static int
+ext4_ext_walk_header(struct inode *ip, struct ext4_extent_header *eh)
{
- int i;
+ int i, error = 0;
- printf("header %p => (magic 0x%x entries %d max %d depth %d gen %d)\n",
- ehp, le16toh(ehp->eh_magic), le16toh(ehp->eh_ecount),
- le16toh(ehp->eh_max), le16toh(ehp->eh_depth), le32toh(ehp->eh_gen));
+ error = ext4_ext_check_header(ip, eh);
+ if (error)
+ return (error);
+
+ if (print_extents_walk)
+ printf("header %p => (entries %d max %d depth %d gen %d)\n",
+ eh, le16toh(eh->eh_ecount),
+ le16toh(eh->eh_max), le16toh(eh->eh_depth), le32toh(eh->eh_gen));
- for (i = 0; i < le16toh(ehp->eh_ecount); i++)
- if (ehp->eh_depth != 0)
- ext4_ext_print_index(ip,
- (struct ext4_extent_index *)(ehp + 1 + i), 1);
+ for (i = 0; i < le16toh(eh->eh_ecount) && error == 0; i++)
+ if (eh->eh_depth != 0)
+ error = ext4_ext_walk_index(ip,
+ (struct ext4_extent_index *)(eh + 1 + i), true);
else
- ext4_ext_print_extent((struct ext4_extent *)(ehp + 1 + i));
+ error = ext4_ext_walk_extent(ip, (struct ext4_extent *)(eh + 1 + i));
+
+ return (error);
}
-static void
+static int
ext4_ext_print_path(struct inode *ip, struct ext4_extent_path *path)
{
- int k, l;
+ int k, l, error = 0;
l = path->ep_depth;
- printf("ip=%ju, Path:\n", ip->i_number);
- for (k = 0; k <= l; k++, path++) {
+ if (print_extents_walk)
+ printf("ip=%ju, Path:\n", ip->i_number);
+
+ for (k = 0; k <= l && error == 0; k++, path++) {
if (path->ep_index) {
- ext4_ext_print_index(ip, path->ep_index, 0);
+ error = ext4_ext_walk_index(ip, path->ep_index, false);
} else if (path->ep_ext) {
- ext4_ext_print_extent(path->ep_ext);
+ error = ext4_ext_walk_extent(ip, path->ep_ext);
}
}
+
+ return (error);
}
-void
-ext4_ext_print_extent_tree_status(struct inode *ip)
+int
+ext4_ext_walk(struct inode *ip)
{
struct ext4_extent_header *ehp;
- ehp = (struct ext4_extent_header *)(char *)ip->i_db;
+ ehp = (struct ext4_extent_header *)ip->i_db;
- printf("Extent status:ip=%ju\n", ip->i_number);
- if (!(ip->i_flag & IN_E4EXTENTS))
- return;
+ if (print_extents_walk)
+ printf("Extent status:ip=%ju\n", ip->i_number);
- ext4_ext_print_header(ip, ehp);
+ if (!(ip->i_flag & IN_E4EXTENTS))
+ return (0);
- return;
+ return (ext4_ext_walk_header(ip, ehp));
}
#endif
diff --git a/sys/fs/ext2fs/ext2_extents.h b/sys/fs/ext2fs/ext2_extents.h
index 52a96297b606..f662cc9b5cd3 100644
--- a/sys/fs/ext2fs/ext2_extents.h
+++ b/sys/fs/ext2fs/ext2_extents.h
@@ -122,15 +122,15 @@ struct m_ext2fs;
void ext4_ext_tree_init(struct inode *ip);
int ext4_ext_in_cache(struct inode *, daddr_t, struct ext4_extent *);
void ext4_ext_put_cache(struct inode *, struct ext4_extent *, int);
-int ext4_ext_find_extent(struct inode *, daddr_t, struct ext4_extent_path **);
-void ext4_ext_path_free(struct ext4_extent_path *path);
-int ext4_ext_remove_space(struct inode *ip, off_t length, int flags,
+int ext4_ext_find_extent(struct inode *, daddr_t, struct ext4_extent_path **);
+void ext4_ext_path_free(struct ext4_extent_path *path);
+int ext4_ext_remove_space(struct inode *ip, off_t length, int flags,
struct ucred *cred, struct thread *td);
-int ext4_ext_get_blocks(struct inode *ip, int64_t iblock,
+int ext4_ext_get_blocks(struct inode *ip, int64_t iblock,
unsigned long max_blocks, struct ucred *cred, struct buf **bpp,
int *allocate, daddr_t *);
#ifdef EXT2FS_PRINT_EXTENTS
-void ext4_ext_print_extent_tree_status(struct inode *ip);
+int ext4_ext_walk(struct inode *ip);
#endif
#endif /* !_FS_EXT2FS_EXT2_EXTENTS_H_ */
diff --git a/sys/fs/ext2fs/ext2_inode_cnv.c b/sys/fs/ext2fs/ext2_inode_cnv.c
index a71d5cef21aa..3c79e1162896 100644
--- a/sys/fs/ext2fs/ext2_inode_cnv.c
+++ b/sys/fs/ext2fs/ext2_inode_cnv.c
@@ -86,7 +86,7 @@ ext2_print_inode(struct inode *in)
le16toh(ep->e_start_hi));
printf("\n");
} else {
- printf("BLOCKS:");
+ printf("Blocks:");
for (i = 0; i < (in->i_blocks <= 24 ? (in->i_blocks + 1) / 2 : 12); i++)
printf(" %d", in->i_db[i]);
printf("\n");
diff --git a/sys/fs/ext2fs/ext2_vfsops.c b/sys/fs/ext2fs/ext2_vfsops.c
index 099d6bfec981..43cfdf3a1a0b 100644
--- a/sys/fs/ext2fs/ext2_vfsops.c
+++ b/sys/fs/ext2fs/ext2_vfsops.c
@@ -1283,11 +1283,18 @@ ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp)
for (i = used_blocks; i < EXT2_NDIR_BLOCKS; i++)
ip->i_db[i] = 0;
}
+
+ bqrelse(bp);
+
#ifdef EXT2FS_PRINT_EXTENTS
ext2_print_inode(ip);
- ext4_ext_print_extent_tree_status(ip);
+ error = ext4_ext_walk(ip);
+ if (error) {
+ vput(vp);
+ *vpp = NULL;
+ return (error);
+ }
#endif
- bqrelse(bp);
/*
* Initialize the vnode from the inode, check for aliases.
diff --git a/sys/fs/ext2fs/fs.h b/sys/fs/ext2fs/fs.h
index e07b69b91bce..c09200af3935 100644
--- a/sys/fs/ext2fs/fs.h
+++ b/sys/fs/ext2fs/fs.h
@@ -164,6 +164,6 @@
/*
* Use if additional debug logging is required.
*/
-/* #define EXT2FS_PRINT_EXTENTS */
+/* #define EXT2FS_PRINT_EXTENTS */
#endif /* !_FS_EXT2FS_FS_H_ */
More information about the dev-commits-src-main
mailing list