Package: zerofree
Version: 1.0.1-2
Severity: wishlist
Tags: upstream, patch
This patch adds a "-f [fillval]" option to zerofree allowing unused
blocks to be filled with some other octet.
Why? There's a well-known write performance degradation issue with solid
state drives (SSDs) due to the drive firmware being unaware of which
blocks are unused by the filesystem. Modern SSDs allow the OS to tell
them about unused space. <http://en.wikipedia.org/wiki/TRIM> describes
the issue.
However, only recent SSDs support this. I've seen reports on the
Internet[*] that some older SSDs have firmware which will spot a write
of "erased" values to a block and treat the block as empty, giving the
same rejuvenation as the TRIM command would. 0xFF is a particularly
likely "erased" value, the erase state of the underlying Flash typically
being interpreted as a "1" bit.
[*] for instance
<http://www.ocztechnologyforum.com/forum/showthread.php?67034-Wiping-with-BC-Wipe-to-recover-write-performance>
"zerofree" was approximately the right shape to do this job, hence my
patch.
I've provided two patches: one to the actual code (for Ron and Debian),
and one to the manual page (for Debian).
(Note that I haven't verified that this actually makes any difference on
any real SSD yet; so far I've just tried it on a filesystem image and
checked that fsck is happy with the result.)
--- zerofree-1.0.1/zerofree.c 2007-08-12 10:38:31.000000000 +0100
+++ zerofree-1.0.1-nz/zerofree.c 2010-10-17 18:59:26.000000000 +0100
@@ -10,14 +10,16 @@
*
* 2007-08-12 Allow use on filesystems mounted read-only. Patch from
* Jan Krämer.
+ * 2010-10-17 Allow non-zero fill value. Patch from Jacob Nevins.
*/
#include <ext2fs/ext2fs.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
+#include <stdlib.h>
-#define USAGE "usage: %s [-n] [-v] filesystem\n"
+#define USAGE "usage: %s [-n] [-v] [-f fillval] filesystem\n"
int main(int argc, char **argv)
{
@@ -31,13 +33,14 @@
unsigned char *buf;
unsigned char *empty;
int i, c ;
- unsigned int free, nonzero ;
+ unsigned int free, modified ;
double percent ;
int old_percent ;
+ unsigned int fillval = 0 ;
int verbose = 0 ;
int dryrun = 0 ;
- while ( (c=getopt(argc, argv, "nv")) != -1 ) {
+ while ( (c=getopt(argc, argv, "nvf:")) != -1 ) {
switch (c) {
case 'n' :
dryrun = 1 ;
@@ -45,6 +48,19 @@
case 'v' :
verbose = 1 ;
break ;
+ case 'f' :
+ {
+ char *endptr;
+ fillval = strtol(optarg, &endptr, 0) ;
+ if ( !*optarg || *endptr ) {
+ fprintf(stderr, "%s: invalid argument to -f\n", argv[0]) ;
+ return 1 ;
+ } else if ( fillval > 0xFFu ) {
+ fprintf(stderr, "%s: fill value must be 0-255\n", argv[0]) ;
+ return 1 ;
+ }
+ }
+ break ;
default :
fprintf(stderr, USAGE, argv[0]) ;
return 1 ;
@@ -77,7 +93,7 @@
return 1 ;
}
- empty = (unsigned char *)calloc(1, current_fs->blocksize) ;
+ empty = (unsigned char *)malloc(current_fs->blocksize) ;
buf = (unsigned char *)malloc(current_fs->blocksize) ;
if ( empty == NULL || buf == NULL ) {
@@ -85,6 +101,8 @@
return 1 ;
}
+ memset(empty, fillval, current_fs->blocksize);
+
ret = ext2fs_read_inode_bitmap(current_fs);
if ( ret ) {
fprintf(stderr, "%s: error while reading inode bitmap\n", argv[0]);
@@ -97,7 +115,7 @@
return 1 ;
}
- free = nonzero = 0 ;
+ free = modified = 0 ;
percent = 0.0 ;
old_percent = -1 ;
@@ -129,7 +147,7 @@
}
for ( i=0; i < current_fs->blocksize; ++i ) {
- if ( buf[i] ) {
+ if ( buf[i] != fillval ) {
break ;
}
}
@@ -138,7 +156,7 @@
continue ;
}
- ++nonzero ;
+ ++modified ;
if ( !dryrun ) {
ret = io_channel_write_blk(current_fs->io, blk, 1, empty) ;
@@ -150,7 +168,7 @@
}
if ( verbose ) {
- printf("\r%u/%u/%u\n", nonzero, free,
+ printf("\r%u/%u/%u\n", modified, free,
current_fs->super->s_blocks_count) ;
}
diff -uNr zerofree-1.0.1/debian/zerofree.sgml zerofree-1.0.1-nz/debian/zerofree.sgml
--- zerofree-1.0.1/debian/zerofree.sgml 2009-11-24 18:28:24.000000000 +0000
+++ zerofree-1.0.1-nz/debian/zerofree.sgml 2010-10-17 19:45:03.000000000 +0100
@@ -9,7 +9,7 @@
<!ENTITY dhfirstname "<firstname>Thibaut</firstname>">
<!ENTITY dhsurname "<surname>Paumard</surname>">
<!-- Please adjust the date whenever revising the manpage. -->
- <!ENTITY dhdate "<date>February 6, 2008</date>">
+ <!ENTITY dhdate "<date>October 17, 2010</date>">
<!ENTITY dhsection "<manvolnum>8</manvolnum>">
<!ENTITY dhemail "<email><[email protected]></email>">
<!ENTITY dhusername "Thibaut Paumard">
@@ -54,6 +54,8 @@
<arg><option>-v</option></arg>
+ <arg><option>-f fillval</option></arg>
+
<arg choice=req><replaceable>filesystem</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
@@ -63,12 +65,19 @@
<para><command>&dhpackage;</command> finds the unallocated,
non-zeroed blocks in an ext2 or ext3
<replaceable>filesystem</replaceable> (e.g. /dev/hda1) and
- fills them with zeroes. This is useful if the device on which
+ fills them with zeroes (or another octet of your choice).
+
+ <para>Filling unused areas with zeroes is useful if the device on which
this file-system resides is a disk image. In this case,
depending on the type of disk image, a secondary utility may be
able to reduce the size of the disk image after zerofree has
been run.</para>
+ <para>Filling unused areas may also be useful with solid-state
+ drives (SSDs). On some SSDs, filling blocks with ones (0xFF)
+ is reported to trigger Flash block erasure by the firmware,
+ possibly giving a write performance increase.</para>
+
<para>The usual way to achieve the same result (zeroing the
unallocated blocks) is to run <command>dd</command> (1) to
create a file full of zeroes that takes up the entire free
@@ -115,7 +124,15 @@
<term><option>-v</option>
</term>
<listitem>
- <para>Be verbose.</para>
+ <para>Be verbose;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>-f value</option>
+ </term>
+ <listitem>
+ <para>Specify the octet value to fill empty blocks with (defaults to
+ 0). Argument must be within the range 0 to 255.</para>
</listitem>
</varlistentry>
</variablelist>