mirror of
https://github.com/versity/scoutfs.git
synced 2026-06-08 04:32:35 +00:00
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 <agrover@versity.com> [zab@versity.com: fixed up write_begin error paths]
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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) \
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user