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-all mailing list