[Midnightbsd-cvs] src: sbin/newfs_msdos: newfs_msdos is very slow, especially when working

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Mon Oct 8 22:15:42 EDT 2007


Log Message:
-----------
newfs_msdos is very slow, especially when working with usb flash drives aka memory sticks.  

To speed things up, use 128KB chunks for I/O as they do on Mac OS X.  This patch is based on some code contributed to the freebsd file system mailing list by Mark Day @ apple.

I tested this on a Lexar 1GB stick that is only a few months old.  Before the patch, newfs_msdos took about 2 minutes.  Without the patch, the command returns nearly instantly.  Obviously buffering is occuring.  The file system seems to work fine, although I plan to do further testing.

Modified Files:
--------------
    src/sbin/newfs_msdos:
        Makefile (r1.1.1.1 -> r1.2)
        newfs_msdos.8 (r1.1.1.1 -> r1.2)
        newfs_msdos.c (r1.1.1.1 -> r1.2)

-------------- next part --------------
Index: newfs_msdos.c
===================================================================
RCS file: /home/cvs/src/sbin/newfs_msdos/newfs_msdos.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -Lsbin/newfs_msdos/newfs_msdos.c -Lsbin/newfs_msdos/newfs_msdos.c -u -r1.1.1.1 -r1.2
--- sbin/newfs_msdos/newfs_msdos.c
+++ sbin/newfs_msdos/newfs_msdos.c
@@ -30,6 +30,10 @@
   "$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.21 2005/01/17 14:14:00 delphij Exp $";
 #endif /* not lint */
 
+#include <ctype.h>
+
+__MBSDID("$MidnightBSD$");
+
 #include <sys/param.h>
 #include <sys/fdcio.h>
 #include <sys/disk.h>
@@ -38,7 +42,6 @@
 #include <sys/stat.h>
 #include <sys/time.h>
 
-#include <ctype.h>
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -55,6 +58,7 @@
 
 #define DOSMAGIC  0xaa55	/* DOS magic number */
 #define MINBPS	  128		/* minimum bytes per sector */
+#define MAXBPS    4096		/* maximum bytes per sector */
 #define MAXSPC	  128		/* maximum sectors per cluster */
 #define MAXNFT	  16		/* maximum number of FATs */
 #define DEFBLK	  4096		/* default block size */
@@ -68,6 +72,16 @@
 #define MAXCLS16  0xfff5	/* maximum FAT16 clusters */
 #define MAXCLS32  0xffffff5	/* maximum FAT32 clusters */
 
+/*
+ * The size of our in-memory I/O buffer.  This is the size of the writes we
+ * do to the device (except perhaps a few odd sectors at the end).
+ *
+ * This must be a multiple of the sector size.  Larger is generally faster,
+ * but some old devices have bugs if you ask them to do more than 128KB
+ * per I/O.
+ */
+#define IO_BUFFER_SIZE (128*1024)
+
 #define mincls(fat)  ((fat) == 12 ? MINCLS12 :	\
 		      (fat) == 16 ? MINCLS16 :	\
 				    MINCLS32)
@@ -247,7 +261,8 @@
     struct bsxbpb *bsxbpb;
     struct bsx *bsx;
     struct de *de;
-    u_int8_t *img;
+    u_int8_t *io_buffer;    /* The buffer for sectors being constructed/written */
+    u_int8_t *img;         /* Current sector within io_buffer */
     const char *fname, *dtype, *bname;
     ssize_t n;
     time_t now;
@@ -377,7 +392,10 @@
 	errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps);
     if (bpb.bps < MINBPS)
 	errx(1, "bytes/sector (%u) is too small; minimum is %u",
-	     bpb.bps, MINBPS);
+	    bpb.bps, MINBPS);
+    if (bpb.bps > MAXBPS)
+	errx(1, "bytes/sector (%u) is too large; maximum is %u",
+	    bpb.bps, MAXBPS);
     if (!(fat = opt_F)) {
 	if (opt_f)
 	    fat = 12;
@@ -552,8 +570,9 @@
 	gettimeofday(&tv, NULL);
 	now = tv.tv_sec;
 	tm = localtime(&now);
-	if (!(img = malloc(bpb.bps)))
+	if (!(io_buffer = malloc(IO_BUFFER_SIZE)))
 	    err(1, NULL);
+	img = io_buffer;
 	dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
 	for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
 	    x = lsn;
@@ -653,9 +672,21 @@
 		    (u_int)tm->tm_mday;
 		mk2(de->date, x);
 	    }
-	    if ((n = write(fd, img, bpb.bps)) == -1)
-		err(1, "%s", fname);
-	    if ((unsigned)n != bpb.bps)
+	    img += bpb.bps;
+	    if (img >= (io_buffer + IO_BUFFER_SIZE)) {
+		/* We filled the I/O buffer, so write it out now */
+		if ((n = write(fd, io_buffer, IO_BUFFER_SIZE)) == -1)
+	  	    err(1, "%s", fname);
+		if (n != IO_BUFFER_SIZE)
+		    errx(1, "%s: can't write sector %u", fname, lsn);
+		img = io_buffer;
+           }
+       }
+       if (img != io_buffer) {
+	    /* The I/O buffer was partially full; write it out before exit */
+	    if ((n = write(fd, io_buffer, img-io_buffer)) == -1)
+                err(1, "%s", fname);
+	    if ((unsigned)n != (img-io_buffer))
 		errx(1, "%s: can't write sector %u", fname, lsn);
 	}
     }
Index: newfs_msdos.8
===================================================================
RCS file: /home/cvs/src/sbin/newfs_msdos/newfs_msdos.8,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -Lsbin/newfs_msdos/newfs_msdos.8 -Lsbin/newfs_msdos/newfs_msdos.8 -u -r1.1.1.1 -r1.2
--- sbin/newfs_msdos/newfs_msdos.8
+++ sbin/newfs_msdos/newfs_msdos.8
@@ -23,6 +23,7 @@
 .\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 .\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
+.\" $MidnightBSD$
 .\" $FreeBSD: src/sbin/newfs_msdos/newfs_msdos.8,v 1.20 2005/02/13 22:25:16 ru Exp $
 .\"
 .Dd July 6, 1998
Index: Makefile
===================================================================
RCS file: /home/cvs/src/sbin/newfs_msdos/Makefile,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -Lsbin/newfs_msdos/Makefile -Lsbin/newfs_msdos/Makefile -u -r1.1.1.1 -r1.2
--- sbin/newfs_msdos/Makefile
+++ sbin/newfs_msdos/Makefile
@@ -1,3 +1,4 @@
+# $MidnightBSD$
 # $FreeBSD: src/sbin/newfs_msdos/Makefile,v 1.11 2005/01/24 01:56:06 cognet Exp $
 
 PROG=	newfs_msdos


More information about the Midnightbsd-cvs mailing list