wiping of unused space on ext3

Ron Yorston rmy at tigress.co.uk
Fri Sep 8 18:13:33 UTC 2006


Here we are:  RHEL 4 versions of my zerofree patches.  I add these to
the kernel spec file at about Patch6000.

Ron

-------------- next part --------------
--- linux-2.6.9/include/linux/ext2_fs.h.zerofree2	2004-10-18 22:53:21.000000000 +0100
+++ linux-2.6.9/include/linux/ext2_fs.h	2006-08-29 19:49:10.000000000 +0100
@@ -310,6 +310,7 @@ struct ext2_inode {
 #define EXT2_MOUNT_MINIX_DF		0x0080	/* Mimics the Minix statfs */
 #define EXT2_MOUNT_NOBH			0x0100	/* No buffer_heads */
 #define EXT2_MOUNT_NO_UID32		0x0200  /* Disable 32-bit UIDs */
+#define EXT2_MOUNT_ZEROFREE		0x0400	/* Zero freed blocks */
 #define EXT2_MOUNT_XATTR_USER		0x4000	/* Extended user attributes */
 #define EXT2_MOUNT_POSIX_ACL		0x8000	/* POSIX Access Control Lists */
 
--- linux-2.6.9/fs/ext2/balloc.c.zerofree2	2004-10-18 22:53:51.000000000 +0100
+++ linux-2.6.9/fs/ext2/balloc.c	2006-08-29 19:46:35.000000000 +0100
@@ -173,9 +173,28 @@ static void group_release_blocks(struct 
 	}
 }
 
