Date: Sun, 22 Aug 2010 19:17:48 +0800 From: gnehzuil <gnehzuil@gmail.com> To: fs@freebsd.org Cc: jhb@FreeBSD.org Subject: [patch] ext4fs read only mode Message-ID: <4C71075C.9010802@gmail.com>
next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------000709010802090406030102
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Hi all,
This patch makes ext2fs can read ext4 filesystem in read-only mode.
There are two files in attachments. 'ext4fs_ro_makefile.patch' is for
Makefile in modules/ext2fs/. 'ext4fs_ro_src.patch' is for source code in
fs/ext2fs/. Please use the following command to mount disk: 'mount -t
ext2fs -r /dev/XXX /YYY'.
Now you can use it to read data from ext4 filesystem in the following
features:
+ HAS_JOURNAL(*)
+ FILE_TYPE
+ SPARSE_SUPER
+ HUGE_FILE
+ EXTENTS
+ DIR_NLINK
+ UNINIT_BG
+ FLEX_BG(*)
+ EXTRA_ISIZE(*)
+ DIR_INDEX(**)
* I don't implement this feature. However you don't need to worry about
it because it doesn't be used in read-only mode.
** I have implemented a hash directory index in ext2_lookup() function.
But there are two functions that I think they seem to be contaminated
kernel source code. So this patch doesn't include hash directory index.
Please test it.
Best regards,
lz
--------------000709010802090406030102
Content-Type: text/x-patch;
name="ext4fs_ro_makefile.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="ext4fs_ro_makefile.patch"
--- /usr/src/sys/modules/ext2fs/Makefile 2010-01-14 22:30:54.000000000 +0800
+++ Makefile 2010-08-22 22:53:28.000000000 +0800
@@ -3,8 +3,8 @@
.PATH: ${.CURDIR}/../../fs/ext2fs
KMOD= ext2fs
SRCS= opt_ddb.h opt_quota.h opt_suiddir.h vnode_if.h \
- ext2_alloc.c ext2_balloc.c ext2_bmap.c ext2_inode.c \
- ext2_inode_cnv.c ext2_lookup.c ext2_subr.c ext2_vfsops.c \
- ext2_vnops.c
+ ext2_alloc.c ext2_balloc.c ext2_bmap.c ext2_extents.c \
+ ext2_inode.c ext2_inode_cnv.c ext2_lookup.c ext2_subr.c \
+ ext2_vfsops.c ext2_vnops.c
.include <bsd.kmod.mk>
--------------000709010802090406030102
Content-Type: text/x-patch;
name="ext4fs_ro_src.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="ext4fs_ro_src.patch"
diff -urN /usr/src/sys/fs/ext2fs/ext2_alloc.c src/ext2_alloc.c
--- /usr/src/sys/fs/ext2fs/ext2_alloc.c 2010-01-14 22:30:54.000000000 +0800
+++ src/ext2_alloc.c 2010-08-22 22:41:52.000000000 +0800
@@ -116,12 +116,12 @@
if (cred == NOCRED)
panic("ext2_alloc: missing credential");
#endif /* DIAGNOSTIC */
- if (size == fs->e2fs_bsize && fs->e2fs->e2fs_fbcount == 0)
+ if (size == fs->e2fs_bsize && fs->e2fs->e2fs_fbcount_lo == 0)
goto nospace;
if (cred->cr_uid != 0 &&
- fs->e2fs->e2fs_fbcount < fs->e2fs->e2fs_rbcount)
+ fs->e2fs->e2fs_fbcount_lo < fs->e2fs->e2fs_rbcount_lo)
goto nospace;
- if (bpref >= fs->e2fs->e2fs_bcount)
+ if (bpref >= fs->e2fs->e2fs_bcount_lo)
bpref = 0;
if (bpref == 0)
cg = ino_to_cg(fs, ip->i_number);
@@ -443,7 +443,7 @@
fs = pip->i_e2fs;
avgifree = fs->e2fs->e2fs_ficount / fs->e2fs_gcount;
- avgbfree = fs->e2fs->e2fs_fbcount / fs->e2fs_gcount;
+ avgbfree = fs->e2fs->e2fs_fbcount_lo / fs->e2fs_gcount;
avgndir = fs->e2fs_total_dir / fs->e2fs_gcount;
/*
@@ -455,18 +455,18 @@
mincg = prefcg;
minndir = fs->e2fs_ipg;
for (cg = prefcg; cg < fs->e2fs_gcount; cg++)
- if (fs->e2fs_gd[cg].ext2bgd_ndirs < minndir &&
- fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree &&
- fs->e2fs_gd[cg].ext2bgd_nbfree >= avgbfree) {
+ if (fs->e2fs_gd[cg].ext2bgd_ndirs_lo < minndir &&
+ fs->e2fs_gd[cg].ext2bgd_nifree_lo >= avgifree &&
+ fs->e2fs_gd[cg].ext2bgd_nbfree_lo >= avgbfree) {
mincg = cg;
- minndir = fs->e2fs_gd[cg].ext2bgd_ndirs;
+ minndir = fs->e2fs_gd[cg].ext2bgd_ndirs_lo;
}
for (cg = 0; cg < prefcg; cg++)
- if (fs->e2fs_gd[cg].ext2bgd_ndirs < minndir &&
- fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree &&
- fs->e2fs_gd[cg].ext2bgd_nbfree >= avgbfree) {
+ if (fs->e2fs_gd[cg].ext2bgd_ndirs_lo < minndir &&
+ fs->e2fs_gd[cg].ext2bgd_nifree_lo >= avgifree &&
+ fs->e2fs_gd[cg].ext2bgd_nbfree_lo >= avgbfree) {
mincg = cg;
- minndir = fs->e2fs_gd[cg].ext2bgd_ndirs;
+ minndir = fs->e2fs_gd[cg].ext2bgd_ndirs_lo;
}
return (mincg);
@@ -503,16 +503,16 @@
*/
prefcg = ino_to_cg(fs, pip->i_number);
for (cg = prefcg; cg < fs->e2fs_gcount; cg++)
- if (fs->e2fs_gd[cg].ext2bgd_ndirs < maxndir &&
- fs->e2fs_gd[cg].ext2bgd_nifree >= minifree &&
- fs->e2fs_gd[cg].ext2bgd_nbfree >= minbfree) {
+ if (fs->e2fs_gd[cg].ext2bgd_ndirs_lo < maxndir &&
+ fs->e2fs_gd[cg].ext2bgd_nifree_lo >= minifree &&
+ fs->e2fs_gd[cg].ext2bgd_nbfree_lo >= minbfree) {
if (fs->e2fs_contigdirs[cg] < maxcontigdirs)
return (cg);
}
for (cg = 0; cg < prefcg; cg++)
- if (fs->e2fs_gd[cg].ext2bgd_ndirs < maxndir &&
- fs->e2fs_gd[cg].ext2bgd_nifree >= minifree &&
- fs->e2fs_gd[cg].ext2bgd_nbfree >= minbfree) {
+ if (fs->e2fs_gd[cg].ext2bgd_ndirs_lo < maxndir &&
+ fs->e2fs_gd[cg].ext2bgd_nifree_lo >= minifree &&
+ fs->e2fs_gd[cg].ext2bgd_nbfree_lo >= minbfree) {
if (fs->e2fs_contigdirs[cg] < maxcontigdirs)
return (cg);
}
@@ -520,10 +520,10 @@
* This is a backstop when we have deficit in space.
*/
for (cg = prefcg; cg < fs->e2fs_gcount; cg++)
- if (fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree)
+ if (fs->e2fs_gd[cg].ext2bgd_nifree_lo >= avgifree)
return (cg);
for (cg = 0; cg < prefcg; cg++)
- if (fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree)
+ if (fs->e2fs_gd[cg].ext2bgd_nifree_lo >= avgifree)
break;
return (cg);
}
@@ -644,11 +644,11 @@
/* XXX ondisk32 */
fs = ip->i_e2fs;
ump = ip->i_ump;
- if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0)
+ if (fs->e2fs_gd[cg].ext2bgd_nbfree_lo == 0)
return (0);
EXT2_UNLOCK(ump);
error = bread(ip->i_devvp, fsbtodb(fs,
- fs->e2fs_gd[cg].ext2bgd_b_bitmap),
+ fs->e2fs_gd[cg].ext2bgd_b_bitmap_lo),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
@@ -709,8 +709,8 @@
#endif
setbit(bbp, (daddr_t)bno);
EXT2_LOCK(ump);
- fs->e2fs->e2fs_fbcount--;
- fs->e2fs_gd[cg].ext2bgd_nbfree--;
+ fs->e2fs->e2fs_fbcount_lo--;
+ fs->e2fs_gd[cg].ext2bgd_nbfree_lo--;
fs->e2fs_fmod = 1;
EXT2_UNLOCK(ump);
bdwrite(bp);
@@ -736,11 +736,11 @@
ipref = 0;
fs = ip->i_e2fs;
ump = ip->i_ump;
- if (fs->e2fs_gd[cg].ext2bgd_nifree == 0)
+ if (fs->e2fs_gd[cg].ext2bgd_nifree_lo == 0)
return (0);
EXT2_UNLOCK(ump);
error = bread(ip->i_devvp, fsbtodb(fs,
- fs->e2fs_gd[cg].ext2bgd_i_bitmap),
+ fs->e2fs_gd[cg].ext2bgd_i_bitmap_lo),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
@@ -781,11 +781,11 @@
gotit:
setbit(ibp, ipref);
EXT2_LOCK(ump);
- fs->e2fs_gd[cg].ext2bgd_nifree--;
+ fs->e2fs_gd[cg].ext2bgd_nifree_lo--;
fs->e2fs->e2fs_ficount--;
fs->e2fs_fmod = 1;
if ((mode & IFMT) == IFDIR) {
- fs->e2fs_gd[cg].ext2bgd_ndirs++;
+ fs->e2fs_gd[cg].ext2bgd_ndirs_lo++;
fs->e2fs_total_dir++;
}
EXT2_UNLOCK(ump);
@@ -812,14 +812,14 @@
fs = ip->i_e2fs;
ump = ip->i_ump;
cg = dtog(fs, bno);
- if ((u_int)bno >= fs->e2fs->e2fs_bcount) {
+ if ((u_int)bno >= fs->e2fs->e2fs_bcount_lo) {
printf("bad block %lld, ino %llu\n", (long long)bno,
(unsigned long long)ip->i_number);
ext2_fserr(fs, ip->i_uid, "bad block");
return;
}
error = bread(ip->i_devvp,
- fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
+ fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap_lo),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
@@ -834,8 +834,8 @@
}
clrbit(bbp, bno);
EXT2_LOCK(ump);
- fs->e2fs->e2fs_fbcount++;
- fs->e2fs_gd[cg].ext2bgd_nbfree++;
+ fs->e2fs->e2fs_fbcount_lo++;
+ fs->e2fs_gd[cg].ext2bgd_nbfree_lo++;
fs->e2fs_fmod = 1;
EXT2_UNLOCK(ump);
bdwrite(bp);
@@ -868,7 +868,7 @@
cg = ino_to_cg(fs, ino);
error = bread(pip->i_devvp,
- fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
+ fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap_lo),
(int)fs->e2fs_bsize, NOCRED, &bp);
if (error) {
brelse(bp);
@@ -885,9 +885,9 @@
clrbit(ibp, ino);
EXT2_LOCK(ump);
fs->e2fs->e2fs_ficount++;
- fs->e2fs_gd[cg].ext2bgd_nifree++;
+ fs->e2fs_gd[cg].ext2bgd_nifree_lo++;
if ((mode & IFMT) == IFDIR) {
- fs->e2fs_gd[cg].ext2bgd_ndirs--;
+ fs->e2fs_gd[cg].ext2bgd_ndirs_lo--;
fs->e2fs_total_dir--;
}
fs->e2fs_fmod = 1;
diff -urN /usr/src/sys/fs/ext2fs/ext2_bmap.c src/ext2_bmap.c
--- /usr/src/sys/fs/ext2fs/ext2_bmap.c 2010-01-14 22:30:54.000000000 +0800
+++ src/ext2_bmap.c 2010-08-22 22:41:52.000000000 +0800
@@ -46,9 +46,62 @@
#include <sys/stat.h>
#include <fs/ext2fs/inode.h>
+#include <fs/ext2fs/fs.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/ext2_mount.h>
#include <fs/ext2fs/ext2_extern.h>
+#include <fs/ext2fs/ext2_dinode.h>
+
+static int ext4_bmapext(struct vnode *, int32_t, int64_t *, int *, int *);
+
+/*
+ * This function converts 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_header *ehp;
+ struct ext4_extent_path path;
+ daddr_t lbn;
+ int bsize;
+ int depth;
+
+ ip = VTOI(vp);
+ fs = ip->i_e2fs;
+ lbn = bn;
+ bsize = blksize(fs, ip, lbn);
+
+ /*
+ * TODO: need to implement read ahead to improve the performance.
+ */
+ if (runp != NULL)
+ *runp = 0;
+
+ if (runb != NULL)
+ *runb = 0;
+
+ ext4_ext_find_extent(fs, ip, lbn, &path);
+ depth = ((struct ext4_extent_header *)(ip->i_db))->eh_depth;
+ if (path.ep_ext == NULL && depth != 0)
+ return (EIO);
+
+ ehp = path.ep_header;
+ ep = path.ep_ext;
+ if (ep == NULL)
+ return (EIO);
+
+ *bnp = fsbtodb(fs, (lbn - ep->e_blk +
+ (ep->e_start_lo | ((daddr_t)(ep->e_start_hi) << 31) << 1)));
+
+ if (*bnp == 0)
+ *bnp = -1;
+
+ return (0);
+}
/*
* Bmap converts the logical block number of a file to its physical block
@@ -66,7 +119,7 @@
int *a_runb;
} */ *ap;
{
- int32_t blkno;
+ int64_t blkno;
int error;
/*
@@ -78,8 +131,12 @@
if (ap->a_bnp == NULL)
return (0);
- error = ext2_bmaparray(ap->a_vp, ap->a_bn, &blkno,
- ap->a_runp, ap->a_runb);
+ if (VTOI(ap->a_vp)->i_flags & EXT4_EXTENTS)
+ error = ext4_bmapext(ap->a_vp, ap->a_bn, &blkno,
+ ap->a_runp, ap->a_runb);
+ else
+ error = ext2_bmaparray(ap->a_vp, ap->a_bn, &blkno,
+ ap->a_runp, ap->a_runb);
*ap->a_bnp = blkno;
return (error);
}
@@ -102,7 +159,7 @@
ext2_bmaparray(vp, bn, bnp, runp, runb)
struct vnode *vp;
int32_t bn;
- int32_t *bnp;
+ int64_t *bnp;
int *runp;
int *runb;
{
diff -urN /usr/src/sys/fs/ext2fs/ext2_dinode.h src/ext2_dinode.h
--- /usr/src/sys/fs/ext2fs/ext2_dinode.h 2010-01-14 22:30:54.000000000 +0800
+++ src/ext2_dinode.h 2010-08-22 22:41:52.000000000 +0800
@@ -29,8 +29,6 @@
#ifndef _FS_EXT2FS_EXT2_DINODE_H_
#define _FS_EXT2FS_EXT2_DINODE_H_
-#define e2di_size_high e2di_dacl
-
/*
* Inode flags
* The current implementation uses only EXT2_IMMUTABLE and EXT2_APPEND flags
@@ -43,7 +41,21 @@
#define EXT2_APPEND 0x00000020 /* writes to file may only append */
#define EXT2_NODUMP 0x00000040 /* do not dump file */
#define EXT2_NOATIME 0x00000080 /* do not update atime */
-
+/* NOT implementation. Reserved for compression usage. */
+#define EXT4_DIRTY 0x00000100
+#define EXT4_COMPRBLK 0x00000200 /* One or more compressed clusters */
+#define EXT4_NOCOMPR 0x00000400 /* Don't compress */
+#define EXT4_ECOMPR 0x00000800 /* Compression error */
+/* End compression flags */
+#define EXT4_INDEX 0x00001000 /* Hash-indexed directory */
+#define EXT4_IMAGIC 0x00002000 /* AFS directory */
+#define EXT4_JOURNAL_DATA 0x00004000 /* File data should be journaled */
+#define EXT4_NOTAIL 0x00008000 /* File tail should not be merged */
+#define EXT4_DIRSYNC 0x00010000 /* dirsync behavior */
+#define EXT4_TOPDIR 0x00020000 /* top of directory hierarchies */
+#define EXT4_HUGE_FILE 0x00040000 /* Set to each huge file */
+#define EXT4_EXTENTS 0x00080000 /* Inode uses extents */
+#define EXT4_RESERVED 0x80000000 /* Reserved for ext4 lib */
/*
* Structure of an inode on the disk
@@ -51,27 +63,62 @@
struct ext2fs_dinode {
u_int16_t e2di_mode; /* 0: IFMT, permissions; see below. */
u_int16_t e2di_uid; /* 2: Owner UID */
- u_int32_t e2di_size; /* 4: Size (in bytes) */
+ u_int32_t e2di_size_lo; /* 4: Size (in bytes) */
u_int32_t e2di_atime; /* 8: Access time */
u_int32_t e2di_ctime; /* 12: Create time */
u_int32_t e2di_mtime; /* 16: Modification time */
u_int32_t e2di_dtime; /* 20: Deletion time */
u_int16_t e2di_gid; /* 24: Owner GID */
u_int16_t e2di_nlink; /* 26: File link count */
- u_int32_t e2di_nblock; /* 28: Blocks count */
+ u_int32_t e2di_nblock_lo; /* 28: Blocks count */
u_int32_t e2di_flags; /* 32: Status flags (chflags) */
- u_int32_t e2di_linux_reserved1; /* 36 */
+ union {
+ struct {
+ u_int32_t e2di_version;
+ } linux1;
+ struct {
+ u_int32_t e2di_translator;
+ } hurd1;
+ struct {
+ u_int32_t e2di_reserved1;
+ } masix1;
+ } osd1; /* 36: */
u_int32_t e2di_blocks[EXT2_N_BLOCKS]; /* 40: disk blocks */
u_int32_t e2di_gen; /* 100: generation number */
u_int32_t e2di_facl; /* 104: file ACL (not implemented) */
u_int32_t e2di_dacl; /* 108: dir ACL (not implemented) */
+#define e2di_size_high e2di_dacl
u_int32_t e2di_faddr; /* 112: fragment address */
- u_int8_t e2di_nfrag; /* 116: fragment number */
- u_int8_t e2di_fsize; /* 117: fragment size */
- u_int16_t e2di_linux_reserved2; /* 118 */
- u_int16_t e2di_uid_high; /* 120: Owner UID top 16 bits */
- u_int16_t e2di_gid_high; /* 122: Owner GID top 16 bits */
- u_int32_t e2di_linux_reserved3; /* 124 */
+ union {
+ struct {
+ u_int16_t e2di_l_blk_high;
+#define e2di_nblock_high osd2.linux2.e2di_l_blk_high
+ u_int16_t e2di_l_facl_high;
+ u_int16_t e2di_l_uid_high;
+ u_int16_t e2di_l_gid_high;
+ u_int32_t e2di_l_reserved2;
+ } linux2;
+ struct {
+ u_int16_t e2di_h_reserved1;
+ u_int16_t e2di_h_mode_high;
+ u_int16_t e2di_h_uid_high;
+ u_int16_t e2di_h_gid_high;
+ u_int32_t e2di_h_author;
+ } hurd2;
+ struct {
+ u_int16_t e2di_m_reserved1;
+ u_int16_t e2di_m_facl_high;
+ u_int32_t e2di_reserved2[2];
+ } masix2;
+ } osd2;
+ u_int16_t e2di_extra_isize;
+ u_int16_t e2di_pad;
+ u_int32_t e2di_ctime_extra;
+ u_int32_t e2di_mtime_extra;
+ u_int32_t e2di_atime_extra;
+ u_int32_t e2di_crtime;
+ u_int32_t e2di_crtime_extra;
+ u_int32_t e2di_version_hi;
};
#endif /* _FS_EXT2FS_EXT2_DINODE_H_ */
diff -urN /usr/src/sys/fs/ext2fs/ext2_extents.c src/ext2_extents.c
--- /usr/src/sys/fs/ext2fs/ext2_extents.c 1970-01-01 08:00:00.000000000 +0800
+++ src/ext2_extents.c 2010-08-22 22:41:52.000000000 +0800
@@ -0,0 +1,191 @@
+/*-
+ * Copyright (c) 2010, 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: 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)));
+ r = (struct ext4_extent_index *)(((char *)(ehp) +
+ sizeof(struct ext4_extent_header))) + 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) +
+ sizeof(struct ext4_extent_header)));
+ r = (struct ext4_extent *)(((char *)(ehp) +
+ sizeof(struct ext4_extent_header))) + 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_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);
+}
+
+/*
+ * put a 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_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) << 31) << 1) | ep->e_start_lo;
+}
+
+/*
+ * 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;
+ int depth, i, error, size;
+ daddr_t nblk;
+
+ vp = ITOV(ip);
+ ehp = (struct ext4_extent_header *)((char *)ip->i_db);
+ depth = ehp->eh_depth;
+
+ if (ehp->eh_magic != EXT4_EXT_MAGIC)
+ return (NULL);
+
+ path->ep_header = ehp;
+
+ i = depth;
+ while (i) {
+ ext4_ext_binsearch_index(ip, path, lbn);
+ path->ep_blk = (((daddr_t)(path->ep_index->ei_leaf_hi) << 31) << 1) |
+ path->ep_index->ei_leaf_lo;
+ path->ep_depth = i;
+ path->ep_ext = NULL;
+
+ size = blksize(fs, ip, path->ep_blk);
+ nblk = path->ep_blk;
+ if (path->ep_bp != NULL) {
+ brelse(path->ep_bp);
+ path->ep_bp = NULL;
+ }
+ error = bread(ip->i_devvp, fsbtodb(fs, nblk), size, NOCRED, &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;
+ i--;
+ }
+
+ path->ep_depth = i;
+ path->ep_ext = NULL;
+ path->ep_index = NULL;
+
+ ext4_ext_binsearch(ip, path, lbn);
+ if (path->ep_ext != NULL)
+ path->ep_blk = (((daddr_t)(path->ep_ext->e_start_hi) << 31) << 1) |
+ path->ep_ext->e_start_lo;
+
+ return (path);
+}
diff -urN /usr/src/sys/fs/ext2fs/ext2_extents.h src/ext2_extents.h
--- /usr/src/sys/fs/ext2fs/ext2_extents.h 1970-01-01 08:00:00.000000000 +0800
+++ src/ext2_extents.h 2010-08-22 22:41:52.000000000 +0800
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 2010, 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: src/sys/fs/ext2fs/ext2_extents.h,v 0.1 2010/06/22 18:01:51 lz Exp $
+ */
+#ifndef _FS_EXT2FS_EXT2_EXTENTS_H_
+#define _FS_EXT2FS_EXT2_EXTENTS_H_
+
+#include <sys/types.h>
+
+#define EXT4_EXT_MAGIC 0xf30a
+
+/* lock/unlock ext lock */
+#define EXT4_EXT_LOCK(ip) mtx_lock(&(ip)->i_ext_lock)
+#define EXT4_EXT_UNLOCK(ip) mtx_unlock(&(ip)->i_ext_lock)
+
+#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 {
+ u_int32_t e_blk; /* first logical block */
+ u_int16_t e_len; /* number of blocks */
+ u_int16_t e_start_hi; /* high 16 bits of physical block */
+ u_int32_t e_start_lo; /* low 32 bits of physical block */
+};
+
+/*
+ * extent index on disk
+ */
+struct ext4_extent_index {
+ u_int32_t ei_blk; /* indexes logical blocks */
+ u_int32_t ei_leaf_lo; /* pointes to physical block of the next level */
+ u_int16_t ei_leaf_hi; /* high 16 bits of physical block */
+ u_int16_t ei_unused;
+};
+
+/*
+ * extent tree header
+ */
+struct ext4_extent_header {
+ u_int16_t eh_magic; /* magic number: 0xf30a */
+ u_int16_t eh_ecount; /* number of valid entries */
+ u_int16_t eh_max; /* capacity of store in entries */
+ u_int16_t eh_depth; /* the depth of extent tree */
+ u_int32_t eh_gen; /* generation of extent tree */
+};
+
+/*
+ * save cached extent
+ */
+struct ext4_extent_cache {
+ daddr_t ec_start; /* extent start */
+ u_int32_t ec_blk; /* logical block */
+ u_int32_t ec_len;
+ u_int32_t ec_type;
+};
+
+/*
+ * save path to some extent.
+ */
+struct ext4_extent_path {
+ daddr_t ep_blk;
+ u_int16_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 -urN /usr/src/sys/fs/ext2fs/ext2_extern.h src/ext2_extern.h
--- /usr/src/sys/fs/ext2fs/ext2_extern.h 2010-01-14 22:30:54.000000000 +0800
+++ src/ext2_extern.h 2010-08-22 22:41:52.000000000 +0800
@@ -54,7 +54,7 @@
void ext2_blkfree(struct inode *, int32_t, long);
int32_t ext2_blkpref(struct inode *, int32_t, int, int32_t *, int32_t);
int ext2_bmap(struct vop_bmap_args *);
-int ext2_bmaparray(struct vnode *, int32_t, int32_t *, int *, int *);
+int ext2_bmaparray(struct vnode *, int32_t, int64_t *, int *, int *);
void ext2_dirbad(struct inode *ip, doff_t offset, char *how);
void ext2_ei2i(struct ext2fs_dinode *, struct inode *);
int ext2_getlbns(struct vnode *, int32_t, struct indir *, int *);
diff -urN /usr/src/sys/fs/ext2fs/ext2_inode.c src/ext2_inode.c
--- /usr/src/sys/fs/ext2fs/ext2_inode.c 2010-01-14 22:30:54.000000000 +0800
+++ src/ext2_inode.c 2010-08-22 22:41:52.000000000 +0800
@@ -153,6 +153,7 @@
}
fs = oip->i_e2fs;
osize = oip->i_size;
+
/*
* Lengthen the size of the file. We must ensure that the
* last byte of the file is allocated. Since the smallest
@@ -525,11 +526,15 @@
if (prtactive && vrefcnt(vp) != 0)
vprint("ufs_reclaim: pushing active", vp);
ip = VTOI(vp);
+
if (ip->i_flag & IN_LAZYMOD) {
ip->i_flag |= IN_MODIFIED;
ext2_update(vp, 0);
}
vfs_hash_remove(vp);
+
+ mtx_destroy(&ip->i_ext_lock);
+
free(vp->v_data, M_EXT2NODE);
vp->v_data = 0;
vnode_destroy_vobject(vp);
diff -urN /usr/src/sys/fs/ext2fs/ext2_inode_cnv.c src/ext2_inode_cnv.c
--- /usr/src/sys/fs/ext2fs/ext2_inode_cnv.c 2010-01-14 22:30:54.000000000 +0800
+++ src/ext2_inode_cnv.c 2010-08-22 22:50:00.000000000 +0800
@@ -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" */
@@ -49,7 +52,7 @@
printf( "User: %5lu Group: %5lu Size: %lu\n",
(unsigned long)in->i_uid, (unsigned long)in->i_gid,
(unsigned long)in->i_size);
- printf( "Links: %3d Blockcount: %d\n",
+ printf( "Links: %3d Blockcount: %lld\n",
in->i_nlink, in->i_blocks);
printf( "ctime: 0x%x", in->i_ctime);
printf( "atime: 0x%x", in->i_atime);
@@ -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");
}
@@ -77,17 +89,18 @@
I can see that this might lead to problems in an undelete.
*/
ip->i_mode = ei->e2di_nlink ? ei->e2di_mode : 0;
- ip->i_size = ei->e2di_size;
+ ip->i_size = ei->e2di_size_lo;
if (S_ISREG(ip->i_mode))
ip->i_size |= ((u_int64_t)ei->e2di_size_high) << 32;
ip->i_atime = ei->e2di_atime;
ip->i_mtime = ei->e2di_mtime;
ip->i_ctime = ei->e2di_ctime;
- ip->i_flags = 0;
- ip->i_flags |= (ei->e2di_flags & EXT2_APPEND) ? SF_APPEND : 0;
- ip->i_flags |= (ei->e2di_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
- ip->i_flags |= (ei->e2di_flags & EXT2_NODUMP) ? UF_NODUMP : 0;
- ip->i_blocks = ei->e2di_nblock;
+ ip->i_flags = ei->e2di_flags; /* we need to entire flags to check new features */
+ ip->i_gen = ei->e2di_gen;
+ if (ip->i_e2fs->e2fs->e2fs_features_incompat & EXT4F_ROCOMPAT_HUGE_FILE)
+ ip->i_blocks = ((int64_t)(ei->e2di_nblock_high)) << 32 | ei->e2di_nblock_lo;
+ else
+ ip->i_blocks = ei->e2di_nblock_lo;
ip->i_gen = ei->e2di_gen;
ip->i_uid = ei->e2di_uid;
ip->i_gid = ei->e2di_gid;
@@ -115,7 +128,7 @@
has been deleted, this would correspond to a zero link count
*/
ei->e2di_dtime = ei->e2di_nlink ? 0 : ip->i_mtime;
- ei->e2di_size = ip->i_size;
+ ei->e2di_size_lo = ip->i_size;
if (S_ISREG(ip->i_mode))
ei->e2di_size_high = ip->i_size >> 32;
ei->e2di_atime = ip->i_atime;
@@ -126,7 +139,7 @@
ei->e2di_flags |= (ip->i_flags & SF_APPEND) ? EXT2_APPEND: 0;
ei->e2di_flags |= (ip->i_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
ei->e2di_flags |= (ip->i_flags & UF_NODUMP) ? EXT2_NODUMP: 0;
- ei->e2di_nblock = ip->i_blocks;
+ ei->e2di_nblock_lo = ip->i_blocks;
ei->e2di_gen = ip->i_gen;
ei->e2di_uid = ip->i_uid;
ei->e2di_gid = ip->i_gid;
diff -urN /usr/src/sys/fs/ext2fs/ext2_readwrite.c src/ext2_readwrite.c
--- /usr/src/sys/fs/ext2fs/ext2_readwrite.c 2010-01-14 22:30:54.000000000 +0800
+++ src/ext2_readwrite.c 2010-08-22 22:41:52.000000000 +0800
@@ -36,6 +36,9 @@
* $FreeBSD: src/sys/fs/ext2fs/ext2_readwrite.c,v 1.1 2010/01/14 14:30:54 lulf Exp $
*/
+#include <fs/ext2fs/ext2_dinode.h>
+#include <fs/ext2fs/ext2_extents.h>
+
/* XXX TODO: remove these obfuscations (as in ffs_vnops.c). */
#define BLKSIZE(a, b, c) blksize(a, b, c)
#define FS struct m_ext2fs
@@ -45,17 +48,124 @@
#define WRITE ext2_write
#define WRITE_S "ext2_write"
+static int ext4_ext_read(struct vop_read_args *);
+static int ext2_ind_read(struct vop_read_args *);
+
/*
- * Vnode op for reading.
+ * this function handles ext4 extents block mapping
*/
static int
-READ(ap)
- struct vop_read_args /* {
- struct vnode *a_vp;
- struct uio *a_uio;
- int a_ioflag;
- struct ucred *a_cred;
- } */ *ap;
+ext4_ext_read(struct vop_read_args *ap)
+{
+ struct vnode *vp;
+ struct inode *ip;
+ struct uio *uio;
+ struct m_ext2fs *fs;
+ struct buf *bp;
+ struct ext4_extent nex, *ep;
+ struct ext4_extent_header *ehp;
+ struct ext4_extent_path path;
+ daddr_t lbn, nextlbn, newblk = 0;
+ off_t bytesinfile;
+ u_short mode;
+ int cache_type;
+ int orig_resid;
+ int error = 0;
+ int depth = 0;
+ long size, xfersize, blkoffset;
+
+ vp = ap->a_vp;
+ ip = VTOI(vp);
+ mode = ip->i_mode;
+ uio = ap->a_uio;
+ memset(&path, 0, sizeof(path));
+
+ orig_resid = uio->uio_resid;
+ KASSERT(orig_resid >= 0, ("ext2_read: uio->uio_resid < 0"));
+ if (orig_resid == 0)
+ return (0);
+ KASSERT(uio->uio_offset >= 0, ("ext2_read: uio->uio_offset < 0"));
+ fs = ip->I_FS;
+ if (uio->uio_offset < ip->i_size && uio->uio_offset >= fs->e2fs_maxfilesize)
+ return (EOVERFLOW);
+
+ 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 {
+ ext4_ext_find_extent(fs, ip, lbn, &path);
+ depth = ((struct ext4_extent_header *)(ip->i_db))->eh_depth;
+ if (path.ep_ext == NULL && depth != 0)
+ return (EIO);
+
+ ehp = path.ep_header;
+ ep = path.ep_ext;
+ if (ep == NULL)
+ return (EIO);
+
+ ext4_ext_put_cache(ip, ep, EXT4_EXT_CACHE_IN);
+
+ newblk = lbn - ep->e_blk +
+ (ep->e_start_lo | ((daddr_t)(ep->e_start_hi) << 31) << 1);
+
+ if (path.ep_bp != NULL) {
+ brelse(path.ep_bp);
+ path.ep_bp = NULL;
+ }
+ }
+
+ error = bread(ip->i_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);
+
+ return (error);
+}
+
+/*
+ * this function handles traditional block mapping
+ */
+static int
+ext2_ind_read(struct vop_read_args *ap)
{
struct vnode *vp;
struct inode *ip;
@@ -152,6 +262,35 @@
}
/*
+ * Vnode op for reading.
+ */
+static int
+READ(ap)
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ struct vnode *vp;
+ struct inode *ip;
+ int error;
+
+ vp = ap->a_vp;
+ ip = VTOI(vp);
+
+ /*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);*/
+
+ return (error);
+}
+
+/*
* Vnode op for writing.
*/
static int
diff -urN /usr/src/sys/fs/ext2fs/ext2_subr.c src/ext2_subr.c
--- /usr/src/sys/fs/ext2fs/ext2_subr.c 2010-01-14 22:30:54.000000000 +0800
+++ src/ext2_subr.c 2010-08-22 22:41:52.000000000 +0800
@@ -50,6 +50,7 @@
#include <fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/ext2fs.h>
#include <fs/ext2fs/fs.h>
+#include <fs/ext2fs/ext2_extents.h>
#ifdef KDB
void ext2_checkoverlap(struct buf *, struct inode *);
@@ -70,22 +71,57 @@
struct inode *ip;
struct m_ext2fs *fs;
struct buf *bp;
+ struct ext4_extent *ep;
+ struct ext4_extent_header *ehp;
+ struct ext4_extent_path path;
int32_t lbn;
int bsize, error;
+ int depth;
+ daddr_t newblk;
ip = VTOI(vp);
fs = ip->i_e2fs;
lbn = lblkno(fs, offset);
bsize = blksize(fs, ip, lbn);
+ memset(&path, 0, sizeof(path));
*bpp = NULL;
- if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) {
- brelse(bp);
- return (error);
- }
- if (res)
- *res = (char *)bp->b_data + blkoff(fs, offset);
- *bpp = bp;
+ if (ext4_ext_find_extent(fs, ip, lbn, &path) == NULL)
+ goto normal;
+ depth = ((struct ext4_extent_header *)(ip->i_db))->eh_depth;
+ if (path.ep_ext == NULL && depth != 0)
+ goto normal;
+ ehp = path.ep_header;
+ ep = path.ep_ext;
+ if (ep == NULL)
+ goto normal;
+
+ newblk = lbn - ep->e_blk +
+ (ep->e_start_lo | ((daddr_t)(ep->e_start_hi) << 31) << 1);
+
+ if (path.ep_bp != NULL) {
+ brelse(path.ep_bp);
+ path.ep_bp = NULL;
+ }
+ if ((error = bread(ip->i_devvp, fsbtodb(fs, newblk), bsize, NOCRED, &bp)) != 0) {
+ brelse(bp);
+ return (error);
+ }
+ if (res)
+ *res = (char *)bp->b_data + blkoff(fs, offset);
+ *bpp = bp;
+ return (0);
+
+normal:
+ if (*bpp == NULL) {
+ if ((error = bread(vp, lbn, bsize, NOCRED, &bp)) != 0) {
+ brelse(bp);
+ return (error);
+ }
+ if (res)
+ *res = (char *)bp->b_data + blkoff(fs, offset);
+ *bpp = bp;
+ }
return (0);
}
diff -urN /usr/src/sys/fs/ext2fs/ext2_vfsops.c src/ext2_vfsops.c
--- /usr/src/sys/fs/ext2fs/ext2_vfsops.c 2010-01-14 22:30:54.000000000 +0800
+++ src/ext2_vfsops.c 2010-08-22 22:41:52.000000000 +0800
@@ -51,6 +51,9 @@
#include <sys/malloc.h>
#include <sys/stat.h>
#include <sys/mutex.h>
+#include <sys/types.h>
+
+#include <machine/atomic.h>
#include <geom/geom.h>
#include <geom/geom_vfs.h>
@@ -61,6 +64,7 @@
#include <fs/ext2fs/fs.h>
#include <fs/ext2fs/ext2_extern.h>
#include <fs/ext2fs/ext2fs.h>
+#include <fs/ext2fs/ext2_dinode.h>
static int ext2_flushfiles(struct mount *mp, int flags, struct thread *td);
static int ext2_mountfs(struct vnode *, struct mount *);
@@ -288,7 +292,8 @@
return (1);
}
if (es->e2fs_rev > E2FS_REV0) {
- if (es->e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP) {
+ /*if (es->e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP) {*/
+ if (es->e2fs_features_incompat & ~EXT4F_INCOMPAT_SUPP) {
printf(
"WARNING: mount of %s denied due to unsupported optional features\n",
devtoname(dev));
@@ -334,7 +339,6 @@
} else {
fs->e2fs_first_inode = es->e2fs_first_ino;
fs->e2fs_isize = es->e2fs_inode_size;
-
/*
* Simple sanity check for superblock inode size value.
*/
@@ -350,8 +354,9 @@
fs->e2fs_itpg = fs->e2fs_ipg /fs->e2fs_ipb;
fs->e2fs_descpb = fs->e2fs_bsize / sizeof (struct ext2_gd);
/* s_resuid / s_resgid ? */
- fs->e2fs_gcount = (es->e2fs_bcount - es->e2fs_first_dblock +
- EXT2_BLOCKS_PER_GROUP(fs) - 1) / EXT2_BLOCKS_PER_GROUP(fs);
+ fs->e2fs_gcount = (((int64_t)(es->e2fs_bcount_hi) << 32 | es->e2fs_bcount_lo)
+ - es->e2fs_first_dblock + EXT2_BLOCKS_PER_GROUP(fs) - 1) /
+ EXT2_BLOCKS_PER_GROUP(fs);
db_count = (fs->e2fs_gcount + EXT2_DESC_PER_BLOCK(fs) - 1) /
EXT2_DESC_PER_BLOCK(fs);
fs->e2fs_gdbcount = db_count;
@@ -383,9 +388,10 @@
brelse(bp);
bp = NULL;
}
+
fs->e2fs_total_dir = 0;
for (i=0; i < fs->e2fs_gcount; i++){
- fs->e2fs_total_dir += fs->e2fs_gd[i].ext2bgd_ndirs;
+ fs->e2fs_total_dir += (fs->e2fs_gd[i].ext2bgd_ndirs_lo);
fs->e2fs_contigdirs[i] = 0;
}
if (es->e2fs_rev == E2FS_REV0 ||
@@ -393,6 +399,25 @@
fs->e2fs_maxfilesize = 0x7fffffff;
else
fs->e2fs_maxfilesize = 0x7fffffffffffffff;
+
+ /* check inode size */
+ if (fs->e2fs_isize > E2FS_REV0_INODE_SIZE) {
+ fs->e2fs_want_extra_isize = sizeof(struct ext2fs_dinode) -
+ E2FS_REV0_INODE_SIZE;
+
+ if (es->e2fs_features_rocompat & EXT4F_ROCOMPAT_EXTRA_ISIZE) {
+ if (fs->e2fs_want_extra_isize < es->e2fs_want_extra_isize)
+ fs->e2fs_want_extra_isize = es->e2fs_want_extra_isize;
+ if (fs->e2fs_want_extra_isize < es->e2fs_min_extra_isize)
+ fs->e2fs_want_extra_isize = es->e2fs_min_extra_isize;
+ }
+ }
+
+ if (E2FS_REV0_INODE_SIZE + fs->e2fs_want_extra_isize >
+ fs->e2fs_isize)
+ printf("EXT2-fs: no space for extra inode.\n");
+
+
return (0);
}
@@ -745,9 +770,12 @@
sbp->f_bsize = EXT2_FRAG_SIZE(fs);
sbp->f_iosize = EXT2_BLOCK_SIZE(fs);
- sbp->f_blocks = fs->e2fs->e2fs_bcount - overhead;
- sbp->f_bfree = fs->e2fs->e2fs_fbcount;
- sbp->f_bavail = sbp->f_bfree - fs->e2fs->e2fs_rbcount;
+ sbp->f_blocks = ((int64_t)(fs->e2fs->e2fs_bcount_hi) << 32 |
+ fs->e2fs->e2fs_bcount_lo) - overhead;
+ sbp->f_bfree = ((int64_t)(fs->e2fs->e2fs_fbcount_hi) << 32 |
+ fs->e2fs->e2fs_fbcount_lo);
+ sbp->f_bavail = sbp->f_bfree - ((int64_t)(fs->e2fs->e2fs_rbcount_hi) << 32 |
+ fs->e2fs->e2fs_rbcount_lo);
sbp->f_files = fs->e2fs->e2fs_icount;
sbp->f_ffree = fs->e2fs->e2fs_ficount;
return (0);
@@ -853,8 +881,8 @@
struct vnode *vp;
struct cdev *dev;
struct thread *td;
- int i, error;
- int used_blocks;
+ int error;
+ int i, used_blocks;
td = curthread;
error = vfs_hash_get(mp, ino, flags, td, vpp, NULL, NULL);
@@ -910,6 +938,7 @@
*vpp = NULL;
return (error);
}
+
/* convert ext2 inode to dinode */
ext2_ei2i((struct ext2fs_dinode *) ((char *)bp->b_data + EXT2_INODE_SIZE(fs) *
ino_to_fsbo(fs, ino)), ip);
@@ -919,19 +948,31 @@
ip->i_prealloc_count = 0;
ip->i_prealloc_block = 0;
+ /* initialize ext lock */
+ bzero(&ip->i_ext_lock, sizeof(struct mtx));
+ mtx_init(&ip->i_ext_lock, "inode ext lock", NULL, MTX_DEF);
+
/*
* Now we want to make sure that block pointers for unused
* blocks are zeroed out - ext2_balloc depends on this
* although for regular files and directories only
*/
- if(S_ISDIR(ip->i_mode) || S_ISREG(ip->i_mode)) {
- used_blocks = (ip->i_size+fs->e2fs_bsize-1) / fs->e2fs_bsize;
- for(i = used_blocks; i < EXT2_NDIR_BLOCKS; i++)
- ip->i_db[i] = 0;
- }
-/*
- ext2_print_inode(ip);
-*/
+
+ /*
+ * NOTE: When ext4 file system use extents, we don't zero
+ * block pointers.
+ */
+ if (!(fs->e2fs->e2fs_features_incompat & EXT4F_INCOMPAT_EXTENTS)) {
+ if(S_ISDIR(ip->i_mode) || S_ISREG(ip->i_mode)) {
+ used_blocks = (ip->i_size+fs->e2fs_bsize-1) / fs->e2fs_bsize;
+ for(i = used_blocks; i < EXT2_NDIR_BLOCKS; i++)
+ ip->i_db[i] = 0;
+ }
+ }
+
+
+ /*ext2_print_inode(ip);*/
+
bqrelse(bp);
/*
diff -urN /usr/src/sys/fs/ext2fs/ext2_vnops.c src/ext2_vnops.c
--- /usr/src/sys/fs/ext2fs/ext2_vnops.c 2010-02-20 18:19:19.000000000 +0800
+++ src/ext2_vnops.c 2010-08-22 22:41:52.000000000 +0800
@@ -1419,7 +1419,7 @@
struct vnode *vp = ap->a_vp;
struct inode *ip;
struct bufobj *bo;
- int32_t blkno;
+ int64_t blkno;
int error;
ip = VTOI(vp);
diff -urN /usr/src/sys/fs/ext2fs/ext2fs.h src/ext2fs.h
--- /usr/src/sys/fs/ext2fs/ext2fs.h 2010-01-14 22:30:54.000000000 +0800
+++ src/ext2fs.h 2010-08-22 22:50:30.000000000 +0800
@@ -38,6 +38,7 @@
#define _FS_EXT2FS_EXT2_FS_H
#include <sys/types.h>
+#include <sys/lock.h>
/*
* Special inode numbers
@@ -71,7 +72,7 @@
/*
* Maximal count of links to a file
*/
-#define EXT2_LINK_MAX 32000
+#define EXT2_LINK_MAX 65000
/*
* Constants relative to the data blocks
@@ -95,9 +96,9 @@
*/
struct ext2fs {
u_int32_t e2fs_icount; /* Inode count */
- u_int32_t e2fs_bcount; /* blocks count */
- u_int32_t e2fs_rbcount; /* reserved blocks count */
- u_int32_t e2fs_fbcount; /* free blocks count */
+ u_int32_t e2fs_bcount_lo; /* blocks count */
+ u_int32_t e2fs_rbcount_lo; /* reserved blocks count */
+ u_int32_t e2fs_fbcount_lo; /* free blocks count */
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) */
@@ -130,8 +131,36 @@
char e2fs_vname[16]; /* volume name */
char e2fs_fsmnt[64]; /* name mounted on */
u_int32_t e2fs_algo; /* For comcate for dir */
- u_int16_t e2fs_reserved_ngdb; /* # of reserved gd blocks for resize */
- u_int32_t reserved2[204];
+ u_int8_t e2fs_prealloc_blk; /* number of blocks to try to preallocate */
+ u_int8_t e2fs_prealloc_dblk; /* number of dirs to preallocate */
+ u_int16_t e2fs_reserved_ngdb; /* # of reserved gd blocks for resize */
+ u_int8_t e2fs_journal_uuid[16]; /* uuid of journal superblock */
+ u_int32_t e2fs_journal_inum; /* inode number of journal file */
+ u_int32_t e2fs_journal_dev; /* device number of journal file */
+ u_int32_t e2fs_last_orphan; /* start of list of inodes to delete */
+ u_int32_t e2fs_hash_seed[4]; /* HTREE hash seed */
+ u_int8_t e2fs_def_hash_ver; /* default hash version to use */
+ u_int8_t e2fs_char_pad;
+ u_int16_t e2fs_desc_size; /* size of group descriptor */
+ u_int32_t e2fs_def_mnt_opts;
+ u_int32_t e2fs_first_meta_bg; /* first metablock block group */
+ u_int32_t e2fs_mkfs_time; /* when the fs was created */
+ u_int32_t e2fs_jnl_blks[17]; /* backup of the journal inode */
+ u_int32_t e2fs_bcount_hi; /* block count */
+ u_int32_t e2fs_rbcount_hi; /* reserved blocks count */
+ u_int32_t e2fs_fbcount_hi; /* free blocks count */
+ u_int16_t e2fs_min_extra_isize;/* all inodes have at least some bytes */
+ u_int16_t e2fs_want_extra_isize; /* new inodes should reserve some bytes */
+ u_int32_t e2fs_flags; /* miscellaneous flags */
+ u_int16_t e2fs_raid_stride; /* RAID stride */
+ u_int16_t e2fs_mmpintv; /* number of seconds to wait in MMP checking */
+ u_int64_t e2fs_mmpblk; /* block for multi-mount protection */
+ u_int32_t e2fs_raid_stripe_wid;/* blocks on all data disks (N * stride) */
+ u_int8_t e2fs_log_gpf; /* FLEX_BG group size */
+ u_int8_t e2fs_char_pad2;
+ u_int16_t e2fs_pad;
+ u_int64_t e2fs_kbytes_written; /* number of lifetime kilobytes written */
+ u_int32_t reserved2[160];
};
@@ -173,7 +202,10 @@
uint8_t *e2fs_contigdirs;
char e2fs_wasvalid; /* valid at mount time */
off_t e2fs_maxfilesize;
- struct ext2_gd *e2fs_gd; /* Group Descriptors */
+ struct ext2_gd *e2fs_gd; /* Group Descriptors */
+
+ u_int16_t e2fs_min_extra_isize; /* all inodes have at least some bytes */
+ u_int16_t e2fs_want_extra_isize; /* new inodes should reserve some bytes */
};
/*
@@ -198,13 +230,28 @@
*/
#define EXT2F_COMPAT_PREALLOC 0x0001
#define EXT2F_COMPAT_RESIZE 0x0010
+#define EXT4F_COMPAT_IMAGIC_INODES 0x0002
+#define EXT4F_COMPAT_HAS_JOURNAL 0x0004
+#define EXT4F_COMPAT_EXT_ATTR 0x0008
+#define EXT4F_COMPAT_DIR_INDEX 0x0020
#define EXT2F_ROCOMPAT_SPARSESUPER 0x0001
#define EXT2F_ROCOMPAT_LARGEFILE 0x0002
#define EXT2F_ROCOMPAT_BTREE_DIR 0x0004
+#define EXT4F_ROCOMPAT_HUGE_FILE 0x0008
+#define EXT4F_ROCOMPAT_GDT_CSUM 0x0010
+#define EXT4F_ROCOMPAT_DIR_NLINK 0x0020
+#define EXT4F_ROCOMPAT_EXTRA_ISIZE 0x0040
#define EXT2F_INCOMPAT_COMP 0x0001
#define EXT2F_INCOMPAT_FTYPE 0x0002
+#define EXT4F_INCOMPAT_RECOVER 0x0004
+#define EXT4F_INCOMPAT_JOURNAL_DEV 0x0008
+#define EXT4F_INCOMPAT_META_BG 0x0010
+#define EXT4F_INCOMPAT_EXTENTS 0x0040
+#define EXT4F_INCOMPAT_64BIT 0x0080
+#define EXT4F_INCOMPAT_MMP 0x0100
+#define EXT4F_INCOMPAT_FLEX_BG 0x0200
/*
* Features supported in this implementation
@@ -220,6 +267,20 @@
#define EXT2F_INCOMPAT_SUPP EXT2F_INCOMPAT_FTYPE
/*
+ * Features supported in ext4 read-only mode
+ */
+#define EXT4F_INCOMPAT_SUPP (EXT2F_INCOMPAT_FTYPE \
+ | EXT4F_INCOMPAT_EXTENTS \
+ | EXT4F_INCOMPAT_FLEX_BG)
+#define EXT4F_ROCOMPAT_SUPP (EXT2F_ROCOMPAT_SPARSESUPER \
+ | EXT2F_ROCOMPAT_LARGEFILE \
+ | EXT2F_ROCOMPAT_BTREE_DIR \
+ | EXT4F_ROCOMPAT_GDT_CSUM \
+ | EXT4F_ROCOMPAT_DIR_NLINK \
+ | EXT4F_ROCOMPAT_EXTRA_ISIZE \
+ | EXT4F_ROCOMPAT_HUGE_FILE)
+
+/*
* Feature set definitions
*/
#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
@@ -255,14 +316,26 @@
/* ext2 file system block group descriptor */
struct ext2_gd {
- u_int32_t ext2bgd_b_bitmap; /* blocks bitmap block */
- u_int32_t ext2bgd_i_bitmap; /* inodes bitmap block */
- u_int32_t ext2bgd_i_tables; /* inodes table block */
- u_int16_t ext2bgd_nbfree; /* number of free blocks */
- u_int16_t ext2bgd_nifree; /* number of free inodes */
- u_int16_t ext2bgd_ndirs; /* number of directories */
- u_int16_t reserved;
- u_int32_t reserved2[3];
+ u_int32_t ext2bgd_b_bitmap_lo; /* blocks bitmap block */
+ u_int32_t ext2bgd_i_bitmap_lo; /* inodes bitmap block */
+ u_int32_t ext2bgd_i_tables_lo; /* inodes table block */
+ u_int16_t ext2bgd_nbfree_lo; /* number of free blocks */
+ u_int16_t ext2bgd_nifree_lo; /* number of free inodes */
+ u_int16_t ext2bgd_ndirs_lo; /* number of directories */
+ u_int16_t ext2bgd_flags; /* EXT4_BG_flags */
+#if 0
+ u_int32_t reserved[2];
+ u_int16_t ext2bgd_i_tables_unused_lo; /* number of unused inodes */
+ u_int16_t ext2bgd_chksum; /* crc16 checksum */
+ u_int32_t ext2bgd_b_bitmap_hi; /* blocks bitmap block MSB */
+ u_int32_t ext2bgd_i_bitmap_hi; /* inodes bitmap block MSB */
+ u_int32_t ext2bgd_i_tables_hi; /* inodes table block MSB */
+ u_int16_t ext2bgd_nbfree_hi; /* number of free blocks MSB */
+ u_int16_t ext2bgd_nifree_hi; /* number of free inodes MSB */
+ u_int16_t ext2bgd_ndirs_hi; /* number of directories MSB */
+ u_int16_t ext2bgd_i_tables_unused_hi; /* number of unused inodes MSB */
+#endif
+ u_int32_t reserved2[3];
};
/* EXT2FS metadatas are stored in little-endian byte order. These macros
@@ -275,7 +348,7 @@
* Macro-instructions used to manage several block sizes
*/
#define EXT2_MIN_BLOCK_SIZE 1024
-#define EXT2_MAX_BLOCK_SIZE 4096
+#define EXT2_MAX_BLOCK_SIZE 65536
#define EXT2_MIN_BLOCK_LOG_SIZE 10
#if defined(_KERNEL)
# define EXT2_BLOCK_SIZE(s) ((s)->e2fs_bsize)
diff -urN /usr/src/sys/fs/ext2fs/fs.h src/fs.h
--- /usr/src/sys/fs/ext2fs/fs.h 2010-01-14 22:30:54.000000000 +0800
+++ src/fs.h 2010-08-22 22:41:52.000000000 +0800
@@ -93,7 +93,7 @@
/* get block containing inode from its number x */
#define ino_to_fsba(fs, x) \
- ((fs)->e2fs_gd[ino_to_cg((fs), (x))].ext2bgd_i_tables + \
+ ((fs)->e2fs_gd[ino_to_cg((fs), (x))].ext2bgd_i_tables_lo + \
(((x) - 1) % (fs)->e2fs->e2fs_ipg) / (fs)->e2fs_ipb)
/* get offset for inode in block */
diff -urN /usr/src/sys/fs/ext2fs/inode.h src/inode.h
--- /usr/src/sys/fs/ext2fs/inode.h 2010-01-14 22:30:54.000000000 +0800
+++ src/inode.h 2010-08-22 22:41:52.000000000 +0800
@@ -38,9 +38,13 @@
#ifndef _FS_EXT2FS_INODE_H_
#define _FS_EXT2FS_INODE_H_
+#include <sys/param.h>
#include <sys/lock.h>
+#include <sys/mutex.h>
#include <sys/queue.h>
+#include <fs/ext2fs/ext2_extents.h>
+
#define ROOTINO ((ino_t)2)
#define NDADDR 12 /* Direct addresses in inode. */
@@ -85,7 +89,7 @@
/* Fields from struct dinode in UFS. */
u_int16_t i_mode; /* IFMT, permissions; see below. */
- int16_t i_nlink; /* File link count. */
+ u_int16_t i_nlink; /* File link count. */
u_int64_t i_size; /* File byte count. */
int32_t i_atime; /* Last access time. */
int32_t i_atimensec; /* Last access time. */
@@ -96,10 +100,15 @@
int32_t i_db[NDADDR]; /* Direct disk blocks. */
int32_t i_ib[NIADDR]; /* Indirect disk blocks. */
u_int32_t i_flags; /* Status flags (chflags). */
- int32_t i_blocks; /* Blocks actually held. */
+ int64_t i_blocks; /* Blocks actually held. */
int32_t i_gen; /* Generation number. */
u_int32_t i_uid; /* File owner. */
u_int32_t i_gid; /* File group. */
+
+ /* ext4 extents support */
+ struct mtx i_ext_lock; /* this lock only is required in read/write mode
+ but we still use it in read-only mode. */
+ struct ext4_extent_cache i_ext_cache; /* cache for ext4 extent */
};
/*
--------------000709010802090406030102--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4C71075C.9010802>
