Add/replace fallocate/persistent allocate patches, and add jbd-stats
[ext4-patch-queue.git] / fallocate-3-extent-overlap-bugfix
blobe9e5e87d5aa9adf4f4ca57f64f1f2b2fb89db70d
1 From: "Amit K. Arora" <aarora@linux.vnet.ibm.com>
2 Subject: [PATCH 3/5] ext4: Extent overlap bugfix
3 Cc: linux-ext4@vger.kernel.org, suparna@in.ibm.com, cmm@us.ibm.com
5 This is a fix for an extent-overlap bug. The fallocate() implementation
6 on ext4 depends on this bugfix. Though this fix had been posted earlier,
7 but because it is still not part of mainline code, I have attached it
8 here too.
10 Signed-off-by: Amit Arora <aarora@in.ibm.com>
11 ---
12  fs/ext4/extents.c               |   50 ++++++++++++++++++++++++++++++++++++++--
13  include/linux/ext4_fs_extents.h |    1 
14  2 files changed, 49 insertions(+), 2 deletions(-)
16 Index: linux-2.6.21/fs/ext4/extents.c
17 ===================================================================
18 --- linux-2.6.21.orig/fs/ext4/extents.c
19 +++ linux-2.6.21/fs/ext4/extents.c
20 @@ -1129,6 +1129,45 @@ ext4_can_extents_be_merged(struct inode 
21  }
23  /*
24 + * ext4_ext_check_overlap:
25 + * check if a portion of the "newext" extent overlaps with an
26 + * existing extent.
27 + *
28 + * If there is an overlap discovered, it updates the length of the newext
29 + * such that there will be no overlap, and then returns 1.
30 + * If there is no overlap found, it returns 0.
31 + */
32 +unsigned int ext4_ext_check_overlap(struct inode *inode,
33 +                                       struct ext4_extent *newext,
34 +                                       struct ext4_ext_path *path)
36 +       unsigned long b1, b2;
37 +       unsigned int depth, len1;
39 +       b1 = le32_to_cpu(newext->ee_block);
40 +       len1 = le16_to_cpu(newext->ee_len);
41 +       depth = ext_depth(inode);
42 +       if (!path[depth].p_ext)
43 +               goto out;
44 +       b2 = le32_to_cpu(path[depth].p_ext->ee_block);
46 +       /* get the next allocated block if the extent in the path
47 +        * is before the requested block(s) */
48 +       if (b2 < b1) {
49 +               b2 = ext4_ext_next_allocated_block(path);
50 +               if (b2 == EXT_MAX_BLOCK)
51 +                       goto out;
52 +       }
54 +       if (b1 + len1 > b2) {
55 +               newext->ee_len = cpu_to_le16(b2 - b1);
56 +               return 1;
57 +       }
58 +out:
59 +       return 0;
62 +/*
63   * ext4_ext_insert_extent:
64   * tries to merge requsted extent into the existing extent or
65   * inserts requested extent as new one into the tree,
66 @@ -2032,7 +2071,15 @@ int ext4_ext_get_blocks(handle_t *handle
68         /* allocate new block */
69         goal = ext4_ext_find_goal(inode, path, iblock);
70 -       allocated = max_blocks;
72 +       /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */
73 +       newex.ee_block = cpu_to_le32(iblock);
74 +       newex.ee_len = cpu_to_le16(max_blocks);
75 +       err = ext4_ext_check_overlap(inode, &newex, path);
76 +       if (err)
77 +               allocated = le16_to_cpu(newex.ee_len);
78 +       else
79 +               allocated = max_blocks;
80         newblock = ext4_new_blocks(handle, inode, goal, &allocated, &err);
81         if (!newblock)
82                 goto out2;
83 @@ -2040,7 +2087,6 @@ int ext4_ext_get_blocks(handle_t *handle
84                         goal, newblock, allocated);
86         /* try to insert new extent into found leaf and return */
87 -       newex.ee_block = cpu_to_le32(iblock);
88         ext4_ext_store_pblock(&newex, newblock);
89         newex.ee_len = cpu_to_le16(allocated);
90         err = ext4_ext_insert_extent(handle, inode, path, &newex);
91 Index: linux-2.6.21/include/linux/ext4_fs_extents.h
92 ===================================================================
93 --- linux-2.6.21.orig/include/linux/ext4_fs_extents.h
94 +++ linux-2.6.21/include/linux/ext4_fs_extents.h
95 @@ -190,6 +190,7 @@ ext4_ext_invalidate_cache(struct inode *
97  extern int ext4_extent_tree_init(handle_t *, struct inode *);
98  extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *);
99 +extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *);
100  extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *);
101  extern int ext4_ext_walk_space(struct inode *, unsigned long, unsigned long, ext_prepare_callback, void *);
102  extern struct ext4_ext_path * ext4_ext_find_extent(struct inode *, int, struct ext4_ext_path *);
104 To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
105 the body of a message to majordomo@vger.kernel.org
106 More majordomo info at  http://vger.kernel.org/majordomo-info.html
107 Please read the FAQ at  http://www.tux.org/lkml/