From 355eac79d2d0ed63e452e8c2c9d8482bf7025abf Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Sat, 16 Jan 2021 12:18:16 -0800 Subject: [PATCH] Retry if transaction cannot alloc for fallocate or write Add a new distinguishable return value (ENOBUFS) from allocator for if the transaction cannot alloc space. This doesn't mean the filesystem is full -- opening a new transaction may result in forward progress. Alter fallocate and get_blocks code to check for this err val and retry with a new transaction. Handling actual ENOSPC can still happen, of course. Add counter called "alloc_trans_retry" and increment it from both spots. Signed-off-by: Andy Grover [zab@versity.com: fixed up write_begin error paths] --- kmod/src/alloc.c | 7 ++++++- kmod/src/counters.h | 2 ++ kmod/src/data.c | 28 ++++++++++++++++++++-------- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/kmod/src/alloc.c b/kmod/src/alloc.c index 1d370dda..530e261f 100644 --- a/kmod/src/alloc.c +++ b/kmod/src/alloc.c @@ -770,8 +770,13 @@ int scoutfs_alloc_data(struct super_block *sb, struct scoutfs_alloc *alloc, ret = 0; out: if (ret < 0) { + /* + * Special retval meaning there wasn't space to alloc from + * this txn. Doesn't mean filesystem is completely full. + * Maybe upper layers want to try again. + */ if (ret == -ENOENT) - ret = -ENOSPC; + ret = -ENOBUFS; *blkno_ret = 0; *count_ret = 0; } else { diff --git a/kmod/src/counters.h b/kmod/src/counters.h index 6c470e58..819cf67c 100644 --- a/kmod/src/counters.h +++ b/kmod/src/counters.h @@ -58,6 +58,8 @@ EXPAND_COUNTER(corrupt_symlink_inode_size) \ EXPAND_COUNTER(corrupt_symlink_missing_item) \ EXPAND_COUNTER(corrupt_symlink_not_null_term) \ + EXPAND_COUNTER(data_fallocate_enobufs_retry) \ + EXPAND_COUNTER(data_write_begin_enobufs_retry) \ EXPAND_COUNTER(dentry_revalidate_error) \ EXPAND_COUNTER(dentry_revalidate_invalid) \ EXPAND_COUNTER(dentry_revalidate_locked) \ diff --git a/kmod/src/data.c b/kmod/src/data.c index 73b29e5a..33061d8d 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -751,6 +751,7 @@ static int scoutfs_write_begin(struct file *file, goto out; } +retry: do { ret = scoutfs_inode_index_start(sb, &ind_seq) ?: scoutfs_inode_index_prepare(sb, &wbd->ind_locks, inode, @@ -765,17 +766,22 @@ static int scoutfs_write_begin(struct file *file, flags |= AOP_FLAG_NOFS; /* generic write_end updates i_size and calls dirty_inode */ - ret = scoutfs_dirty_inode_item(inode, wbd->lock); - if (ret == 0) - ret = block_write_begin(mapping, pos, len, flags, pagep, - scoutfs_get_block_write); - if (ret) + ret = scoutfs_dirty_inode_item(inode, wbd->lock) ?: + block_write_begin(mapping, pos, len, flags, pagep, + scoutfs_get_block_write); + if (ret < 0) { scoutfs_release_trans(sb); -out: - if (ret) { scoutfs_inode_index_unlock(sb, &wbd->ind_locks); - kfree(wbd); + if (ret == -ENOBUFS) { + /* Retry with a new transaction. */ + scoutfs_inc_counter(sb, data_write_begin_enobufs_retry); + goto retry; + } } + +out: + if (ret < 0) + kfree(wbd); return ret; } @@ -1022,6 +1028,12 @@ long scoutfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) scoutfs_release_trans(sb); scoutfs_inode_index_unlock(sb, &ind_locks); + /* txn couldn't meet the request. Let's try with a new txn */ + if (ret == -ENOBUFS) { + scoutfs_inc_counter(sb, data_fallocate_enobufs_retry); + continue; + } + if (ret <= 0) goto out;