The branch main has been updated by fsu:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=5679656e09fb58254da1613ebda75e368074c507

commit 5679656e09fb58254da1613ebda75e368074c507
Author:     Fedor Uporov <f...@freebsd.org>
AuthorDate: 2021-02-18 07:48:10 +0000
Commit:     Fedor Uporov <f...@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_ */
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to