Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 11 Jul 2010 05:01:25 GMT
From:      Zheng Liu <lz@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 180748 for review
Message-ID:  <201007110501.o6B51Pgu078079@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@180748?ac=10

Change 180748 by lz@gnehzuil-freebsd on 2010/07/11 05:01:01

	       Now ext2fs just can read ext4 extents from root directory.
	
	       * It can read ext4 extents from root directory.
	       * It can not read ext4 extents from sub-directory.
	       * It can not read big file (size > 128M).

Affected files ...

.. //depot/projects/soc2010/ext4fs/src/sys/fs/ext2fs/ext2_extents.c#3 edit
.. //depot/projects/soc2010/ext4fs/src/sys/fs/ext2fs/ext2_extents.h#4 edit
.. //depot/projects/soc2010/ext4fs/src/sys/fs/ext2fs/ext2_inode_cnv.c#5 edit
.. //depot/projects/soc2010/ext4fs/src/sys/fs/ext2fs/ext2_readwrite.c#4 edit

Differences ...

==== //depot/projects/soc2010/ext4fs/src/sys/fs/ext2fs/ext2_extents.c#3 (text+ko) ====

@@ -26,11 +26,69 @@
  * $FreeBSD: src/sys/fs/ext2fs/ext2_extents.c,v 0.1 2010/07/02 17:22:00 lz Exp $
  */
 
+#include <sys/param.h>
+#include <sys/systm.h>
 #include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/vnode.h>
+#include <sys/bio.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
 
+#include <fs/ext2fs/ext2_mount.h>
+#include <fs/ext2fs/fs.h>
 #include <fs/ext2fs/inode.h>
+#include <fs/ext2fs/ext2fs.h>
 #include <fs/ext2fs/ext2_extents.h>
+#include <fs/ext2fs/ext2_extern.h>
+
+static void ext4_ext_binsearch_index(struct inode *, struct ext4_extent_path *, daddr_t);
+static void ext4_ext_binsearch(struct inode *, struct ext4_extent_path *, daddr_t);
 
+static void
+ext4_ext_binsearch_index(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn)
+{
+        struct ext4_extent_header *ehp = path->ep_header;
+        struct ext4_extent_index *l, *r, *m;
+
+        l = (struct ext4_extent_index *)(((char *)(ehp) +
+            sizeof(struct ext4_extent_header))) + 1;
+        r = l + ehp->eh_ecount;
+        while (l <= r) {
+                m = l + (r - l) / 2;
+                if (lbn < m->ei_blk)
+                        r = m - 1;
+                else
+                        l = m + 1;
+        }
+
+        path->ep_index = l - 1;
+}
+
+static void
+ext4_ext_binsearch(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn)
+{
+        struct ext4_extent_header *ehp = path->ep_header;
+        struct ext4_extent *l, *r, *m;
+
+        if (ehp->eh_ecount == 0)
+                return;
+
+        l = (struct ext4_extent *)(((char *)(ehp) +
+            sizeof(struct ext4_extent_header)));
+        r = l + ehp->eh_ecount - 1;
+        while (l <= r) {
+                m = l + (r - l) / 2;
+                if (lbn < m->e_blk)
+                        r = m - 1;
+                else
+                        l = m + 1;
+        }
+
+        path->ep_ext = l - 1;
+}
+
 /*
  * find a block in ext4 extent cache.
  */
@@ -42,5 +100,76 @@
 
         ecp = &ip->i_ext_cache;
 
+        /* cache is invalid */
+        if (ecp->ec_type == EXT4_EXT_CACHE_NO)
+                return (ret);
+
+        if (lbn >= ecp->ec_blk && lbn < ecp->ec_blk + ecp->ec_len) {
+                ep->e_blk = ecp->ec_blk;
+                ep->e_start_lo = (ecp->ec_start & 0xffffffff);
+                ep->e_start_hi = (((ecp->ec_start >> 31) >> 1) & 0xffff);
+                ep->e_len = ecp->ec_len;
+                ret = ecp->ec_type;
+        }
+
         return (ret);
 }
+
+/*
+ * find a extent.
+ */
+struct ext4_extent_path *
+ext4_ext_find_extent(struct m_ext2fs *fs, struct inode *ip,
+    daddr_t lbn, struct ext4_extent_path *path)
+{
+        struct vnode *vp;
+        struct ext4_extent_header *ehp;
+        struct buf *bp = NULL;
+        int depth, i, error, size, pos = 0;
+
+        vp = ITOV(ip);
+        ehp = (struct ext4_extent_header *)((char *)ip->i_db);
+        depth = ehp->eh_depth;
+
+        if (path == NULL) {
+                path = malloc(sizeof(struct ext4_extent_path) * (depth * 2),
+                    M_EXT2NODE, M_WAITOK | M_ZERO);
+
+                if (path == NULL)
+                        return NULL;
+        }
+
+        path[0].ep_header = ehp;
+
+        i = depth;
+        while (i) {
+                ext4_ext_binsearch_index(ip, path + pos, lbn);
+                path[pos].ep_blk = (((daddr_t)(path[pos].ep_index->ei_leaf_hi) << 31) << 1) |
+                    path[pos].ep_index->ei_leaf_lo;
+                path[pos].ep_depth = i;
+                path[pos].ep_ext = NULL;
+
+                size = blksize(fs, ip, path[pos].ep_blk);
+                error = bread(vp, path[pos].ep_blk, size, NOCRED, &bp);
+                if (error) {
+                        brelse(bp);
+                        bp = NULL;
+                        return NULL;
+                }
+                ehp = (struct ext4_extent_header *)bp->b_data;
+                pos++;
+                path[pos].ep_header = ehp;
+                i--;
+        }
+
+        path[pos].ep_depth = i;
+        path[pos].ep_ext = NULL;
+        path[pos].ep_index = NULL;
+
+        ext4_ext_binsearch(ip, path + pos, lbn);
+        if (path[pos].ep_ext != NULL)
+                path[pos].ep_blk = (((daddr_t)(path[pos].ep_ext->e_start_hi) << 31) << 1) |
+                    path[pos].ep_ext->e_start_lo;
+
+        return path;
+}

==== //depot/projects/soc2010/ext4fs/src/sys/fs/ext2fs/ext2_extents.h#4 (text+ko) ====

@@ -81,7 +81,21 @@
         u_int32_t ec_type;
 };
 
+/*
+ * save path to some extent.
+ */
+struct ext4_extent_path {
+        daddr_t   ep_blk;
+        u_int16_t ep_depth;
+        struct ext4_extent        *ep_ext;
+        struct ext4_extent_index  *ep_index;
+        struct ext4_extent_header *ep_header;
+};
+
 struct inode;
+struct m_ext2fs;
 int ext4_ext_in_cache(struct inode *, daddr_t, struct ext4_extent *);
+struct ext4_extent_path *ext4_ext_find_extent(struct m_ext2fs *fs, struct inode *,
+                                              daddr_t, struct ext4_extent_path *);
 
 #endif /* !_FS_EXT2FS_EXT2_EXTENTS_H_ */

==== //depot/projects/soc2010/ext4fs/src/sys/fs/ext2fs/ext2_inode_cnv.c#5 (text+ko) ====

@@ -35,12 +35,15 @@
 #include <fs/ext2fs/ext2fs.h>
 #include <fs/ext2fs/ext2_extern.h>
 #include <fs/ext2fs/ext2_dinode.h>
