kern/153584: Performance fix and cleanups for BSD licensed ext2fs

Pedro F. Giffuni giffunip at tutopia.com
Fri Dec 31 16:00:25 UTC 2010


>Number:         153584
>Category:       kern
>Synopsis:       Performance fix and cleanups for BSD licensed ext2fs
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Fri Dec 31 16:00:24 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator:     Pedro F. Giffuni
>Release:        8.2-BETA1
>Organization:
>Environment:
Non-relevant: I added the BSD-licensed ext2fs to my 8.2 kernel (i386)
>Description:
Since the adoption of the BSD licensed ext2fs implementation, a performance decrease was observed.
Bruce Evans found the source for some of the problems:
http://lists.freebsd.org/pipermail/freebsd-fs/2010-September/009589.html

In addition to these, some merges from UFS1 have been backported and some style issues have been fixed. See PR 142924 and 143345 for the details.

This patch include bde's fixes and applies the basic cleanups from the previous PRs.

It also adds back the async mount option as it is operational after the initial BSD licensed backporting: this has been tested as part of the recent GSoC project.
>How-To-Repeat:

>Fix:
Patch follows.

Patch attached with submission follows:

diff -ru ext2fs.orig/ext2_alloc.c ext2fs/ext2_alloc.c
--- ext2fs.orig/ext2_alloc.c	2010-12-29 15:14:06.000000000 +0000
+++ ext2fs/ext2_alloc.c	2010-12-31 10:04:27.000000000 +0000
@@ -59,6 +59,10 @@
 						int));
 static daddr_t	ext2_nodealloccg(struct inode *, int, daddr_t, int);
 static daddr_t  ext2_mapsearch(struct m_ext2fs *, char *, daddr_t);
+#ifdef FANCY_REALLOC
+static int	ext2_reallocblks(struct vop_reallocblks_args *);
+#endif
+
 /*
  * Allocate a block in the file system.
  *
@@ -76,7 +80,6 @@
  *   2) quadradically rehash into other cylinder groups, until an
  *        available block is located.
  */
-
 int
 ext2_alloc(ip, lbn, bpref, size, cred, bnp)
 	struct inode *ip;
@@ -116,6 +119,10 @@
         bno = (daddr_t)ext2_hashalloc(ip, cg, bpref, fs->e2fs_bsize,
                                                  ext2_alloccg);
         if (bno > 0) {
+		/* set next_alloc fields as done in block_getblk */
+		ip->i_next_alloc_block = lbn;
+		ip->i_next_alloc_goal = bno;
+
                 ip->i_blocks += btodb(fs->e2fs_bsize);
                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
                 *bnp = bno;
@@ -144,9 +151,13 @@
  */
 
 #ifdef FANCY_REALLOC
-#include <sys/sysctl.h>
+SYSCTL_NODE(_vfs, OID_AUTO, ext2, CTLFLAG_RW, 0, "EXT2FS filesystem");
+
 static int doasyncfree = 1;
+SYSCTL_INT(_vfs_ext2, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, "");
+
 static int doreallocblks = 1;
+SYSCTL_INT(_vfs_ext2s, OID_AUTO, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, "");
 
 #ifdef	OPT_DEBUG
 SYSCTL_INT(_debug, 14, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, "");
@@ -173,7 +184,7 @@
 	struct ext2mount *ump;
 	struct cluster_save *buflist;
 	struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
-	int32_t start_lbn, end_lbn, soff, newblk, blkno =0;
+	int32_t start_lbn, end_lbn, soff, newblk, blkno;
 	int i, len, start_lvl, end_lvl, pref, ssize;
 
 	vp = ap->a_vp;
@@ -223,7 +234,7 @@
 	 * Find the preferred location for the cluster.
 	 */
 	EXT2_LOCK(ump); 
-	pref = ext2_blkpref(ip, start_lbn, soff, sbap, blkno);
+	pref = ext2_blkpref(ip, start_lbn, soff, sbap, blkno=0);
 	/*
 	 * If the block range spans two block maps, get the second map.
 	 */
@@ -625,7 +636,7 @@
 	struct m_ext2fs *fs;
 	struct buf *bp;
 	struct ext2mount *ump;
-	int error, bno, start, end, loc;
+	int error, bno;
 	char *bbp;
 	/* XXX ondisk32 */
 	fs = ip->i_e2fs;
@@ -658,26 +669,7 @@
 	/*
 	 * no blocks in the requested cylinder, so take next
 	 * available one in this cylinder group.
-	 * first try to get 8 contigous blocks, then fall back to a single
-	 * block.
 	 */
-	if (bpref)
-		start = dtogd(fs, bpref) / NBBY;
-	else
-		start = 0;
-	end = howmany(fs->e2fs->e2fs_fpg, NBBY) - start;
-	for (loc = start; loc < end; loc++) {
-		if (bbp[loc] == 0) {
-			bno = loc * NBBY;
-			goto gotit;
-		}
-	}
-	for (loc = 0; loc < start; loc++) {
-		if (bbp[loc] == 0) {
-			bno = loc * NBBY;
-			goto gotit;
-		}
-	}
 
 	bno = ext2_mapsearch(fs, bbp, bpref);
 	if (bno < 0){
diff -ru ext2fs.orig/ext2_dinode.h ext2fs/ext2_dinode.h
--- ext2fs.orig/ext2_dinode.h	2010-12-29 15:14:23.000000000 +0000
+++ ext2fs/ext2_dinode.h	2010-12-30 23:18:21.000000000 +0000
@@ -32,6 +32,18 @@
 #define e2di_size_high	e2di_dacl
 
 /*
+ * Special inode numbers
+ * The root inode is the root of the file system.  Inode 0 can't be used for
+ * normal purposes and bad blocks are normally linked to inode 1, thus
+ * the root inode is 2.
+ * Inode 3 to 10 are reserved in ext2fs.
+ */
+#define EXT2_BAD_INO		 1	/* Bad blocks inode */
+#define EXT2_ROOT_INO		 2	/* Root inode */
+#define EXT2_BOOT_LOADER_INO	 5	/* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO	 6	/* Undelete directory inode */
+
+/*
  * Inode flags
  * The current implementation uses only EXT2_IMMUTABLE and EXT2_APPEND flags
  */
@@ -74,5 +86,5 @@
 	u_int32_t	e2di_linux_reserved3; /* 124 */
 };
 
-#endif /* _FS_EXT2FS_EXT2_DINODE_H_ */
+#endif /* !_FS_EXT2FS_EXT2_DINODE_H_ */
 
diff -ru ext2fs.orig/ext2_lookup.c ext2fs/ext2_lookup.c
--- ext2fs.orig/ext2_lookup.c	2010-12-29 15:14:51.000000000 +0000
+++ ext2fs/ext2_lookup.c	2010-12-30 23:16:06.000000000 +0000
@@ -347,6 +347,7 @@
 		slotneeded = (sizeof(struct direct) - MAXNAMLEN +
 			cnp->cn_namelen + 3) &~ 3; */
 	}
