Add Jan Kara's ext4 data corruption bugs for blocksize < pagesize
[ext4-patch-queue.git] / pass-allocation_request-struct-to-ext4_alloc_branch
blobd7fdfe8e345d6dc374c33eeef8058ba36bef4c89
1 ext4: pass allocation_request struct to ext4_(alloc,splice)_branch
3 Instead of initializing the allocation_request structure in
4 ext4_alloc_branch(), set it up in ext4_ind_map_blocks(), and then pass
5 it to ext4_alloc_branch() and ext4_splice_branch().
7 This allows ext4_ind_map_blocks to pass flags in the allocation
8 request structure without having to add Yet Another argument to
9 ext4_alloc_branch().
11 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
12 Reviewed-by: Jan Kara <jack@suse.cz>
13 ---
14  fs/ext4/indirect.c | 82 +++++++++++++++++++++++++++++----------------------------------
15  1 file changed, 38 insertions(+), 44 deletions(-)
17 diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
18 index e75f840..69af0cd 100644
19 --- a/fs/ext4/indirect.c
20 +++ b/fs/ext4/indirect.c
21 @@ -318,34 +318,22 @@ static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks,
22   *     ext4_alloc_block() (normally -ENOSPC). Otherwise we set the chain
23   *     as described above and return 0.
24   */
25 -static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
26 -                            ext4_lblk_t iblock, int indirect_blks,
27 -                            int *blks, ext4_fsblk_t goal,
28 -                            ext4_lblk_t *offsets, Indirect *branch)
29 +static int ext4_alloc_branch(handle_t *handle,
30 +                            struct ext4_allocation_request *ar,
31 +                            int indirect_blks, ext4_lblk_t *offsets,
32 +                            Indirect *branch)
33  {
34 -       struct ext4_allocation_request  ar;
35         struct buffer_head *            bh;
36         ext4_fsblk_t                    b, new_blocks[4];
37         __le32                          *p;
38         int                             i, j, err, len = 1;
40 -       /*
41 -        * Set up for the direct block allocation
42 -        */
43 -       memset(&ar, 0, sizeof(ar));
44 -       ar.inode = inode;
45 -       ar.len = *blks;
46 -       ar.logical = iblock;
47 -       if (S_ISREG(inode->i_mode))
48 -               ar.flags = EXT4_MB_HINT_DATA;
50         for (i = 0; i <= indirect_blks; i++) {
51                 if (i == indirect_blks) {
52 -                       ar.goal = goal;
53 -                       new_blocks[i] = ext4_mb_new_blocks(handle, &ar, &err);
54 +                       new_blocks[i] = ext4_mb_new_blocks(handle, ar, &err);
55                 } else
56 -                       goal = new_blocks[i] = ext4_new_meta_blocks(handle, inode,
57 -                                                       goal, 0, NULL, &err);
58 +                       ar->goal = new_blocks[i] = ext4_new_meta_blocks(handle,
59 +                                   ar->inode, ar->goal, 0, NULL, &err);
60                 if (err) {
61                         i--;
62                         goto failed;
63 @@ -354,7 +342,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
64                 if (i == 0)
65                         continue;
67 -               bh = branch[i].bh = sb_getblk(inode->i_sb, new_blocks[i-1]);
68 +               bh = branch[i].bh = sb_getblk(ar->inode->i_sb, new_blocks[i-1]);
69                 if (unlikely(!bh)) {
70                         err = -ENOMEM;
71                         goto failed;
72 @@ -372,7 +360,7 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
73                 b = new_blocks[i];
75                 if (i == indirect_blks)
76 -                       len = ar.len;
77 +                       len = ar->len;
78                 for (j = 0; j < len; j++)
79                         *p++ = cpu_to_le32(b++);
81 @@ -381,11 +369,10 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
82                 unlock_buffer(bh);
84                 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
85 -               err = ext4_handle_dirty_metadata(handle, inode, bh);
86 +               err = ext4_handle_dirty_metadata(handle, ar->inode, bh);
87                 if (err)
88                         goto failed;
89         }
90 -       *blks = ar.len;
91         return 0;
92  failed:
93         for (; i >= 0; i--) {
94 @@ -396,10 +383,10 @@ failed:
95                  * existing before ext4_alloc_branch() was called.
96                  */
97                 if (i > 0 && i != indirect_blks && branch[i].bh)
98 -                       ext4_forget(handle, 1, inode, branch[i].bh,
99 +                       ext4_forget(handle, 1, ar->inode, branch[i].bh,
100                                     branch[i].bh->b_blocknr);
101 -               ext4_free_blocks(handle, inode, NULL, new_blocks[i],
102 -                                (i == indirect_blks) ? ar.len : 1, 0);
103 +               ext4_free_blocks(handle, ar->inode, NULL, new_blocks[i],
104 +                                (i == indirect_blks) ? ar->len : 1, 0);
105         }
106         return err;
108 @@ -419,9 +406,9 @@ failed:
109   * inode (->i_blocks, etc.). In case of success we end up with the full
110   * chain to new block and return 0.
111   */
112 -static int ext4_splice_branch(handle_t *handle, struct inode *inode,
113 -                             ext4_lblk_t block, Indirect *where, int num,
114 -                             int blks)
115 +static int ext4_splice_branch(handle_t *handle,
116 +                             struct ext4_allocation_request *ar,
117 +                             Indirect *where, int num)
119         int i;
120         int err = 0;
121 @@ -446,9 +433,9 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
122          * Update the host buffer_head or inode to point to more just allocated
123          * direct blocks blocks
124          */
125 -       if (num == 0 && blks > 1) {
126 +       if (num == 0 && ar->len > 1) {
127                 current_block = le32_to_cpu(where->key) + 1;
128 -               for (i = 1; i < blks; i++)
129 +               for (i = 1; i < ar->len; i++)
130                         *(where->p + i) = cpu_to_le32(current_block++);
131         }
133 @@ -465,14 +452,14 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
134                  */
135                 jbd_debug(5, "splicing indirect only\n");
136                 BUFFER_TRACE(where->bh, "call ext4_handle_dirty_metadata");
137 -               err = ext4_handle_dirty_metadata(handle, inode, where->bh);
138 +               err = ext4_handle_dirty_metadata(handle, ar->inode, where->bh);
139                 if (err)
140                         goto err_out;
141         } else {
142                 /*
143                  * OK, we spliced it into the inode itself on a direct block.
144                  */
145 -               ext4_mark_inode_dirty(handle, inode);
146 +               ext4_mark_inode_dirty(handle, ar->inode);
147                 jbd_debug(5, "splicing direct\n");
148         }
149         return err;
150 @@ -484,11 +471,11 @@ err_out:
151                  * need to revoke the block, which is why we don't
152                  * need to set EXT4_FREE_BLOCKS_METADATA.
153                  */
154 -               ext4_free_blocks(handle, inode, where[i].bh, 0, 1,
155 +               ext4_free_blocks(handle, ar->inode, where[i].bh, 0, 1,
156                                  EXT4_FREE_BLOCKS_FORGET);
157         }
158 -       ext4_free_blocks(handle, inode, NULL, le32_to_cpu(where[num].key),
159 -                        blks, 0);
160 +       ext4_free_blocks(handle, ar->inode, NULL, le32_to_cpu(where[num].key),
161 +                        ar->len, 0);
163         return err;
165 @@ -525,11 +512,11 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
166                         struct ext4_map_blocks *map,
167                         int flags)
169 +       struct ext4_allocation_request ar;
170         int err = -EIO;
171         ext4_lblk_t offsets[4];
172         Indirect chain[4];
173         Indirect *partial;
174 -       ext4_fsblk_t goal;
175         int indirect_blks;
176         int blocks_to_boundary = 0;
177         int depth;
178 @@ -579,7 +566,14 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
179                 return -ENOSPC;
180         }
182 -       goal = ext4_find_goal(inode, map->m_lblk, partial);
183 +       /* Set up for the direct block allocation */
184 +       memset(&ar, 0, sizeof(ar));
185 +       ar.inode = inode;
186 +       ar.logical = map->m_lblk;
187 +       if (S_ISREG(inode->i_mode))
188 +               ar.flags = EXT4_MB_HINT_DATA;
190 +       ar.goal = ext4_find_goal(inode, map->m_lblk, partial);
192         /* the number of blocks need to allocate for [d,t]indirect blocks */
193         indirect_blks = (chain + depth) - partial - 1;
194 @@ -588,13 +582,13 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
195          * Next look up the indirect map to count the totoal number of
196          * direct blocks to allocate for this branch.
197          */
198 -       count = ext4_blks_to_allocate(partial, indirect_blks,
199 -                                     map->m_len, blocks_to_boundary);
200 +       ar.len = ext4_blks_to_allocate(partial, indirect_blks,
201 +                                      map->m_len, blocks_to_boundary);
203         /*
204          * Block out ext4_truncate while we alter the tree
205          */
206 -       err = ext4_alloc_branch(handle, inode, map->m_lblk, indirect_blks,
207 -                               &count, goal,
208 +       err = ext4_alloc_branch(handle, &ar, indirect_blks,
209                                 offsets + (partial - chain), partial);
211         /*
212 @@ -605,14 +599,14 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
213          * may need to return -EAGAIN upwards in the worst case.  --sct
214          */
215         if (!err)
216 -               err = ext4_splice_branch(handle, inode, map->m_lblk,
217 -                                        partial, indirect_blks, count);
218 +               err = ext4_splice_branch(handle, &ar, partial, indirect_blks);
219         if (err)
220                 goto cleanup;
222         map->m_flags |= EXT4_MAP_NEW;
224         ext4_update_inode_fsync_trans(handle, inode, 1);
225 +       count = ar.len;
226  got_it:
227         map->m_flags |= EXT4_MAP_MAPPED;
228         map->m_pblk = le32_to_cpu(chain[depth-1].key);