aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2011-06-07 15:07:51 -0400
committerJosef Bacik <josef@redhat.com>2011-07-11 09:58:47 -0400
commitb5009945be18023942ce28327893c7bc1e58fe54 (patch)
treefe2e04196c833a3b609a1cf947293aafcf90a7bd /fs
parentfa09200b8334f9a6af3f656edae924a98d85630f (diff)
Btrfs: do transaction space reservation before joining the transaction
We have to do weird things when handling enospc in the transaction joining code. Because we've already joined the transaction we cannot commit the transaction within the reservation code since it will deadlock, so we have to return EAGAIN and then make sure we don't retry too many times. Instead of doing this, just do the reservation the normal way before we join the transaction, that way we can do whatever we want to try and reclaim space, and then if it fails we know for sure we are out of space and we can return ENOSPC. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/extent-tree.c20
-rw-r--r--fs/btrfs/transaction.c36
3 files changed, 17 insertions, 42 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 60e13ef23a5e..28e170bcdcb5 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -2223,9 +2223,6 @@ void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde);
2223void btrfs_clear_space_info_full(struct btrfs_fs_info *info); 2223void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
2224int btrfs_check_data_free_space(struct inode *inode, u64 bytes); 2224int btrfs_check_data_free_space(struct inode *inode, u64 bytes);
2225void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes); 2225void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes);
2226int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
2227 struct btrfs_root *root,
2228 int num_items);
2229void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, 2226void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
2230 struct btrfs_root *root); 2227 struct btrfs_root *root);
2231int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans, 2228int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 71cd456fdb60..0ed5fe03a06a 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3874,26 +3874,6 @@ int btrfs_truncate_reserve_metadata(struct btrfs_trans_handle *trans,
3874 return 0; 3874 return 0;
3875} 3875}
3876 3876
3877int btrfs_trans_reserve_metadata(struct btrfs_trans_handle *trans,
3878 struct btrfs_root *root,
3879 int num_items)
3880{
3881 u64 num_bytes;
3882 int ret;
3883
3884 if (num_items == 0 || root->fs_info->chunk_root == root)
3885 return 0;
3886
3887 num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
3888 ret = btrfs_block_rsv_add(trans, root, &root->fs_info->trans_block_rsv,
3889 num_bytes);
3890 if (!ret) {
3891 trans->bytes_reserved += num_bytes;
3892 trans->block_rsv = &root->fs_info->trans_block_rsv;
3893 }
3894 return ret;
3895}
3896
3897void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, 3877void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
3898 struct btrfs_root *root) 3878 struct btrfs_root *root)
3899{ 3879{
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 51dcec86757f..654755b18951 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -260,7 +260,7 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
260{ 260{
261 struct btrfs_trans_handle *h; 261 struct btrfs_trans_handle *h;
262 struct btrfs_transaction *cur_trans; 262 struct btrfs_transaction *cur_trans;
263 int retries = 0; 263 u64 num_bytes = 0;
264 int ret; 264 int ret;
265 265
266 if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) 266 if (root->fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)
@@ -274,6 +274,19 @@ static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
274 h->block_rsv = NULL; 274 h->block_rsv = NULL;
275 goto got_it; 275 goto got_it;
276 } 276 }
277
278 /*
279 * Do the reservation before we join the transaction so we can do all
280 * the appropriate flushing if need be.
281 */
282 if (num_items > 0 && root != root->fs_info->chunk_root) {
283 num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
284 ret = btrfs_block_rsv_add(NULL, root,
285 &root->fs_info->trans_block_rsv,
286 num_bytes);
287 if (ret)
288 return ERR_PTR(ret);
289 }
277again: 290again:
278 h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS); 291 h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
279 if (!h) 292 if (!h)
@@ -310,24 +323,9 @@ again:
310 goto again; 323 goto again;
311 } 324 }
312 325
313 if (num_items > 0) { 326 if (num_bytes) {
314 ret = btrfs_trans_reserve_metadata(h, root, num_items); 327 h->block_rsv = &root->fs_info->trans_block_rsv;
315 if (ret == -EAGAIN && !retries) { 328 h->bytes_reserved = num_bytes;
316 retries++;
317 btrfs_commit_transaction(h, root);
318 goto again;
319 } else if (ret == -EAGAIN) {
320 /*
321 * We have already retried and got EAGAIN, so really we
322 * don't have space, so set ret to -ENOSPC.
323 */
324 ret = -ENOSPC;
325 }
326
327 if (ret < 0) {
328 btrfs_end_transaction(h, root);
329 return ERR_PTR(ret);
330 }
331 } 329 }
332 330
333got_it: 331got_it: