[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <4E8F865E.9070909@linux.vnet.ibm.com>
Date: Fri, 07 Oct 2011 16:08:14 -0700
From: Allison Henderson <achender@...ux.vnet.ibm.com>
To: djwong@...ibm.com
CC: linux-ext4@...r.kernel.org, linux-fsdevel@...r.kernel.org
Subject: Re: [Ext4 Secure Delete 3/7v4] ext4: Secure Delete: Add secure delete
functions
On 10/07/2011 11:07 AM, Darrick J. Wong wrote:
> On Fri, Oct 07, 2011 at 12:11:01AM -0700, Allison Henderson wrote:
>> This patch adds two new routines: ext4_secure_delete_pblks
>> and ext4_secure_delete_lblks.
>>
>> ext4_secure_delete_pblks() will write zeros to the specified
>> physical blocks or random data if the EXT4_SECRM_RANDOM_FL flag is
>> set. If the device supports secure discard, the secure
>> discard will be used instead. ext4_secure_delete_lblks handels walking
>
> handles
>
>> the logical blocks of a file and calling ext4_secure_delete_pblks()
>> as needed.
>>
>> Signed-off-by: Allison Henderson<achender@...ux.vnet.ibm.com>
>> ---
>> v1->v2
>> Removed check for discard mount option and replaced with
>> check for secure discard and discard_zeroes_data
>>
>> Added BLKDEV_DISCARD_SECURE to the sb_issue_discard call
>>
>> v2->v3
>> Removed code for discard. A seperate patch will
>
> separate
>
>> be done to add that code in the block layer
>>
>> v3->v4
>> Discard code will be kept in the vfs layer. Code
>> for secure delete is now in its own function,
>> ext4_secure_delete_pblks and is called
>> by a new function ext4_secure_delete_lblks
>> before any blocks are released
>>
>> :100644 100644 5c9f88c... 34f82a1... M fs/ext4/ext4.h
>> :100644 100644 095c36f... 10180e3... M fs/ext4/ext4_extents.h
>> :100644 100644 57cf568... 40d4e50... M fs/ext4/extents.c
>> :100644 100644 9dc8c14... 0a526c4... M fs/ext4/inode.c
>> fs/ext4/ext4.h | 5 +
>> fs/ext4/ext4_extents.h | 2 +
>> fs/ext4/extents.c | 2 +-
>> fs/ext4/inode.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++
>> 4 files changed, 204 insertions(+), 1 deletions(-)
>>
>> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
>> index 5c9f88c..34f82a1 100644
>> --- a/fs/ext4/ext4.h
>> +++ b/fs/ext4/ext4.h
>> @@ -2220,6 +2220,11 @@ extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
>> struct ext4_map_blocks *map, int flags);
>> extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
>> __u64 start, __u64 len);
>> +extern int ext4_secure_delete_lblks(struct inode *inode,
>> + ext4_lblk_t first_block, unsigned long count);
>> +extern int ext4_secure_delete_pblks(struct inode *inode,
>> + ext4_fsblk_t block, unsigned long count);
>> +
>> /* move_extent.c */
>> extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
>> __u64 start_orig, __u64 start_donor,
>> diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
>> index 095c36f..10180e3 100644
>> --- a/fs/ext4/ext4_extents.h
>> +++ b/fs/ext4/ext4_extents.h
>> @@ -290,5 +290,7 @@ extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t,
>> struct ext4_ext_path *);
>> extern void ext4_ext_drop_refs(struct ext4_ext_path *);
>> extern int ext4_ext_check_inode(struct inode *inode);
>> +extern int ext4_ext_check_cache(struct inode *inode, ext4_lblk_t block,
>> + struct ext4_ext_cache *ex);
>> #endif /* _EXT4_EXTENTS */
>>
>> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
>> index 57cf568..40d4e50 100644
>> --- a/fs/ext4/extents.c
>> +++ b/fs/ext4/extents.c
>> @@ -2034,7 +2034,7 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
>> *
>> * Return 0 if cache is invalid; 1 if the cache is valid
>> */
>> -static int ext4_ext_check_cache(struct inode *inode, ext4_lblk_t block,
>> +int ext4_ext_check_cache(struct inode *inode, ext4_lblk_t block,
>> struct ext4_ext_cache *ex){
>> struct ext4_ext_cache *cex;
>> struct ext4_sb_info *sbi;
>> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
>> index 9dc8c14..0a526c4 100644
>> --- a/fs/ext4/inode.c
>> +++ b/fs/ext4/inode.c
>> @@ -38,6 +38,7 @@
>> #include<linux/printk.h>
>> #include<linux/slab.h>
>> #include<linux/ratelimit.h>
>> +#include<linux/random.h>
>>
>> #include "ext4_jbd2.h"
>> #include "xattr.h"
>> @@ -713,6 +714,201 @@ static int ext4_ind_hole_lookup(struct inode *inode, ext4_lblk_t block)
>> return 0;
>> }
>>
>> +
>> +/*
>> + * ext4_secure_delete_pblks
>> + *
>> + * Securely delete physical blocks.
>> + * If the devices supports secure discard,
>> + * blocks will be discarded. Otherwise
>> + * the blocks will be either zeroed or
>> + * randomized if the random secure delete
>> + * flag is on
>
> The fact that random secure delete produces zeroed blocks on discard devices is
> documented somewhere user-visible, right? Just in case someone actually
> depends on the randomizing.
At the moment no, the code is just the result of reviews and
brainstorming, but I can add in some documentation somewhere so that it
is more clear. Will catch the misspellings too, thx! :)
>
>> + * inode: The files inode
>> + * block: The physical block at which to start deleteing
>
> deleting
>
>> + * count: The number of blocks to delete
>> + *
>> + * Returns 0 on sucess or negative on error
>> + */
>> +int ext4_secure_delete_pblks(struct inode *inode, ext4_fsblk_t block,
>> + unsigned long count){
>> +
>> + struct fstrim_range range;
>> + ext4_fsblk_t iblock, last_block;
>> + struct buffer_head *bh;
>> + struct super_block *sb = inode->i_sb;
>> + struct request_queue *q = bdev_get_queue(sb->s_bdev);
>> + struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
>> + int err = 0;
>> +
>> + last_block = block + count;
>> + /*
>> + * Check to see if the device supports secure discard,
>> + * And also that read after discard returns zeros
>> + */
>> + if (blk_queue_secdiscard(q)&& q->limits.discard_zeroes_data) {
>> + err = sb_issue_discard(sb, block, count,
>> + GFP_NOFS, BLKDEV_DISCARD_SECURE);
>> + if (err)
>> + goto zero_out;
>> +
>> + range.start = block;
>> + range.len = count;
>> + range.minlen = 1;
>> + err = ext4_trim_fs(sb,&range);
>> +
>> + if (err)
>> + goto zero_out;
>> +
>> + return 0;
>> + }
>> +
>> + if (EXT4_I(inode)->i_flags& EXT4_SECRM_RANDOM_FL) {
>> + for (iblock = block; iblock< last_block; iblock++) {
>> + bh = sb_getblk(sb, iblock);
>> + get_random_bytes(bh->b_data, bh->b_size);
>> + set_buffer_dirty(bh);
>> +
>> + sync_dirty_buffer(bh);
>> + if (buffer_req(bh)&& !buffer_uptodate(bh)) {
>> + es->s_last_error_block =
>> + cpu_to_le64(bh->b_blocknr);
>> + ext4_error_inode(inode, __func__,
>> + __LINE__, bh->b_blocknr,
>> + "IO error syncing itable block");
>
> itable block?
>
>> + err = -EIO;
>> + brelse(bh);
>> + goto zero_out;
>> + }
>> + brelse(bh);
>> + }
>> + return 0;
>> + }
>> +
>> +zero_out:
>> + return sb_issue_zeroout(sb, block, count, GFP_NOFS);
>> +
>> +}
>> +
>> +/*
>> + * ext4_secure_delete_lblks
>> + *
>> + * Secure deletes the data blocks of a file
>> + * starting at the given logical block
>> + *
>> + * @inode: The files inode
>> + * @first_block: Starting logical block
>> + * @count: The number of blocks to secure delete
>> + *
>> + * Returns 0 on sucess or negative on error
>> + */
>> +int ext4_secure_delete_lblks(struct inode *inode, ext4_lblk_t first_block,
>> + unsigned long count){
>> + handle_t *handle;
>> + struct ext4_map_blocks map;
>> + struct ext4_ext_cache cache_ex;
>> + ext4_lblk_t num_blocks, max_blocks = 0;
>> + ext4_lblk_t last_block = first_block + count;
>> + ext4_lblk_t iblock = first_block;
>> + int ret, credits, hole_len, err = 0;
>> +
>> + credits = ext4_writepage_trans_blocks(inode);
>> + handle = ext4_journal_start(inode, credits);
>> + if (IS_ERR(handle))
>> + return PTR_ERR(handle);
>> +
>> + down_write(&EXT4_I(inode)->i_data_sem);
>> + ext4_ext_invalidate_cache(inode);
>> + ext4_discard_preallocations(inode);
>> +
>> + /* Do not allow last_block to wrap when caller passes EXT_MAX_BLOCK */
>> + if (last_block< first_block)
>> + last_block = EXT_MAX_BLOCKS;
>> +
>> + while (iblock< last_block) {
>> + max_blocks = last_block - iblock;
>> + num_blocks = 1;
>> + memset(&map, 0, sizeof(map));
>> + map.m_lblk = iblock;
>> + map.m_len = max_blocks;
>> +
>> + if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
>> + ret = ext4_ext_map_blocks(handle, inode,&map, 0);
>> + else
>> + ret = ext4_ind_map_blocks(handle, inode,&map, 0);
>> +
>> + if (ret> 0) {
>> + err = ext4_secure_delete_pblks(inode,
>> + map.m_pblk, map.m_len);
>> + if (err)
>> + break;
>> + num_blocks = ret;
>> + } else if (ret == 0) {
>> + if (ext4_test_inode_flag(inode,
>> + EXT4_INODE_EXTENTS)) {
>> + /*
>> + * If map blocks could not find the block,
>> + * then it is in a hole. If the hole was
>> + * not already cached, then map blocks should
>> + * put it in the cache. So we can get the hole
>> + * out of the cache
>> + */
>> + memset(&cache_ex, 0, sizeof(cache_ex));
>> + if ((ext4_ext_check_cache(inode, iblock,
>> + &cache_ex))&& !cache_ex.ec_start) {
>> +
>> + /* The hole is cached */
>> + num_blocks = cache_ex.ec_block +
>> + cache_ex.ec_len - iblock;
>> +
>> + } else {
>> + /* reached EOF of extent file */
>> + break;
>> + }
>> + } else {
>> + hole_len = ext4_ind_hole_lookup(inode, iblock);
>> +
>> + if (hole_len> 0) {
>> + /* Skip over the hole */
>> + num_blocks = hole_len;
>> + } else if (hole_len == 0) {
>> + /* No hole, EOF reached */
>> + break;
>> + } else {
>> + /* Hole look up err */
>> + err = hole_len;
>> + break;
>> + }
>> + }
>> + } else {
>> + /* Map blocks error */
>> + err = ret;
>> + break;
>> + }
>> +
>> + if (num_blocks == 0) {
>> + /* This condition should never happen */
>> + ext_debug("Block lookup failed");
>> + err = -EIO;
>> + break;
>> + }
>> +
>> + iblock += num_blocks;
>> + }
>> +
>> + if (IS_SYNC(inode))
>> + ext4_handle_sync(handle);
>> +
>> + up_write(&EXT4_I(inode)->i_data_sem);
>> +
>> + inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
>> + ext4_mark_inode_dirty(handle, inode);
>> + ext4_journal_stop(handle);
>> +
>> + return err;
>> +}
>> +
>> struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
>> ext4_lblk_t block, int create, int *err)
>> {
>> --
>> 1.7.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
>> the body of a message to majordomo@...r.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists