add patch fix-off-by-one-fsmap-error-on-1k-block-filesystems
[ext4-patch-queue.git] / cleanup-transaction-restarts-during-inode-deletion
blob2a793aad7b8c3f4b23a84b6f94bac3b4a5dad1d8
1 ext4: cleanup transaction restarts during inode deletion
3 From: Tahsin Erdogan <tahsin@google.com>
5 During inode deletion, the number of journal credits that will be
6 needed is hard to determine.  For that reason we have journal
7 extend/restart calls in several places.  Whenever a transaction is
8 restarted, filesystem must be in a consistent state because there is
9 no atomicity guarantee beyond a restart call.
11 Add ext4_xattr_ensure_credits() helper function which takes care of
12 journal extend/restart logic.  It also handles getting jbd2 write
13 access and dirty metadata calls.  This function is called at every
14 iteration of handling an ea_inode reference.
16 Signed-off-by: Tahsin Erdogan <tahsin@google.com>
17 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
18 ---
19 v3: fixed checkpatch.pl warnings about long lines and indented label 
21 v2: made ext4_xattr_ensure_credits() static
23  fs/ext4/inode.c |  66 ++++-----------
24  fs/ext4/xattr.c | 258 ++++++++++++++++++++++++++++++++++++--------------------
25  fs/ext4/xattr.h |   3 +-
26  3 files changed, 184 insertions(+), 143 deletions(-)
28 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
29 index cf91532765a4..cd007f9757d1 100644
30 --- a/fs/ext4/inode.c
31 +++ b/fs/ext4/inode.c
32 @@ -239,7 +239,11 @@ void ext4_evict_inode(struct inode *inode)
33          */
34         sb_start_intwrite(inode->i_sb);
36 -       handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, extra_credits);
37 +       if (!IS_NOQUOTA(inode))
38 +               extra_credits += EXT4_MAXQUOTAS_DEL_BLOCKS(inode->i_sb);
40 +       handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE,
41 +                                ext4_blocks_for_truncate(inode)+extra_credits);
42         if (IS_ERR(handle)) {
43                 ext4_std_error(inode->i_sb, PTR_ERR(handle));
44                 /*
45 @@ -251,36 +255,9 @@ void ext4_evict_inode(struct inode *inode)
46                 sb_end_intwrite(inode->i_sb);
47                 goto no_delete;
48         }
50         if (IS_SYNC(inode))
51                 ext4_handle_sync(handle);
53 -       /*
54 -        * Delete xattr inode before deleting the main inode.
55 -        */
56 -       err = ext4_xattr_delete_inode(handle, inode, &ea_inode_array);
57 -       if (err) {
58 -               ext4_warning(inode->i_sb,
59 -                            "couldn't delete inode's xattr (err %d)", err);
60 -               goto stop_handle;
61 -       }
63 -       if (!IS_NOQUOTA(inode))
64 -               extra_credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb);
66 -       if (!ext4_handle_has_enough_credits(handle,
67 -                       ext4_blocks_for_truncate(inode) + extra_credits)) {
68 -               err = ext4_journal_extend(handle,
69 -                       ext4_blocks_for_truncate(inode) + extra_credits);
70 -               if (err > 0)
71 -                       err = ext4_journal_restart(handle,
72 -                       ext4_blocks_for_truncate(inode) + extra_credits);
73 -               if (err != 0) {
74 -                       ext4_warning(inode->i_sb,
75 -                                    "couldn't extend journal (err %d)", err);
76 -                       goto stop_handle;
77 -               }
78 -       }
80         inode->i_size = 0;
81         err = ext4_mark_inode_dirty(handle, inode);
82         if (err) {
83 @@ -298,25 +275,17 @@ void ext4_evict_inode(struct inode *inode)
84                 }
85         }
87 -       /*
88 -        * ext4_ext_truncate() doesn't reserve any slop when it
89 -        * restarts journal transactions; therefore there may not be
90 -        * enough credits left in the handle to remove the inode from
91 -        * the orphan list and set the dtime field.
92 -        */
93 -       if (!ext4_handle_has_enough_credits(handle, extra_credits)) {
94 -               err = ext4_journal_extend(handle, extra_credits);
95 -               if (err > 0)
96 -                       err = ext4_journal_restart(handle, extra_credits);
97 -               if (err != 0) {
98 -                       ext4_warning(inode->i_sb,
99 -                                    "couldn't extend journal (err %d)", err);
100 -               stop_handle:
101 -                       ext4_journal_stop(handle);
102 -                       ext4_orphan_del(NULL, inode);
103 -                       sb_end_intwrite(inode->i_sb);
104 -                       goto no_delete;
105 -               }
106 +       /* Remove xattr references. */
107 +       err = ext4_xattr_delete_inode(handle, inode, &ea_inode_array,
108 +                                     extra_credits);
109 +       if (err) {
110 +               ext4_warning(inode->i_sb, "xattr delete (err %d)", err);
111 +stop_handle:
112 +               ext4_journal_stop(handle);
113 +               ext4_orphan_del(NULL, inode);
114 +               sb_end_intwrite(inode->i_sb);
115 +               ext4_xattr_inode_array_free(ea_inode_array);
116 +               goto no_delete;
117         }
119         /*
120 @@ -342,7 +311,6 @@ void ext4_evict_inode(struct inode *inode)
121                 ext4_clear_inode(inode);
122         else
123                 ext4_free_inode(handle, inode);
125         ext4_journal_stop(handle);
126         sb_end_intwrite(inode->i_sb);
127         ext4_xattr_inode_array_free(ea_inode_array);
128 diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
129 index fd73dbc92c21..94f04b9fb421 100644
130 --- a/fs/ext4/xattr.c
131 +++ b/fs/ext4/xattr.c
132 @@ -108,6 +108,10 @@ const struct xattr_handler *ext4_xattr_handlers[] = {
133  #define EA_BLOCK_CACHE(inode)  (((struct ext4_sb_info *) \
134                                 inode->i_sb->s_fs_info)->s_ea_block_cache)
136 +static int
137 +ext4_expand_inode_array(struct ext4_xattr_inode_array **ea_inode_array,
138 +                       struct inode *inode);
140  #ifdef CONFIG_LOCKDEP
141  void ext4_xattr_inode_set_class(struct inode *ea_inode)
143 @@ -652,6 +656,128 @@ static void ext4_xattr_update_super_block(handle_t *handle,
144         }
147 +static int ext4_xattr_ensure_credits(handle_t *handle, struct inode *inode,
148 +                                    int credits, struct buffer_head *bh,
149 +                                    bool dirty, bool block_csum)
151 +       int error;
153 +       if (!ext4_handle_valid(handle))
154 +               return 0;
156 +       if (handle->h_buffer_credits >= credits)
157 +               return 0;
159 +       error = ext4_journal_extend(handle, credits - handle->h_buffer_credits);
160 +       if (!error)
161 +               return 0;
162 +       if (error < 0) {
163 +               ext4_warning(inode->i_sb, "Extend journal (error %d)", error);
164 +               return error;
165 +       }
167 +       if (bh && dirty) {
168 +               if (block_csum)
169 +                       ext4_xattr_block_csum_set(inode, bh);
170 +               error = ext4_handle_dirty_metadata(handle, NULL, bh);
171 +               if (error) {
172 +                       ext4_warning(inode->i_sb, "Handle metadata (error %d)",
173 +                                    error);
174 +                       return error;
175 +               }
176 +       }
178 +       error = ext4_journal_restart(handle, credits);
179 +       if (error) {
180 +               ext4_warning(inode->i_sb, "Restart journal (error %d)", error);
181 +               return error;
182 +       }
184 +       if (bh) {
185 +               error = ext4_journal_get_write_access(handle, bh);
186 +               if (error) {
187 +                       ext4_warning(inode->i_sb,
188 +                                    "Get write access failed (error %d)",
189 +                                    error);
190 +                       return error;
191 +               }
192 +       }
193 +       return 0;
196 +static void
197 +ext4_xattr_inode_remove_all(handle_t *handle, struct inode *parent,
198 +                           struct buffer_head *bh,
199 +                           struct ext4_xattr_entry *first, bool block_csum,
200 +                           struct ext4_xattr_inode_array **ea_inode_array,
201 +                           int extra_credits)
203 +       struct inode *ea_inode;
204 +       struct ext4_xattr_entry *entry;
205 +       bool dirty = false;
206 +       unsigned int ea_ino;
207 +       int err;
208 +       int credits;
210 +       /* One credit for dec ref on ea_inode, one for orphan list addition, */
211 +       credits = 2 + extra_credits;
213 +       for (entry = first; !IS_LAST_ENTRY(entry);
214 +            entry = EXT4_XATTR_NEXT(entry)) {
215 +               if (!entry->e_value_inum)
216 +                       continue;
217 +               ea_ino = le32_to_cpu(entry->e_value_inum);
218 +               err = ext4_xattr_inode_iget(parent, ea_ino, &ea_inode);
219 +               if (err)
220 +                       continue;
222 +               err = ext4_expand_inode_array(ea_inode_array, ea_inode);
223 +               if (err) {
224 +                       ext4_warning_inode(ea_inode,
225 +                                          "Expand inode array err=%d", err);
226 +                       iput(ea_inode);
227 +                       continue;
228 +               }
230 +               err = ext4_xattr_ensure_credits(handle, parent, credits, bh,
231 +                                               dirty, block_csum);
232 +               if (err) {
233 +                       ext4_warning_inode(ea_inode, "Ensure credits err=%d",
234 +                                          err);
235 +                       continue;
236 +               }
238 +               inode_lock(ea_inode);
239 +               clear_nlink(ea_inode);
240 +               ext4_orphan_add(handle, ea_inode);
241 +               inode_unlock(ea_inode);
243 +               /*
244 +                * Forget about ea_inode within the same transaction that
245 +                * decrements the ref count. This avoids duplicate decrements in
246 +                * case the rest of the work spills over to subsequent
247 +                * transactions.
248 +                */
249 +               entry->e_value_inum = 0;
250 +               entry->e_value_size = 0;
252 +               dirty = true;
253 +       }
255 +       if (dirty) {
256 +               /*
257 +                * Note that we are deliberately skipping csum calculation for
258 +                * the final update because we do not expect any journal
259 +                * restarts until xattr block is freed.
260 +                */
262 +               err = ext4_handle_dirty_metadata(handle, NULL, bh);
263 +               if (err)
264 +                       ext4_warning_inode(parent,
265 +                                          "handle dirty metadata err=%d", err);
266 +       }
269  /*
270   * Release the xattr block BH: If the reference count is > 1, decrement it;
271   * otherwise free the block.
272 @@ -1984,42 +2110,6 @@ ext4_expand_inode_array(struct ext4_xattr_inode_array **ea_inode_array,
273         return 0;
276 -/**
277 - * Add xattr inode to orphan list
278 - */
279 -static int
280 -ext4_xattr_inode_orphan_add(handle_t *handle, struct inode *inode, int credits,
281 -                           struct ext4_xattr_inode_array *ea_inode_array)
283 -       int idx = 0, error = 0;
284 -       struct inode *ea_inode;
286 -       if (ea_inode_array == NULL)
287 -               return 0;
289 -       for (; idx < ea_inode_array->count; ++idx) {
290 -               if (!ext4_handle_has_enough_credits(handle, credits)) {
291 -                       error = ext4_journal_extend(handle, credits);
292 -                       if (error > 0)
293 -                               error = ext4_journal_restart(handle, credits);
295 -                       if (error != 0) {
296 -                               ext4_warning(inode->i_sb,
297 -                                       "couldn't extend journal "
298 -                                       "(err %d)", error);
299 -                               return error;
300 -                       }
301 -               }
302 -               ea_inode = ea_inode_array->inodes[idx];
303 -               inode_lock(ea_inode);
304 -               ext4_orphan_add(handle, ea_inode);
305 -               inode_unlock(ea_inode);
306 -               /* the inode's i_count will be released by caller */
307 -       }
309 -       return 0;
312  /*
313   * ext4_xattr_delete_inode()
314   *
315 @@ -2032,16 +2122,23 @@ ext4_xattr_inode_orphan_add(handle_t *handle, struct inode *inode, int credits,
316   */
317  int
318  ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
319 -                       struct ext4_xattr_inode_array **ea_inode_array)
320 +                       struct ext4_xattr_inode_array **ea_inode_array,
321 +                       int extra_credits)
323         struct buffer_head *bh = NULL;
324         struct ext4_xattr_ibody_header *header;
325         struct ext4_inode *raw_inode;
326 -       struct ext4_iloc iloc;
327 -       struct ext4_xattr_entry *entry;
328 -       struct inode *ea_inode;
329 -       unsigned int ea_ino;
330 -       int credits = 3, error = 0;
331 +       struct ext4_iloc iloc = { .bh = NULL };
332 +       int error;
334 +       error = ext4_xattr_ensure_credits(handle, inode, extra_credits,
335 +                                         NULL /* bh */,
336 +                                         false /* dirty */,
337 +                                         false /* block_csum */);
338 +       if (error) {
339 +               EXT4_ERROR_INODE(inode, "ensure credits (error %d)", error);
340 +               goto cleanup;
341 +       }
343         if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR))
344                 goto delete_external_ea;
345 @@ -2049,31 +2146,20 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
346         error = ext4_get_inode_loc(inode, &iloc);
347         if (error)
348                 goto cleanup;
350 +       error = ext4_journal_get_write_access(handle, iloc.bh);
351 +       if (error)
352 +               goto cleanup;
354         raw_inode = ext4_raw_inode(&iloc);
355         header = IHDR(inode, raw_inode);
356 -       for (entry = IFIRST(header); !IS_LAST_ENTRY(entry);
357 -            entry = EXT4_XATTR_NEXT(entry)) {
358 -               if (!entry->e_value_inum)
359 -                       continue;
360 -               ea_ino = le32_to_cpu(entry->e_value_inum);
361 -               error = ext4_xattr_inode_iget(inode, ea_ino, &ea_inode);
362 -               if (error)
363 -                       continue;
364 -               error = ext4_expand_inode_array(ea_inode_array, ea_inode);
365 -               if (error) {
366 -                       iput(ea_inode);
367 -                       brelse(iloc.bh);
368 -                       goto cleanup;
369 -               }
370 -               entry->e_value_inum = 0;
371 -       }
372 -       brelse(iloc.bh);
373 +       ext4_xattr_inode_remove_all(handle, inode, iloc.bh, IFIRST(header),
374 +                                   false /* block_csum */, ea_inode_array,
375 +                                   extra_credits);
377  delete_external_ea:
378         if (!EXT4_I(inode)->i_file_acl) {
379 -               /* add xattr inode to orphan list */
380 -               error = ext4_xattr_inode_orphan_add(handle, inode, credits,
381 -                                                   *ea_inode_array);
382 +               error = 0;
383                 goto cleanup;
384         }
385         bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
386 @@ -2091,46 +2177,32 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
387                 goto cleanup;
388         }
390 -       for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry);
391 -            entry = EXT4_XATTR_NEXT(entry)) {
392 -               if (!entry->e_value_inum)
393 -                       continue;
394 -               ea_ino = le32_to_cpu(entry->e_value_inum);
395 -               error = ext4_xattr_inode_iget(inode, ea_ino, &ea_inode);
396 -               if (error)
397 -                       continue;
398 -               error = ext4_expand_inode_array(ea_inode_array, ea_inode);
399 -               if (error)
400 -                       goto cleanup;
401 -               entry->e_value_inum = 0;
402 -       }
404 -       /* add xattr inode to orphan list */
405 -       error = ext4_xattr_inode_orphan_add(handle, inode, credits,
406 -                                       *ea_inode_array);
407 -       if (error)
408 -               goto cleanup;
410 -       if (!IS_NOQUOTA(inode))
411 -               credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb);
413 -       if (!ext4_handle_has_enough_credits(handle, credits)) {
414 -               error = ext4_journal_extend(handle, credits);
415 -               if (error > 0)
416 -                       error = ext4_journal_restart(handle, credits);
417 +       if (ext4_has_feature_ea_inode(inode->i_sb)) {
418 +               error = ext4_journal_get_write_access(handle, bh);
419                 if (error) {
420 -                       ext4_warning(inode->i_sb,
421 -                               "couldn't extend journal (err %d)", error);
422 +                       EXT4_ERROR_INODE(inode, "write access %llu",
423 +                                        EXT4_I(inode)->i_file_acl);
424                         goto cleanup;
425                 }
426 +               ext4_xattr_inode_remove_all(handle, inode, bh,
427 +                                           BFIRST(bh),
428 +                                           true /* block_csum */,
429 +                                           ea_inode_array,
430 +                                           extra_credits);
431         }
433         ext4_xattr_release_block(handle, inode, bh);
434 +       /* Update i_file_acl within the same transaction that releases block. */
435         EXT4_I(inode)->i_file_acl = 0;
437 +       error = ext4_mark_inode_dirty(handle, inode);
438 +       if (error) {
439 +               EXT4_ERROR_INODE(inode, "mark inode dirty (error %d)",
440 +                                error);
441 +               goto cleanup;
442 +       }
443  cleanup:
444 +       brelse(iloc.bh);
445         brelse(bh);
447         return error;
450 diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
451 index adf761518a73..b2005a2716d9 100644
452 --- a/fs/ext4/xattr.h
453 +++ b/fs/ext4/xattr.h
454 @@ -169,7 +169,8 @@ extern int ext4_xattr_set_credits(struct inode *inode, size_t value_len);
456  extern int ext4_xattr_inode_unlink(struct inode *inode, unsigned long ea_ino);
457  extern int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode,
458 -                                  struct ext4_xattr_inode_array **array);
459 +                                  struct ext4_xattr_inode_array **array,
460 +                                  int extra_credits);
461  extern void ext4_xattr_inode_array_free(struct ext4_xattr_inode_array *array);
463  extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
464 -- 
465 2.13.1.611.g7e3b11ae1-goog