qgroup.c (370a11b8114bcca3738fe6a5d7ed8babcc212f39) qgroup.c (f616f5cd9da7fceb7d884812da380b26040cd083)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2011 STRATO. All rights reserved.
4 */
5
6#include <linux/sched.h>
7#include <linux/pagemap.h>
8#include <linux/writeback.h>

--- 3954 unchanged lines hidden (view full) ---

3963out_unlock:
3964 spin_unlock(&blocks->lock);
3965out:
3966 if (ret < 0)
3967 fs_info->qgroup_flags |=
3968 BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
3969 return ret;
3970}
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2011 STRATO. All rights reserved.
4 */
5
6#include <linux/sched.h>
7#include <linux/pagemap.h>
8#include <linux/writeback.h>

--- 3954 unchanged lines hidden (view full) ---

3963out_unlock:
3964 spin_unlock(&blocks->lock);
3965out:
3966 if (ret < 0)
3967 fs_info->qgroup_flags |=
3968 BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
3969 return ret;
3970}
3971
3972/*
3973 * Check if the tree block is a subtree root, and if so do the needed
3974 * delayed subtree trace for qgroup.
3975 *
3976 * This is called during btrfs_cow_block().
3977 */
3978int btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans,
3979 struct btrfs_root *root,
3980 struct extent_buffer *subvol_eb)
3981{
3982 struct btrfs_fs_info *fs_info = root->fs_info;
3983 struct btrfs_qgroup_swapped_blocks *blocks = &root->swapped_blocks;
3984 struct btrfs_qgroup_swapped_block *block;
3985 struct extent_buffer *reloc_eb = NULL;
3986 struct rb_node *node;
3987 bool found = false;
3988 bool swapped = false;
3989 int level = btrfs_header_level(subvol_eb);
3990 int ret = 0;
3991 int i;
3992
3993 if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags))
3994 return 0;
3995 if (!is_fstree(root->root_key.objectid) || !root->reloc_root)
3996 return 0;
3997
3998 spin_lock(&blocks->lock);
3999 if (!blocks->swapped) {
4000 spin_unlock(&blocks->lock);
4001 return 0;
4002 }
4003 node = blocks->blocks[level].rb_node;
4004
4005 while (node) {
4006 block = rb_entry(node, struct btrfs_qgroup_swapped_block, node);
4007 if (block->subvol_bytenr < subvol_eb->start) {
4008 node = node->rb_left;
4009 } else if (block->subvol_bytenr > subvol_eb->start) {
4010 node = node->rb_right;
4011 } else {
4012 found = true;
4013 break;
4014 }
4015 }
4016 if (!found) {
4017 spin_unlock(&blocks->lock);
4018 goto out;
4019 }
4020 /* Found one, remove it from @blocks first and update blocks->swapped */
4021 rb_erase(&block->node, &blocks->blocks[level]);
4022 for (i = 0; i < BTRFS_MAX_LEVEL; i++) {
4023 if (RB_EMPTY_ROOT(&blocks->blocks[i])) {
4024 swapped = true;
4025 break;
4026 }
4027 }
4028 blocks->swapped = swapped;
4029 spin_unlock(&blocks->lock);
4030
4031 /* Read out reloc subtree root */
4032 reloc_eb = read_tree_block(fs_info, block->reloc_bytenr,
4033 block->reloc_generation, block->level,
4034 &block->first_key);
4035 if (IS_ERR(reloc_eb)) {
4036 ret = PTR_ERR(reloc_eb);
4037 reloc_eb = NULL;
4038 goto free_out;
4039 }
4040 if (!extent_buffer_uptodate(reloc_eb)) {
4041 ret = -EIO;
4042 goto free_out;
4043 }
4044
4045 ret = qgroup_trace_subtree_swap(trans, reloc_eb, subvol_eb,
4046 block->last_snapshot, block->trace_leaf);
4047free_out:
4048 kfree(block);
4049 free_extent_buffer(reloc_eb);
4050out:
4051 if (ret < 0) {
4052 btrfs_err_rl(fs_info,
4053 "failed to account subtree at bytenr %llu: %d",
4054 subvol_eb->start, ret);
4055 fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
4056 }
4057 return ret;
4058}