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;