Module Name: src
Committed By: christos
Date: Fri Jun 3 15:35:48 UTC 2016
Modified Files:
src/sys/ufs/ext2fs: ext2fs.h ext2fs_bmap.c
Added Files:
src/sys/ufs/ext2fs: ext2fs_extents.c ext2fs_extents.h
Log Message:
Add ext4 extent support from GSoC 2016 (Hrishikesh Goyal), from the FreeBSD
ext2 code.
To generate a diff of this commit:
cvs rdiff -u -r1.36 -r1.37 src/sys/ufs/ext2fs/ext2fs.h
cvs rdiff -u -r1.26 -r1.27 src/sys/ufs/ext2fs/ext2fs_bmap.c
cvs rdiff -u -r0 -r1.1 src/sys/ufs/ext2fs/ext2fs_extents.c \
src/sys/ufs/ext2fs/ext2fs_extents.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/ufs/ext2fs/ext2fs.h
diff -u src/sys/ufs/ext2fs/ext2fs.h:1.36 src/sys/ufs/ext2fs/ext2fs.h:1.37
--- src/sys/ufs/ext2fs/ext2fs.h:1.36 Sun Jun 23 03:28:37 2013
+++ src/sys/ufs/ext2fs/ext2fs.h Fri Jun 3 11:35:48 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs.h,v 1.36 2013/06/23 07:28:37 dholland Exp $ */
+/* $NetBSD: ext2fs.h,v 1.37 2016/06/03 15:35:48 christos Exp $ */
/*
* Copyright (c) 1982, 1986, 1993
@@ -86,6 +86,11 @@
#define BBLOCK ((daddr_t)(0))
#define SBLOCK ((daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE))
+#define fsbtodb(fs, b) ((daddr_t)(b) << (fs)->e2fs_fsbtodb)
+/* calculates (loc / fs->fs_bsize) */
+#define lblkno(fs, loc) ((loc) >> (fs->e2fs_bshift))
+#define blksize(fs, ip, lbn) ((fs)->e2fs_bsize)
+
/*
* Addresses stored in inodes are capable of addressing blocks
* XXX
@@ -132,7 +137,7 @@ struct ext2fs {
uint32_t e2fs_fbcount; /* free blocks count */
uint32_t e2fs_ficount; /* free inodes count */
uint32_t e2fs_first_dblock; /* first data block */
- uint32_t e2fs_log_bsize; /* block size = 1024*(2^e2fs_log_bsize) */
+ uint32_t e2fs_log_bsize; /* bsize = 1024*(2^e2fs_log_bsize) */
uint32_t e2fs_fsize; /* fragment size */
uint32_t e2fs_bpg; /* blocks per group */
uint32_t e2fs_fpg; /* frags per group */
@@ -165,7 +170,62 @@ struct ext2fs {
uint8_t e2fs_prealloc; /* # of blocks to preallocate */
uint8_t e2fs_dir_prealloc; /* # of blocks to preallocate for dir */
uint16_t e2fs_reserved_ngdb; /* # of reserved gd blocks for resize */
- uint32_t reserved2[204];
+
+ /* Additional fields */
+ char e3fs_journal_uuid[16];/* uuid of journal superblock */
+ uint32_t e3fs_journal_inum; /* inode number of journal file */
+ uint32_t e3fs_journal_dev; /* device number of journal file */
+ uint32_t e3fs_last_orphan; /* start of list of inodes to delete */
+ uint32_t e3fs_hash_seed[4]; /* HTREE hash seed */
+ char e3fs_def_hash_version;/* Default hash version to use */
+ char e3fs_jnl_backup_type;
+ uint16_t e3fs_desc_size; /* size of group descriptor */
+ uint32_t e3fs_default_mount_opts;
+ uint32_t e3fs_first_meta_bg; /* First metablock block group */
+ uint32_t e3fs_mkfs_time; /* when the fs was created */
+ uint32_t e3fs_jnl_blks[17]; /* backup of the journal inode */
+ uint32_t e4fs_bcount_hi; /* high bits of blocks count */
+ uint32_t e4fs_rbcount_hi; /* high bits of reserved blocks count */
+ uint32_t e4fs_fbcount_hi; /* high bits of free blocks count */
+ uint16_t e4fs_min_extra_isize; /* all inodes have some bytes */
+ uint16_t e4fs_want_extra_isize;/* inodes must reserve some bytes */
+ uint32_t e4fs_flags; /* miscellaneous flags */
+ uint16_t e4fs_raid_stride; /* RAID stride */
+ uint16_t e4fs_mmpintv; /* seconds to wait in MMP checking */
+ uint64_t e4fs_mmpblk; /* block for multi-mount protection */
+ uint32_t e4fs_raid_stripe_wid; /* blocks on data disks (N * stride) */
+ uint8_t e4fs_log_gpf; /* FLEX_BG group size */
+ uint8_t e4fs_chksum_type; /* metadata checksum algorithm used */
+ uint8_t e4fs_encrypt; /* versioning level for encryption */
+ uint8_t e4fs_reserved_pad;
+ uint64_t e4fs_kbytes_written; /* number of lifetime kilobytes */
+ uint32_t e4fs_snapinum; /* inode number of active snapshot */
+ uint32_t e4fs_snapid; /* sequential ID of active snapshot */
+ uint64_t e4fs_snaprbcount; /* rsvd blocks for active snapshot */
+ uint32_t e4fs_snaplist; /* inode number for on-disk snapshot */
+ uint32_t e4fs_errcount; /* number of file system errors */
+ uint32_t e4fs_first_errtime; /* first time an error happened */
+ uint32_t e4fs_first_errino; /* inode involved in first error */
+ uint64_t e4fs_first_errblk; /* block involved of first error */
+ uint8_t e4fs_first_errfunc[32];/* function where error happened */
+ uint32_t e4fs_first_errline; /* line number where error happened */
+ uint32_t e4fs_last_errtime; /* most recent time of an error */
+ uint32_t e4fs_last_errino; /* inode involved in last error */
+ uint32_t e4fs_last_errline; /* line number where error happened */
+ uint64_t e4fs_last_errblk; /* block involved of last error */
+ uint8_t e4fs_last_errfunc[32];/* function where error happened */
+ uint8_t e4fs_mount_opts[64];
+ uint32_t e4fs_usrquota_inum; /* inode for tracking user quota */
+ uint32_t e4fs_grpquota_inum; /* inode for tracking group quota */
+ uint32_t e4fs_overhead_clusters;/* overhead blocks/clusters */
+ uint32_t e4fs_backup_bgs[2]; /* groups with sparse_super2 SBs */
+ uint8_t e4fs_encrypt_algos[4];/* encryption algorithms in use */
+ uint8_t e4fs_encrypt_pw_salt[16];/* salt used for string2key */
+ uint32_t e4fs_lpf_ino; /* location of the lost+found inode */
+ uint32_t e4fs_proj_quota_inum; /* inode for tracking project quota */
+ uint32_t e4fs_chksum_seed; /* checksum seed */
+ uint32_t e4fs_reserved[98]; /* padding to the end of the block */
+ uint32_t e4fs_sbchksum; /* superblock checksum */
};
@@ -267,7 +327,8 @@ struct m_ext2fs {
#define EXT2F_ROCOMPAT_SUPP (EXT2F_ROCOMPAT_SPARSESUPER \
| EXT2F_ROCOMPAT_LARGEFILE \
| EXT2F_ROCOMPAT_HUGE_FILE)
-#define EXT2F_INCOMPAT_SUPP EXT2F_INCOMPAT_FTYPE
+#define EXT2F_INCOMPAT_SUPP (EXT2F_INCOMPAT_FTYPE \
+ | EXT2F_INCOMPAT_EXTENTS)
/*
* Definitions of behavior on errors
Index: src/sys/ufs/ext2fs/ext2fs_bmap.c
diff -u src/sys/ufs/ext2fs/ext2fs_bmap.c:1.26 src/sys/ufs/ext2fs/ext2fs_bmap.c:1.27
--- src/sys/ufs/ext2fs/ext2fs_bmap.c:1.26 Tue Jan 22 04:39:15 2013
+++ src/sys/ufs/ext2fs/ext2fs_bmap.c Fri Jun 3 11:35:48 2016
@@ -1,4 +1,4 @@
-/* $NetBSD: ext2fs_bmap.c,v 1.26 2013/01/22 09:39:15 dholland Exp $ */
+/* $NetBSD: ext2fs_bmap.c,v 1.27 2016/06/03 15:35:48 christos Exp $ */
/*
* Copyright (c) 1989, 1991, 1993
@@ -65,7 +65,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_bmap.c,v 1.26 2013/01/22 09:39:15 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_bmap.c,v 1.27 2016/06/03 15:35:48 christos Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -84,8 +84,10 @@ __KERNEL_RCSID(0, "$NetBSD: ext2fs_bmap.
#include <ufs/ext2fs/ext2fs.h>
#include <ufs/ext2fs/ext2fs_extern.h>
-static int ext2fs_bmaparray(struct vnode *, daddr_t, daddr_t *,
- struct indir *, int *, int *);
+
+static int ext4_bmapext(struct vnode *, int32_t, int64_t *, int *, int *);
+static int ext2fs_bmaparray(struct vnode *, daddr_t, daddr_t *, struct indir *,
+ int *, int *);
#define is_sequential(ump, a, b) ((b) == (a) + ump->um_seqinc)
@@ -112,11 +114,79 @@ ext2fs_bmap(void *v)
*ap->a_vpp = VTOI(ap->a_vp)->i_devvp;
if (ap->a_bnp == NULL)
return (0);
+
+
+ if (VTOI(ap->a_vp)->i_din.e2fs_din->e2di_flags & IN_E4EXTENTS)
+ return ext4_bmapext(ap->a_vp, ap->a_bn, ap->a_bnp,
+ ap->a_runp, NULL);
+ else
+ return ext2fs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, NULL,
+ NULL, ap->a_runp);
+
+
+}
+
+/*
+ * Convert the logical block number of a file to its physical block number
+ * on the disk within ext4 extents.
+ */
+static int
+ext4_bmapext(struct vnode *vp, int32_t bn, int64_t *bnp, int *runp, int *runb)
+{
+ struct inode *ip;
+ struct m_ext2fs *fs;
+ struct ext4_extent *ep;
+ struct ext4_extent_path path = { .ep_bp = NULL };
+ daddr_t lbn;
+ int error = 0;
+
+ ip = VTOI(vp);
+ fs = ip->i_e2fs;
+ lbn = bn;
+
+ /* XXX: Should not initialize on error? */
+ if (runp != NULL)
+ *runp = 0;
+
+ if (runb != NULL)
+ *runb = 0;
- return (ext2fs_bmaparray(ap->a_vp, ap->a_bn, ap->a_bnp, NULL, NULL,
- ap->a_runp));
+ ext4_ext_find_extent(fs, ip, lbn, &path);
+ if (path.ep_is_sparse) {
+ *bnp = -1;
+ if (runp != NULL)
+ *runp = path.ep_sparse_ext.e_len -
+ (lbn - path.ep_sparse_ext.e_blk) - 1;
+ if (runb != NULL)
+ *runb = lbn - path.ep_sparse_ext.e_blk;
+ } else {
+ if (path.ep_ext == NULL) {
+ error = EIO;
+ goto out;
+ }
+ ep = path.ep_ext;
+ *bnp = fsbtodb(fs, lbn - ep->e_blk
+ + (ep->e_start_lo | (daddr_t)ep->e_start_hi << 32));
+
+ if (*bnp == 0)
+ *bnp = -1;
+
+ if (runp != NULL)
+ *runp = ep->e_len - (lbn - ep->e_blk) - 1;
+ if (runb != NULL)
+ *runb = lbn - ep->e_blk;
+ }
+
+out:
+ if (path.ep_bp != NULL) {
+ brelse(path.ep_bp, 0);
+ }
+
+ return error;
}
+
+
/*
* Indirect blocks are now on the vnode for the file. They are given negative
* logical block numbers. Indirect blocks are addressed by the negative
Added files:
Index: src/sys/ufs/ext2fs/ext2fs_extents.c
diff -u /dev/null src/sys/ufs/ext2fs/ext2fs_extents.c:1.1
--- /dev/null Fri Jun 3 11:35:48 2016
+++ src/sys/ufs/ext2fs/ext2fs_extents.c Fri Jun 3 11:35:48 2016
@@ -0,0 +1,232 @@
+/* $NetBSD: ext2fs_extents.c,v 1.1 2016/06/03 15:35:48 christos Exp $ */
+
+/*-
+ * Copyright (c) 2010 Zheng Liu <[email protected]>
+ * 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 295523 2016-02-11 15:27:14Z pfg $
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_extents.c,v 1.1 2016/06/03 15:35:48 christos Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/resourcevar.h>
+#include <sys/kernel.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/signalvar.h>
+#include <sys/kauth.h>
+
+#include <ufs/ufs/inode.h>
+#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 bool
+ext4_ext_binsearch_index(struct inode *ip, struct ext4_extent_path *path,
+ daddr_t lbn, daddr_t *first_lbn, daddr_t *last_lbn)
+{
+ struct ext4_extent_header *ehp = path->ep_header;
+ struct ext4_extent_index *first, *last, *l, *r, *m;
+
+ first = (struct ext4_extent_index *)(char *)(ehp + 1);
+ last = first + ehp->eh_ecount - 1;
+ l = first;
+ r = last;
+ while (l <= r) {
+ m = l + (r - l) / 2;
+ if (lbn < m->ei_blk)
+ r = m - 1;
+ else
+ l = m + 1;
+ }
+
+ if (l == first) {
+ path->ep_sparse_ext.e_blk = *first_lbn;
+ path->ep_sparse_ext.e_len = first->ei_blk - *first_lbn;
+ path->ep_sparse_ext.e_start_hi = 0;
+ path->ep_sparse_ext.e_start_lo = 0;
+ path->ep_is_sparse = true;
+ return (true);
+ }
+ path->ep_index = l - 1;
+ *first_lbn = path->ep_index->ei_blk;
+ if (path->ep_index < last)
+ *last_lbn = l->ei_blk - 1;
+ return (false);
+}
+
+static void
+ext4_ext_binsearch(struct inode *ip, struct ext4_extent_path *path, daddr_t lbn,
+ daddr_t first_lbn, daddr_t last_lbn)
+{
+ struct ext4_extent_header *ehp = path->ep_header;
+ struct ext4_extent *first, *l, *r, *m;
+
+ if (ehp->eh_ecount == 0)
+ return;
+
+ first = (struct ext4_extent *)(char *)(ehp + 1);
+ l = first;
+ r = first + ehp->eh_ecount - 1;
+ while (l <= r) {
+ m = l + (r - l) / 2;
+ if (lbn < m->e_blk)
+ r = m - 1;
+ else
+ l = m + 1;
+ }
+
+ if (l == first) {
+ path->ep_sparse_ext.e_blk = first_lbn;
+ path->ep_sparse_ext.e_len = first->e_blk - first_lbn;
+ path->ep_sparse_ext.e_start_hi = 0;
+ path->ep_sparse_ext.e_start_lo = 0;
+ path->ep_is_sparse = true;
+ return;
+ }
+ path->ep_ext = l - 1;
+ if (path->ep_ext->e_blk + path->ep_ext->e_len <= lbn) {
+ path->ep_sparse_ext.e_blk = path->ep_ext->e_blk +
+ path->ep_ext->e_len;
+ if (l <= (first + ehp->eh_ecount - 1))
+ path->ep_sparse_ext.e_len = l->e_blk -
+ path->ep_sparse_ext.e_blk;
+ else
+ path->ep_sparse_ext.e_len = last_lbn -
+ path->ep_sparse_ext.e_blk + 1;
+ path->ep_sparse_ext.e_start_hi = 0;
+ path->ep_sparse_ext.e_start_lo = 0;
+ path->ep_is_sparse = true;
+ }
+}
+
+/*
+ * 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->inode_ext.e2fs.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 >> 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->inode_ext.e2fs.i_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 ext4_extent_header *ehp;
+ uint16_t i;
+ int error, size;
+ daddr_t nblk;
+
+ ehp = (struct ext4_extent_header *)ip->i_din.e2fs_din->e2di_blocks;
+
+ if (ehp->eh_magic != EXT4_EXT_MAGIC)
+ return (NULL);
+
+ path->ep_header = ehp;
+
+ daddr_t first_lbn = 0;
+ daddr_t last_lbn = lblkno(ip->i_e2fs, ip->i_size);
+
+ for (i = ehp->eh_depth; i != 0; --i) {
+ path->ep_depth = i;
+ path->ep_ext = NULL;
+ if (ext4_ext_binsearch_index(ip, path, lbn, &first_lbn,
+ &last_lbn)) {
+ return (path);
+ }
+
+ nblk = (daddr_t)path->ep_index->ei_leaf_hi << 32 |
+ path->ep_index->ei_leaf_lo;
+ size = blksize(fs, ip, nblk);
+ if (path->ep_bp != NULL) {
+ brelse(path->ep_bp, 0);
+ path->ep_bp = NULL;
+ }
+ error = bread(ip->i_devvp, fsbtodb(fs, nblk), size, 0,
+ &path->ep_bp);
+ if (error) {
+ brelse(path->ep_bp, 0);
+ 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;
+ path->ep_is_sparse = false;
+
+ ext4_ext_binsearch(ip, path, lbn, first_lbn, last_lbn);
+ return (path);
+}
Index: src/sys/ufs/ext2fs/ext2fs_extents.h
diff -u /dev/null src/sys/ufs/ext2fs/ext2fs_extents.h:1.1
--- /dev/null Fri Jun 3 11:35:48 2016
+++ src/sys/ufs/ext2fs/ext2fs_extents.h Fri Jun 3 11:35:48 2016
@@ -0,0 +1,107 @@
+/* $NetBSD: ext2fs_extents.h,v 1.1 2016/06/03 15:35:48 christos Exp $ */
+
+/*-
+ * Copyright (c) 2012, 2010 Zheng Liu <[email protected]>
+ * 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 295523 2016-02-11 15:27:14Z pfg $
+ */
+
+#ifndef _UFS_EXT2FS_EXT2FS_EXTENTS_H_
+#define _UFS_EXT2FS_EXT2FS_EXTENTS_H_
+
+#include <sys/types.h>
+#include <ufs/ufs/inode.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;
+ bool ep_is_sparse;
+ union {
+ struct ext4_extent ep_sparse_ext;
+ 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 /* !_UFS_EXT2FS_EXT2FS_EXTENTS_H_ */