Commit 80fa46d6 authored by Theodore Ts'o's avatar Theodore Ts'o

ext4: limit the number of retries after discarding preallocations blocks

This patch avoids threads live-locking for hours when a large number
threads are competing over the last few free extents as they blocks
getting added and removed from preallocation pools.  From our bug
reporter:

   A reliable way for triggering this has multiple writers
   continuously write() to files when the filesystem is full, while
   small amounts of space are freed (e.g. by truncating a large file
   -1MiB at a time). In the local filesystem, this can be done by
   simply not checking the return code of write (0) and/or the error
   (ENOSPACE) that is set. Over NFS with an async mount, even clients
   with proper error checking will behave this way since the linux NFS
   client implementation will not propagate the server errors [the
   write syscalls immediately return success] until the file handle is
   closed. This leads to a situation where NFS clients send a
   continuous stream of WRITE rpcs which result in ERRNOSPACE -- but
   since the client isn't seeing this, the stream of writes continues
   at maximum network speed.

   When some space does appear, multiple writers will all attempt to
   claim it for their current write. For NFS, we may see dozens to
   hundreds of threads that do this.

   The real-world scenario of this is database backup tooling (in
   particular, github.com/mdkent/percona-xtrabackup) which may write
   large files (>1TiB) to NFS for safe keeping. Some temporary files
   are written, rewound, and read back -- all before closing the file
   handle (the temp file is actually unlinked, to trigger automatic
   deletion on close/crash.) An application like this operating on an
   async NFS mount will not see an error code until TiB have been
   written/read.

   The lockup was observed when running this database backup on large
   filesystems (64 TiB in this case) with a high number of block
   groups and no free space. Fragmentation is generally not a factor
   in this filesystem (~thousands of large files, mostly contiguous
   except for the parts written while the filesystem is at capacity.)
Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
Cc: stable@kernel.org
parent 29a5b8a1
...@@ -5533,6 +5533,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, ...@@ -5533,6 +5533,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
ext4_fsblk_t block = 0; ext4_fsblk_t block = 0;
unsigned int inquota = 0; unsigned int inquota = 0;
unsigned int reserv_clstrs = 0; unsigned int reserv_clstrs = 0;
int retries = 0;
u64 seq; u64 seq;
might_sleep(); might_sleep();
...@@ -5635,7 +5636,8 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, ...@@ -5635,7 +5636,8 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle,
ar->len = ac->ac_b_ex.fe_len; ar->len = ac->ac_b_ex.fe_len;
} }
} else { } else {
if (ext4_mb_discard_preallocations_should_retry(sb, ac, &seq)) if (++retries < 3 &&
ext4_mb_discard_preallocations_should_retry(sb, ac, &seq))
goto repeat; goto repeat;
/* /*
* If block allocation fails then the pa allocated above * If block allocation fails then the pa allocated above
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment