Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 15 Mar 2011 20:17:11 +0800
From:      gnehzuil <gnehzuil@gmail.com>
To:        freebsd-fs@freebsd.org
Cc:        "Pedro F. Giffuni" <giffunip@yahoo.com>
Subject:   [ext2fs][patch] reallocblks
Message-ID:  <4D7F58C7.4060402@gmail.com>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------040509040101080104050601
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Hi there,

I have implemented reallocblks in ext2fs. I added some structures in 
m_ext2fs to record cluster summary information due to group descriptor 
has not a structure to record these data in disk. So I implemented it in 
memory. The implementation is almost the same to in ffs.

I have done some simple benchmarks with dbench. This patch can improve 
the performance a little.

Best regards,
lz

--------------040509040101080104050601
Content-Type: text/x-patch;
 name="patch-realloc.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="patch-realloc.diff"

diff -u ext2fs/ext2_alloc.c ext2fs_realloc/ext2_alloc.c
--- ext2fs/ext2_alloc.c	2011-03-15 19:57:35.000000000 +0000
+++ ext2fs_realloc/ext2_alloc.c	2011-03-15 19:53:56.000000000 +0000
@@ -42,6 +42,7 @@
 #include <sys/vnode.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
+#include <sys/sysctl.h>
 #include <sys/syslog.h>
 #include <sys/buf.h>
 
@@ -52,6 +53,7 @@
 #include <fs/ext2fs/ext2_extern.h>
 
 static daddr_t	ext2_alloccg(struct inode *, int, daddr_t, int);
+static daddr_t	ext2_clusteralloc(struct inode *, int, daddr_t, int);
 static u_long	ext2_dirpref(struct inode *);
 static void	ext2_fserr(struct m_ext2fs *, uid_t, char *);
 static u_long	ext2_hashalloc(struct inode *, int, long, int,
@@ -59,9 +61,6 @@
 						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.
@@ -150,7 +149,6 @@
  * the previous block allocation will be used.
  */
 
-#ifdef FANCY_REALLOC
 SYSCTL_NODE(_vfs, OID_AUTO, ext2fs, CTLFLAG_RW, 0, "EXT2FS filesystem");
 
 static int doasyncfree = 1;
@@ -159,7 +157,6 @@
 
 static int doreallocblks = 1;
 SYSCTL_INT(_vfs_ext2fs, OID_AUTO, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, "");
-#endif
 
 int
 ext2_reallocblks(ap)
@@ -168,11 +165,6 @@
 		struct cluster_save *a_buflist;
 	} */ *ap;
 {
-#ifndef FANCY_REALLOC
-/* printf("ext2_reallocblks not implemented\n"); */
-return ENOSPC;
-#else
-
 	struct m_ext2fs *fs;
 	struct inode *ip;
 	struct vnode *vp;
@@ -181,17 +173,19 @@
 	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;
 	ip = VTOI(vp);
 	fs = ip->i_e2fs;
 	ump = ip->i_ump;
-#ifdef UNKLAR
-	if (fs->fs_contigsumsize <= 0)
+
+	if (doreallocblks == 0)
 		return (ENOSPC);
-#endif
+	if (fs->e2fs_contigsumsize <= 0)
+		return (ENOSPC);
+
 	buflist = ap->a_buflist;
 	len = buflist->bs_nchildren;
 	start_lbn = buflist->bs_children[0]->b_lblkno;
@@ -228,11 +222,6 @@
 		soff = idp->in_off;
 	}
 	/*
-	 * Find the preferred location for the cluster.
-	 */
-	EXT2_LOCK(ump);
-	pref = ext2_blkpref(ip, start_lbn, soff, sbap, blkno);
-	/*
 	 * If the block range spans two block maps, get the second map.
 	 */
 	if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) {
@@ -243,13 +232,16 @@
 			panic("ext2_reallocblk: start == end");
 #endif
 		ssize = len - (idp->in_off + 1);
-		if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &ebp)){
-			EXT2_UNLOCK(ump);	
+		if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &ebp))
 			goto fail;