+#include <fs/ext2fs/ext2_extents.h>
 
 void
 ext2_print_inode( in )
 	struct inode *in;
 {
 	int i;
+        struct ext4_extent_header *ehp;
+        struct ext4_extent *ep;
 
 	printf( "Inode: %5d", in->i_number);
 	printf( /* "Inode: %5d" */
@@ -57,6 +60,15 @@
 	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");
+
+        printf( "Extents:\n");
+        ehp = (struct ext4_extent_header *)in->i_db;
+        printf( "Header (magic 0x%x entries %d max %d depth %d gen %d)\n",
+                ehp->eh_magic, ehp->eh_ecount, ehp->eh_max, ehp->eh_depth, ehp->eh_gen);
+        ep = (struct ext4_extent *)((char *)(in->i_db) + sizeof(struct ext4_extent_header));
+        printf( "Index (blk %d len %d start_lo %d start_hi %d)\n",
+                ep->e_blk, ep->e_len, ep->e_start_lo, ep->e_start_hi);
 	printf("\n");
 }
 

==== //depot/projects/soc2010/ext4fs/src/sys/fs/ext2fs/ext2_readwrite.c#4 (text+ko) ====

@@ -61,17 +61,26 @@
 	struct inode *ip;
         struct uio *uio;
 	struct m_ext2fs *fs;
-        struct ext4_extent nex;
-        daddr_t lbn, nextlbn;
+        struct buf *bp;
+        struct ext2mount *ump;
+        struct ext4_extent nex, *ep;
+        struct ext4_extent_header *ehp;
+        /*struct ext4_extent_path *path = NULL;*/
+        struct ext4_extent_path path[20];
+        daddr_t lbn, nextlbn, newblk = 0;
+        off_t bytesinfile;
         u_short mode;
         int cache_type;
 	int orig_resid;
         int error = 0;
+        int depth;
+        long size, xfersize, blkoffset;
 
 	vp = ap->a_vp;
 	ip = VTOI(vp);
         mode = ip->i_mode;
         uio = ap->a_uio;
+        ump = ip->i_ump;
 
 	orig_resid = uio->uio_resid;
 	KASSERT(orig_resid >= 0, ("ext2_read: uio->uio_resid < 0"));
@@ -82,10 +91,82 @@
 	if (uio->uio_offset < ip->i_size && uio->uio_offset >= fs->e2fs_maxfilesize)
 		return (EOVERFLOW);
 
-        lbn = lblkno(fs, uio->uio_offset);
-        nextlbn = lbn + 1;
+        for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
+                if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
+                        break;
+                lbn = lblkno(fs, uio->uio_offset);
+                nextlbn = lbn + 1;
+                size = BLKSIZE(fs, ip, lbn);
+                blkoffset = blkoff(fs, uio->uio_offset);
+
+                xfersize = fs->e2fs_fsize - blkoffset;
+                if (uio->uio_resid < xfersize)
+                        xfersize = uio->uio_resid;
+                if (bytesinfile < xfersize)
+                        xfersize = bytesinfile;
+
+                /* get block from ext4 extent cache */
+                cache_type = ext4_ext_in_cache(ip, lbn, &nex);
+                if (cache_type != 0) {
+                        /* block does not be allocated yet */
+                        if (cache_type == EXT4_EXT_CACHE_GAP)
+                                return (error);
+                        else if (cache_type == EXT4_EXT_CACHE_IN)
+                                newblk = lbn - nex.e_blk +
+                                    (nex.e_start_lo | ((daddr_t)(nex.e_start_hi) << 31) << 1);
+                } else {
+                        /*path = ext4_ext_find_extent(fs, ip, lbn, NULL);*/
+                        ext4_ext_find_extent(fs, ip, lbn, path);
+#if 0
+                        if (path == NULL) {
+                                path = NULL;
+                                return (error);
+                        }
+#endif
+
+                        depth = ((struct ext4_extent_header *)(ip->i_db))->eh_depth;
+
+                        if (path[depth].ep_ext == NULL && depth != 0)
+                                return (EIO);
+
+                        ehp = path[depth].ep_header;
+                        ep = path[depth].ep_ext;
+
+                        if (ep == NULL)
+                                return (EIO);
+
+                        newblk = lbn - ep->e_blk +
+                            (ep->e_start_lo | ((daddr_t)(ep->e_start_hi) << 31) << 1);
+                }
+
+                error = bread(ump->um_devvp, fsbtodb(fs, newblk), size, NOCRED, &bp);
+                if (error) {
+                        brelse(bp);
+                        bp = NULL;
+                        break;
+                }
+
+                size -= bp->b_resid;
+                if (size < xfersize) {
+                        if (size == 0)
+                                break;
+                        xfersize = size;
+                }
+                error = uiomove((char *)bp->b_data + blkoffset,
+                    (int)xfersize, uio);
+                if (error)
+                        break;
+
+                bqrelse(bp);
+        }
+
+        if (bp != NULL)
+                bqrelse(bp);
 
-        cache_type = ext4_ext_in_cache(ip, lbn, &nex);
+#if 0
+        if (path != NULL)
+                free(path, M_EXT2NODE);
+#endif
 
         return (error);
 }
@@ -209,12 +290,12 @@
 	vp = ap->a_vp;
 	ip = VTOI(vp);
 
-        EXT4_EXT_LOCK(ip);
+        /*EXT4_EXT_LOCK(ip);*/
         if (ip->i_flags & EXT4_EXTENTS)
                 error = ext4_ext_read(ap);
         else
                 error = ext2_ind_read(ap);
-        EXT4_EXT_UNLOCK(ip);
+        /*EXT4_EXT_UNLOCK(ip);*/
 
         return (error);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201007110501.o6B51Pgu078079>