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 *);