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>
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
32 @@ -239,7 +239,11 @@ void ext4_evict_inode(struct inode *inode)
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);
43 ext4_std_error(inode->i_sb, PTR_ERR(handle));
45 @@ -251,36 +255,9 @@ void ext4_evict_inode(struct inode *inode)
46 sb_end_intwrite(inode->i_sb);
51 ext4_handle_sync(handle);
54 - * Delete xattr inode before deleting the main inode.
56 - err = ext4_xattr_delete_inode(handle, inode, &ea_inode_array);
58 - ext4_warning(inode->i_sb,
59 - "couldn't delete inode's xattr (err %d)", err);
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);
71 - err = ext4_journal_restart(handle,
72 - ext4_blocks_for_truncate(inode) + extra_credits);
74 - ext4_warning(inode->i_sb,
75 - "couldn't extend journal (err %d)", err);
81 err = ext4_mark_inode_dirty(handle, inode);
83 @@ -298,25 +275,17 @@ void ext4_evict_inode(struct inode *inode)
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.
93 - if (!ext4_handle_has_enough_credits(handle, extra_credits)) {
94 - err = ext4_journal_extend(handle, extra_credits);
96 - err = ext4_journal_restart(handle, extra_credits);
98 - ext4_warning(inode->i_sb,
99 - "couldn't extend journal (err %d)", err);
101 - ext4_journal_stop(handle);
102 - ext4_orphan_del(NULL, inode);
103 - sb_end_intwrite(inode->i_sb);
106 + /* Remove xattr references. */
107 + err = ext4_xattr_delete_inode(handle, inode, &ea_inode_array,
110 + ext4_warning(inode->i_sb, "xattr delete (err %d)", err);
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);
120 @@ -342,7 +311,6 @@ void ext4_evict_inode(struct inode *inode)
121 ext4_clear_inode(inode);
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)
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,
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)
153 + if (!ext4_handle_valid(handle))
156 + if (handle->h_buffer_credits >= credits)
159 + error = ext4_journal_extend(handle, credits - handle->h_buffer_credits);
163 + ext4_warning(inode->i_sb, "Extend journal (error %d)", error);
169 + ext4_xattr_block_csum_set(inode, bh);
170 + error = ext4_handle_dirty_metadata(handle, NULL, bh);
172 + ext4_warning(inode->i_sb, "Handle metadata (error %d)",
178 + error = ext4_journal_restart(handle, credits);
180 + ext4_warning(inode->i_sb, "Restart journal (error %d)", error);
185 + error = ext4_journal_get_write_access(handle, bh);
187 + ext4_warning(inode->i_sb,
188 + "Get write access failed (error %d)",
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,
203 + struct inode *ea_inode;
204 + struct ext4_xattr_entry *entry;
205 + bool dirty = false;
206 + unsigned int ea_ino;
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)
217 + ea_ino = le32_to_cpu(entry->e_value_inum);
218 + err = ext4_xattr_inode_iget(parent, ea_ino, &ea_inode);
222 + err = ext4_expand_inode_array(ea_inode_array, ea_inode);
224 + ext4_warning_inode(ea_inode,
225 + "Expand inode array err=%d", err);
230 + err = ext4_xattr_ensure_credits(handle, parent, credits, bh,
231 + dirty, block_csum);
233 + ext4_warning_inode(ea_inode, "Ensure credits err=%d",
238 + inode_lock(ea_inode);
239 + clear_nlink(ea_inode);
240 + ext4_orphan_add(handle, ea_inode);
241 + inode_unlock(ea_inode);
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
249 + entry->e_value_inum = 0;
250 + entry->e_value_size = 0;
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.
262 + err = ext4_handle_dirty_metadata(handle, NULL, bh);
264 + ext4_warning_inode(parent,
265 + "handle dirty metadata err=%d", err);
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,
277 - * Add xattr inode to orphan list
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)
289 - for (; idx < ea_inode_array->count; ++idx) {
290 - if (!ext4_handle_has_enough_credits(handle, credits)) {
291 - error = ext4_journal_extend(handle, credits);
293 - error = ext4_journal_restart(handle, credits);
296 - ext4_warning(inode->i_sb,
297 - "couldn't extend journal "
298 - "(err %d)", error);
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 */
313 * ext4_xattr_delete_inode()
315 @@ -2032,16 +2122,23 @@ ext4_xattr_inode_orphan_add(handle_t *handle, struct inode *inode, int credits,
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,
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 };
334 + error = ext4_xattr_ensure_credits(handle, inode, extra_credits,
337 + false /* block_csum */);
339 + EXT4_ERROR_INODE(inode, "ensure credits (error %d)", error);
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);
350 + error = ext4_journal_get_write_access(handle, iloc.bh);
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)
360 - ea_ino = le32_to_cpu(entry->e_value_inum);
361 - error = ext4_xattr_inode_iget(inode, ea_ino, &ea_inode);
364 - error = ext4_expand_inode_array(ea_inode_array, ea_inode);
370 - entry->e_value_inum = 0;
373 + ext4_xattr_inode_remove_all(handle, inode, iloc.bh, IFIRST(header),
374 + false /* block_csum */, ea_inode_array,
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,
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,
390 - for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry);
391 - entry = EXT4_XATTR_NEXT(entry)) {
392 - if (!entry->e_value_inum)
394 - ea_ino = le32_to_cpu(entry->e_value_inum);
395 - error = ext4_xattr_inode_iget(inode, ea_ino, &ea_inode);
398 - error = ext4_expand_inode_array(ea_inode_array, ea_inode);
401 - entry->e_value_inum = 0;
404 - /* add xattr inode to orphan list */
405 - error = ext4_xattr_inode_orphan_add(handle, inode, credits,
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);
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);
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);
426 + ext4_xattr_inode_remove_all(handle, inode, bh,
428 + true /* block_csum */,
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);
439 + EXT4_ERROR_INODE(inode, "mark inode dirty (error %d)",
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,
465 2.13.1.611.g7e3b11ae1-goog