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>