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