ext4 (extents) read support
authorpelikan <pelikan@openbsd.org>
Sun, 13 Jul 2014 13:28:26 +0000 (13:28 +0000)
committerpelikan <pelikan@openbsd.org>
Sun, 13 Jul 2014 13:28:26 +0000 (13:28 +0000)
Tested on amd64 with > 4GB files and 50,000 subdirectories.
From FreeBSD, thanks!

ok deraadt guenther

sys/conf/files
sys/ufs/ext2fs/ext2fs.h
sys/ufs/ext2fs/ext2fs_bmap.c
sys/ufs/ext2fs/ext2fs_bswap.c
sys/ufs/ext2fs/ext2fs_extents.c [new file with mode: 0644]
sys/ufs/ext2fs/ext2fs_extents.h [new file with mode: 0644]
sys/ufs/ext2fs/ext2fs_readwrite.c
sys/ufs/ext2fs/ext2fs_subr.c
sys/ufs/ext2fs/ext2fs_vfsops.c
sys/ufs/ufs/inode.h

index ae98d65..2ba37e0 100644 (file)
@@ -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
index 3896d91..cfe3dd9 100644 (file)
@@ -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 $       */
 
 /*
  * 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 */
index adfc79e..66f73e3 100644 (file)
@@ -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 $ */
 
 /*
 #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,10 +80,44 @@ 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
@@ -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;
index d837a2c..232d746 100644 (file)
@@ -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 (file)
index 0000000..840a025
--- /dev/null
@@ -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 (file)
index 0000000..8a5076f
--- /dev/null
@@ -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_ */
index e01a785..d5a29d3 100644 (file)
@@ -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 $        */
 
 /*-
 #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.
  */
index c0f3ba1..cd4f22e 100644 (file)
@@ -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);
index 7bfe1f3..1ebe7c2 100644 (file)
@@ -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);
index b5b8943..46e7e53 100644 (file)
@@ -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 $    */
 
 /*
 #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
 
        /*