This patch should make undelete process for deleted files under ext4 fs easier. Signed-off-by: Lubos Uhliarik <uhliarik@xxxxxxxxx> --- 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; -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html