-		}
 		ebap = (int32_t *)ebp->b_data;
 	}
 	/*
+	 * Find the preferred location for the cluster.
+	 */
+	EXT2_LOCK(ump);
+	pref = ext2_blkpref(ip, start_lbn, soff, sbap, 0);
+	/*
 	 * Search the block map looking for an allocation of the desired size.
 	 */
 	if ((newblk = (int32_t)ext2_hashalloc(ip, dtog(fs, pref), pref,
@@ -264,15 +256,23 @@
 	 * block pointers in the inode and indirect blocks associated
 	 * with the file.
 	 */
+#ifdef DEBUG
+	printf("realloc: ino %d, lbns %jd-%jd\n\told:", ip->i_number,
+	    (intmax_t)start_lbn, (intmax_t)end_lbn);
+#endif /* DEBUG */
 	blkno = newblk;
 	for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->e2fs_fpb) {
-		if (i == ssize)
+		if (i == ssize) {
 			bap = ebap;
 			soff = -i;
+		}
 #ifdef DIAGNOSTIC
 		if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap))
 			panic("ext2_reallocblks: alloc mismatch");
 #endif
+#ifdef DEBUG
+	printf(" %d,", *bap);
+#endif /* DEBUG */
 		*bap++ = blkno;
 	}
 	/*
@@ -308,11 +308,20 @@
 	/*
 	 * Last, free the old blocks and assign the new blocks to the buffers.
 	 */
+#ifdef DEBUG
+	printf("\n\tnew:");
+#endif /* DEBUG */
 	for (blkno = newblk, i = 0; i < len; i++, blkno += fs->e2fs_fpb) {
 		ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno),
 		    fs->e2fs_bsize);
 		buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
-	}
+#ifdef DEBUG
+		printf(" %d,", blkno);
+#endif /* DEBUG */
+	}
+#ifdef DEBUG
+	printf("\n");
+#endif /* DEBUG */
 	return (0);
 
 fail:
@@ -321,8 +330,6 @@
 	if (sbap != &ip->i_db[0])
 		brelse(sbp);
 	return (ENOSPC);
