From patchwork Tue Mar 18 15:09:44 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lubos Uhliarik X-Patchwork-Id: 331456 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 4AFFD2C00AD for ; Wed, 19 Mar 2014 02:21:36 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756210AbaCRPVe (ORCPT ); Tue, 18 Mar 2014 11:21:34 -0400 Received: from smtp2.seznam.cz ([77.75.76.43]:51461 "EHLO smtp2.seznam.cz" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754926AbaCRPVe (ORCPT ); Tue, 18 Mar 2014 11:21:34 -0400 X-Greylist: delayed 711 seconds by postgrey-1.27 at vger.kernel.org; Tue, 18 Mar 2014 11:21:33 EDT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=seznam.cz; s=beta; t=1395156091; bh=zWU1TPG/aVcxD6KIhSWrPd+7JQAAt3vLP/hzHwi8c60=; h=Received:Message-ID:Subject:From:To:Cc:Date:Content-Type:X-Mailer: Mime-Version:Content-Transfer-Encoding:X-Smtpd:X-Seznam-User: X-Session:X-Country; b=Di+lD//0SCnR3TvLVKMspmb+NlAQbWcsxa2LZ4y/1aNgcJpIn3VokhhSPMTLzAvJ3 LrFdXbk6+hrgEY5t1vbnMEPEkqSc3W8KgvjGj25+UQKmIjGiMr/LrmrpufJ8G09edo ZRYjigIt7T9NVFySUfGBbVQJU/TaxyYXPJhauA/I= Received: from [10.0.0.146] (60.195.broadband10.iol.cz [90.177.195.60]) by email-relay5.ng.seznam.cz (Seznam SMTPD UNKNOWN@UNKNOWN) with ESMTP; Tue, 18 Mar 2014 16:09:46 +0100 (CET) Message-ID: <1395155384.15587.10.camel@zerobox.home> Subject: [RFC][PATCH 1/1] ext4: Undelete Feature for Ext4 From: Lubos Uhliarik To: linux-ext4@vger.kernel.org Cc: vojnar@fit.vutbr.cz, lczerner@redhat.com Date: Tue, 18 Mar 2014 16:09:44 +0100 X-Mailer: Evolution 3.8.5-2+b1 Mime-Version: 1.0 X-Smtpd: UNKNOWN@UNKNOWN X-Seznam-User: uhliarik@seznam.cz X-Session: 18 X-Country: CZ Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org This patch should make undelete process for deleted files under ext4 fs easier. Signed-off-by: Lubos Uhliarik --- fs/ext4/ext4_extents.h | 14 +++++++++++ fs/ext4/extents.c | 67 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index 5074fe2..22cf2cd 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h @@ -251,6 +251,20 @@ static inline void ext4_ext_store_pblock(struct ext4_extent *ex, 0xffff); } +static inline void ext4_ext_store_entries(struct ext4_extent_header *eh, + __u16 eh_entries){ + eh->eh_generation &= cpu_to_le32((unsigned long) 0x0000ffff); + eh->eh_generation |= cpu_to_le32(((unsigned long) (eh_entries) << 16) + & 0xffff0000); +} + +static inline void ext4_ext_store_depth(struct ext4_extent_header *eh, + __u16 eh_depth){ + eh->eh_generation &= cpu_to_le32((unsigned long) 0xffff0000); + eh->eh_generation |= cpu_to_le32(((unsigned long) (eh_depth)) + & 0x0000ffff); +} + /* * ext4_idx_store_pblock: * stores a large physical block number into an index struct, diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 74bc2d5..f0f3615 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -2565,6 +2565,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, ext4_lblk_t ex_ee_block; unsigned short ex_ee_len; unsigned uninitialized = 0; + unsigned short ex_ee_entries; struct ext4_extent *ex; ext4_fsblk_t pblk; @@ -2584,6 +2585,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, ex_ee_block = le32_to_cpu(ex->ee_block); ex_ee_len = ext4_ext_get_actual_len(ex); + ex_ee_entries = le16_to_cpu(eh->eh_entries); trace_ext4_ext_rm_leaf(inode, start, ex, *partial_cluster); @@ -2662,11 +2664,9 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, if (err) goto out; - if (num == 0) - /* this extent is removed; mark slot entirely unused */ - ext4_ext_store_pblock(ex, 0); + if (num != 0) + ex->ee_len = cpu_to_le16(num); - ex->ee_len = cpu_to_le16(num); /* * Do not mark uninitialized if all the blocks in the * extent have been removed. @@ -2726,8 +2726,19 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, /* if this leaf is free, then we should * remove it from index block above */ - if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL) + if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL) { + err = ext4_ext_get_access(handle, inode, path + depth); + if (err) + goto out; + + ext4_ext_store_entries(path[depth].p_hdr, ex_ee_entries); + + err = ext4_ext_dirty(handle, inode, path + depth); + if (err) + goto out; + err = ext4_ext_rm_idx(handle, inode, path, depth); + } out: return err; @@ -2760,6 +2771,7 @@ int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, struct super_block *sb = inode->i_sb; int depth = ext_depth(inode); struct ext4_ext_path *path = NULL; + unsigned short *entries_path = NULL; long long partial_cluster = 0; handle_t *handle; int i = 0, err = 0; @@ -2864,6 +2876,18 @@ again: } err = 0; + if (!inode->i_nlink) { + entries_path = kzalloc(sizeof(short) * (depth + 1), + GFP_NOFS); + if (entries_path == NULL) { + kfree(path); + ext4_journal_stop(handle); + return -ENOMEM; + } + + entries_path[0] = le16_to_cpu(ext_inode_hdr(inode)->eh_entries); + } + while (i >= 0 && err == 0) { if (i == depth) { /* this is leaf block */ @@ -2890,6 +2914,10 @@ again: ext_debug("init index ptr: hdr 0x%p, num %d\n", path[i].p_hdr, le16_to_cpu(path[i].p_hdr->eh_entries)); + if (entries_path != NULL) { + entries_path[i] = le16_to_cpu( + path[i].p_hdr->eh_entries); + } } else { /* we were already here, see at next index */ path[i].p_idx--; @@ -2928,10 +2956,24 @@ again: } else { /* we finished processing this index, go up */ if (path[i].p_hdr->eh_entries == 0 && i > 0) { + if (entries_path != NULL) { + err = ext4_ext_get_access(handle, + inode, path); + if (err == 0) { + ext4_ext_store_entries( + path[i].p_hdr, + (entries_path[i])); + err = ext4_ext_dirty(handle, + inode, path); + } + } + /* index is empty, remove it; * handle must be already prepared by the * truncatei_leaf() */ - err = ext4_ext_rm_idx(handle, inode, path, i); + if (err == 0) + err = ext4_ext_rm_idx(handle, inode, + path, i); } /* root level has p_bh == NULL, brelse() eats this */ brelse(path[i].p_bh); @@ -2964,6 +3006,17 @@ again: */ err = ext4_ext_get_access(handle, inode, path); if (err == 0) { + /* Store depth and entries to eh_generation to make + * recovering deleted files easier. */ + if (entries_path != NULL) { + ext4_ext_store_entries(ext_inode_hdr(inode), + (entries_path[0])); + + ext4_ext_store_depth(ext_inode_hdr(inode), + le16_to_cpu( + ext_inode_hdr(inode)->eh_depth)); + } + ext_inode_hdr(inode)->eh_depth = 0; ext_inode_hdr(inode)->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0)); @@ -2973,6 +3026,8 @@ again: out: ext4_ext_drop_refs(path); kfree(path); + kfree(entries_path); + if (err == -EAGAIN) { path = NULL; goto again;