[CentOS] [PATCH] ext2: zero freed blocks
Ron Yorston
rmy at tigress.co.uk
Fri Sep 8 09:04:05 UTC 2006
Add a zerofree mount option to the ext2 filesystem. This causes freed
blocks to be filled with zeros.
ext2_zero_blocks has an additional argument to specify whether or not
zeroing is required: there's no point in zeroing blocks that have
just come from the free list.
Some rerrangement of code in xattr.c is required to ensure that
ext2_zero_blocks is never called with a locked buffer.
Signed-off-by: Ron Yorston <rmy at tigress.co.uk>
---
--- linux-2.6.17/Documentation/filesystems/ext2.txt.zerofree2 2006-06-18 02:49:35.000000000 +0100
+++ linux-2.6.17/Documentation/filesystems/ext2.txt 2006-08-25 20:08:06.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.17/fs/ext2/balloc.c.zerofree2 2006-06-18 02:49:35.000000000 +0100
+++ linux-2.6.17/fs/ext2/balloc.c 2006-08-25 20:08:26.000000000 +0100
@@ -174,9 +174,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;
@@ -201,6 +220,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.17/fs/ext2/super.c.zerofree2 2006-06-18 02:49:35.000000000 +0100
+++ linux-2.6.17/fs/ext2/super.c 2006-08-25 20:08:06.000000000 +0100
@@ -287,7 +287,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 = {
@@ -310,6 +310,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"},
@@ -393,6 +394,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.17/fs/ext2/xattr.c.zerofree2 2006-06-18 02:49:35.000000000 +0100
+++ linux-2.6.17/fs/ext2/xattr.c 2006-08-25 20:08:06.000000000 +0100
@@ -676,7 +676,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;
}
@@ -715,25 +715,26 @@ 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. */
HDR(old_bh)->h_refcount = cpu_to_le32(
@@ -744,8 +745,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:
@@ -789,10 +790,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 {
HDR(bh)->h_refcount = cpu_to_le32(
le32_to_cpu(HDR(bh)->h_refcount) - 1);
--- linux-2.6.17/fs/ext2/inode.c.zerofree2 2006-06-18 02:49:35.000000000 +0100
+++ linux-2.6.17/fs/ext2/inode.c 2006-08-25 20:08:06.000000000 +0100
@@ -100,7 +100,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);
@@ -467,7 +467,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;
}
@@ -527,7 +527,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;
}
@@ -837,7 +837,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;
@@ -846,7 +846,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);
}
}
@@ -889,7 +889,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.17/fs/ext2/ext2.h.zerofree2 2006-06-18 02:49:35.000000000 +0100
+++ linux-2.6.17/fs/ext2/ext2.h 2006-08-25 20:08:06.000000000 +0100
@@ -94,7 +94,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.17/include/linux/ext2_fs.h.zerofree2 2006-06-18 02:49:35.000000000 +0100
+++ linux-2.6.17/include/linux/ext2_fs.h 2006-08-25 20:08:06.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 */
More information about the CentOS
mailing list