Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ext4: reset retry counter when ext4_alloc_file_blocks() makes progress

Change the retry policy in ext4_alloc_file_blocks() to allow for a full
retry cycle whenever a portion of an allocation request has been
fulfilled. A large allocation request often results in multiple calls
to ext4_map_blocks(), each of which is potentially subject to a
temporary ENOSPC condition and retry cycle. The current code only
allows for a single retry cycle.

This patch does not address a known bug or reported complaint.
However, it should make block allocation for fallocate and zero range
more robust.

In addition, simplify the conditional controlling the allocation while
loop, where testing len alone is sufficient. Remove the assignment to
ret2 in the error path after the call to ext4_map_blocks() since its
value isn't subsequently used.

Signed-off-by: Eric Whitney <enwlinux@gmail.com>
Link: https://lore.kernel.org/r/20210113221403.18258-1-enwlinux@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>

authored by

Eric Whitney and committed by
Theodore Ts'o
3258386a b5776e75

+8 -8
+8 -8
fs/ext4/extents.c
··· 4382 4382 { 4383 4383 struct inode *inode = file_inode(file); 4384 4384 handle_t *handle; 4385 - int ret = 0; 4386 - int ret2 = 0, ret3 = 0; 4385 + int ret, ret2 = 0, ret3 = 0; 4387 4386 int retries = 0; 4388 4387 int depth = 0; 4389 4388 struct ext4_map_blocks map; ··· 4407 4408 depth = ext_depth(inode); 4408 4409 4409 4410 retry: 4410 - while (ret >= 0 && len) { 4411 + while (len) { 4411 4412 /* 4412 4413 * Recalculate credits when extent tree depth changes. 4413 4414 */ ··· 4429 4430 inode->i_ino, map.m_lblk, 4430 4431 map.m_len, ret); 4431 4432 ext4_mark_inode_dirty(handle, inode); 4432 - ret2 = ext4_journal_stop(handle); 4433 + ext4_journal_stop(handle); 4433 4434 break; 4434 4435 } 4436 + /* 4437 + * allow a full retry cycle for any remaining allocations 4438 + */ 4439 + retries = 0; 4435 4440 map.m_lblk += ret; 4436 4441 map.m_len = len = len - ret; 4437 4442 epos = (loff_t)map.m_lblk << inode->i_blkbits; ··· 4453 4450 if (unlikely(ret2)) 4454 4451 break; 4455 4452 } 4456 - if (ret == -ENOSPC && 4457 - ext4_should_retry_alloc(inode->i_sb, &retries)) { 4458 - ret = 0; 4453 + if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) 4459 4454 goto retry; 4460 - } 4461 4455 4462 4456 return ret > 0 ? ret2 : ret; 4463 4457 }