diff options
author | Martin Pelikan <pelikan@cvs.openbsd.org> | 2014-07-13 13:28:27 +0000 |
---|---|---|
committer | Martin Pelikan <pelikan@cvs.openbsd.org> | 2014-07-13 13:28:27 +0000 |
commit | fc08a83358c78094f736f5bd28d9cbce62c20a02 (patch) | |
tree | 341c6b3118ee236feeb11e86ff2d362d7a083500 | |
parent | eb09aa80ddba288298f52d827341a6f415281e2e (diff) |
ext4 (extents) read support
Tested on amd64 with > 4GB files and 50,000 subdirectories.
From FreeBSD, thanks!
ok deraadt guenther
-rw-r--r-- | sys/conf/files | 3 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs.h | 10 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_bmap.c | 46 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_bswap.c | 4 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_extents.c | 176 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_extents.h | 99 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_readwrite.c | 83 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_subr.c | 34 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_vfsops.c | 16 | ||||
-rw-r--r-- | sys/ufs/ufs/inode.h | 13 |
10 files changed, 463 insertions, 21 deletions
diff --git a/sys/conf/files b/sys/conf/files index ae98d65ba19..2ba37e05d54 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.573 2014/07/11 21:54:38 tedu Exp $ +# $OpenBSD: files,v 1.574 2014/07/13 13:28:26 pelikan Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -926,6 +926,7 @@ file ufs/ext2fs/ext2fs_alloc.c ext2fs file ufs/ext2fs/ext2fs_balloc.c ext2fs file ufs/ext2fs/ext2fs_bmap.c ext2fs file ufs/ext2fs/ext2fs_bswap.c ext2fs +file ufs/ext2fs/ext2fs_extents.c ext2fs file ufs/ext2fs/ext2fs_inode.c ext2fs file ufs/ext2fs/ext2fs_lookup.c ext2fs file ufs/ext2fs/ext2fs_readwrite.c ext2fs diff --git a/sys/ufs/ext2fs/ext2fs.h b/sys/ufs/ext2fs/ext2fs.h index 3896d9185a3..cfe3dd93eac 100644 --- a/sys/ufs/ext2fs/ext2fs.h +++ b/sys/ufs/ext2fs/ext2fs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs.h,v 1.18 2014/07/11 14:30:52 pelikan Exp $ */ +/* $OpenBSD: ext2fs.h,v 1.19 2014/07/13 13:28:26 pelikan Exp $ */ /* $NetBSD: ext2fs.h,v 1.10 2000/01/28 16:00:23 bouyer Exp $ */ /* @@ -69,9 +69,12 @@ * thus changes to (struct cg) must keep its size within MINBSIZE. * Note that super blocks are always of size SBSIZE, * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE. + * FSIZE means fragment size. */ -#define LOG_MINBSIZE 10 +#define LOG_MINBSIZE 10 #define MINBSIZE (1 << LOG_MINBSIZE) +#define LOG_MINFSIZE 10 +#define MINFSIZE (1 << LOG_MINFSIZE) /* * The path name on which the file system is mounted is maintained @@ -105,7 +108,7 @@ struct ext2fs { u_int32_t e2fs_ficount; /* free inodes count */ u_int32_t e2fs_first_dblock; /* first data block */ u_int32_t e2fs_log_bsize; /* block size = 1024*(2^e2fs_log_bsize) */ - u_int32_t e2fs_fsize; /* fragment size */ + u_int32_t e2fs_log_fsize; /* fragment size log2 */ u_int32_t e2fs_bpg; /* blocks per group */ u_int32_t e2fs_fpg; /* frags per group */ u_int32_t e2fs_ipg; /* inodes per group */ @@ -147,6 +150,7 @@ struct m_ext2fs { u_char e2fs_fsmnt[MAXMNTLEN]; /* name mounted on */ int8_t e2fs_ronly; /* mounted read-only flag */ int8_t e2fs_fmod; /* super block modified flag */ + int32_t e2fs_fsize; /* fragment size */ int32_t e2fs_bsize; /* block size */ int32_t e2fs_bshift; /* ``lblkno'' calc of logical blkno */ int32_t e2fs_bmask; /* ``blkoff'' calc of blk offsets */ diff --git a/sys/ufs/ext2fs/ext2fs_bmap.c b/sys/ufs/ext2fs/ext2fs_bmap.c index adfc79effff..66f73e3e98d 100644 --- a/sys/ufs/ext2fs/ext2fs_bmap.c +++ b/sys/ufs/ext2fs/ext2fs_bmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_bmap.c,v 1.22 2014/05/27 14:31:24 krw Exp $ */ +/* $OpenBSD: ext2fs_bmap.c,v 1.23 2014/07/13 13:28:26 pelikan Exp $ */ /* $NetBSD: ext2fs_bmap.c,v 1.5 2000/03/30 12:41:11 augustss Exp $ */ /* @@ -53,10 +53,13 @@ #include <ufs/ufs/ufsmount.h> #include <ufs/ufs/ufs_extern.h> #include <ufs/ext2fs/ext2fs.h> +#include <ufs/ext2fs/ext2fs_extents.h> #include <ufs/ext2fs/ext2fs_extern.h> -static int ext2fs_bmaparray(struct vnode *, int32_t, daddr_t *, - struct indir *, int *, int *); +static int ext4_bmapext(struct vnode *, daddr_t, daddr_t *, struct indir *, + int *, int *); +static int ext2fs_bmaparray(struct vnode *, daddr_t, daddr_t *, struct indir *, + int *, int *); /* * Bmap converts a the logical block number of a file to its physical block @@ -67,6 +70,7 @@ int ext2fs_bmap(void *v) { struct vop_bmap_args *ap = v; + /* * Check for underlying vnode requests and ensure that logical * to physical mapping is requested. @@ -76,11 +80,45 @@ ext2fs_bmap(void *v) if (ap->a_bnp == NULL) return (0); + if (VTOI(ap->a_vp)->i_e2din->e2di_flags & EXT4_EXTENTS) { + return (ext4_bmapext(ap->a_vp, ap->a_bn, ap->a_bnp, NULL, NULL, + ap->a_runp)); + } return (ext2fs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, NULL, NULL, ap->a_runp)); } /* + * Logical block number of a file -> physical block number on disk within ext4 extents. + */ +int +ext4_bmapext(struct vnode *vp, daddr_t bn, daddr_t *bnp, struct indir *ap, int *nump, int *runp) +{ + struct inode *ip; + struct m_ext2fs *fs; + struct ext4_extent *ep; + struct ext4_extent_path path; + daddr_t pos; + + ip = VTOI(vp); + fs = ip->i_e2fs; + + if (runp != NULL) + *runp = 0; + if (nump != NULL) + *nump = 0; + + ext4_ext_find_extent(fs, ip, bn, &path); + if ((ep = path.ep_ext) == NULL) + return (EIO); + + pos = bn - ep->e_blk + (((daddr_t)ep->e_start_hi << 32) | ep->e_start_lo); + if ((*bnp = fsbtodb(fs, pos)) == 0) + *bnp = -1; + return (0); +} + +/* * Indirect blocks are now on the vnode for the file. They are given negative * logical block numbers. Indirect blocks are addressed by the negative * address of the first data block to which they point. Double indirect blocks @@ -95,7 +133,7 @@ ext2fs_bmap(void *v) */ int -ext2fs_bmaparray(struct vnode *vp, int32_t bn, daddr_t *bnp, +ext2fs_bmaparray(struct vnode *vp, daddr_t bn, daddr_t *bnp, struct indir *ap, int *nump, int *runp) { struct inode *ip; diff --git a/sys/ufs/ext2fs/ext2fs_bswap.c b/sys/ufs/ext2fs/ext2fs_bswap.c index d837a2ce52e..232d746e5e1 100644 --- a/sys/ufs/ext2fs/ext2fs_bswap.c +++ b/sys/ufs/ext2fs/ext2fs_bswap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_bswap.c,v 1.5 2014/07/11 16:04:25 pelikan Exp $ */ +/* $OpenBSD: ext2fs_bswap.c,v 1.6 2014/07/13 13:28:26 pelikan Exp $ */ /* $NetBSD: ext2fs_bswap.c,v 1.6 2000/07/24 00:23:10 mycroft Exp $ */ /* @@ -58,7 +58,7 @@ e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new) new->e2fs_ficount = swap32(old->e2fs_ficount); new->e2fs_first_dblock = swap32(old->e2fs_first_dblock); new->e2fs_log_bsize = swap32(old->e2fs_log_bsize); - new->e2fs_fsize = swap32(old->e2fs_fsize); + new->e2fs_log_fsize = swap32(old->e2fs_log_fsize); new->e2fs_bpg = swap32(old->e2fs_bpg); new->e2fs_fpg = swap32(old->e2fs_fpg); new->e2fs_ipg = swap32(old->e2fs_ipg); diff --git a/sys/ufs/ext2fs/ext2fs_extents.c b/sys/ufs/ext2fs/ext2fs_extents.c new file mode 100644 index 00000000000..840a0259259 --- /dev/null +++ b/sys/ufs/ext2fs/ext2fs_extents.c @@ -0,0 +1,176 @@ +/*- + * Copyright (c) 2010 Zheng Liu <lz@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/sys/fs/ext2fs/ext2_extents.c 254260 2013-08-12 21:34:48Z pfg $ + */ + +#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/mount.h> +#include <sys/buf.h> +#include <sys/conf.h> + +#include <ufs/ufs/quota.h> +#include <ufs/ufs/ufsmount.h> +#include <ufs/ufs/inode.h> +#include <ufs/ext2fs/ext2fs.h> +#include <ufs/ext2fs/ext2fs_extents.h> +#include <ufs/ext2fs/ext2fs_extern.h> + +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 + 1); + r = (struct ext4_extent_index *)(char *)(ehp + 1) + ehp->eh_ecount - 1; + 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 + 1); + r = (struct ext4_extent *)(char *)(ehp + 1) + 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. + */ +int +ext4_ext_in_cache(struct inode *ip, daddr_t lbn, struct ext4_extent *ep) +{ + struct ext4_extent_cache *ecp; + int ret = EXT4_EXT_CACHE_NO; + + ecp = &ip->i_e2fs_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 >> 32 & 0xffff; + ep->e_len = ecp->ec_len; + ret = ecp->ec_type; + } + return (ret); +} + +/* + * Put an ext4_extent structure in ext4 cache. + */ +void +ext4_ext_put_cache(struct inode *ip, struct ext4_extent *ep, int type) +{ + struct ext4_extent_cache *ecp; + + ecp = &ip->i_e2fs_ext_cache; + ecp->ec_type = type; + ecp->ec_blk = ep->e_blk; + ecp->ec_len = ep->e_len; + ecp->ec_start = (daddr_t)ep->e_start_hi << 32 | ep->e_start_lo; +} + +/* + * Find an 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; + uint16_t i; + int error; + daddr_t nblk; + + vp = ITOV(ip); + ehp = (struct ext4_extent_header *)(char *)ip->i_e2fs_blocks; + + if (ehp->eh_magic != EXT4_EXT_MAGIC) + return (NULL); + + path->ep_header = ehp; + + for (i = ehp->eh_depth; i != 0; --i) { + ext4_ext_binsearch_index(ip, path, lbn); + path->ep_depth = 0; + path->ep_ext = NULL; + + nblk = (daddr_t)path->ep_index->ei_leaf_hi << 32 | + path->ep_index->ei_leaf_lo; + if (path->ep_bp != NULL) { + brelse(path->ep_bp); + path->ep_bp = NULL; + } + error = bread(ip->i_devvp, fsbtodb(fs, nblk), fs->e2fs_fsize, + &path->ep_bp); + if (error) { + brelse(path->ep_bp); + path->ep_bp = NULL; + return (NULL); + } + ehp = (struct ext4_extent_header *)path->ep_bp->b_data; + path->ep_header = ehp; + } + + path->ep_depth = i; + path->ep_ext = NULL; + path->ep_index = NULL; + + ext4_ext_binsearch(ip, path, lbn); + return (path); +} diff --git a/sys/ufs/ext2fs/ext2fs_extents.h b/sys/ufs/ext2fs/ext2fs_extents.h new file mode 100644 index 00000000000..8a5076f6bf5 --- /dev/null +++ b/sys/ufs/ext2fs/ext2fs_extents.h @@ -0,0 +1,99 @@ +/*- + * Copyright (c) 2012, 2010 Zheng Liu <lz@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/sys/fs/ext2fs/ext2_extents.h 262623 2014-02-28 21:25:32Z pfg $ + */ +#ifndef _FS_EXT2FS_EXT2_EXTENTS_H_ +#define _FS_EXT2FS_EXT2_EXTENTS_H_ + +#include <sys/types.h> + +#define EXT4_EXT_MAGIC 0xf30a + +#define EXT4_EXT_CACHE_NO 0 +#define EXT4_EXT_CACHE_GAP 1 +#define EXT4_EXT_CACHE_IN 2 + +/* + * Ext4 file system extent on disk. + */ +struct ext4_extent { + uint32_t e_blk; /* first logical block */ + uint16_t e_len; /* number of blocks */ + uint16_t e_start_hi; /* high 16 bits of physical block */ + uint32_t e_start_lo; /* low 32 bits of physical block */ +}; + +/* + * Extent index on disk. + */ +struct ext4_extent_index { + uint32_t ei_blk; /* indexes logical blocks */ + uint32_t ei_leaf_lo; /* points to physical block of the + * next level */ + uint16_t ei_leaf_hi; /* high 16 bits of physical block */ + uint16_t ei_unused; +}; + +/* + * Extent tree header. + */ +struct ext4_extent_header { + uint16_t eh_magic; /* magic number: 0xf30a */ + uint16_t eh_ecount; /* number of valid entries */ + uint16_t eh_max; /* capacity of store in entries */ + uint16_t eh_depth; /* the depth of extent tree */ + uint32_t eh_gen; /* generation of extent tree */ +}; + +/* + * Save cached extent. + */ +struct ext4_extent_cache { + daddr_t ec_start; /* extent start */ + uint32_t ec_blk; /* logical block */ + uint32_t ec_len; + uint32_t ec_type; +}; + +/* + * Save path to some extent. + */ +struct ext4_extent_path { + uint16_t ep_depth; + struct buf *ep_bp; + 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 *); +void ext4_ext_put_cache(struct inode *, struct ext4_extent *, int); +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_ */ diff --git a/sys/ufs/ext2fs/ext2fs_readwrite.c b/sys/ufs/ext2fs/ext2fs_readwrite.c index e01a785ab8b..d5a29d3faed 100644 --- a/sys/ufs/ext2fs/ext2fs_readwrite.c +++ b/sys/ufs/ext2fs/ext2fs_readwrite.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_readwrite.c,v 1.31 2014/07/11 15:11:00 pelikan Exp $ */ +/* $OpenBSD: ext2fs_readwrite.c,v 1.32 2014/07/13 13:28:26 pelikan Exp $ */ /* $NetBSD: ext2fs_readwrite.c,v 1.16 2001/02/27 04:37:47 chs Exp $ */ /*- @@ -49,12 +49,14 @@ #include <sys/signalvar.h> #include <ufs/ufs/quota.h> +#include <ufs/ufs/ufsmount.h> #include <ufs/ufs/inode.h> #include <ufs/ext2fs/ext2fs.h> #include <ufs/ext2fs/ext2fs_extern.h> static int ext2_ind_read(struct vnode *, struct inode *, struct m_ext2fs *, struct uio *); +static int ext4_ext_read(struct vnode *, struct inode *, struct m_ext2fs *, struct uio *); #define doclusterread 0 /* XXX underway */ #define doclusterwrite 0 @@ -77,7 +79,10 @@ ext2fs_read(void *v) uio = ap->a_uio; fs = ip->i_e2fs; - return ext2_ind_read(vp, ip, fs, uio); + if (ip->i_e2fs_flags & EXT4_EXTENTS) + return ext4_ext_read(vp, ip, fs, uio); + else + return ext2_ind_read(vp, ip, fs, uio); } static int @@ -159,6 +164,80 @@ ext2_ind_read(struct vnode *vp, struct inode *ip, struct m_ext2fs *fs, return (error); } +int +ext4_ext_read(struct vnode *vp, struct inode *ip, struct m_ext2fs *fs, struct uio *uio) +{ + struct ext4_extent_path path; + struct ext4_extent nex, *ep; + struct buf *bp; + size_t orig_resid; + daddr_t lbn, pos; + off_t bytesinfile; + long size, xfersize, blkoffset; + int error, cache_type; + + memset(&path, 0, sizeof path); + + orig_resid = uio->uio_resid; + if (orig_resid == 0) + return (0); + + if (e2fs_overflow(fs, 0, uio->uio_offset)) + return (EFBIG); + + while (uio->uio_resid > 0) { + if ((bytesinfile = ext2fs_size(ip) - uio->uio_offset) <= 0) + break; + lbn = lblkno(fs, uio->uio_offset); + size = fs->e2fs_bsize; + blkoffset = blkoff(fs, uio->uio_offset); + + xfersize = fs->e2fs_fsize - blkoffset; + xfersize = MIN(xfersize, uio->uio_resid); + xfersize = MIN(xfersize, bytesinfile); + + cache_type = ext4_ext_in_cache(ip, lbn, &nex); + switch (cache_type) { + case EXT4_EXT_CACHE_NO: + ext4_ext_find_extent(fs, ip, lbn, &path); + if ((ep = path.ep_ext) == NULL) + return (EIO); + ext4_ext_put_cache(ip, ep, EXT4_EXT_CACHE_IN); + + pos = lbn - ep->e_blk + (((daddr_t) ep->e_start_hi << 32) | ep->e_start_lo); + if (path.ep_bp != NULL) { + brelse(path.ep_bp); + path.ep_bp = NULL; + } + break; + case EXT4_EXT_CACHE_GAP: + /* block has not been allocated yet */ + return (0); + case EXT4_EXT_CACHE_IN: + pos = lbn - nex.e_blk + (((daddr_t) nex.e_start_hi << 32) | nex.e_start_lo); + break; + } + error = bread(ip->i_devvp, fsbtodb(fs, pos), size, &bp); + if (error) { + brelse(bp); + return (error); + } + size -= bp->b_resid; + if (size < xfersize) { + if (size == 0) { + brelse(bp); + break; + } + xfersize = size; + } + error = uiomove(bp->b_data + blkoffset, xfersize, uio); + brelse(bp); + if (error) + return (error); + } + return (0); +} + /* * Vnode op for writing. */ diff --git a/sys/ufs/ext2fs/ext2fs_subr.c b/sys/ufs/ext2fs/ext2fs_subr.c index c0f3ba18fbf..cd4f22e9908 100644 --- a/sys/ufs/ext2fs/ext2fs_subr.c +++ b/sys/ufs/ext2fs/ext2fs_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_subr.c,v 1.30 2013/11/02 00:08:17 krw Exp $ */ +/* $OpenBSD: ext2fs_subr.c,v 1.31 2014/07/13 13:28:26 pelikan Exp $ */ /* $NetBSD: ext2fs_subr.c,v 1.1 1997/06/11 09:34:03 bouyer Exp $ */ /* @@ -47,6 +47,7 @@ #include <ufs/ext2fs/ext2fs.h> #include <ufs/ext2fs/ext2fs_extern.h> +#include <ufs/ext2fs/ext2fs_extents.h> #include <miscfs/fifofs/fifo.h> @@ -82,13 +83,42 @@ ext2fs_bufatoff(struct inode *ip, off_t offset, char **res, struct buf **bpp) struct vnode *vp; struct m_ext2fs *fs; struct buf *bp; - int32_t lbn; + daddr_t lbn, pos; int error; vp = ITOV(ip); fs = ip->i_e2fs; lbn = lblkno(fs, offset); + if (ip->i_e2din->e2di_flags & EXT4_EXTENTS) { + struct ext4_extent_path path; + struct ext4_extent *ep; + + memset(&path, 0, sizeof path); + if (ext4_ext_find_extent(fs, ip, lbn, &path) == NULL || + (ep = path.ep_ext) == NULL) + goto normal; + + if (path.ep_bp != NULL) { + brelse(path.ep_bp); + path.ep_bp = NULL; + } + pos = lbn - ep->e_blk + (((daddr_t)ep->e_start_hi << 32) | ep->e_start_lo); + error = bread(ip->i_devvp, fsbtodb(fs, pos), fs->e2fs_bsize, &bp); + if (error) { + brelse(bp); + return (error); + } + + if (res) + *res = (char *)bp->b_data + blkoff(fs, offset); + + *bpp = bp; + + return (0); + } + + normal: *bpp = NULL; if ((error = bread(vp, lbn, fs->e2fs_bsize, &bp)) != 0) { brelse(bp); diff --git a/sys/ufs/ext2fs/ext2fs_vfsops.c b/sys/ufs/ext2fs/ext2fs_vfsops.c index 7bfe1f3c9d4..1ebe7c243fa 100644 --- a/sys/ufs/ext2fs/ext2fs_vfsops.c +++ b/sys/ufs/ext2fs/ext2fs_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_vfsops.c,v 1.79 2014/07/12 18:44:01 tedu Exp $ */ +/* $OpenBSD: ext2fs_vfsops.c,v 1.80 2014/07/13 13:28:26 pelikan Exp $ */ /* $NetBSD: ext2fs_vfsops.c,v 1.1 1997/06/11 09:34:07 bouyer Exp $ */ /* @@ -396,6 +396,7 @@ e2fs_sbfill(struct vnode *devvp, struct m_ext2fs *fs, struct ext2fs *sb) fs->e2fs_fsbtodb = sb->e2fs_log_bsize + 1; fs->e2fs_bsize = 1024 << sb->e2fs_log_bsize; fs->e2fs_bshift = LOG_MINBSIZE + sb->e2fs_log_bsize; + fs->e2fs_fsize = 1024 << sb->e2fs_log_fsize; fs->e2fs_qbmask = fs->e2fs_bsize - 1; fs->e2fs_bmask = ~fs->e2fs_qbmask; @@ -1090,11 +1091,22 @@ e2fs_sbcheck(struct ext2fs *fs, int ronly) } tmp = letoh32(fs->e2fs_features_incompat); - if (tmp & ~EXT2F_INCOMPAT_SUPP) { + if (tmp & ~(EXT2F_INCOMPAT_SUPP | EXT4F_RO_INCOMPAT_SUPP)) { printf("ext2fs: unsupported incompat features 0x%x\n", tmp); return (EINVAL); /* XXX needs translation */ } + if (!ronly && (tmp & EXT4F_RO_INCOMPAT_SUPP)) { + printf("ext4fs: only read-only support right now\n"); + return (EROFS); /* XXX needs translation */ + } + + if (tmp & EXT2F_INCOMPAT_RECOVER) { + printf("ext2fs: your file system says it needs recovery\n"); + if (!ronly) + return (EROFS); /* XXX needs translation */ + } + tmp = letoh32(fs->e2fs_features_rocompat); if (!ronly && (tmp & ~EXT2F_ROCOMPAT_SUPP)) { printf("ext2fs: unsupported R/O compat features 0x%x\n", tmp); diff --git a/sys/ufs/ufs/inode.h b/sys/ufs/ufs/inode.h index b5b8943ad1b..46e7e53705a 100644 --- a/sys/ufs/ufs/inode.h +++ b/sys/ufs/ufs/inode.h @@ -1,4 +1,4 @@ -/* $OpenBSD: inode.h,v 1.47 2014/07/11 12:08:21 pelikan Exp $ */ +/* $OpenBSD: inode.h,v 1.48 2014/07/13 13:28:26 pelikan Exp $ */ /* $NetBSD: inode.h,v 1.8 1995/06/15 23:22:50 cgd Exp $ */ /* @@ -42,16 +42,18 @@ #include <ufs/ufs/dinode.h> #include <ufs/ufs/dir.h> #include <ufs/ext2fs/ext2fs_dinode.h> +#include <ufs/ext2fs/ext2fs_extents.h> /* * Per-filesystem inode extensions. */ struct ext2fs_inode_ext { - int32_t ext2fs_last_lblk; /* last logical block allocated */ - int32_t ext2fs_last_blk; /* last block allocated on disk */ - u_int32_t ext2fs_effective_uid; /* effective inode uid */ - u_int32_t ext2fs_effective_gid; /* effective inode gid */ + int32_t ext2fs_last_lblk; /* last logical block allocated */ + int32_t ext2fs_last_blk; /* last block allocated on disk */ + u_int32_t ext2fs_effective_uid; /* effective inode uid */ + u_int32_t ext2fs_effective_gid; /* effective inode gid */ + struct ext4_extent_cache ext2fs_extent_cache; }; /* @@ -108,6 +110,7 @@ struct inode { #define i_e2fs_last_blk inode_ext.e2fs.ext2fs_last_blk #define i_e2fs_uid inode_ext.e2fs.ext2fs_effective_uid #define i_e2fs_gid inode_ext.e2fs.ext2fs_effective_gid +#define i_e2fs_ext_cache inode_ext.e2fs.ext2fs_extent_cache #define i_dirhash inode_ext.dirhash /* |