-
-#endif /* FANCY_REALLOC */
 }
 
 /*
@@ -747,6 +754,7 @@
 #endif
 	setbit(bbp, bno);
 	EXT2_LOCK(ump);
+	ext2_clusteracct(fs, bbp, cg, bno, -1);
 	fs->e2fs->e2fs_fbcount--;
 	fs->e2fs_gd[cg].ext2bgd_nbfree--;
 	fs->e2fs_fmod = 1;
@@ -755,6 +763,113 @@
 	return (cg * fs->e2fs->e2fs_fpg + fs->e2fs->e2fs_first_dblock + bno);
 }
 
+static daddr_t
+ext2_clusteralloc(struct inode *ip, int cg, daddr_t bpref, int len)
+{
+	struct m_ext2fs *fs;
+	struct ext2mount *ump;
+	struct buf *bp;
+	char *bbp;
+	int bit, error, got, i, loc, run;
+	int32_t *lp;
+	daddr_t bno;
+
+	fs = ip->i_e2fs;
+	ump = ip->i_ump;
+
+	if (fs->e2fs_maxcluster[cg] < len)
+		return (0);
+
+	EXT2_UNLOCK(ump);
+	error = bread(ip->i_devvp,
+	    fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
+	    (int)fs->e2fs_bsize, NOCRED, &bp);
+	if (error)
+		goto fail_lock;
+
+	bbp = (char *)bp->b_data;
+	bp->b_xflags |= BX_BKGRDWRITE;
+
+	EXT2_LOCK(ump);
+	/*
+	 * Check to see if a cluster of the needed size (or bigger) is
+	 * available in this cylinder group.
+	 */
+	lp = &fs->e2fs_clustersum[cg].cs_sum[len];
+	for (i = len; i <= fs->e2fs_contigsumsize; i++)
+		if (*lp++ > 0)
+			break;
+	if (i > fs->e2fs_contigsumsize) {
+		/*
+		 * Update the cluster summary information to reflect
+		 * the true maximum sized cluster so that future cluster
+		 * allocation requests can avoid reading the bitmap only
+		 * to find no cluster.
+		 */
+		lp = &fs->e2fs_clustersum[cg].cs_sum[len - 1];
+			for (i = len - 1; i > 0; i--)
+				if (*lp-- > 0)
+					break;
+		fs->e2fs_maxcluster[cg] = i;
+		goto fail;
+	}
+	EXT2_UNLOCK(ump);
+
+	/* Search the bitmap to find a bit enough cluster like ffs. */
+	if (dtog(fs, bpref) != cg)
+		bpref = 0;
+	if (bpref != 0)
+		bpref = dtogd(fs, bpref);
+	loc = bpref / NBBY;
+	bit = 1 << (bpref % NBBY);
+	for (run = 0, got = bpref; got < fs->e2fs->e2fs_fpg; got++) {
+		if ((bbp[loc] & bit) != 0)
+			run = 0;
+		else {
+			run++;
+			if (run == len)
+				break;
+		}
+		if ((got & (NBBY - 1)) != (NBBY - 1))
+			bit <<= 1;
+		else {
+			loc++;
+			bit = 1;
+		}
+	}
+
+	if (got >= fs->e2fs->e2fs_fpg)
+		goto fail_lock;
+
+	/* Allocate the cluster that we have found. */
+	for (i = 1; i < len; i++)
+		if (!isclr(bbp, got - run + i))
+			panic("ext2_clusteralloc: map mismatch");
+
+	bno = got - run + 1;
+	if (bno >= fs->e2fs->e2fs_fpg)
+		panic("ext2_clusteralloc: allocated out of group");
+
+	EXT2_LOCK(ump);
+	for (i = 0; i < len; i += fs->e2fs_fpb) {
+		setbit(bbp, bno + i);
+		ext2_clusteracct(fs, bbp, cg, bno + i, -1);
+		fs->e2fs->e2fs_fbcount--;
+		fs->e2fs_gd[cg].ext2bgd_nbfree--;
+	}
+	fs->e2fs_fmod = 1;
+	EXT2_UNLOCK(ump);
+
+	bdwrite(bp);
+	return (cg * fs->e2fs->e2fs_fpg + fs->e2fs->e2fs_first_dblock + bno);
+
+fail_lock:
+	EXT2_LOCK(ump);
+fail:
+	brelse(bp);
+	return (0);
+}
+
 /*
  * Determine whether an inode can be allocated.
  *
@@ -877,6 +992,7 @@
         }
         clrbit(bbp, bno);
 	EXT2_LOCK(ump);
+	ext2_clusteracct(fs, bbp, cg, bno, 1);
         fs->e2fs->e2fs_fbcount++;
         fs->e2fs_gd[cg].ext2bgd_nbfree++;
         fs->e2fs_fmod = 1;
diff -u ext2fs/ext2_extern.h ext2fs_realloc/ext2_extern.h
--- ext2fs/ext2_extern.h	2011-03-15 19:57:35.000000000 +0000
+++ ext2fs_realloc/ext2_extern.h	2011-03-15 19:53:56.000000000 +0000
@@ -55,6 +55,7 @@
 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 *);
+void	ext2_clusteracct(struct m_ext2fs *, char *, int, daddr_t, 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 -u ext2fs/ext2_subr.c ext2fs_realloc/ext2_subr.c
--- ext2fs/ext2_subr.c	2011-03-15 19:57:35.000000000 +0000
+++ ext2fs_realloc/ext2_subr.c	2011-03-15 19:53:56.000000000 +0000
@@ -120,3 +120,107 @@
 	}
 }
 #endif /* KDB */