+	bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
 
 	/*
 	 * If there is cached information on a previous search of
@@ -359,7 +360,6 @@
 	 * profiling time and hence has been removed in the interest
 	 * of simplicity.
 	 */
-	bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1;
 	if (nameiop != LOOKUP || i_diroff == 0 ||
 	    i_diroff > dp->i_size) {
 		entryoffsetinblock = 0;
diff -ru ext2fs.orig/ext2_vfsops.c ext2fs/ext2_vfsops.c
--- ext2fs.orig/ext2_vfsops.c	2010-12-29 15:15:11.000000000 +0000
+++ ext2fs/ext2_vfsops.c	2010-12-31 10:01:28.000000000 +0000
@@ -95,9 +95,9 @@
 static int	compute_sb_data(struct vnode * devvp,
 		    struct ext2fs * es, struct m_ext2fs * fs);
 
-static const char *ext2_opts[] = { "from", "export", "acls", "noexec",
-    "noatime", "union", "suiddir", "multilabel", "nosymfollow",
-    "noclusterr", "noclusterw", "force", NULL };
+static const char *ext2_opts[] = { "acls", "async", "noatime", "noclusterr", 
+    "noclusterw", "noexec", "export", "force", "from", "multilabel",
+    "suiddir", "nosymfollow", "sync", "union", NULL };
 
 /*
  * VFS Operations.
@@ -945,9 +945,8 @@
 	}
 
 	/*
-	 * Finish inode initialization now that aliasing has been resolved.
+	 * Finish inode initialization.
 	 */
-	ip->i_devvp = ump->um_devvp;
 
 	/*
 	 * Set up a generation number for this inode if it does not
diff -ru ext2fs.orig/ext2fs.h ext2fs/ext2fs.h
--- ext2fs.orig/ext2fs.h	2010-12-29 15:15:21.000000000 +0000
+++ ext2fs/ext2fs.h	2010-12-30 23:18:21.000000000 +0000
@@ -39,22 +39,6 @@
 
 #include <sys/types.h>
 
-/*
- * Special inode numbers
- */
-#define	EXT2_BAD_INO		 1	/* Bad blocks inode */
-#define EXT2_ROOT_INO		 2	/* Root inode */
-#define EXT2_BOOT_LOADER_INO	 5	/* Boot loader inode */
-#define EXT2_UNDEL_DIR_INO	 6	/* Undelete directory inode */
-
-/* First non-reserved inode for old ext2 filesystems */
-#define E2FS_REV0_FIRST_INO	11
-
-/*
- * The second extended file system magic number
- */
-#define E2FS_MAGIC		0xEF53
-
 #if defined(_KERNEL)
 /*
  * FreeBSD passes the pointer to the in-core struct with relevant
@@ -129,7 +113,9 @@
 	u_int8_t   e2fs_uuid[16];	/* 128-bit uuid for volume */
 	char       e2fs_vname[16];	/* volume name */
 	char       e2fs_fsmnt[64]; 	/* name mounted on */
-	u_int32_t  e2fs_algo;		/* For comcate for dir */
+	u_int32_t  e2fs_algo;		/* for compression */
+	uint8_t	   e2fs_prealloc;	/* # of blocks to preallocate */
+	uint8_t	   e2fs_dir_prealloc;	/* # of blocks to preallocate for dir */
 	u_int16_t  e2fs_reserved_ngdb; /* # of reserved gd blocks for resize */
 	u_int32_t  reserved2[204];
 };
@@ -153,8 +139,8 @@
 	uint32_t e2fs_bshift;     /* calc of logical block no */
 	int32_t e2fs_bmask;       /* calc of block offset */
 	int32_t e2fs_bpg;         /* Number of blocks per group */
-	int64_t e2fs_qbmask;       /* = s_blocksize -1 */
-	uint32_t e2fs_fsbtodb;     /* Shift to get disk block */
+	int64_t e2fs_qbmask;      /* = s_blocksize -1 */
+	uint32_t e2fs_fsbtodb;    /* Shift to get disk block */
 	uint32_t e2fs_ipg;        /* Number of inodes per group */
 	uint32_t e2fs_ipb;        /* Number of inodes per block */
 	uint32_t e2fs_itpg;       /* Number of inode table per group */
@@ -169,8 +155,8 @@
 	int32_t  e2fs_isize;      /* Size of inode */
 	uint32_t e2fs_mount_opt;
 	uint32_t e2fs_blocksize_bits;
+	uint8_t	*e2fs_contigdirs; /* (u) # of contig. allocated dirs */
 	uint32_t e2fs_total_dir;  /* Total number of directories */
-	uint8_t	*e2fs_contigdirs;
 	char e2fs_wasvalid;       /* valid at mount time */
 	off_t e2fs_maxfilesize;
 	struct ext2_gd *e2fs_gd; /* Group Descriptors */
@@ -182,6 +168,14 @@
 #define E2FS_DATE		"95/08/09"
 #define E2FS_VERSION		"0.5b"
 
+/* First non-reserved inode for old ext2 filesystems */
+#define E2FS_REV0_FIRST_INO	11
+
+/*
+ * The second extended file system magic number
+ */
+#define E2FS_MAGIC		0xEF53
+
 /*
  * Revision levels
  */
@@ -197,6 +191,7 @@
  * compatible/incompatible features
  */
 #define EXT2F_COMPAT_PREALLOC		0x0001
+#define EXT2F_COMPAT_HASJOURNAL		0x0004
 #define EXT2F_COMPAT_RESIZE		0x0010
 
 #define EXT2F_ROCOMPAT_SPARSESUPER	0x0001
@@ -326,4 +321,4 @@
 
 #endif
 
-#endif	/* _LINUX_EXT2_FS_H */
+#endif	/* !_FS_EXT2FS_EXT2FS_H */
diff -ru ext2fs.orig/inode.h ext2fs/inode.h
--- ext2fs.orig/inode.h	2010-12-29 15:15:30.000000000 +0000
+++ ext2fs/inode.h	2010-12-30 23:16:06.000000000 +0000
@@ -62,7 +62,6 @@
  */
 struct inode {
 	struct	vnode  *i_vnode;/* Vnode associated with this inode. */
-	struct	vnode  *i_devvp;/* Vnode for block I/O. */
 	struct	ext2mount *i_ump;
 	u_int32_t i_flag;	/* flags, see below */
 	ino_t	  i_number;	/* The identity of the inode. */
@@ -143,6 +142,9 @@
 #define	IN_SPACECOUNTED	0x0080		/* Blocks to be freed in free count. */
 #define IN_LAZYACCESS   0x0100		/* Process IN_ACCESS after the
 					    suspension finished */
+
+#define i_devvp i_ump->um_devvp
+
 #ifdef _KERNEL
 /*
  * Structure used to pass around logical block paths generated by


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list