diff options
Diffstat (limited to 'fs/btrfs/transaction.c')
-rw-r--r-- | fs/btrfs/transaction.c | 36 |
1 files changed, 17 insertions, 19 deletions
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 | } | ||
277 | again: | 290 | again: |
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 | ||
333 | got_it: | 331 | got_it: |