+
+/*
+ * Update the cluster map because of an allocation of free like ffs.
+ *
+ * Cnt == 1 means free; cnt == -1 means allocating.
+ */
+void
+ext2_clusteracct(struct m_ext2fs *fs, char *bbp, int cg, daddr_t bno, int cnt)
+{
+	int32_t *sump = fs->e2fs_clustersum[cg].cs_sum;
+	int32_t *lp;
+	int back, bit, end, forw, i, loc, start;
+
+	/* Initialize the cluster summary array. */
+	if (fs->e2fs_clustersum[cg].cs_init == 0) {
+		int run = 0;
+		bit = 1;
+		loc = 0;
+
+		for (i = 0; i < fs->e2fs->e2fs_fpg; i++) {
+			if ((bbp[loc] & bit) == 0)
+				run++;
+			else if (run != 0) {
+				if (run > fs->e2fs_contigsumsize)
+					run = fs->e2fs_contigsumsize;
+				sump[run]++;
+				run = 0;
+			}
+			if ((i & (NBBY - 1)) != (NBBY - 1))
+				bit <<= 1;
+			else {
+				loc++;
+				bit = 1;
+			}
+		}
+		if (run != 0) {
+			if (run > fs->e2fs_contigsumsize)
+				run = fs->e2fs_contigsumsize;
+			sump[run]++;
+		}
+		fs->e2fs_clustersum[cg].cs_init = 1;
+	}
+
+	if (fs->e2fs_contigsumsize <= 0)
+		return;
+
+	/* Find the size of the cluster going forward. */
+	start = bno + 1;
+	end = start + fs->e2fs_contigsumsize;
+	if (end > fs->e2fs->e2fs_fpg)
+		end = fs->e2fs->e2fs_fpg;
+	loc = start / NBBY;
+	bit = 1 << (start % NBBY);
+	for (i = start; i < end; i++) {
+		if ((bbp[loc] & bit) != 0)
+			break;
+		if ((i & (NBBY - 1)) != (NBBY - 1))
+			bit <<= 1;
+		else {
+			loc++;
+			bit = 1;
+		}
+	}
+	forw = i - start;
+
+	/* Find the size of the cluster going backward. */
+	start = bno - 1;
+	end = start - fs->e2fs_contigsumsize;
+	if (end < 0)
+		end = -1;
+	loc = start / NBBY;
+	bit = 1 << (start % NBBY);
+	for (i = start; i > end; i--) {
+		if ((bbp[loc] & bit) != 0)
+			break;
+		if ((i & (NBBY - 1)) != 0)
+			bit >>= 1;
+		else {
+			loc--;
+			bit = 1 << (NBBY - 1);
+		}
+	}
+	back = start - i;
+
+	/*
+	 * Account for old cluster and the possibly new forward and
+	 * back clusters.
+	 */
+	i = back + forw + 1;
+	if (i > fs->e2fs_contigsumsize)
+		i = fs->e2fs_contigsumsize;
+	sump[i] += cnt;
+	if (back > 0)
+		sump[back] -= cnt;
+	if (forw > 0)
+		sump[forw] -= cnt;
+
+	/* Update cluster summary information. */
+	lp = &sump[fs->e2fs_contigsumsize];
+	for (i = fs->e2fs_contigsumsize; i > 0; i--)
+		if (*lp-- > 0)
+			break;
+	fs->e2fs_maxcluster[cg] = i;
+}
diff -u ext2fs/ext2_vfsops.c ext2fs_realloc/ext2_vfsops.c
--- ext2fs/ext2_vfsops.c	2011-03-15 19:57:35.000000000 +0000
+++ ext2fs_realloc/ext2_vfsops.c	2011-03-15 19:53:56.000000000 +0000
@@ -405,7 +405,7 @@
  * Things to do to update the mount:
  *	1) invalidate all cached meta-data.
  *	2) re-read superblock from disk.
- *	3) re-read summary information from disk.
+ *	3) invalidate all cluster summary information.
  *	4) invalidate all inactive vnodes.
  *	5) invalidate all cached file data.
  *	6) re-read inode data for all active vnodes.
@@ -419,7 +419,9 @@
 	struct buf *bp;
 	struct ext2fs *es;
 	struct m_ext2fs *fs;
-	int error;
+	struct csum *sump;
+	int error, i;
+	int32_t *lp;
 
 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
 		return (EINVAL);
@@ -456,6 +458,19 @@
 #endif
 	brelse(bp);
 
+	/*
+	 * Step 3: invalidate all cluster summary information.
+	 */
+	if (fs->e2fs_contigsumsize > 0) {
+		lp = fs->e2fs_maxcluster;
+		sump = fs->e2fs_clustersum;
+		for (i = 0; i < fs->e2fs_gcount; i++, sump++) {
+			*lp++ = fs->e2fs_contigsumsize;
+			sump->cs_init = 0;
+			bzero(sump->cs_sum, fs->e2fs_contigsumsize + 1);
+		}
+	}
+
 loop:
 	MNT_ILOCK(mp);
 	MNT_VNODE_FOREACH(vp, mp, mvp) {
@@ -511,8 +526,11 @@
 	struct cdev *dev = devvp->v_rdev;
 	struct g_consumer *cp;
 	struct bufobj *bo;
+	struct csum *sump;
 	int error;
 	int ronly;
+	int i, size;
+	int32_t *lp;
 
 	ronly = vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0);
 	/* XXX: use VOP_ACESS to check FS perms */
@@ -582,6 +600,33 @@
 	if ((error = compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs)))
 		goto out;
 
