diff options
author | Qu Wenruo <quwenruo@cn.fujitsu.com> | 2015-04-16 03:37:33 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2015-06-10 12:25:49 -0400 |
commit | 550d7a2ed5db35756222ec17cff3376ff38d78e2 (patch) | |
tree | c8b60650e4ac8facdf25f498e2901b7eebb3f4ae | |
parent | 21633fc6037f8ceb2bb927dacc3f9ef46ccae891 (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.h | 0 | ||||
-rw-r--r-- | fs/btrfs/qgroup.c | 116 | ||||
-rw-r--r-- | fs/btrfs/qgroup.h | 2 |
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 | ||
2458 | static int | ||
2459 | btrfs_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; | ||
2523 | out: | ||
2524 | spin_unlock(&fs_info->qgroup_lock); | ||
2525 | out_free: | ||
2526 | ulist_free(tmp); | ||
2527 | ulist_free(qgroups); | ||
2528 | ulist_free(old_roots); | ||
2529 | ulist_free(new_roots); | ||
2530 | return ret; | ||
2531 | } | ||
2532 | |||
2533 | int 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 | } | ||
2563 | cleanup: | ||
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, | |||
103 | struct btrfs_qgroup_extent_record | 103 | struct 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); |
106 | int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans, | ||
107 | struct btrfs_fs_info *fs_info); | ||
106 | int btrfs_delayed_qgroup_accounting(struct btrfs_trans_handle *trans, | 108 | int btrfs_delayed_qgroup_accounting(struct btrfs_trans_handle *trans, |
107 | struct btrfs_fs_info *fs_info); | 109 | struct btrfs_fs_info *fs_info); |
108 | void btrfs_remove_qgroup_operation(struct btrfs_trans_handle *trans, | 110 | void btrfs_remove_qgroup_operation(struct btrfs_trans_handle *trans, |