mirror of
https://github.com/versity/scoutfs.git
synced 2026-04-18 04:31:04 +00:00
Avoid premature metadata enospc
server_get_log_trees() sets the low flag in a mount's meta_avail allocator, triggering enospc for any space consuming allocatins in the mount, if the server's global meta_vail pool falls below the reserved block count. Before each server transaction opens we swap the global meta_avail and meta_freed allocators to ensure that the transaction has at least the reserved count of blocks available. This creates a risk of premature enospc as the global meta_avail pool drains and swaps to the larger meta_freed. The pool can be close to the reserved count, perhaps at it exactly. _get_log_trees can fill the client's mount, even a little, and drop the global meta_avail total under the reserved count, triggering enospc, even though meta_Freed could have had quite a lot of blocks. The fix is to ensure that the global meta_avail has 2x the reserved count and swapping if it falls under that. This ensures that a server transaction can consume an entire reserved count and still have enough to avoid triggering enospc. This fixes a scattering of rare premature enospc returns that were hitting during tests. It was rare for meta_avail to fall just at the reserved count and for get_log_trees to have to refill the client allocator, but it happened. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
@@ -323,7 +323,6 @@ static void scoutfs_server_commit_func(struct work_struct *work)
|
||||
struct commit_waiter *cw;
|
||||
struct commit_waiter *pos;
|
||||
struct llist_node *node;
|
||||
u64 reserved;
|
||||
int ret;
|
||||
|
||||
trace_scoutfs_server_commit_work_enter(sb, 0, 0);
|
||||
@@ -389,16 +388,19 @@ static void scoutfs_server_commit_func(struct work_struct *work)
|
||||
server->other_freed = &super->server_meta_freed[server->other_ind];
|
||||
|
||||
/*
|
||||
* The reserved metadata blocks includes the max size of
|
||||
* outstanding allocators and a server transaction could be
|
||||
* asked to refill all those allocators from meta_avail. If our
|
||||
* meta_avail falls below the reserved count, and freed is still
|
||||
* above it, then swap so that we don't start returning enospc
|
||||
* until we're truly low.
|
||||
* get_log_trees sets ALLOC_LOW when its allocator drops below
|
||||
* the reserved blocks after having filled the log trees's avail
|
||||
* allocator during its transaction. To avoid prematurely
|
||||
* setting the low flag and causing enospc we make sure that the
|
||||
* next transaction's meta_avail has 2x the reserved blocks so
|
||||
* that it can consume a full reserved amount and still have
|
||||
* enough to avoid enospc. We swap to freed if avail is under
|
||||
* the buffer and freed is larger.
|
||||
*/
|
||||
reserved = scoutfs_server_reserved_meta_blocks(sb);
|
||||
if (le64_to_cpu(server->meta_avail->total_len) <= reserved &&
|
||||
le64_to_cpu(server->meta_freed->total_len) > reserved)
|
||||
if ((le64_to_cpu(server->meta_avail->total_len) <
|
||||
(scoutfs_server_reserved_meta_blocks(sb) * 2)) &&
|
||||
(le64_to_cpu(server->meta_freed->total_len) >
|
||||
le64_to_cpu(server->meta_avail->total_len)))
|
||||
swap(server->meta_avail, server->meta_freed);
|
||||
|
||||
ret = 0;
|
||||
|
||||
Reference in New Issue
Block a user