summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Pelikan <pelikan@cvs.openbsd.org>2014-07-13 13:28:27 +0000
committerMartin Pelikan <pelikan@cvs.openbsd.org>2014-07-13 13:28:27 +0000
commitfc08a83358c78094f736f5bd28d9cbce62c20a02 (patch)
tree341c6b3118ee236feeb11e86ff2d362d7a083500
parenteb09aa80ddba288298f52d827341a6f415281e2e (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/files3
-rw-r--r--sys/ufs/ext2fs/ext2fs.h10
-rw-r--r--sys/ufs/ext2fs/ext2fs_bmap.c46
-rw-r--r--sys/ufs/ext2fs/ext2fs_bswap.c4
-rw-r--r--sys/ufs/ext2fs/ext2fs_extents.c176
-rw-r--r--sys/ufs/ext2fs/ext2fs_extents.h99
-rw-r--r--sys/ufs/ext2fs/ext2fs_readwrite.c83
-rw-r--r--sys/ufs/ext2fs/ext2fs_subr.c34
-rw-r--r--sys/ufs/ext2fs/ext2fs_vfsops.c16
-rw-r--r--sys/ufs/ufs/inode.h13
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
/*