[CentOS] [PATCH] ext3: zero freed blocks

Fri Sep 8 09:04:53 UTC 2006
Ron Yorston <rmy at tigress.co.uk>

Add a zerofree mount option to the ext3 filesystem.  This causes freed
blocks to be filled with zeros.

Zeroing is only applied to data blocks, not metadata.  This means that
directory blocks and extended attributes are not zeroed.

Signed-off-by; Ron Yorston <rmy at tigress.co.uk>

---

--- linux-2.6.17/Documentation/filesystems/ext3.txt.zerofree3	2006-06-18 02:49:35.000000000 +0100
+++ linux-2.6.17/Documentation/filesystems/ext3.txt	2006-08-26 19:07:34.000000000 +0100
@@ -113,6 +113,8 @@ noquota
 grpquota
 usrquota
 
+zerofree		Zero data blocks when they are freed.
+
 
 Specification
 =============
--- linux-2.6.17/fs/ext3/super.c.zerofree3	2006-08-26 19:06:57.000000000 +0100
+++ linux-2.6.17/fs/ext3/super.c	2006-08-26 19:07:34.000000000 +0100
@@ -675,7 +675,7 @@ enum {
 	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
 	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
 	Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
-	Opt_grpquota
+	Opt_grpquota, Opt_zerofree
 };
 
 static match_table_t tokens = {
@@ -720,6 +720,7 @@ static match_table_t tokens = {
 	{Opt_jqfmt_vfsold, "jqfmt=vfsold"},
 	{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
 	{Opt_grpquota, "grpquota"},
+	{Opt_zerofree, "zerofree"},
 	{Opt_noquota, "noquota"},
 	{Opt_quota, "quota"},
 	{Opt_usrquota, "usrquota"},
@@ -1052,6 +1053,9 @@ clear_qf_name:
 		case Opt_nobh:
 			set_opt(sbi->s_mount_opt, NOBH);
 			break;
+		case Opt_zerofree:
+			set_opt(sbi->s_mount_opt, ZEROFREE);
+			break;
 		default:
 			printk (KERN_ERR
 				"EXT3-fs: Unrecognized mount option \"%s\" "
--- linux-2.6.17/fs/ext3/balloc.c.zerofree3	2006-06-18 02:49:35.000000000 +0100
+++ linux-2.6.17/fs/ext3/balloc.c	2006-08-26 19:08:14.000000000 +0100
@@ -491,9 +491,28 @@ error_return:
 	return;
 }
 
+static void ext3_zero_blocks(struct super_block *sb, unsigned long block,
+		unsigned long count)
+{
+	unsigned long i;
+	struct buffer_head *bh;
+
+	for (i = 0; i < count; i++) {
+		bh = sb_getblk(sb, block+i);
+		if (!bh)
+			continue;
+
+		lock_buffer(bh) ;
+		memset(bh->b_data, 0, bh->b_size);
+		mark_buffer_dirty(bh);
+		unlock_buffer(bh) ;
+		brelse(bh);
+	}
+}
+
 /* Free given blocks, update quota and i_blocks field */
 void ext3_free_blocks(handle_t *handle, struct inode *inode,
-			unsigned long block, unsigned long count)
+			unsigned long block, unsigned long count, int zero)
 {
 	struct super_block * sb;
 	int dquot_freed_blocks;
@@ -503,6 +522,8 @@ void ext3_free_blocks(handle_t *handle, 
 		printk ("ext3_free_blocks: nonexistent device");
 		return;
 	}
+	if (test_opt(sb, ZEROFREE) && zero && !ext3_should_journal_data(inode))
+		ext3_zero_blocks(sb, block, count);
 	ext3_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks);
 	if (dquot_freed_blocks)
 		DQUOT_FREE_BLOCK(inode, dquot_freed_blocks);
--- linux-2.6.17/fs/ext3/inode.c.zerofree3	2006-08-26 19:06:57.000000000 +0100
+++ linux-2.6.17/fs/ext3/inode.c	2006-08-26 19:07:34.000000000 +0100
@@ -562,7 +562,7 @@ static int ext3_alloc_blocks(handle_t *h
 	return ret;
 failed_out:
 	for (i = 0; i <index; i++)
-		ext3_free_blocks(handle, inode, new_blocks[i], 1);
+		ext3_free_blocks(handle, inode, new_blocks[i], 1, 0);
 	return ret;
 }
 
@@ -661,9 +661,9 @@ failed:
 		ext3_journal_forget(handle, branch[i].bh);
 	}
 	for (i = 0; i <indirect_blks; i++)
-		ext3_free_blocks(handle, inode, new_blocks[i], 1);
+		ext3_free_blocks(handle, inode, new_blocks[i], 1, 0);
 
-	ext3_free_blocks(handle, inode, new_blocks[i], num);
+	ext3_free_blocks(handle, inode, new_blocks[i], num, 0);
 
 	return err;
 }
