aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQu Wenruo <quwenruo@cn.fujitsu.com>2015-04-16 03:37:33 -0400
committerChris Mason <clm@fb.com>2015-06-10 12:25:49 -0400
commit550d7a2ed5db35756222ec17cff3376ff38d78e2 (patch)
treec8b60650e4ac8facdf25f498e2901b7eebb3f4ae
parent21633fc6037f8ceb2bb927dacc3f9ef46ccae891 (diff)
btrfs: qgroup: Add new qgroup calculation function
btrfs_qgroup_account_extents(). The new btrfs_qgroup_account_extents() function should be called in btrfs_commit_transaction() and it will update all the qgroup according to delayed_ref_root->dirty_extent_root. The new function can handle both normal operation during commit_transaction() or in rescan in a unified method with clearer logic. Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: Chris Mason <clm@fb.com>
-rw-r--r--fs/btrfs/extent-tree.h0
-rw-r--r--fs/btrfs/qgroup.c116
-rw-r--r--fs/btrfs/qgroup.h2
3 files changed, 118 insertions, 0 deletions
diff --git a/fs/btrfs/extent-tree.h b/fs/btrfs/extent-tree.h
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/fs/btrfs/extent-tree.h
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 7b18fff558ca..607c6ca34955 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -2455,6 +2455,122 @@ static int btrfs_qgroup_account(struct btrfs_trans_handle *trans,
2455 return ret; 2455 return ret;
2456} 2456}
2457 2457
2458static int
2459btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans,
2460 struct btrfs_fs_info *fs_info,
2461 u64 bytenr, u64 num_bytes,
2462 struct ulist *old_roots, struct ulist *new_roots)
2463{
2464 struct ulist *qgroups = NULL;
2465 struct ulist *tmp = NULL;
2466 u64 seq;
2467 u64 nr_new_roots = 0;
2468 u64 nr_old_roots = 0;
2469 int ret = 0;
2470
2471 if (new_roots)
2472 nr_new_roots = new_roots->nnodes;
2473 if (old_roots)
2474 nr_old_roots = old_roots->nnodes;
2475
2476 if (!fs_info->quota_enabled)
2477 goto out_free;
2478 BUG_ON(!fs_info->quota_root);
2479
2480 qgroups = ulist_alloc(GFP_NOFS);
2481 if (!qgroups) {
2482 ret = -ENOMEM;
2483 goto out_free;
2484 }
2485 tmp = ulist_alloc(GFP_NOFS);
2486 if (!tmp) {
2487 ret = -ENOMEM;
2488 goto out_free;
2489 }
2490
2491 mutex_lock(&fs_info->qgroup_rescan_lock);
2492 if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) {
2493 if (fs_info->qgroup_rescan_progress.objectid <= bytenr) {
2494 mutex_unlock(&fs_info->qgroup_rescan_lock);
2495 ret = 0;
2496 goto out_free;
2497 }
2498 }
2499 mutex_unlock(&fs_info->qgroup_rescan_lock);
2500
2501 spin_lock(&fs_info->qgroup_lock);
2502 seq = fs_info->qgroup_seq;
2503
2504 /* Update old refcnts using old_roots */
2505 ret = qgroup_update_refcnt(fs_info, old_roots, tmp, qgroups, seq,
2506 UPDATE_OLD);
2507 if (ret < 0)
2508 goto out;
2509
2510 /* Update new refcnts using new_roots */
2511 ret = qgroup_update_refcnt(fs_info, new_roots, tmp, qgroups, seq,
2512 UPDATE_NEW);
2513 if (ret < 0)
2514 goto out;
2515
2516 qgroup_update_counters(fs_info, qgroups, nr_old_roots, nr_new_roots,
2517 num_bytes, seq);
2518
2519 /*
2520 * Bump qgroup_seq to avoid seq overlap
2521 */
2522 fs_info->qgroup_seq += max(nr_old_roots, nr_new_roots) + 1;
2523out:
2524 spin_unlock(&fs_info->qgroup_lock);
2525out_free:
2526 ulist_free(tmp);
2527 ulist_free(qgroups);
2528 ulist_free(old_roots);
2529 ulist_free(new_roots);
2530 return ret;
2531}
2532
2533int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans,
2534 struct btrfs_fs_info *fs_info)
2535{
2536 struct btrfs_qgroup_extent_record *record;
2537 struct btrfs_delayed_ref_root *delayed_refs;
2538 struct ulist *new_roots = NULL;
2539 struct rb_node *node;
2540 int ret = 0;
2541
2542 delayed_refs = &trans->transaction->delayed_refs;
2543 while ((node = rb_first(&delayed_refs->dirty_extent_root))) {
2544 record = rb_entry(node, struct btrfs_qgroup_extent_record,
2545 node);
2546
2547 if (!ret) {
2548 /*
2549 * Use (u64)-1 as time_seq to do special search, which
2550 * doesn't lock tree or delayed_refs and search current
2551 * root. It's safe inside commit_transaction().
2552 */
2553 ret = btrfs_find_all_roots(trans, fs_info,
2554 record->bytenr, (u64)-1, &new_roots);
2555 if (ret < 0)
2556 goto cleanup;
2557 ret = btrfs_qgroup_account_extent(trans, fs_info,
2558 record->bytenr, record->num_bytes,
2559 record->old_roots, new_roots);
2560 record->old_roots = NULL;
2561 new_roots = NULL;
2562 }
2563cleanup:
2564 ulist_free(record->old_roots);
2565 ulist_free(new_roots);
2566 new_roots = NULL;
2567 rb_erase(node, &delayed_refs->dirty_extent_root);
2568 kfree(record);
2569
2570 }
2571 return ret;
2572}
2573
2458/* 2574/*
2459 * Needs to be called everytime we run delayed refs, even if there is an error 2575 * Needs to be called everytime we run delayed refs, even if there is an error
2460 * in order to cleanup outstanding operations. 2576 * in order to cleanup outstanding operations.
diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h
index 6fe249f078ac..cb703f859af6 100644
--- a/fs/btrfs/qgroup.h
+++ b/fs/btrfs/qgroup.h
@@ -103,6 +103,8 @@ int btrfs_qgroup_prepare_account_extents(struct btrfs_trans_handle *trans,
103struct btrfs_qgroup_extent_record 103struct btrfs_qgroup_extent_record
104*btrfs_qgroup_insert_dirty_extent(struct btrfs_delayed_ref_root *delayed_refs, 104*btrfs_qgroup_insert_dirty_extent(struct btrfs_delayed_ref_root *delayed_refs,
105 struct btrfs_qgroup_extent_record *record); 105 struct btrfs_qgroup_extent_record *record);
106int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans,
107 struct btrfs_fs_info *fs_info);
106int btrfs_delayed_qgroup_accounting(struct btrfs_trans_handle *trans, 108int btrfs_delayed_qgroup_accounting(struct btrfs_trans_handle *trans,
107 struct btrfs_fs_info *fs_info); 109 struct btrfs_fs_info *fs_info);
108void btrfs_remove_qgroup_operation(struct btrfs_trans_handle *trans, 110void btrfs_remove_qgroup_operation(struct btrfs_trans_handle *trans,