+static void ext2_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 ext2_free_blocks (struct inode * inode, unsigned long block,
-		       unsigned long count)
+		       unsigned long count, int zero)
 {
 	struct buffer_head *bitmap_bh = NULL;
 	struct buffer_head * bh2;
@@ -200,6 +219,9 @@ void ext2_free_blocks (struct inode * in
 
 	ext2_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1);
 
+	if (test_opt(sb, ZEROFREE) && zero)
+		ext2_zero_blocks(sb, block, count);
+
 do_more:
 	overflow = 0;
 	block_group = (block - le32_to_cpu(es->s_first_data_block)) /
--- linux-2.6.9/fs/ext2/super.c.zerofree2	2006-08-29 19:44:53.000000000 +0100
+++ linux-2.6.9/fs/ext2/super.c	2006-08-29 19:54:05.000000000 +0100
@@ -293,7 +293,7 @@ enum {
 	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
 	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
 	Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh,
-	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
+	Opt_zerofree, Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
 	Opt_ignore, Opt_err,
 };
 
@@ -318,6 +318,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"},
@@ -407,6 +408,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.9/fs/ext2/xattr.c.zerofree2	2006-08-29 19:40:46.000000000 +0100
+++ linux-2.6.9/fs/ext2/xattr.c	2006-08-29 19:55:25.000000000 +0100
@@ -679,7 +679,7 @@ ext2_xattr_set2(struct inode *inode, str
 
 			new_bh = sb_getblk(sb, block);
 			if (!new_bh) {
-				ext2_free_blocks(inode, block, 1);
+				ext2_free_blocks(inode, block, 1, 0);
 				error = -EIO;
 				goto cleanup;
 			}
@@ -712,24 +712,25 @@ ext2_xattr_set2(struct inode *inode, str
 
 	error = 0;
 	if (old_bh && old_bh != new_bh) {
+		unsigned long block = old_bh->b_blocknr;
 		struct mb_cache_entry *ce;
 		/*
 		 * If there was an old block and we are no longer using it,
 		 * release the old block.
 		 */
-		ce = mb_cache_entry_get(ext2_xattr_cache, old_bh->b_bdev,
-					old_bh->b_blocknr);
+		ce = mb_cache_entry_get(ext2_xattr_cache, old_bh->b_bdev, block);
 		lock_buffer(old_bh);
 		if (HDR(old_bh)->h_refcount == cpu_to_le32(1)) {
 			/* Free the old block. */
 			if (ce)
 				mb_cache_entry_free(ce);
 			ea_bdebug(old_bh, "freeing");
-			ext2_free_blocks(inode, old_bh->b_blocknr, 1);
+			unlock_buffer(old_bh);
 			/* We let our caller release old_bh, so we
 			 * need to duplicate the buffer before. */
 			get_bh(old_bh);
 			bforget(old_bh);
+			ext2_free_blocks(inode, block, 1, 1);
 		} else {
 			/* Decrement the refcount only. */
 			if (ce)
@@ -740,8 +741,8 @@ ext2_xattr_set2(struct inode *inode, str
 			mark_buffer_dirty(old_bh);
 			ea_bdebug(old_bh, "refcount now=%d",
 				le32_to_cpu(HDR(old_bh)->h_refcount));
+			unlock_buffer(old_bh);
 		}
-		unlock_buffer(old_bh);
 	}
 
 cleanup:
@@ -786,10 +787,10 @@ ext2_xattr_delete_inode(struct inode *in
 	if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
 		if (ce)
 			mb_cache_entry_free(ce);
-		ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1);
+		unlock_buffer(bh);
 		get_bh(bh);
 		bforget(bh);
-		unlock_buffer(bh);
+		ext2_free_blocks(inode, EXT2_I(inode)->i_file_acl, 1, 1);
 	} else {
 		if (ce)
 			mb_cache_entry_release(ce);
--- linux-2.6.9/fs/ext2/inode.c.zerofree2	2006-08-29 19:44:53.000000000 +0100
+++ linux-2.6.9/fs/ext2/inode.c	2006-08-29 19:46:35.000000000 +0100
@@ -99,7 +99,7 @@ void ext2_discard_prealloc (struct inode
 		ei->i_prealloc_count = 0;
 		ei->i_prealloc_block = 0;
 		write_unlock(&ei->i_meta_lock);
-		ext2_free_blocks (inode, block, total);
+		ext2_free_blocks (inode, block, total, 0);
 		return;
 	} else
 		write_unlock(&ei->i_meta_lock);
@@ -462,7 +462,7 @@ static int ext2_alloc_branch(struct inod
 	for (i = 1; i < n; i++)
 		bforget(branch[i].bh);
 	for (i = 0; i < n; i++)
-		ext2_free_blocks(inode, le32_to_cpu(branch[i].key), 1);
+		ext2_free_blocks(inode, le32_to_cpu(branch[i].key), 1, 0);
 	return err;
 }
 
@@ -522,7 +522,7 @@ changed:
 	for (i = 1; i < num; i++)
 		bforget(where[i].bh);
 	for (i = 0; i < num; i++)
-		ext2_free_blocks(inode, le32_to_cpu(where[i].key), 1);
+		ext2_free_blocks(inode, le32_to_cpu(where[i].key), 1, 1);
 	return -EAGAIN;
 }
 
@@ -821,7 +821,7 @@ static inline void ext2_free_data(struct
 				count++;
 			else {
 				mark_inode_dirty(inode);
-				ext2_free_blocks (inode, block_to_free, count);
+				ext2_free_blocks (inode, block_to_free, count, 1);
 			free_this:
 				block_to_free = nr;
 				count = 1;
@@ -830,7 +830,7 @@ static inline void ext2_free_data(struct
 	}
 	if (count > 0) {
 		mark_inode_dirty(inode);
-		ext2_free_blocks (inode, block_to_free, count);
+		ext2_free_blocks (inode, block_to_free, count, 1);
 	}
 }
 
@@ -873,7 +873,7 @@ static void ext2_free_branches(struct in
 					   (__le32*)bh->b_data + addr_per_block,
 					   depth);
 			bforget(bh);
-			ext2_free_blocks(inode, nr, 1);
+			ext2_free_blocks(inode, nr, 1, 1);
 			mark_inode_dirty(inode);
 		}
 	} else
--- linux-2.6.9/fs/ext2/ext2.h.zerofree2	2006-08-29 19:44:53.000000000 +0100
+++ linux-2.6.9/fs/ext2/ext2.h	2006-08-29 19:46:35.000000000 +0100
@@ -85,7 +85,7 @@ extern unsigned long ext2_bg_num_gdb(str
 extern int ext2_new_block (struct inode *, unsigned long,
 			   __u32 *, __u32 *, int *);
 extern void ext2_free_blocks (struct inode *, unsigned long,
-			      unsigned long);
+			      unsigned long, int);
 extern unsigned long ext2_count_free_blocks (struct super_block *);
 extern unsigned long ext2_count_dirs (struct super_block *);
 extern void ext2_check_blocks_bitmap (struct super_block *);
--- linux-2.6.9/Documentation/filesystems/ext2.txt.zerofree2	2004-10-18 22:53:43.000000000 +0100
+++ linux-2.6.9/Documentation/filesystems/ext2.txt	2006-08-29 19:46:35.000000000 +0100
@@ -62,6 +62,8 @@ resgid=n			The group ID which may use th
 
 sb=n				Use alternate superblock at this location.
 
+zerofree			Zero data blocks when they are freed.
+
 grpquota,noquota,quota,usrquota	Quota options are silently ignored by ext2.
 
 
-------------- next part --------------
--- linux-2.6.9/include/linux/ext3_fs.h.zerofree3	2006-08-30 20:44:40.000000000 +0100
+++ linux-2.6.9/include/linux/ext3_fs.h	2006-08-30 20:47:19.000000000 +0100
@@ -355,6 +355,7 @@ struct ext3_inode {
 #define EXT3_MOUNT_POSIX_ACL		0x08000	/* POSIX Access Control Lists */
 #define EXT3_MOUNT_BARRIER		0x10000 /* Use block barriers */
 #define EXT3_MOUNT_RESERVATION		0x20000	/* Preallocation */
+#define EXT3_MOUNT_ZEROFREE		0x40000 /* Zero freed blocks */
 
 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
 #ifndef _LINUX_EXT2_FS_H
@@ -713,7 +714,7 @@ extern int ext3_bg_has_super(struct supe
 extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group);
 extern int ext3_new_block (handle_t *, struct inode *, 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 *);
--- linux-2.6.9/fs/ext3/super.c.zerofree3	2006-08-30 20:45:30.000000000 +0100
+++ linux-2.6.9/fs/ext3/super.c	2006-08-30 20:47:19.000000000 +0100
@@ -631,7 +631,7 @@ enum {
 	Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
 	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
 	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
-	Opt_ignore, Opt_barrier, Opt_err, Opt_resize,
+	Opt_zerofree, Opt_ignore, Opt_barrier, Opt_err, Opt_resize,
 };
 
 static match_table_t tokens = {
@@ -674,6 +674,7 @@ static match_table_t tokens = {
 	{Opt_grpjquota, "grpjquota=%s"},
 	{Opt_jqfmt_vfsold, "jqfmt=vfsold"},
 	{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
+	{Opt_zerofree, "zerofree"},
 	{Opt_ignore, "grpquota"},
 	{Opt_ignore, "noquota"},
 	{Opt_ignore, "quota"},
@@ -970,6 +971,9 @@ clear_qf_name:
 			match_int(&args[0], &option);
 			*n_blocks_count = option;
 			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.9/fs/ext3/balloc.c.zerofree3	2006-08-30 20:44:40.000000000 +0100
+++ linux-2.6.9/fs/ext3/balloc.c	2006-08-30 20:47:19.000000000 +0100
@@ -451,9 +451,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;
@@ -463,6 +482,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.9/fs/ext3/inode.c.zerofree3	2006-08-30 20:44:40.000000000 +0100
+++ linux-2.6.9/fs/ext3/inode.c	2006-08-30 20:47:19.000000000 +0100
@@ -571,7 +571,7 @@ static int ext3_alloc_branch(handle_t *h
 		ext3_journal_forget(handle, branch[i].bh);
 	}
 	for (i = 0; i < keys; i++)
-		ext3_free_blocks(handle, inode, le32_to_cpu(branch[i].key), 1);
+		ext3_free_blocks(handle, inode, le32_to_cpu(branch[i].key), 1, 0);
 	return err;
 }
 
@@ -672,7 +672,7 @@ err_out:
 	if (err == -EAGAIN)
 		for (i = 0; i < num; i++)
 			ext3_free_blocks(handle, inode, 
-					 le32_to_cpu(where[i].key), 1);
+					 le32_to_cpu(where[i].key), 1, 0);
 	return err;
 }
 
@@ -1819,7 +1819,7 @@ ext3_clear_blocks(handle_t *handle, stru
 		}
 	}
 
-	ext3_free_blocks(handle, inode, block_to_free, count);
+	ext3_free_blocks(handle, inode, block_to_free, count, 1);
 }
 
 /**
@@ -1992,7 +1992,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.9/fs/ext3/xattr.c.zerofree3	2006-08-30 20:45:00.000000000 +0100
+++ linux-2.6.9/fs/ext3/xattr.c	2006-08-30 20:48:06.000000000 +0100
@@ -699,7 +699,7 @@ ext3_xattr_set_handle2(handle_t *handle,
 			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;
 			}
@@ -746,7 +746,7 @@ getblk_failed:
 			if (ce)
 				mb_cache_entry_free(ce);
 			ea_bdebug(old_bh, "freeing");
-			ext3_free_blocks(handle, inode, old_bh->b_blocknr, 1);
+			ext3_free_blocks(handle, inode, old_bh->b_blocknr, 1, 0);
 
 			/* ext3_forget() calls bforget() for us, but we
 			   let our caller release old_bh, so we need to
@@ -845,7 +845,7 @@ ext3_xattr_delete_inode(handle_t *handle
 	if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
 		if (ce)
 			mb_cache_entry_free(ce);
-		ext3_free_blocks(handle, inode, EXT3_I(inode)->i_file_acl, 1);
+		ext3_free_blocks(handle, inode, EXT3_I(inode)->i_file_acl, 1, 0);
 		get_bh(bh);
 		ext3_forget(handle, 1, inode, bh, EXT3_I(inode)->i_file_acl);
 	} else {
--- linux-2.6.9/Documentation/filesystems/ext3.txt.zerofree3	2004-10-18 22:53:51.000000000 +0100
+++ linux-2.6.9/Documentation/filesystems/ext3.txt	2006-08-30 20:47:19.000000000 +0100
@@ -108,6 +108,8 @@ noquota			(see fs/ext3/super.c, line 594
 grpquota
 usrquota
 
+zerofree		Zero data blocks when they are freed.
+
 
 Specification
 =============


More information about the Ext3-users mailing list