@@ -760,9 +760,9 @@ err_out:
 	for (i = 1; i <= num; i++) {
 		BUFFER_TRACE(where[i].bh, "call journal_forget");
 		ext3_journal_forget(handle, where[i].bh);
-		ext3_free_blocks(handle,inode,le32_to_cpu(where[i-1].key),1);
+		ext3_free_blocks(handle,inode,le32_to_cpu(where[i-1].key),1,0);
 	}
-	ext3_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks);
+	ext3_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks, 0);
 
 	return err;
 }
@@ -1996,7 +1996,7 @@ static void ext3_clear_blocks(handle_t *
 		}
 	}
 
-	ext3_free_blocks(handle, inode, block_to_free, count);
+	ext3_free_blocks(handle, inode, block_to_free, count, 1);
 }
 
 /**
@@ -2169,7 +2169,7 @@ static void ext3_free_branches(handle_t 
 				ext3_journal_test_restart(handle, inode);
 			}
 
-			ext3_free_blocks(handle, inode, nr, 1);
+			ext3_free_blocks(handle, inode, nr, 1, 0);
 
 			if (parent_bh) {
 				/*
--- linux-2.6.17/fs/ext3/xattr.c.zerofree3	2006-06-18 02:49:35.000000000 +0100
+++ linux-2.6.17/fs/ext3/xattr.c	2006-08-26 19:07:34.000000000 +0100
@@ -484,7 +484,7 @@ ext3_xattr_release_block(handle_t *handl
 		ea_bdebug(bh, "refcount now=0; freeing");
 		if (ce)
 			mb_cache_entry_free(ce);
-		ext3_free_blocks(handle, inode, bh->b_blocknr, 1);
+		ext3_free_blocks(handle, inode, bh->b_blocknr, 1, 0);
 		get_bh(bh);
 		ext3_forget(handle, 1, inode, bh, bh->b_blocknr);
 	} else {
@@ -804,7 +804,7 @@ inserted:
 			new_bh = sb_getblk(sb, block);
 			if (!new_bh) {
 getblk_failed:
-				ext3_free_blocks(handle, inode, block, 1);
+				ext3_free_blocks(handle, inode, block, 1, 0);
 				error = -EIO;
 				goto cleanup;
 			}
--- linux-2.6.17/include/linux/ext3_fs.h.zerofree3	2006-08-26 19:06:57.000000000 +0100
+++ linux-2.6.17/include/linux/ext3_fs.h	2006-08-26 19:07:34.000000000 +0100
@@ -376,6 +376,7 @@ struct ext3_inode {
 #define EXT3_MOUNT_QUOTA		0x80000 /* Some quota option set */
 #define EXT3_MOUNT_USRQUOTA		0x100000 /* "old" user quota */
 #define EXT3_MOUNT_GRPQUOTA		0x200000 /* "old" group quota */
+#define EXT3_MOUNT_ZEROFREE		0x400000 /* Zero freed blocks */
 
 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
@@ -745,7 +746,7 @@ extern int ext3_new_block (handle_t *, s
 extern int ext3_new_blocks (handle_t *, struct inode *, unsigned long,
 			unsigned long *, int *);
 extern void ext3_free_blocks (handle_t *, struct inode *, unsigned long,
-			      unsigned long);
+			      unsigned long, int);
 extern void ext3_free_blocks_sb (handle_t *, struct super_block *,
 				 unsigned long, unsigned long, int *);
 extern unsigned long ext3_count_free_blocks (struct super_block *);