PERFORCE change 180748 for review
Zheng Liu
lz at FreeBSD.org
Sun Jul 11 05:01:26 UTC 2010
http://p4web.freebsd.org/@@180748?ac=10
Change 180748 by lz at 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);
}
More information about the p4-projects
mailing list