+	/*
+	 * We calculate the max contiguous blks and size of cluster summary
+	 * array. In ffs, these works are done in newfs. But superblock in
+	 * ext2fs doesn't have these variables. So we just can calculate them
+	 * in here.
+	 */
+	ump->um_e2fs->e2fs_maxcontig = MAX(1, MAXPHYS / ump->um_e2fs->e2fs_bsize);
+	if (ump->um_e2fs->e2fs_maxcontig > 0)
+		ump->um_e2fs->e2fs_contigsumsize =
+		    MIN(ump->um_e2fs->e2fs_maxcontig, EXT2_MAXCONTIG);
+	else
+		ump->um_e2fs->e2fs_contigsumsize = 0;
+	if (ump->um_e2fs->e2fs_contigsumsize > 0) {
+		size = ump->um_e2fs->e2fs_gcount * sizeof(int32_t);
+		ump->um_e2fs->e2fs_maxcluster = malloc(size, M_EXT2MNT, M_WAITOK);
+		size = ump->um_e2fs->e2fs_gcount * sizeof(struct csum);
+		ump->um_e2fs->e2fs_clustersum = malloc(size, M_EXT2MNT, M_WAITOK);
+		lp = ump->um_e2fs->e2fs_maxcluster;
+		sump = ump->um_e2fs->e2fs_clustersum;
+		for (i = 0; i < ump->um_e2fs->e2fs_gcount; i++, sump++) {
+			*lp++ = ump->um_e2fs->e2fs_contigsumsize;
+			sump->cs_init = 0;
+			sump->cs_sum = malloc((ump->um_e2fs->e2fs_contigsumsize + 1) *
+			    sizeof(int32_t), M_EXT2MNT, M_WAITOK | M_ZERO);
+		}
+	}
+
 	brelse(bp);
 	bp = NULL;
 	fs = ump->um_e2fs;
@@ -656,7 +701,8 @@
 {
 	struct ext2mount *ump;
 	struct m_ext2fs *fs;
-	int error, flags, ronly;
+	struct csum *sump;
+	int error, flags, i, ronly;
 
 	flags = 0;
 	if (mntflags & MNT_FORCE) {
@@ -681,6 +727,11 @@
 	g_topology_unlock();
 	PICKUP_GIANT();
 	vrele(ump->um_devvp);
+	sump = fs->e2fs_clustersum;
+	for (i = 0; i < fs->e2fs_gcount; i++, sump++)
+		free(sump->cs_sum, M_EXT2MNT);
+	free(fs->e2fs_clustersum, M_EXT2MNT);
+	free(fs->e2fs_maxcluster, M_EXT2MNT);
 	free(fs->e2fs_gd, M_EXT2MNT);
 	free(fs->e2fs_contigdirs, M_EXT2MNT);
 	free(fs->e2fs, M_EXT2MNT);
diff -u ext2fs/ext2fs.h ext2fs_realloc/ext2fs.h
--- ext2fs/ext2fs.h	2011-03-15 19:57:35.000000000 +0000
+++ ext2fs_realloc/ext2fs.h	2011-03-15 19:53:56.000000000 +0000
@@ -45,6 +45,17 @@
 #define EXT2_LINK_MAX		32000
 
 /*
+ * A summary of contiguous blocks of various sizes in maintained
+ * in each cylinder group. Normally this is set by the initial
+ * value of fs_maxcontig. To conserve space, a maximum summary size
+ * is set by EXT2_MAXCONTIG.
+ *
+ * XXX:FS_MAXCONTIG is set to 16 to conserve space. Here we set it to
+ * 32 for performance.
+ */
+#define EXT2_MAXCONTIG		32
+
+/*
  * Constants relative to the data blocks
  */
 #define	EXT2_NDIR_BLOCKS		12
@@ -140,6 +151,10 @@
 	char e2fs_wasvalid;       /* valid at mount time */
 	off_t e2fs_maxfilesize;
 	struct ext2_gd *e2fs_gd; /* Group Descriptors */
+	int32_t  e2fs_maxcontig;        /* max number of contiguous blks */
+	int32_t  e2fs_contigsumsize;    /* size of cluster summary array */
+	int32_t *e2fs_maxcluster;       /* max cluster in each cyl group */
+	struct   csum *e2fs_clustersum; /* cluster summary in each cyl group */
 };
 
 /*
@@ -242,6 +257,13 @@
 	u_int32_t reserved2[3];
 };
 
+/* cluster summary information */
+
+struct csum {
+	int8_t   cs_init; /* cluster summary has been initialized */
+	int32_t *cs_sum;  /* cluster summary array */
+};
+
 /* EXT2FS metadatas are stored in little-endian byte order. These macros
  * helps reading these metadatas
  */

--------------040509040101080104050601--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4D7F58C7.4060402>