A couple of years ago there was a discussion on lkml under the thread
'PATCH - ext2fs privacy (i.e. secure deletion) patch' about zapping
deleted data in the filesystem as a security mechanism. The discussion
wandered off into how 'chattr +s' could be implemented and whether
encrypting filesystems wouldn't be a better solution to the problem.
I've been maintaining a simplified version of the patch for a different
reason: to keep filesystems in files sparse. Filesystem images for use
by things like user-mode Linux and Xen are often created as sparse files.
After they've been in use for a while their sparseness is reduced even
though they may have lots of free space. Having the guest kernel fill
deleted blocks with zeros doesn't make the underlying file sparse,
but it does help. I've got a page with more details:
http://intgat.tigress.co.uk/rmy/uml/sparsify.html
Anyway, a couple of things:
1. The patch (see below) is pretty simple. I've been using it for some
time in UML build systems for old versions of software (rh62, anyone?),
and today I even tried it for several seconds in a Xen domU kernel.
It seems to do what I want, but is it any good?
2. The patch is now for ext2 only, the original ext3 version having
succumbed to bitrot. What would it take to implement something
similar for ext3 these days?
Ron
--- linux-2.6.16/Documentation/filesystems/ext2.txt.zerofree 2006-03-20
05:53:29.000000000 +0000
+++ linux-2.6.16/Documentation/filesystems/ext2.txt 2006-04-02
09:21:52.000000000 +0100
@@ -58,6 +58,8 @@ nobh Do not attach buffer_heads to fi
xip Use execute in place (no caching) if possible
+zerofree Zero data blocks when they are freed.
+
grpquota,noquota,quota,usrquota Quota options are silently ignored by ext2.
--- linux-2.6.16/fs/ext2/balloc.c.zerofree 2006-03-20 05:53:29.000000000 +0000
+++ linux-2.6.16/fs/ext2/balloc.c 2006-04-02 09:21:52.000000000 +0100
@@ -174,6 +174,16 @@ static void group_release_blocks(struct
}
}
+static inline void zero_block(struct super_block *sb, unsigned long block)
+{
+ struct buffer_head * bh;
+
+ bh = sb_getblk(sb, block);
+ memset(bh->b_data, 0, bh->b_size);
+ mark_buffer_dirty(bh);
+ brelse(bh);
+}
+
/* Free given blocks, update quota and i_blocks field */
void ext2_free_blocks (struct inode * inode, unsigned long block,
unsigned long count)
@@ -242,6 +252,9 @@ do_more:
"bit already cleared for block %lu", block + i);
} else {
group_freed++;
+ if ( test_opt(sb, ZEROFREE) ) {
+ zero_block(sb, block+i);
+ }
}
}
--- linux-2.6.16/fs/ext2/super.c.zerofree 2006-03-20 05:53:29.000000000 +0000
+++ linux-2.6.16/fs/ext2/super.c 2006-04-02 09:21:52.000000000 +0100
@@ -289,7 +289,7 @@ enum {
Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug,
Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr,
Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota,
- Opt_usrquota, Opt_grpquota
+ Opt_usrquota, Opt_grpquota, Opt_zerofree
};
static match_table_t tokens = {
@@ -312,6 +312,7 @@ static match_table_t tokens = {
{Opt_oldalloc, "oldalloc"},
{Opt_orlov, "orlov"},
{Opt_nobh, "nobh"},
+ {Opt_zerofree, "zerofree"},
{Opt_user_xattr, "user_xattr"},
{Opt_nouser_xattr, "nouser_xattr"},
{Opt_acl, "acl"},
@@ -395,6 +396,9 @@ static int parse_options (char * options
case Opt_nobh:
set_opt (sbi->s_mount_opt, NOBH);
break;
+ case Opt_zerofree:
+ set_opt (sbi->s_mount_opt, ZEROFREE);
+ break;
#ifdef CONFIG_EXT2_FS_XATTR
case Opt_user_xattr:
set_opt (sbi->s_mount_opt, XATTR_USER);
--- linux-2.6.16/include/linux/ext2_fs.h.zerofree 2006-03-20 05:53:29.000000000
+0000
+++ linux-2.6.16/include/linux/ext2_fs.h 2006-04-02 09:21:52.000000000 +0100
@@ -310,6 +310,7 @@ struct ext2_inode {
#define EXT2_MOUNT_MINIX_DF 0x000080 /* Mimics the Minix statfs */
#define EXT2_MOUNT_NOBH 0x000100 /* No buffer_heads */
#define EXT2_MOUNT_NO_UID32 0x000200 /* Disable 32-bit UIDs */
+#define EXT2_MOUNT_ZEROFREE 0x000400 /* Zero freed blocks */
#define EXT2_MOUNT_XATTR_USER 0x004000 /* Extended user attributes */
#define EXT2_MOUNT_POSIX_ACL 0x008000 /* POSIX Access Control Lists */
#define EXT2_MOUNT_XIP 0x010000 /* Execute in place */