18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2011 STRATO. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/sched.h> 78c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 88c2ecf20Sopenharmony_ci#include <linux/writeback.h> 98c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 108c2ecf20Sopenharmony_ci#include <linux/rbtree.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 138c2ecf20Sopenharmony_ci#include <linux/btrfs.h> 148c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "ctree.h" 178c2ecf20Sopenharmony_ci#include "transaction.h" 188c2ecf20Sopenharmony_ci#include "disk-io.h" 198c2ecf20Sopenharmony_ci#include "locking.h" 208c2ecf20Sopenharmony_ci#include "ulist.h" 218c2ecf20Sopenharmony_ci#include "backref.h" 228c2ecf20Sopenharmony_ci#include "extent_io.h" 238c2ecf20Sopenharmony_ci#include "qgroup.h" 248c2ecf20Sopenharmony_ci#include "block-group.h" 258c2ecf20Sopenharmony_ci#include "sysfs.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* TODO XXX FIXME 288c2ecf20Sopenharmony_ci * - subvol delete -> delete when ref goes to 0? delete limits also? 298c2ecf20Sopenharmony_ci * - reorganize keys 308c2ecf20Sopenharmony_ci * - compressed 318c2ecf20Sopenharmony_ci * - sync 328c2ecf20Sopenharmony_ci * - copy also limits on subvol creation 338c2ecf20Sopenharmony_ci * - limit 348c2ecf20Sopenharmony_ci * - caches for ulists 358c2ecf20Sopenharmony_ci * - performance benchmarks 368c2ecf20Sopenharmony_ci * - check all ioctl parameters 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * Helpers to access qgroup reservation 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * Callers should ensure the lock context and type are valid 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic u64 qgroup_rsv_total(const struct btrfs_qgroup *qgroup) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci u64 ret = 0; 488c2ecf20Sopenharmony_ci int i; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++) 518c2ecf20Sopenharmony_ci ret += qgroup->rsv.values[i]; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return ret; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#ifdef CONFIG_BTRFS_DEBUG 578c2ecf20Sopenharmony_cistatic const char *qgroup_rsv_type_str(enum btrfs_qgroup_rsv_type type) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci if (type == BTRFS_QGROUP_RSV_DATA) 608c2ecf20Sopenharmony_ci return "data"; 618c2ecf20Sopenharmony_ci if (type == BTRFS_QGROUP_RSV_META_PERTRANS) 628c2ecf20Sopenharmony_ci return "meta_pertrans"; 638c2ecf20Sopenharmony_ci if (type == BTRFS_QGROUP_RSV_META_PREALLOC) 648c2ecf20Sopenharmony_ci return "meta_prealloc"; 658c2ecf20Sopenharmony_ci return NULL; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci#endif 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void qgroup_rsv_add(struct btrfs_fs_info *fs_info, 708c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup, u64 num_bytes, 718c2ecf20Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci trace_qgroup_update_reserve(fs_info, qgroup, num_bytes, type); 748c2ecf20Sopenharmony_ci qgroup->rsv.values[type] += num_bytes; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void qgroup_rsv_release(struct btrfs_fs_info *fs_info, 788c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup, u64 num_bytes, 798c2ecf20Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci trace_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes, type); 828c2ecf20Sopenharmony_ci if (qgroup->rsv.values[type] >= num_bytes) { 838c2ecf20Sopenharmony_ci qgroup->rsv.values[type] -= num_bytes; 848c2ecf20Sopenharmony_ci return; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci#ifdef CONFIG_BTRFS_DEBUG 878c2ecf20Sopenharmony_ci WARN_RATELIMIT(1, 888c2ecf20Sopenharmony_ci "qgroup %llu %s reserved space underflow, have %llu to free %llu", 898c2ecf20Sopenharmony_ci qgroup->qgroupid, qgroup_rsv_type_str(type), 908c2ecf20Sopenharmony_ci qgroup->rsv.values[type], num_bytes); 918c2ecf20Sopenharmony_ci#endif 928c2ecf20Sopenharmony_ci qgroup->rsv.values[type] = 0; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void qgroup_rsv_add_by_qgroup(struct btrfs_fs_info *fs_info, 968c2ecf20Sopenharmony_ci struct btrfs_qgroup *dest, 978c2ecf20Sopenharmony_ci struct btrfs_qgroup *src) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci int i; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++) 1028c2ecf20Sopenharmony_ci qgroup_rsv_add(fs_info, dest, src->rsv.values[i], i); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic void qgroup_rsv_release_by_qgroup(struct btrfs_fs_info *fs_info, 1068c2ecf20Sopenharmony_ci struct btrfs_qgroup *dest, 1078c2ecf20Sopenharmony_ci struct btrfs_qgroup *src) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int i; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++) 1128c2ecf20Sopenharmony_ci qgroup_rsv_release(fs_info, dest, src->rsv.values[i], i); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void btrfs_qgroup_update_old_refcnt(struct btrfs_qgroup *qg, u64 seq, 1168c2ecf20Sopenharmony_ci int mod) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci if (qg->old_refcnt < seq) 1198c2ecf20Sopenharmony_ci qg->old_refcnt = seq; 1208c2ecf20Sopenharmony_ci qg->old_refcnt += mod; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void btrfs_qgroup_update_new_refcnt(struct btrfs_qgroup *qg, u64 seq, 1248c2ecf20Sopenharmony_ci int mod) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci if (qg->new_refcnt < seq) 1278c2ecf20Sopenharmony_ci qg->new_refcnt = seq; 1288c2ecf20Sopenharmony_ci qg->new_refcnt += mod; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic inline u64 btrfs_qgroup_get_old_refcnt(struct btrfs_qgroup *qg, u64 seq) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci if (qg->old_refcnt < seq) 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci return qg->old_refcnt - seq; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic inline u64 btrfs_qgroup_get_new_refcnt(struct btrfs_qgroup *qg, u64 seq) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci if (qg->new_refcnt < seq) 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci return qg->new_refcnt - seq; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/* 1468c2ecf20Sopenharmony_ci * glue structure to represent the relations between qgroups. 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_cistruct btrfs_qgroup_list { 1498c2ecf20Sopenharmony_ci struct list_head next_group; 1508c2ecf20Sopenharmony_ci struct list_head next_member; 1518c2ecf20Sopenharmony_ci struct btrfs_qgroup *group; 1528c2ecf20Sopenharmony_ci struct btrfs_qgroup *member; 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic inline u64 qgroup_to_aux(struct btrfs_qgroup *qg) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return (u64)(uintptr_t)qg; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic inline struct btrfs_qgroup* unode_aux_to_qgroup(struct ulist_node *n) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci return (struct btrfs_qgroup *)(uintptr_t)n->aux; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int 1668c2ecf20Sopenharmony_ciqgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, 1678c2ecf20Sopenharmony_ci int init_flags); 1688c2ecf20Sopenharmony_cistatic void qgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci/* must be called with qgroup_ioctl_lock held */ 1718c2ecf20Sopenharmony_cistatic struct btrfs_qgroup *find_qgroup_rb(struct btrfs_fs_info *fs_info, 1728c2ecf20Sopenharmony_ci u64 qgroupid) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct rb_node *n = fs_info->qgroup_tree.rb_node; 1758c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci while (n) { 1788c2ecf20Sopenharmony_ci qgroup = rb_entry(n, struct btrfs_qgroup, node); 1798c2ecf20Sopenharmony_ci if (qgroup->qgroupid < qgroupid) 1808c2ecf20Sopenharmony_ci n = n->rb_left; 1818c2ecf20Sopenharmony_ci else if (qgroup->qgroupid > qgroupid) 1828c2ecf20Sopenharmony_ci n = n->rb_right; 1838c2ecf20Sopenharmony_ci else 1848c2ecf20Sopenharmony_ci return qgroup; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci return NULL; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci/* must be called with qgroup_lock held */ 1908c2ecf20Sopenharmony_cistatic struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info, 1918c2ecf20Sopenharmony_ci u64 qgroupid) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci struct rb_node **p = &fs_info->qgroup_tree.rb_node; 1948c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 1958c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci while (*p) { 1988c2ecf20Sopenharmony_ci parent = *p; 1998c2ecf20Sopenharmony_ci qgroup = rb_entry(parent, struct btrfs_qgroup, node); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (qgroup->qgroupid < qgroupid) 2028c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 2038c2ecf20Sopenharmony_ci else if (qgroup->qgroupid > qgroupid) 2048c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 2058c2ecf20Sopenharmony_ci else 2068c2ecf20Sopenharmony_ci return qgroup; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci qgroup = kzalloc(sizeof(*qgroup), GFP_ATOMIC); 2108c2ecf20Sopenharmony_ci if (!qgroup) 2118c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci qgroup->qgroupid = qgroupid; 2148c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qgroup->groups); 2158c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qgroup->members); 2168c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&qgroup->dirty); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci rb_link_node(&qgroup->node, parent, p); 2198c2ecf20Sopenharmony_ci rb_insert_color(&qgroup->node, &fs_info->qgroup_tree); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return qgroup; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic void __del_qgroup_rb(struct btrfs_fs_info *fs_info, 2258c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct btrfs_qgroup_list *list; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci list_del(&qgroup->dirty); 2308c2ecf20Sopenharmony_ci while (!list_empty(&qgroup->groups)) { 2318c2ecf20Sopenharmony_ci list = list_first_entry(&qgroup->groups, 2328c2ecf20Sopenharmony_ci struct btrfs_qgroup_list, next_group); 2338c2ecf20Sopenharmony_ci list_del(&list->next_group); 2348c2ecf20Sopenharmony_ci list_del(&list->next_member); 2358c2ecf20Sopenharmony_ci kfree(list); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci while (!list_empty(&qgroup->members)) { 2398c2ecf20Sopenharmony_ci list = list_first_entry(&qgroup->members, 2408c2ecf20Sopenharmony_ci struct btrfs_qgroup_list, next_member); 2418c2ecf20Sopenharmony_ci list_del(&list->next_group); 2428c2ecf20Sopenharmony_ci list_del(&list->next_member); 2438c2ecf20Sopenharmony_ci kfree(list); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/* must be called with qgroup_lock held */ 2488c2ecf20Sopenharmony_cistatic int del_qgroup_rb(struct btrfs_fs_info *fs_info, u64 qgroupid) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup = find_qgroup_rb(fs_info, qgroupid); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (!qgroup) 2538c2ecf20Sopenharmony_ci return -ENOENT; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci rb_erase(&qgroup->node, &fs_info->qgroup_tree); 2568c2ecf20Sopenharmony_ci __del_qgroup_rb(fs_info, qgroup); 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/* must be called with qgroup_lock held */ 2618c2ecf20Sopenharmony_cistatic int add_relation_rb(struct btrfs_fs_info *fs_info, 2628c2ecf20Sopenharmony_ci u64 memberid, u64 parentid) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct btrfs_qgroup *member; 2658c2ecf20Sopenharmony_ci struct btrfs_qgroup *parent; 2668c2ecf20Sopenharmony_ci struct btrfs_qgroup_list *list; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci member = find_qgroup_rb(fs_info, memberid); 2698c2ecf20Sopenharmony_ci parent = find_qgroup_rb(fs_info, parentid); 2708c2ecf20Sopenharmony_ci if (!member || !parent) 2718c2ecf20Sopenharmony_ci return -ENOENT; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci list = kzalloc(sizeof(*list), GFP_ATOMIC); 2748c2ecf20Sopenharmony_ci if (!list) 2758c2ecf20Sopenharmony_ci return -ENOMEM; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci list->group = parent; 2788c2ecf20Sopenharmony_ci list->member = member; 2798c2ecf20Sopenharmony_ci list_add_tail(&list->next_group, &member->groups); 2808c2ecf20Sopenharmony_ci list_add_tail(&list->next_member, &parent->members); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/* must be called with qgroup_lock held */ 2868c2ecf20Sopenharmony_cistatic int del_relation_rb(struct btrfs_fs_info *fs_info, 2878c2ecf20Sopenharmony_ci u64 memberid, u64 parentid) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct btrfs_qgroup *member; 2908c2ecf20Sopenharmony_ci struct btrfs_qgroup *parent; 2918c2ecf20Sopenharmony_ci struct btrfs_qgroup_list *list; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci member = find_qgroup_rb(fs_info, memberid); 2948c2ecf20Sopenharmony_ci parent = find_qgroup_rb(fs_info, parentid); 2958c2ecf20Sopenharmony_ci if (!member || !parent) 2968c2ecf20Sopenharmony_ci return -ENOENT; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci list_for_each_entry(list, &member->groups, next_group) { 2998c2ecf20Sopenharmony_ci if (list->group == parent) { 3008c2ecf20Sopenharmony_ci list_del(&list->next_group); 3018c2ecf20Sopenharmony_ci list_del(&list->next_member); 3028c2ecf20Sopenharmony_ci kfree(list); 3038c2ecf20Sopenharmony_ci return 0; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci return -ENOENT; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 3108c2ecf20Sopenharmony_ciint btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid, 3118c2ecf20Sopenharmony_ci u64 rfer, u64 excl) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, qgroupid); 3168c2ecf20Sopenharmony_ci if (!qgroup) 3178c2ecf20Sopenharmony_ci return -EINVAL; 3188c2ecf20Sopenharmony_ci if (qgroup->rfer != rfer || qgroup->excl != excl) 3198c2ecf20Sopenharmony_ci return -EINVAL; 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci#endif 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci/* 3258c2ecf20Sopenharmony_ci * The full config is read in one go, only called from open_ctree() 3268c2ecf20Sopenharmony_ci * It doesn't use any locking, as at this point we're still single-threaded 3278c2ecf20Sopenharmony_ci */ 3288c2ecf20Sopenharmony_ciint btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci struct btrfs_key key; 3318c2ecf20Sopenharmony_ci struct btrfs_key found_key; 3328c2ecf20Sopenharmony_ci struct btrfs_root *quota_root = fs_info->quota_root; 3338c2ecf20Sopenharmony_ci struct btrfs_path *path = NULL; 3348c2ecf20Sopenharmony_ci struct extent_buffer *l; 3358c2ecf20Sopenharmony_ci int slot; 3368c2ecf20Sopenharmony_ci int ret = 0; 3378c2ecf20Sopenharmony_ci u64 flags = 0; 3388c2ecf20Sopenharmony_ci u64 rescan_progress = 0; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL); 3448c2ecf20Sopenharmony_ci if (!fs_info->qgroup_ulist) { 3458c2ecf20Sopenharmony_ci ret = -ENOMEM; 3468c2ecf20Sopenharmony_ci goto out; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 3508c2ecf20Sopenharmony_ci if (!path) { 3518c2ecf20Sopenharmony_ci ret = -ENOMEM; 3528c2ecf20Sopenharmony_ci goto out; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci ret = btrfs_sysfs_add_qgroups(fs_info); 3568c2ecf20Sopenharmony_ci if (ret < 0) 3578c2ecf20Sopenharmony_ci goto out; 3588c2ecf20Sopenharmony_ci /* default this to quota off, in case no status key is found */ 3598c2ecf20Sopenharmony_ci fs_info->qgroup_flags = 0; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* 3628c2ecf20Sopenharmony_ci * pass 1: read status, all qgroup infos and limits 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ci key.objectid = 0; 3658c2ecf20Sopenharmony_ci key.type = 0; 3668c2ecf20Sopenharmony_ci key.offset = 0; 3678c2ecf20Sopenharmony_ci ret = btrfs_search_slot_for_read(quota_root, &key, path, 1, 1); 3688c2ecf20Sopenharmony_ci if (ret) 3698c2ecf20Sopenharmony_ci goto out; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci while (1) { 3728c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci slot = path->slots[0]; 3758c2ecf20Sopenharmony_ci l = path->nodes[0]; 3768c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(l, &found_key, slot); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if (found_key.type == BTRFS_QGROUP_STATUS_KEY) { 3798c2ecf20Sopenharmony_ci struct btrfs_qgroup_status_item *ptr; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci ptr = btrfs_item_ptr(l, slot, 3828c2ecf20Sopenharmony_ci struct btrfs_qgroup_status_item); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (btrfs_qgroup_status_version(l, ptr) != 3858c2ecf20Sopenharmony_ci BTRFS_QGROUP_STATUS_VERSION) { 3868c2ecf20Sopenharmony_ci btrfs_err(fs_info, 3878c2ecf20Sopenharmony_ci "old qgroup version, quota disabled"); 3888c2ecf20Sopenharmony_ci goto out; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci if (btrfs_qgroup_status_generation(l, ptr) != 3918c2ecf20Sopenharmony_ci fs_info->generation) { 3928c2ecf20Sopenharmony_ci flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 3938c2ecf20Sopenharmony_ci btrfs_err(fs_info, 3948c2ecf20Sopenharmony_ci "qgroup generation mismatch, marked as inconsistent"); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, 3978c2ecf20Sopenharmony_ci ptr); 3988c2ecf20Sopenharmony_ci rescan_progress = btrfs_qgroup_status_rescan(l, ptr); 3998c2ecf20Sopenharmony_ci goto next1; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (found_key.type != BTRFS_QGROUP_INFO_KEY && 4038c2ecf20Sopenharmony_ci found_key.type != BTRFS_QGROUP_LIMIT_KEY) 4048c2ecf20Sopenharmony_ci goto next1; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, found_key.offset); 4078c2ecf20Sopenharmony_ci if ((qgroup && found_key.type == BTRFS_QGROUP_INFO_KEY) || 4088c2ecf20Sopenharmony_ci (!qgroup && found_key.type == BTRFS_QGROUP_LIMIT_KEY)) { 4098c2ecf20Sopenharmony_ci btrfs_err(fs_info, "inconsistent qgroup config"); 4108c2ecf20Sopenharmony_ci flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci if (!qgroup) { 4138c2ecf20Sopenharmony_ci qgroup = add_qgroup_rb(fs_info, found_key.offset); 4148c2ecf20Sopenharmony_ci if (IS_ERR(qgroup)) { 4158c2ecf20Sopenharmony_ci ret = PTR_ERR(qgroup); 4168c2ecf20Sopenharmony_ci goto out; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup); 4208c2ecf20Sopenharmony_ci if (ret < 0) 4218c2ecf20Sopenharmony_ci goto out; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci switch (found_key.type) { 4248c2ecf20Sopenharmony_ci case BTRFS_QGROUP_INFO_KEY: { 4258c2ecf20Sopenharmony_ci struct btrfs_qgroup_info_item *ptr; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci ptr = btrfs_item_ptr(l, slot, 4288c2ecf20Sopenharmony_ci struct btrfs_qgroup_info_item); 4298c2ecf20Sopenharmony_ci qgroup->rfer = btrfs_qgroup_info_rfer(l, ptr); 4308c2ecf20Sopenharmony_ci qgroup->rfer_cmpr = btrfs_qgroup_info_rfer_cmpr(l, ptr); 4318c2ecf20Sopenharmony_ci qgroup->excl = btrfs_qgroup_info_excl(l, ptr); 4328c2ecf20Sopenharmony_ci qgroup->excl_cmpr = btrfs_qgroup_info_excl_cmpr(l, ptr); 4338c2ecf20Sopenharmony_ci /* generation currently unused */ 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci case BTRFS_QGROUP_LIMIT_KEY: { 4378c2ecf20Sopenharmony_ci struct btrfs_qgroup_limit_item *ptr; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci ptr = btrfs_item_ptr(l, slot, 4408c2ecf20Sopenharmony_ci struct btrfs_qgroup_limit_item); 4418c2ecf20Sopenharmony_ci qgroup->lim_flags = btrfs_qgroup_limit_flags(l, ptr); 4428c2ecf20Sopenharmony_ci qgroup->max_rfer = btrfs_qgroup_limit_max_rfer(l, ptr); 4438c2ecf20Sopenharmony_ci qgroup->max_excl = btrfs_qgroup_limit_max_excl(l, ptr); 4448c2ecf20Sopenharmony_ci qgroup->rsv_rfer = btrfs_qgroup_limit_rsv_rfer(l, ptr); 4458c2ecf20Sopenharmony_ci qgroup->rsv_excl = btrfs_qgroup_limit_rsv_excl(l, ptr); 4468c2ecf20Sopenharmony_ci break; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_cinext1: 4508c2ecf20Sopenharmony_ci ret = btrfs_next_item(quota_root, path); 4518c2ecf20Sopenharmony_ci if (ret < 0) 4528c2ecf20Sopenharmony_ci goto out; 4538c2ecf20Sopenharmony_ci if (ret) 4548c2ecf20Sopenharmony_ci break; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci btrfs_release_path(path); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* 4598c2ecf20Sopenharmony_ci * pass 2: read all qgroup relations 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_ci key.objectid = 0; 4628c2ecf20Sopenharmony_ci key.type = BTRFS_QGROUP_RELATION_KEY; 4638c2ecf20Sopenharmony_ci key.offset = 0; 4648c2ecf20Sopenharmony_ci ret = btrfs_search_slot_for_read(quota_root, &key, path, 1, 0); 4658c2ecf20Sopenharmony_ci if (ret) 4668c2ecf20Sopenharmony_ci goto out; 4678c2ecf20Sopenharmony_ci while (1) { 4688c2ecf20Sopenharmony_ci slot = path->slots[0]; 4698c2ecf20Sopenharmony_ci l = path->nodes[0]; 4708c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(l, &found_key, slot); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (found_key.type != BTRFS_QGROUP_RELATION_KEY) 4738c2ecf20Sopenharmony_ci goto next2; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (found_key.objectid > found_key.offset) { 4768c2ecf20Sopenharmony_ci /* parent <- member, not needed to build config */ 4778c2ecf20Sopenharmony_ci /* FIXME should we omit the key completely? */ 4788c2ecf20Sopenharmony_ci goto next2; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci ret = add_relation_rb(fs_info, found_key.objectid, 4828c2ecf20Sopenharmony_ci found_key.offset); 4838c2ecf20Sopenharmony_ci if (ret == -ENOENT) { 4848c2ecf20Sopenharmony_ci btrfs_warn(fs_info, 4858c2ecf20Sopenharmony_ci "orphan qgroup relation 0x%llx->0x%llx", 4868c2ecf20Sopenharmony_ci found_key.objectid, found_key.offset); 4878c2ecf20Sopenharmony_ci ret = 0; /* ignore the error */ 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci if (ret) 4908c2ecf20Sopenharmony_ci goto out; 4918c2ecf20Sopenharmony_cinext2: 4928c2ecf20Sopenharmony_ci ret = btrfs_next_item(quota_root, path); 4938c2ecf20Sopenharmony_ci if (ret < 0) 4948c2ecf20Sopenharmony_ci goto out; 4958c2ecf20Sopenharmony_ci if (ret) 4968c2ecf20Sopenharmony_ci break; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ciout: 4998c2ecf20Sopenharmony_ci btrfs_free_path(path); 5008c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= flags; 5018c2ecf20Sopenharmony_ci if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) 5028c2ecf20Sopenharmony_ci clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); 5038c2ecf20Sopenharmony_ci else if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN && 5048c2ecf20Sopenharmony_ci ret >= 0) 5058c2ecf20Sopenharmony_ci ret = qgroup_rescan_init(fs_info, rescan_progress, 0); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (ret < 0) { 5088c2ecf20Sopenharmony_ci ulist_free(fs_info->qgroup_ulist); 5098c2ecf20Sopenharmony_ci fs_info->qgroup_ulist = NULL; 5108c2ecf20Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; 5118c2ecf20Sopenharmony_ci btrfs_sysfs_del_qgroups(fs_info); 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return ret < 0 ? ret : 0; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci/* 5188c2ecf20Sopenharmony_ci * Called in close_ctree() when quota is still enabled. This verifies we don't 5198c2ecf20Sopenharmony_ci * leak some reserved space. 5208c2ecf20Sopenharmony_ci * 5218c2ecf20Sopenharmony_ci * Return false if no reserved space is left. 5228c2ecf20Sopenharmony_ci * Return true if some reserved space is leaked. 5238c2ecf20Sopenharmony_ci */ 5248c2ecf20Sopenharmony_cibool btrfs_check_quota_leak(struct btrfs_fs_info *fs_info) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct rb_node *node; 5278c2ecf20Sopenharmony_ci bool ret = false; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 5308c2ecf20Sopenharmony_ci return ret; 5318c2ecf20Sopenharmony_ci /* 5328c2ecf20Sopenharmony_ci * Since we're unmounting, there is no race and no need to grab qgroup 5338c2ecf20Sopenharmony_ci * lock. And here we don't go post-order to provide a more user 5348c2ecf20Sopenharmony_ci * friendly sorted result. 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ci for (node = rb_first(&fs_info->qgroup_tree); node; node = rb_next(node)) { 5378c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 5388c2ecf20Sopenharmony_ci int i; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci qgroup = rb_entry(node, struct btrfs_qgroup, node); 5418c2ecf20Sopenharmony_ci for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++) { 5428c2ecf20Sopenharmony_ci if (qgroup->rsv.values[i]) { 5438c2ecf20Sopenharmony_ci ret = true; 5448c2ecf20Sopenharmony_ci btrfs_warn(fs_info, 5458c2ecf20Sopenharmony_ci "qgroup %hu/%llu has unreleased space, type %d rsv %llu", 5468c2ecf20Sopenharmony_ci btrfs_qgroup_level(qgroup->qgroupid), 5478c2ecf20Sopenharmony_ci btrfs_qgroup_subvolid(qgroup->qgroupid), 5488c2ecf20Sopenharmony_ci i, qgroup->rsv.values[i]); 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci return ret; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci/* 5568c2ecf20Sopenharmony_ci * This is called from close_ctree() or open_ctree() or btrfs_quota_disable(), 5578c2ecf20Sopenharmony_ci * first two are in single-threaded paths.And for the third one, we have set 5588c2ecf20Sopenharmony_ci * quota_root to be null with qgroup_lock held before, so it is safe to clean 5598c2ecf20Sopenharmony_ci * up the in-memory structures without qgroup_lock held. 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_civoid btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct rb_node *n; 5648c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci while ((n = rb_first(&fs_info->qgroup_tree))) { 5678c2ecf20Sopenharmony_ci qgroup = rb_entry(n, struct btrfs_qgroup, node); 5688c2ecf20Sopenharmony_ci rb_erase(n, &fs_info->qgroup_tree); 5698c2ecf20Sopenharmony_ci __del_qgroup_rb(fs_info, qgroup); 5708c2ecf20Sopenharmony_ci btrfs_sysfs_del_one_qgroup(fs_info, qgroup); 5718c2ecf20Sopenharmony_ci kfree(qgroup); 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci /* 5748c2ecf20Sopenharmony_ci * We call btrfs_free_qgroup_config() when unmounting 5758c2ecf20Sopenharmony_ci * filesystem and disabling quota, so we set qgroup_ulist 5768c2ecf20Sopenharmony_ci * to be null here to avoid double free. 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_ci ulist_free(fs_info->qgroup_ulist); 5798c2ecf20Sopenharmony_ci fs_info->qgroup_ulist = NULL; 5808c2ecf20Sopenharmony_ci btrfs_sysfs_del_qgroups(fs_info); 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int add_qgroup_relation_item(struct btrfs_trans_handle *trans, u64 src, 5848c2ecf20Sopenharmony_ci u64 dst) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci int ret; 5878c2ecf20Sopenharmony_ci struct btrfs_root *quota_root = trans->fs_info->quota_root; 5888c2ecf20Sopenharmony_ci struct btrfs_path *path; 5898c2ecf20Sopenharmony_ci struct btrfs_key key; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 5928c2ecf20Sopenharmony_ci if (!path) 5938c2ecf20Sopenharmony_ci return -ENOMEM; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci key.objectid = src; 5968c2ecf20Sopenharmony_ci key.type = BTRFS_QGROUP_RELATION_KEY; 5978c2ecf20Sopenharmony_ci key.offset = dst; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci ret = btrfs_insert_empty_item(trans, quota_root, path, &key, 0); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(path->nodes[0]); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci btrfs_free_path(path); 6048c2ecf20Sopenharmony_ci return ret; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int del_qgroup_relation_item(struct btrfs_trans_handle *trans, u64 src, 6088c2ecf20Sopenharmony_ci u64 dst) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci int ret; 6118c2ecf20Sopenharmony_ci struct btrfs_root *quota_root = trans->fs_info->quota_root; 6128c2ecf20Sopenharmony_ci struct btrfs_path *path; 6138c2ecf20Sopenharmony_ci struct btrfs_key key; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 6168c2ecf20Sopenharmony_ci if (!path) 6178c2ecf20Sopenharmony_ci return -ENOMEM; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci key.objectid = src; 6208c2ecf20Sopenharmony_ci key.type = BTRFS_QGROUP_RELATION_KEY; 6218c2ecf20Sopenharmony_ci key.offset = dst; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1); 6248c2ecf20Sopenharmony_ci if (ret < 0) 6258c2ecf20Sopenharmony_ci goto out; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (ret > 0) { 6288c2ecf20Sopenharmony_ci ret = -ENOENT; 6298c2ecf20Sopenharmony_ci goto out; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci ret = btrfs_del_item(trans, quota_root, path); 6338c2ecf20Sopenharmony_ciout: 6348c2ecf20Sopenharmony_ci btrfs_free_path(path); 6358c2ecf20Sopenharmony_ci return ret; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic int add_qgroup_item(struct btrfs_trans_handle *trans, 6398c2ecf20Sopenharmony_ci struct btrfs_root *quota_root, u64 qgroupid) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci int ret; 6428c2ecf20Sopenharmony_ci struct btrfs_path *path; 6438c2ecf20Sopenharmony_ci struct btrfs_qgroup_info_item *qgroup_info; 6448c2ecf20Sopenharmony_ci struct btrfs_qgroup_limit_item *qgroup_limit; 6458c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 6468c2ecf20Sopenharmony_ci struct btrfs_key key; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (btrfs_is_testing(quota_root->fs_info)) 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 6528c2ecf20Sopenharmony_ci if (!path) 6538c2ecf20Sopenharmony_ci return -ENOMEM; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci key.objectid = 0; 6568c2ecf20Sopenharmony_ci key.type = BTRFS_QGROUP_INFO_KEY; 6578c2ecf20Sopenharmony_ci key.offset = qgroupid; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* 6608c2ecf20Sopenharmony_ci * Avoid a transaction abort by catching -EEXIST here. In that 6618c2ecf20Sopenharmony_ci * case, we proceed by re-initializing the existing structure 6628c2ecf20Sopenharmony_ci * on disk. 6638c2ecf20Sopenharmony_ci */ 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci ret = btrfs_insert_empty_item(trans, quota_root, path, &key, 6668c2ecf20Sopenharmony_ci sizeof(*qgroup_info)); 6678c2ecf20Sopenharmony_ci if (ret && ret != -EEXIST) 6688c2ecf20Sopenharmony_ci goto out; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 6718c2ecf20Sopenharmony_ci qgroup_info = btrfs_item_ptr(leaf, path->slots[0], 6728c2ecf20Sopenharmony_ci struct btrfs_qgroup_info_item); 6738c2ecf20Sopenharmony_ci btrfs_set_qgroup_info_generation(leaf, qgroup_info, trans->transid); 6748c2ecf20Sopenharmony_ci btrfs_set_qgroup_info_rfer(leaf, qgroup_info, 0); 6758c2ecf20Sopenharmony_ci btrfs_set_qgroup_info_rfer_cmpr(leaf, qgroup_info, 0); 6768c2ecf20Sopenharmony_ci btrfs_set_qgroup_info_excl(leaf, qgroup_info, 0); 6778c2ecf20Sopenharmony_ci btrfs_set_qgroup_info_excl_cmpr(leaf, qgroup_info, 0); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(leaf); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci btrfs_release_path(path); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci key.type = BTRFS_QGROUP_LIMIT_KEY; 6848c2ecf20Sopenharmony_ci ret = btrfs_insert_empty_item(trans, quota_root, path, &key, 6858c2ecf20Sopenharmony_ci sizeof(*qgroup_limit)); 6868c2ecf20Sopenharmony_ci if (ret && ret != -EEXIST) 6878c2ecf20Sopenharmony_ci goto out; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 6908c2ecf20Sopenharmony_ci qgroup_limit = btrfs_item_ptr(leaf, path->slots[0], 6918c2ecf20Sopenharmony_ci struct btrfs_qgroup_limit_item); 6928c2ecf20Sopenharmony_ci btrfs_set_qgroup_limit_flags(leaf, qgroup_limit, 0); 6938c2ecf20Sopenharmony_ci btrfs_set_qgroup_limit_max_rfer(leaf, qgroup_limit, 0); 6948c2ecf20Sopenharmony_ci btrfs_set_qgroup_limit_max_excl(leaf, qgroup_limit, 0); 6958c2ecf20Sopenharmony_ci btrfs_set_qgroup_limit_rsv_rfer(leaf, qgroup_limit, 0); 6968c2ecf20Sopenharmony_ci btrfs_set_qgroup_limit_rsv_excl(leaf, qgroup_limit, 0); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(leaf); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci ret = 0; 7018c2ecf20Sopenharmony_ciout: 7028c2ecf20Sopenharmony_ci btrfs_free_path(path); 7038c2ecf20Sopenharmony_ci return ret; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic int del_qgroup_item(struct btrfs_trans_handle *trans, u64 qgroupid) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci int ret; 7098c2ecf20Sopenharmony_ci struct btrfs_root *quota_root = trans->fs_info->quota_root; 7108c2ecf20Sopenharmony_ci struct btrfs_path *path; 7118c2ecf20Sopenharmony_ci struct btrfs_key key; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 7148c2ecf20Sopenharmony_ci if (!path) 7158c2ecf20Sopenharmony_ci return -ENOMEM; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci key.objectid = 0; 7188c2ecf20Sopenharmony_ci key.type = BTRFS_QGROUP_INFO_KEY; 7198c2ecf20Sopenharmony_ci key.offset = qgroupid; 7208c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1); 7218c2ecf20Sopenharmony_ci if (ret < 0) 7228c2ecf20Sopenharmony_ci goto out; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci if (ret > 0) { 7258c2ecf20Sopenharmony_ci ret = -ENOENT; 7268c2ecf20Sopenharmony_ci goto out; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci ret = btrfs_del_item(trans, quota_root, path); 7308c2ecf20Sopenharmony_ci if (ret) 7318c2ecf20Sopenharmony_ci goto out; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci btrfs_release_path(path); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci key.type = BTRFS_QGROUP_LIMIT_KEY; 7368c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1); 7378c2ecf20Sopenharmony_ci if (ret < 0) 7388c2ecf20Sopenharmony_ci goto out; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (ret > 0) { 7418c2ecf20Sopenharmony_ci ret = -ENOENT; 7428c2ecf20Sopenharmony_ci goto out; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci ret = btrfs_del_item(trans, quota_root, path); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ciout: 7488c2ecf20Sopenharmony_ci btrfs_free_path(path); 7498c2ecf20Sopenharmony_ci return ret; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_cistatic int update_qgroup_limit_item(struct btrfs_trans_handle *trans, 7538c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci struct btrfs_root *quota_root = trans->fs_info->quota_root; 7568c2ecf20Sopenharmony_ci struct btrfs_path *path; 7578c2ecf20Sopenharmony_ci struct btrfs_key key; 7588c2ecf20Sopenharmony_ci struct extent_buffer *l; 7598c2ecf20Sopenharmony_ci struct btrfs_qgroup_limit_item *qgroup_limit; 7608c2ecf20Sopenharmony_ci int ret; 7618c2ecf20Sopenharmony_ci int slot; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci key.objectid = 0; 7648c2ecf20Sopenharmony_ci key.type = BTRFS_QGROUP_LIMIT_KEY; 7658c2ecf20Sopenharmony_ci key.offset = qgroup->qgroupid; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 7688c2ecf20Sopenharmony_ci if (!path) 7698c2ecf20Sopenharmony_ci return -ENOMEM; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, 0, 1); 7728c2ecf20Sopenharmony_ci if (ret > 0) 7738c2ecf20Sopenharmony_ci ret = -ENOENT; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (ret) 7768c2ecf20Sopenharmony_ci goto out; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci l = path->nodes[0]; 7798c2ecf20Sopenharmony_ci slot = path->slots[0]; 7808c2ecf20Sopenharmony_ci qgroup_limit = btrfs_item_ptr(l, slot, struct btrfs_qgroup_limit_item); 7818c2ecf20Sopenharmony_ci btrfs_set_qgroup_limit_flags(l, qgroup_limit, qgroup->lim_flags); 7828c2ecf20Sopenharmony_ci btrfs_set_qgroup_limit_max_rfer(l, qgroup_limit, qgroup->max_rfer); 7838c2ecf20Sopenharmony_ci btrfs_set_qgroup_limit_max_excl(l, qgroup_limit, qgroup->max_excl); 7848c2ecf20Sopenharmony_ci btrfs_set_qgroup_limit_rsv_rfer(l, qgroup_limit, qgroup->rsv_rfer); 7858c2ecf20Sopenharmony_ci btrfs_set_qgroup_limit_rsv_excl(l, qgroup_limit, qgroup->rsv_excl); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(l); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ciout: 7908c2ecf20Sopenharmony_ci btrfs_free_path(path); 7918c2ecf20Sopenharmony_ci return ret; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic int update_qgroup_info_item(struct btrfs_trans_handle *trans, 7958c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 7988c2ecf20Sopenharmony_ci struct btrfs_root *quota_root = fs_info->quota_root; 7998c2ecf20Sopenharmony_ci struct btrfs_path *path; 8008c2ecf20Sopenharmony_ci struct btrfs_key key; 8018c2ecf20Sopenharmony_ci struct extent_buffer *l; 8028c2ecf20Sopenharmony_ci struct btrfs_qgroup_info_item *qgroup_info; 8038c2ecf20Sopenharmony_ci int ret; 8048c2ecf20Sopenharmony_ci int slot; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (btrfs_is_testing(fs_info)) 8078c2ecf20Sopenharmony_ci return 0; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci key.objectid = 0; 8108c2ecf20Sopenharmony_ci key.type = BTRFS_QGROUP_INFO_KEY; 8118c2ecf20Sopenharmony_ci key.offset = qgroup->qgroupid; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 8148c2ecf20Sopenharmony_ci if (!path) 8158c2ecf20Sopenharmony_ci return -ENOMEM; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, 0, 1); 8188c2ecf20Sopenharmony_ci if (ret > 0) 8198c2ecf20Sopenharmony_ci ret = -ENOENT; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (ret) 8228c2ecf20Sopenharmony_ci goto out; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci l = path->nodes[0]; 8258c2ecf20Sopenharmony_ci slot = path->slots[0]; 8268c2ecf20Sopenharmony_ci qgroup_info = btrfs_item_ptr(l, slot, struct btrfs_qgroup_info_item); 8278c2ecf20Sopenharmony_ci btrfs_set_qgroup_info_generation(l, qgroup_info, trans->transid); 8288c2ecf20Sopenharmony_ci btrfs_set_qgroup_info_rfer(l, qgroup_info, qgroup->rfer); 8298c2ecf20Sopenharmony_ci btrfs_set_qgroup_info_rfer_cmpr(l, qgroup_info, qgroup->rfer_cmpr); 8308c2ecf20Sopenharmony_ci btrfs_set_qgroup_info_excl(l, qgroup_info, qgroup->excl); 8318c2ecf20Sopenharmony_ci btrfs_set_qgroup_info_excl_cmpr(l, qgroup_info, qgroup->excl_cmpr); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(l); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ciout: 8368c2ecf20Sopenharmony_ci btrfs_free_path(path); 8378c2ecf20Sopenharmony_ci return ret; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic int update_qgroup_status_item(struct btrfs_trans_handle *trans) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 8438c2ecf20Sopenharmony_ci struct btrfs_root *quota_root = fs_info->quota_root; 8448c2ecf20Sopenharmony_ci struct btrfs_path *path; 8458c2ecf20Sopenharmony_ci struct btrfs_key key; 8468c2ecf20Sopenharmony_ci struct extent_buffer *l; 8478c2ecf20Sopenharmony_ci struct btrfs_qgroup_status_item *ptr; 8488c2ecf20Sopenharmony_ci int ret; 8498c2ecf20Sopenharmony_ci int slot; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci key.objectid = 0; 8528c2ecf20Sopenharmony_ci key.type = BTRFS_QGROUP_STATUS_KEY; 8538c2ecf20Sopenharmony_ci key.offset = 0; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 8568c2ecf20Sopenharmony_ci if (!path) 8578c2ecf20Sopenharmony_ci return -ENOMEM; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, 0, 1); 8608c2ecf20Sopenharmony_ci if (ret > 0) 8618c2ecf20Sopenharmony_ci ret = -ENOENT; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (ret) 8648c2ecf20Sopenharmony_ci goto out; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci l = path->nodes[0]; 8678c2ecf20Sopenharmony_ci slot = path->slots[0]; 8688c2ecf20Sopenharmony_ci ptr = btrfs_item_ptr(l, slot, struct btrfs_qgroup_status_item); 8698c2ecf20Sopenharmony_ci btrfs_set_qgroup_status_flags(l, ptr, fs_info->qgroup_flags); 8708c2ecf20Sopenharmony_ci btrfs_set_qgroup_status_generation(l, ptr, trans->transid); 8718c2ecf20Sopenharmony_ci btrfs_set_qgroup_status_rescan(l, ptr, 8728c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(l); 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ciout: 8778c2ecf20Sopenharmony_ci btrfs_free_path(path); 8788c2ecf20Sopenharmony_ci return ret; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci/* 8828c2ecf20Sopenharmony_ci * called with qgroup_lock held 8838c2ecf20Sopenharmony_ci */ 8848c2ecf20Sopenharmony_cistatic int btrfs_clean_quota_tree(struct btrfs_trans_handle *trans, 8858c2ecf20Sopenharmony_ci struct btrfs_root *root) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci struct btrfs_path *path; 8888c2ecf20Sopenharmony_ci struct btrfs_key key; 8898c2ecf20Sopenharmony_ci struct extent_buffer *leaf = NULL; 8908c2ecf20Sopenharmony_ci int ret; 8918c2ecf20Sopenharmony_ci int nr = 0; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 8948c2ecf20Sopenharmony_ci if (!path) 8958c2ecf20Sopenharmony_ci return -ENOMEM; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci path->leave_spinning = 1; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci key.objectid = 0; 9008c2ecf20Sopenharmony_ci key.offset = 0; 9018c2ecf20Sopenharmony_ci key.type = 0; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci while (1) { 9048c2ecf20Sopenharmony_ci ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 9058c2ecf20Sopenharmony_ci if (ret < 0) 9068c2ecf20Sopenharmony_ci goto out; 9078c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 9088c2ecf20Sopenharmony_ci nr = btrfs_header_nritems(leaf); 9098c2ecf20Sopenharmony_ci if (!nr) 9108c2ecf20Sopenharmony_ci break; 9118c2ecf20Sopenharmony_ci /* 9128c2ecf20Sopenharmony_ci * delete the leaf one by one 9138c2ecf20Sopenharmony_ci * since the whole tree is going 9148c2ecf20Sopenharmony_ci * to be deleted. 9158c2ecf20Sopenharmony_ci */ 9168c2ecf20Sopenharmony_ci path->slots[0] = 0; 9178c2ecf20Sopenharmony_ci ret = btrfs_del_items(trans, root, path, 0, nr); 9188c2ecf20Sopenharmony_ci if (ret) 9198c2ecf20Sopenharmony_ci goto out; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci btrfs_release_path(path); 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci ret = 0; 9248c2ecf20Sopenharmony_ciout: 9258c2ecf20Sopenharmony_ci btrfs_free_path(path); 9268c2ecf20Sopenharmony_ci return ret; 9278c2ecf20Sopenharmony_ci} 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ciint btrfs_quota_enable(struct btrfs_fs_info *fs_info) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci struct btrfs_root *quota_root; 9328c2ecf20Sopenharmony_ci struct btrfs_root *tree_root = fs_info->tree_root; 9338c2ecf20Sopenharmony_ci struct btrfs_path *path = NULL; 9348c2ecf20Sopenharmony_ci struct btrfs_qgroup_status_item *ptr; 9358c2ecf20Sopenharmony_ci struct extent_buffer *leaf; 9368c2ecf20Sopenharmony_ci struct btrfs_key key; 9378c2ecf20Sopenharmony_ci struct btrfs_key found_key; 9388c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup = NULL; 9398c2ecf20Sopenharmony_ci struct btrfs_trans_handle *trans = NULL; 9408c2ecf20Sopenharmony_ci struct ulist *ulist = NULL; 9418c2ecf20Sopenharmony_ci int ret = 0; 9428c2ecf20Sopenharmony_ci int slot; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* 9458c2ecf20Sopenharmony_ci * We need to have subvol_sem write locked, to prevent races between 9468c2ecf20Sopenharmony_ci * concurrent tasks trying to enable quotas, because we will unlock 9478c2ecf20Sopenharmony_ci * and relock qgroup_ioctl_lock before setting fs_info->quota_root 9488c2ecf20Sopenharmony_ci * and before setting BTRFS_FS_QUOTA_ENABLED. 9498c2ecf20Sopenharmony_ci */ 9508c2ecf20Sopenharmony_ci lockdep_assert_held_write(&fs_info->subvol_sem); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 9538c2ecf20Sopenharmony_ci if (fs_info->quota_root) 9548c2ecf20Sopenharmony_ci goto out; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci ulist = ulist_alloc(GFP_KERNEL); 9578c2ecf20Sopenharmony_ci if (!ulist) { 9588c2ecf20Sopenharmony_ci ret = -ENOMEM; 9598c2ecf20Sopenharmony_ci goto out; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci ret = btrfs_sysfs_add_qgroups(fs_info); 9638c2ecf20Sopenharmony_ci if (ret < 0) 9648c2ecf20Sopenharmony_ci goto out; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci /* 9678c2ecf20Sopenharmony_ci * Unlock qgroup_ioctl_lock before starting the transaction. This is to 9688c2ecf20Sopenharmony_ci * avoid lock acquisition inversion problems (reported by lockdep) between 9698c2ecf20Sopenharmony_ci * qgroup_ioctl_lock and the vfs freeze semaphores, acquired when we 9708c2ecf20Sopenharmony_ci * start a transaction. 9718c2ecf20Sopenharmony_ci * After we started the transaction lock qgroup_ioctl_lock again and 9728c2ecf20Sopenharmony_ci * check if someone else created the quota root in the meanwhile. If so, 9738c2ecf20Sopenharmony_ci * just return success and release the transaction handle. 9748c2ecf20Sopenharmony_ci * 9758c2ecf20Sopenharmony_ci * Also we don't need to worry about someone else calling 9768c2ecf20Sopenharmony_ci * btrfs_sysfs_add_qgroups() after we unlock and getting an error because 9778c2ecf20Sopenharmony_ci * that function returns 0 (success) when the sysfs entries already exist. 9788c2ecf20Sopenharmony_ci */ 9798c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* 9828c2ecf20Sopenharmony_ci * 1 for quota root item 9838c2ecf20Sopenharmony_ci * 1 for BTRFS_QGROUP_STATUS item 9848c2ecf20Sopenharmony_ci * 9858c2ecf20Sopenharmony_ci * Yet we also need 2*n items for a QGROUP_INFO/QGROUP_LIMIT items 9868c2ecf20Sopenharmony_ci * per subvolume. However those are not currently reserved since it 9878c2ecf20Sopenharmony_ci * would be a lot of overkill. 9888c2ecf20Sopenharmony_ci */ 9898c2ecf20Sopenharmony_ci trans = btrfs_start_transaction(tree_root, 2); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 9928c2ecf20Sopenharmony_ci if (IS_ERR(trans)) { 9938c2ecf20Sopenharmony_ci ret = PTR_ERR(trans); 9948c2ecf20Sopenharmony_ci trans = NULL; 9958c2ecf20Sopenharmony_ci goto out; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (fs_info->quota_root) 9998c2ecf20Sopenharmony_ci goto out; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci fs_info->qgroup_ulist = ulist; 10028c2ecf20Sopenharmony_ci ulist = NULL; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci /* 10058c2ecf20Sopenharmony_ci * initially create the quota tree 10068c2ecf20Sopenharmony_ci */ 10078c2ecf20Sopenharmony_ci quota_root = btrfs_create_tree(trans, BTRFS_QUOTA_TREE_OBJECTID); 10088c2ecf20Sopenharmony_ci if (IS_ERR(quota_root)) { 10098c2ecf20Sopenharmony_ci ret = PTR_ERR(quota_root); 10108c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 10118c2ecf20Sopenharmony_ci goto out; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 10158c2ecf20Sopenharmony_ci if (!path) { 10168c2ecf20Sopenharmony_ci ret = -ENOMEM; 10178c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 10188c2ecf20Sopenharmony_ci goto out_free_root; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci key.objectid = 0; 10228c2ecf20Sopenharmony_ci key.type = BTRFS_QGROUP_STATUS_KEY; 10238c2ecf20Sopenharmony_ci key.offset = 0; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci ret = btrfs_insert_empty_item(trans, quota_root, path, &key, 10268c2ecf20Sopenharmony_ci sizeof(*ptr)); 10278c2ecf20Sopenharmony_ci if (ret) { 10288c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 10298c2ecf20Sopenharmony_ci goto out_free_path; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 10338c2ecf20Sopenharmony_ci ptr = btrfs_item_ptr(leaf, path->slots[0], 10348c2ecf20Sopenharmony_ci struct btrfs_qgroup_status_item); 10358c2ecf20Sopenharmony_ci btrfs_set_qgroup_status_generation(leaf, ptr, trans->transid); 10368c2ecf20Sopenharmony_ci btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_STATUS_VERSION); 10378c2ecf20Sopenharmony_ci fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON | 10388c2ecf20Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 10398c2ecf20Sopenharmony_ci btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags); 10408c2ecf20Sopenharmony_ci btrfs_set_qgroup_status_rescan(leaf, ptr, 0); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci btrfs_mark_buffer_dirty(leaf); 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci key.objectid = 0; 10458c2ecf20Sopenharmony_ci key.type = BTRFS_ROOT_REF_KEY; 10468c2ecf20Sopenharmony_ci key.offset = 0; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci btrfs_release_path(path); 10498c2ecf20Sopenharmony_ci ret = btrfs_search_slot_for_read(tree_root, &key, path, 1, 0); 10508c2ecf20Sopenharmony_ci if (ret > 0) 10518c2ecf20Sopenharmony_ci goto out_add_root; 10528c2ecf20Sopenharmony_ci if (ret < 0) { 10538c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 10548c2ecf20Sopenharmony_ci goto out_free_path; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci while (1) { 10588c2ecf20Sopenharmony_ci slot = path->slots[0]; 10598c2ecf20Sopenharmony_ci leaf = path->nodes[0]; 10608c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(leaf, &found_key, slot); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci if (found_key.type == BTRFS_ROOT_REF_KEY) { 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* Release locks on tree_root before we access quota_root */ 10658c2ecf20Sopenharmony_ci btrfs_release_path(path); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci ret = add_qgroup_item(trans, quota_root, 10688c2ecf20Sopenharmony_ci found_key.offset); 10698c2ecf20Sopenharmony_ci if (ret) { 10708c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 10718c2ecf20Sopenharmony_ci goto out_free_path; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci qgroup = add_qgroup_rb(fs_info, found_key.offset); 10758c2ecf20Sopenharmony_ci if (IS_ERR(qgroup)) { 10768c2ecf20Sopenharmony_ci ret = PTR_ERR(qgroup); 10778c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 10788c2ecf20Sopenharmony_ci goto out_free_path; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup); 10818c2ecf20Sopenharmony_ci if (ret < 0) { 10828c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 10838c2ecf20Sopenharmony_ci goto out_free_path; 10848c2ecf20Sopenharmony_ci } 10858c2ecf20Sopenharmony_ci ret = btrfs_search_slot_for_read(tree_root, &found_key, 10868c2ecf20Sopenharmony_ci path, 1, 0); 10878c2ecf20Sopenharmony_ci if (ret < 0) { 10888c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 10898c2ecf20Sopenharmony_ci goto out_free_path; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci if (ret > 0) { 10928c2ecf20Sopenharmony_ci /* 10938c2ecf20Sopenharmony_ci * Shouldn't happen, but in case it does we 10948c2ecf20Sopenharmony_ci * don't need to do the btrfs_next_item, just 10958c2ecf20Sopenharmony_ci * continue. 10968c2ecf20Sopenharmony_ci */ 10978c2ecf20Sopenharmony_ci continue; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci ret = btrfs_next_item(tree_root, path); 11018c2ecf20Sopenharmony_ci if (ret < 0) { 11028c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 11038c2ecf20Sopenharmony_ci goto out_free_path; 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci if (ret) 11068c2ecf20Sopenharmony_ci break; 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ciout_add_root: 11108c2ecf20Sopenharmony_ci btrfs_release_path(path); 11118c2ecf20Sopenharmony_ci ret = add_qgroup_item(trans, quota_root, BTRFS_FS_TREE_OBJECTID); 11128c2ecf20Sopenharmony_ci if (ret) { 11138c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 11148c2ecf20Sopenharmony_ci goto out_free_path; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci qgroup = add_qgroup_rb(fs_info, BTRFS_FS_TREE_OBJECTID); 11188c2ecf20Sopenharmony_ci if (IS_ERR(qgroup)) { 11198c2ecf20Sopenharmony_ci ret = PTR_ERR(qgroup); 11208c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 11218c2ecf20Sopenharmony_ci goto out_free_path; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup); 11248c2ecf20Sopenharmony_ci if (ret < 0) { 11258c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 11268c2ecf20Sopenharmony_ci goto out_free_path; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 11308c2ecf20Sopenharmony_ci /* 11318c2ecf20Sopenharmony_ci * Commit the transaction while not holding qgroup_ioctl_lock, to avoid 11328c2ecf20Sopenharmony_ci * a deadlock with tasks concurrently doing other qgroup operations, such 11338c2ecf20Sopenharmony_ci * adding/removing qgroups or adding/deleting qgroup relations for example, 11348c2ecf20Sopenharmony_ci * because all qgroup operations first start or join a transaction and then 11358c2ecf20Sopenharmony_ci * lock the qgroup_ioctl_lock mutex. 11368c2ecf20Sopenharmony_ci * We are safe from a concurrent task trying to enable quotas, by calling 11378c2ecf20Sopenharmony_ci * this function, since we are serialized by fs_info->subvol_sem. 11388c2ecf20Sopenharmony_ci */ 11398c2ecf20Sopenharmony_ci ret = btrfs_commit_transaction(trans); 11408c2ecf20Sopenharmony_ci trans = NULL; 11418c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 11428c2ecf20Sopenharmony_ci if (ret) 11438c2ecf20Sopenharmony_ci goto out_free_path; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* 11468c2ecf20Sopenharmony_ci * Set quota enabled flag after committing the transaction, to avoid 11478c2ecf20Sopenharmony_ci * deadlocks on fs_info->qgroup_ioctl_lock with concurrent snapshot 11488c2ecf20Sopenharmony_ci * creation. 11498c2ecf20Sopenharmony_ci */ 11508c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 11518c2ecf20Sopenharmony_ci fs_info->quota_root = quota_root; 11528c2ecf20Sopenharmony_ci set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); 11538c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci ret = qgroup_rescan_init(fs_info, 0, 1); 11568c2ecf20Sopenharmony_ci if (!ret) { 11578c2ecf20Sopenharmony_ci qgroup_rescan_zero_tracking(fs_info); 11588c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_running = true; 11598c2ecf20Sopenharmony_ci btrfs_queue_work(fs_info->qgroup_rescan_workers, 11608c2ecf20Sopenharmony_ci &fs_info->qgroup_rescan_work); 11618c2ecf20Sopenharmony_ci } else { 11628c2ecf20Sopenharmony_ci /* 11638c2ecf20Sopenharmony_ci * We have set both BTRFS_FS_QUOTA_ENABLED and 11648c2ecf20Sopenharmony_ci * BTRFS_QGROUP_STATUS_FLAG_ON, so we can only fail with 11658c2ecf20Sopenharmony_ci * -EINPROGRESS. That can happen because someone started the 11668c2ecf20Sopenharmony_ci * rescan worker by calling quota rescan ioctl before we 11678c2ecf20Sopenharmony_ci * attempted to initialize the rescan worker. Failure due to 11688c2ecf20Sopenharmony_ci * quotas disabled in the meanwhile is not possible, because 11698c2ecf20Sopenharmony_ci * we are holding a write lock on fs_info->subvol_sem, which 11708c2ecf20Sopenharmony_ci * is also acquired when disabling quotas. 11718c2ecf20Sopenharmony_ci * Ignore such error, and any other error would need to undo 11728c2ecf20Sopenharmony_ci * everything we did in the transaction we just committed. 11738c2ecf20Sopenharmony_ci */ 11748c2ecf20Sopenharmony_ci ASSERT(ret == -EINPROGRESS); 11758c2ecf20Sopenharmony_ci ret = 0; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ciout_free_path: 11798c2ecf20Sopenharmony_ci btrfs_free_path(path); 11808c2ecf20Sopenharmony_ciout_free_root: 11818c2ecf20Sopenharmony_ci if (ret) 11828c2ecf20Sopenharmony_ci btrfs_put_root(quota_root); 11838c2ecf20Sopenharmony_ciout: 11848c2ecf20Sopenharmony_ci if (ret) { 11858c2ecf20Sopenharmony_ci ulist_free(fs_info->qgroup_ulist); 11868c2ecf20Sopenharmony_ci fs_info->qgroup_ulist = NULL; 11878c2ecf20Sopenharmony_ci btrfs_sysfs_del_qgroups(fs_info); 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 11908c2ecf20Sopenharmony_ci if (ret && trans) 11918c2ecf20Sopenharmony_ci btrfs_end_transaction(trans); 11928c2ecf20Sopenharmony_ci else if (trans) 11938c2ecf20Sopenharmony_ci ret = btrfs_end_transaction(trans); 11948c2ecf20Sopenharmony_ci ulist_free(ulist); 11958c2ecf20Sopenharmony_ci return ret; 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ciint btrfs_quota_disable(struct btrfs_fs_info *fs_info) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct btrfs_root *quota_root = NULL; 12018c2ecf20Sopenharmony_ci struct btrfs_trans_handle *trans = NULL; 12028c2ecf20Sopenharmony_ci int ret = 0; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci /* 12058c2ecf20Sopenharmony_ci * We need to have subvol_sem write locked to prevent races with 12068c2ecf20Sopenharmony_ci * snapshot creation. 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_ci lockdep_assert_held_write(&fs_info->subvol_sem); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci /* 12118c2ecf20Sopenharmony_ci * Lock the cleaner mutex to prevent races with concurrent relocation, 12128c2ecf20Sopenharmony_ci * because relocation may be building backrefs for blocks of the quota 12138c2ecf20Sopenharmony_ci * root while we are deleting the root. This is like dropping fs roots 12148c2ecf20Sopenharmony_ci * of deleted snapshots/subvolumes, we need the same protection. 12158c2ecf20Sopenharmony_ci * 12168c2ecf20Sopenharmony_ci * This also prevents races between concurrent tasks trying to disable 12178c2ecf20Sopenharmony_ci * quotas, because we will unlock and relock qgroup_ioctl_lock across 12188c2ecf20Sopenharmony_ci * BTRFS_FS_QUOTA_ENABLED changes. 12198c2ecf20Sopenharmony_ci */ 12208c2ecf20Sopenharmony_ci mutex_lock(&fs_info->cleaner_mutex); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 12238c2ecf20Sopenharmony_ci if (!fs_info->quota_root) 12248c2ecf20Sopenharmony_ci goto out; 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* 12278c2ecf20Sopenharmony_ci * Unlock the qgroup_ioctl_lock mutex before waiting for the rescan worker to 12288c2ecf20Sopenharmony_ci * complete. Otherwise we can deadlock because btrfs_remove_qgroup() needs 12298c2ecf20Sopenharmony_ci * to lock that mutex while holding a transaction handle and the rescan 12308c2ecf20Sopenharmony_ci * worker needs to commit a transaction. 12318c2ecf20Sopenharmony_ci */ 12328c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci /* 12358c2ecf20Sopenharmony_ci * Request qgroup rescan worker to complete and wait for it. This wait 12368c2ecf20Sopenharmony_ci * must be done before transaction start for quota disable since it may 12378c2ecf20Sopenharmony_ci * deadlock with transaction by the qgroup rescan worker. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_ci clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); 12408c2ecf20Sopenharmony_ci btrfs_qgroup_wait_for_completion(fs_info, false); 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci /* 12438c2ecf20Sopenharmony_ci * 1 For the root item 12448c2ecf20Sopenharmony_ci * 12458c2ecf20Sopenharmony_ci * We should also reserve enough items for the quota tree deletion in 12468c2ecf20Sopenharmony_ci * btrfs_clean_quota_tree but this is not done. 12478c2ecf20Sopenharmony_ci * 12488c2ecf20Sopenharmony_ci * Also, we must always start a transaction without holding the mutex 12498c2ecf20Sopenharmony_ci * qgroup_ioctl_lock, see btrfs_quota_enable(). 12508c2ecf20Sopenharmony_ci */ 12518c2ecf20Sopenharmony_ci trans = btrfs_start_transaction(fs_info->tree_root, 1); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 12548c2ecf20Sopenharmony_ci if (IS_ERR(trans)) { 12558c2ecf20Sopenharmony_ci ret = PTR_ERR(trans); 12568c2ecf20Sopenharmony_ci trans = NULL; 12578c2ecf20Sopenharmony_ci set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); 12588c2ecf20Sopenharmony_ci goto out; 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (!fs_info->quota_root) 12628c2ecf20Sopenharmony_ci goto out; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 12658c2ecf20Sopenharmony_ci quota_root = fs_info->quota_root; 12668c2ecf20Sopenharmony_ci fs_info->quota_root = NULL; 12678c2ecf20Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON; 12688c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci btrfs_free_qgroup_config(fs_info); 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci ret = btrfs_clean_quota_tree(trans, quota_root); 12738c2ecf20Sopenharmony_ci if (ret) { 12748c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 12758c2ecf20Sopenharmony_ci goto out; 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci ret = btrfs_del_root(trans, "a_root->root_key); 12798c2ecf20Sopenharmony_ci if (ret) { 12808c2ecf20Sopenharmony_ci btrfs_abort_transaction(trans, ret); 12818c2ecf20Sopenharmony_ci goto out; 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci spin_lock(&fs_info->trans_lock); 12858c2ecf20Sopenharmony_ci list_del("a_root->dirty_list); 12868c2ecf20Sopenharmony_ci spin_unlock(&fs_info->trans_lock); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci btrfs_tree_lock(quota_root->node); 12898c2ecf20Sopenharmony_ci btrfs_clean_tree_block(quota_root->node); 12908c2ecf20Sopenharmony_ci btrfs_tree_unlock(quota_root->node); 12918c2ecf20Sopenharmony_ci btrfs_free_tree_block(trans, quota_root, quota_root->node, 0, 1); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ciout: 12958c2ecf20Sopenharmony_ci btrfs_put_root(quota_root); 12968c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 12978c2ecf20Sopenharmony_ci if (ret && trans) 12988c2ecf20Sopenharmony_ci btrfs_end_transaction(trans); 12998c2ecf20Sopenharmony_ci else if (trans) 13008c2ecf20Sopenharmony_ci ret = btrfs_end_transaction(trans); 13018c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->cleaner_mutex); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci return ret; 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_cistatic void qgroup_dirty(struct btrfs_fs_info *fs_info, 13078c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup) 13088c2ecf20Sopenharmony_ci{ 13098c2ecf20Sopenharmony_ci if (list_empty(&qgroup->dirty)) 13108c2ecf20Sopenharmony_ci list_add(&qgroup->dirty, &fs_info->dirty_qgroups); 13118c2ecf20Sopenharmony_ci} 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci/* 13148c2ecf20Sopenharmony_ci * The easy accounting, we're updating qgroup relationship whose child qgroup 13158c2ecf20Sopenharmony_ci * only has exclusive extents. 13168c2ecf20Sopenharmony_ci * 13178c2ecf20Sopenharmony_ci * In this case, all exclusive extents will also be exclusive for parent, so 13188c2ecf20Sopenharmony_ci * excl/rfer just get added/removed. 13198c2ecf20Sopenharmony_ci * 13208c2ecf20Sopenharmony_ci * So is qgroup reservation space, which should also be added/removed to 13218c2ecf20Sopenharmony_ci * parent. 13228c2ecf20Sopenharmony_ci * Or when child tries to release reservation space, parent will underflow its 13238c2ecf20Sopenharmony_ci * reservation (for relationship adding case). 13248c2ecf20Sopenharmony_ci * 13258c2ecf20Sopenharmony_ci * Caller should hold fs_info->qgroup_lock. 13268c2ecf20Sopenharmony_ci */ 13278c2ecf20Sopenharmony_cistatic int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, 13288c2ecf20Sopenharmony_ci struct ulist *tmp, u64 ref_root, 13298c2ecf20Sopenharmony_ci struct btrfs_qgroup *src, int sign) 13308c2ecf20Sopenharmony_ci{ 13318c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 13328c2ecf20Sopenharmony_ci struct btrfs_qgroup_list *glist; 13338c2ecf20Sopenharmony_ci struct ulist_node *unode; 13348c2ecf20Sopenharmony_ci struct ulist_iterator uiter; 13358c2ecf20Sopenharmony_ci u64 num_bytes = src->excl; 13368c2ecf20Sopenharmony_ci int ret = 0; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, ref_root); 13398c2ecf20Sopenharmony_ci if (!qgroup) 13408c2ecf20Sopenharmony_ci goto out; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci qgroup->rfer += sign * num_bytes; 13438c2ecf20Sopenharmony_ci qgroup->rfer_cmpr += sign * num_bytes; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci WARN_ON(sign < 0 && qgroup->excl < num_bytes); 13468c2ecf20Sopenharmony_ci qgroup->excl += sign * num_bytes; 13478c2ecf20Sopenharmony_ci qgroup->excl_cmpr += sign * num_bytes; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci if (sign > 0) 13508c2ecf20Sopenharmony_ci qgroup_rsv_add_by_qgroup(fs_info, qgroup, src); 13518c2ecf20Sopenharmony_ci else 13528c2ecf20Sopenharmony_ci qgroup_rsv_release_by_qgroup(fs_info, qgroup, src); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci qgroup_dirty(fs_info, qgroup); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci /* Get all of the parent groups that contain this qgroup */ 13578c2ecf20Sopenharmony_ci list_for_each_entry(glist, &qgroup->groups, next_group) { 13588c2ecf20Sopenharmony_ci ret = ulist_add(tmp, glist->group->qgroupid, 13598c2ecf20Sopenharmony_ci qgroup_to_aux(glist->group), GFP_ATOMIC); 13608c2ecf20Sopenharmony_ci if (ret < 0) 13618c2ecf20Sopenharmony_ci goto out; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci /* Iterate all of the parents and adjust their reference counts */ 13658c2ecf20Sopenharmony_ci ULIST_ITER_INIT(&uiter); 13668c2ecf20Sopenharmony_ci while ((unode = ulist_next(tmp, &uiter))) { 13678c2ecf20Sopenharmony_ci qgroup = unode_aux_to_qgroup(unode); 13688c2ecf20Sopenharmony_ci qgroup->rfer += sign * num_bytes; 13698c2ecf20Sopenharmony_ci qgroup->rfer_cmpr += sign * num_bytes; 13708c2ecf20Sopenharmony_ci WARN_ON(sign < 0 && qgroup->excl < num_bytes); 13718c2ecf20Sopenharmony_ci qgroup->excl += sign * num_bytes; 13728c2ecf20Sopenharmony_ci if (sign > 0) 13738c2ecf20Sopenharmony_ci qgroup_rsv_add_by_qgroup(fs_info, qgroup, src); 13748c2ecf20Sopenharmony_ci else 13758c2ecf20Sopenharmony_ci qgroup_rsv_release_by_qgroup(fs_info, qgroup, src); 13768c2ecf20Sopenharmony_ci qgroup->excl_cmpr += sign * num_bytes; 13778c2ecf20Sopenharmony_ci qgroup_dirty(fs_info, qgroup); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci /* Add any parents of the parents */ 13808c2ecf20Sopenharmony_ci list_for_each_entry(glist, &qgroup->groups, next_group) { 13818c2ecf20Sopenharmony_ci ret = ulist_add(tmp, glist->group->qgroupid, 13828c2ecf20Sopenharmony_ci qgroup_to_aux(glist->group), GFP_ATOMIC); 13838c2ecf20Sopenharmony_ci if (ret < 0) 13848c2ecf20Sopenharmony_ci goto out; 13858c2ecf20Sopenharmony_ci } 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci ret = 0; 13888c2ecf20Sopenharmony_ciout: 13898c2ecf20Sopenharmony_ci return ret; 13908c2ecf20Sopenharmony_ci} 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci/* 13948c2ecf20Sopenharmony_ci * Quick path for updating qgroup with only excl refs. 13958c2ecf20Sopenharmony_ci * 13968c2ecf20Sopenharmony_ci * In that case, just update all parent will be enough. 13978c2ecf20Sopenharmony_ci * Or we needs to do a full rescan. 13988c2ecf20Sopenharmony_ci * Caller should also hold fs_info->qgroup_lock. 13998c2ecf20Sopenharmony_ci * 14008c2ecf20Sopenharmony_ci * Return 0 for quick update, return >0 for need to full rescan 14018c2ecf20Sopenharmony_ci * and mark INCONSISTENT flag. 14028c2ecf20Sopenharmony_ci * Return < 0 for other error. 14038c2ecf20Sopenharmony_ci */ 14048c2ecf20Sopenharmony_cistatic int quick_update_accounting(struct btrfs_fs_info *fs_info, 14058c2ecf20Sopenharmony_ci struct ulist *tmp, u64 src, u64 dst, 14068c2ecf20Sopenharmony_ci int sign) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 14098c2ecf20Sopenharmony_ci int ret = 1; 14108c2ecf20Sopenharmony_ci int err = 0; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, src); 14138c2ecf20Sopenharmony_ci if (!qgroup) 14148c2ecf20Sopenharmony_ci goto out; 14158c2ecf20Sopenharmony_ci if (qgroup->excl == qgroup->rfer) { 14168c2ecf20Sopenharmony_ci ret = 0; 14178c2ecf20Sopenharmony_ci err = __qgroup_excl_accounting(fs_info, tmp, dst, 14188c2ecf20Sopenharmony_ci qgroup, sign); 14198c2ecf20Sopenharmony_ci if (err < 0) { 14208c2ecf20Sopenharmony_ci ret = err; 14218c2ecf20Sopenharmony_ci goto out; 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ciout: 14258c2ecf20Sopenharmony_ci if (ret) 14268c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 14278c2ecf20Sopenharmony_ci return ret; 14288c2ecf20Sopenharmony_ci} 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ciint btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, 14318c2ecf20Sopenharmony_ci u64 dst) 14328c2ecf20Sopenharmony_ci{ 14338c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 14348c2ecf20Sopenharmony_ci struct btrfs_qgroup *parent; 14358c2ecf20Sopenharmony_ci struct btrfs_qgroup *member; 14368c2ecf20Sopenharmony_ci struct btrfs_qgroup_list *list; 14378c2ecf20Sopenharmony_ci struct ulist *tmp; 14388c2ecf20Sopenharmony_ci unsigned int nofs_flag; 14398c2ecf20Sopenharmony_ci int ret = 0; 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci /* Check the level of src and dst first */ 14428c2ecf20Sopenharmony_ci if (btrfs_qgroup_level(src) >= btrfs_qgroup_level(dst)) 14438c2ecf20Sopenharmony_ci return -EINVAL; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci /* We hold a transaction handle open, must do a NOFS allocation. */ 14468c2ecf20Sopenharmony_ci nofs_flag = memalloc_nofs_save(); 14478c2ecf20Sopenharmony_ci tmp = ulist_alloc(GFP_KERNEL); 14488c2ecf20Sopenharmony_ci memalloc_nofs_restore(nofs_flag); 14498c2ecf20Sopenharmony_ci if (!tmp) 14508c2ecf20Sopenharmony_ci return -ENOMEM; 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 14538c2ecf20Sopenharmony_ci if (!fs_info->quota_root) { 14548c2ecf20Sopenharmony_ci ret = -ENOTCONN; 14558c2ecf20Sopenharmony_ci goto out; 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci member = find_qgroup_rb(fs_info, src); 14588c2ecf20Sopenharmony_ci parent = find_qgroup_rb(fs_info, dst); 14598c2ecf20Sopenharmony_ci if (!member || !parent) { 14608c2ecf20Sopenharmony_ci ret = -EINVAL; 14618c2ecf20Sopenharmony_ci goto out; 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci /* check if such qgroup relation exist firstly */ 14658c2ecf20Sopenharmony_ci list_for_each_entry(list, &member->groups, next_group) { 14668c2ecf20Sopenharmony_ci if (list->group == parent) { 14678c2ecf20Sopenharmony_ci ret = -EEXIST; 14688c2ecf20Sopenharmony_ci goto out; 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci } 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_ci ret = add_qgroup_relation_item(trans, src, dst); 14738c2ecf20Sopenharmony_ci if (ret) 14748c2ecf20Sopenharmony_ci goto out; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci ret = add_qgroup_relation_item(trans, dst, src); 14778c2ecf20Sopenharmony_ci if (ret) { 14788c2ecf20Sopenharmony_ci del_qgroup_relation_item(trans, src, dst); 14798c2ecf20Sopenharmony_ci goto out; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 14838c2ecf20Sopenharmony_ci ret = add_relation_rb(fs_info, src, dst); 14848c2ecf20Sopenharmony_ci if (ret < 0) { 14858c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 14868c2ecf20Sopenharmony_ci goto out; 14878c2ecf20Sopenharmony_ci } 14888c2ecf20Sopenharmony_ci ret = quick_update_accounting(fs_info, tmp, src, dst, 1); 14898c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 14908c2ecf20Sopenharmony_ciout: 14918c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 14928c2ecf20Sopenharmony_ci ulist_free(tmp); 14938c2ecf20Sopenharmony_ci return ret; 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_cistatic int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, 14978c2ecf20Sopenharmony_ci u64 dst) 14988c2ecf20Sopenharmony_ci{ 14998c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 15008c2ecf20Sopenharmony_ci struct btrfs_qgroup *parent; 15018c2ecf20Sopenharmony_ci struct btrfs_qgroup *member; 15028c2ecf20Sopenharmony_ci struct btrfs_qgroup_list *list; 15038c2ecf20Sopenharmony_ci struct ulist *tmp; 15048c2ecf20Sopenharmony_ci bool found = false; 15058c2ecf20Sopenharmony_ci unsigned int nofs_flag; 15068c2ecf20Sopenharmony_ci int ret = 0; 15078c2ecf20Sopenharmony_ci int ret2; 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci /* We hold a transaction handle open, must do a NOFS allocation. */ 15108c2ecf20Sopenharmony_ci nofs_flag = memalloc_nofs_save(); 15118c2ecf20Sopenharmony_ci tmp = ulist_alloc(GFP_KERNEL); 15128c2ecf20Sopenharmony_ci memalloc_nofs_restore(nofs_flag); 15138c2ecf20Sopenharmony_ci if (!tmp) 15148c2ecf20Sopenharmony_ci return -ENOMEM; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (!fs_info->quota_root) { 15178c2ecf20Sopenharmony_ci ret = -ENOTCONN; 15188c2ecf20Sopenharmony_ci goto out; 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci member = find_qgroup_rb(fs_info, src); 15228c2ecf20Sopenharmony_ci parent = find_qgroup_rb(fs_info, dst); 15238c2ecf20Sopenharmony_ci /* 15248c2ecf20Sopenharmony_ci * The parent/member pair doesn't exist, then try to delete the dead 15258c2ecf20Sopenharmony_ci * relation items only. 15268c2ecf20Sopenharmony_ci */ 15278c2ecf20Sopenharmony_ci if (!member || !parent) 15288c2ecf20Sopenharmony_ci goto delete_item; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci /* check if such qgroup relation exist firstly */ 15318c2ecf20Sopenharmony_ci list_for_each_entry(list, &member->groups, next_group) { 15328c2ecf20Sopenharmony_ci if (list->group == parent) { 15338c2ecf20Sopenharmony_ci found = true; 15348c2ecf20Sopenharmony_ci break; 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_cidelete_item: 15398c2ecf20Sopenharmony_ci ret = del_qgroup_relation_item(trans, src, dst); 15408c2ecf20Sopenharmony_ci if (ret < 0 && ret != -ENOENT) 15418c2ecf20Sopenharmony_ci goto out; 15428c2ecf20Sopenharmony_ci ret2 = del_qgroup_relation_item(trans, dst, src); 15438c2ecf20Sopenharmony_ci if (ret2 < 0 && ret2 != -ENOENT) 15448c2ecf20Sopenharmony_ci goto out; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci /* At least one deletion succeeded, return 0 */ 15478c2ecf20Sopenharmony_ci if (!ret || !ret2) 15488c2ecf20Sopenharmony_ci ret = 0; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci if (found) { 15518c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 15528c2ecf20Sopenharmony_ci del_relation_rb(fs_info, src, dst); 15538c2ecf20Sopenharmony_ci ret = quick_update_accounting(fs_info, tmp, src, dst, -1); 15548c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ciout: 15578c2ecf20Sopenharmony_ci ulist_free(tmp); 15588c2ecf20Sopenharmony_ci return ret; 15598c2ecf20Sopenharmony_ci} 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ciint btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, 15628c2ecf20Sopenharmony_ci u64 dst) 15638c2ecf20Sopenharmony_ci{ 15648c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 15658c2ecf20Sopenharmony_ci int ret = 0; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 15688c2ecf20Sopenharmony_ci ret = __del_qgroup_relation(trans, src, dst); 15698c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci return ret; 15728c2ecf20Sopenharmony_ci} 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ciint btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) 15758c2ecf20Sopenharmony_ci{ 15768c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 15778c2ecf20Sopenharmony_ci struct btrfs_root *quota_root; 15788c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 15798c2ecf20Sopenharmony_ci int ret = 0; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 15828c2ecf20Sopenharmony_ci if (!fs_info->quota_root) { 15838c2ecf20Sopenharmony_ci ret = -ENOTCONN; 15848c2ecf20Sopenharmony_ci goto out; 15858c2ecf20Sopenharmony_ci } 15868c2ecf20Sopenharmony_ci quota_root = fs_info->quota_root; 15878c2ecf20Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, qgroupid); 15888c2ecf20Sopenharmony_ci if (qgroup) { 15898c2ecf20Sopenharmony_ci ret = -EEXIST; 15908c2ecf20Sopenharmony_ci goto out; 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci ret = add_qgroup_item(trans, quota_root, qgroupid); 15948c2ecf20Sopenharmony_ci if (ret) 15958c2ecf20Sopenharmony_ci goto out; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 15988c2ecf20Sopenharmony_ci qgroup = add_qgroup_rb(fs_info, qgroupid); 15998c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci if (IS_ERR(qgroup)) { 16028c2ecf20Sopenharmony_ci ret = PTR_ERR(qgroup); 16038c2ecf20Sopenharmony_ci goto out; 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup); 16068c2ecf20Sopenharmony_ciout: 16078c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 16088c2ecf20Sopenharmony_ci return ret; 16098c2ecf20Sopenharmony_ci} 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_cistatic bool qgroup_has_usage(struct btrfs_qgroup *qgroup) 16128c2ecf20Sopenharmony_ci{ 16138c2ecf20Sopenharmony_ci return (qgroup->rfer > 0 || qgroup->rfer_cmpr > 0 || 16148c2ecf20Sopenharmony_ci qgroup->excl > 0 || qgroup->excl_cmpr > 0 || 16158c2ecf20Sopenharmony_ci qgroup->rsv.values[BTRFS_QGROUP_RSV_DATA] > 0 || 16168c2ecf20Sopenharmony_ci qgroup->rsv.values[BTRFS_QGROUP_RSV_META_PREALLOC] > 0 || 16178c2ecf20Sopenharmony_ci qgroup->rsv.values[BTRFS_QGROUP_RSV_META_PERTRANS] > 0); 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ciint btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 16238c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 16248c2ecf20Sopenharmony_ci struct btrfs_qgroup_list *list; 16258c2ecf20Sopenharmony_ci int ret = 0; 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 16288c2ecf20Sopenharmony_ci if (!fs_info->quota_root) { 16298c2ecf20Sopenharmony_ci ret = -ENOTCONN; 16308c2ecf20Sopenharmony_ci goto out; 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, qgroupid); 16348c2ecf20Sopenharmony_ci if (!qgroup) { 16358c2ecf20Sopenharmony_ci ret = -ENOENT; 16368c2ecf20Sopenharmony_ci goto out; 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci if (is_fstree(qgroupid) && qgroup_has_usage(qgroup)) { 16408c2ecf20Sopenharmony_ci ret = -EBUSY; 16418c2ecf20Sopenharmony_ci goto out; 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci /* Check if there are no children of this qgroup */ 16458c2ecf20Sopenharmony_ci if (!list_empty(&qgroup->members)) { 16468c2ecf20Sopenharmony_ci ret = -EBUSY; 16478c2ecf20Sopenharmony_ci goto out; 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci ret = del_qgroup_item(trans, qgroupid); 16518c2ecf20Sopenharmony_ci if (ret && ret != -ENOENT) 16528c2ecf20Sopenharmony_ci goto out; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci while (!list_empty(&qgroup->groups)) { 16558c2ecf20Sopenharmony_ci list = list_first_entry(&qgroup->groups, 16568c2ecf20Sopenharmony_ci struct btrfs_qgroup_list, next_group); 16578c2ecf20Sopenharmony_ci ret = __del_qgroup_relation(trans, qgroupid, 16588c2ecf20Sopenharmony_ci list->group->qgroupid); 16598c2ecf20Sopenharmony_ci if (ret) 16608c2ecf20Sopenharmony_ci goto out; 16618c2ecf20Sopenharmony_ci } 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 16648c2ecf20Sopenharmony_ci del_qgroup_rb(fs_info, qgroupid); 16658c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci /* 16688c2ecf20Sopenharmony_ci * Remove the qgroup from sysfs now without holding the qgroup_lock 16698c2ecf20Sopenharmony_ci * spinlock, since the sysfs_remove_group() function needs to take 16708c2ecf20Sopenharmony_ci * the mutex kernfs_mutex through kernfs_remove_by_name_ns(). 16718c2ecf20Sopenharmony_ci */ 16728c2ecf20Sopenharmony_ci btrfs_sysfs_del_one_qgroup(fs_info, qgroup); 16738c2ecf20Sopenharmony_ci kfree(qgroup); 16748c2ecf20Sopenharmony_ciout: 16758c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 16768c2ecf20Sopenharmony_ci return ret; 16778c2ecf20Sopenharmony_ci} 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ciint btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid, 16808c2ecf20Sopenharmony_ci struct btrfs_qgroup_limit *limit) 16818c2ecf20Sopenharmony_ci{ 16828c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 16838c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 16848c2ecf20Sopenharmony_ci int ret = 0; 16858c2ecf20Sopenharmony_ci /* Sometimes we would want to clear the limit on this qgroup. 16868c2ecf20Sopenharmony_ci * To meet this requirement, we treat the -1 as a special value 16878c2ecf20Sopenharmony_ci * which tell kernel to clear the limit on this qgroup. 16888c2ecf20Sopenharmony_ci */ 16898c2ecf20Sopenharmony_ci const u64 CLEAR_VALUE = -1; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 16928c2ecf20Sopenharmony_ci if (!fs_info->quota_root) { 16938c2ecf20Sopenharmony_ci ret = -ENOTCONN; 16948c2ecf20Sopenharmony_ci goto out; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, qgroupid); 16988c2ecf20Sopenharmony_ci if (!qgroup) { 16998c2ecf20Sopenharmony_ci ret = -ENOENT; 17008c2ecf20Sopenharmony_ci goto out; 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 17048c2ecf20Sopenharmony_ci if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_RFER) { 17058c2ecf20Sopenharmony_ci if (limit->max_rfer == CLEAR_VALUE) { 17068c2ecf20Sopenharmony_ci qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_MAX_RFER; 17078c2ecf20Sopenharmony_ci limit->flags &= ~BTRFS_QGROUP_LIMIT_MAX_RFER; 17088c2ecf20Sopenharmony_ci qgroup->max_rfer = 0; 17098c2ecf20Sopenharmony_ci } else { 17108c2ecf20Sopenharmony_ci qgroup->max_rfer = limit->max_rfer; 17118c2ecf20Sopenharmony_ci } 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) { 17148c2ecf20Sopenharmony_ci if (limit->max_excl == CLEAR_VALUE) { 17158c2ecf20Sopenharmony_ci qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_MAX_EXCL; 17168c2ecf20Sopenharmony_ci limit->flags &= ~BTRFS_QGROUP_LIMIT_MAX_EXCL; 17178c2ecf20Sopenharmony_ci qgroup->max_excl = 0; 17188c2ecf20Sopenharmony_ci } else { 17198c2ecf20Sopenharmony_ci qgroup->max_excl = limit->max_excl; 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_RFER) { 17238c2ecf20Sopenharmony_ci if (limit->rsv_rfer == CLEAR_VALUE) { 17248c2ecf20Sopenharmony_ci qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_RSV_RFER; 17258c2ecf20Sopenharmony_ci limit->flags &= ~BTRFS_QGROUP_LIMIT_RSV_RFER; 17268c2ecf20Sopenharmony_ci qgroup->rsv_rfer = 0; 17278c2ecf20Sopenharmony_ci } else { 17288c2ecf20Sopenharmony_ci qgroup->rsv_rfer = limit->rsv_rfer; 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_EXCL) { 17328c2ecf20Sopenharmony_ci if (limit->rsv_excl == CLEAR_VALUE) { 17338c2ecf20Sopenharmony_ci qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_RSV_EXCL; 17348c2ecf20Sopenharmony_ci limit->flags &= ~BTRFS_QGROUP_LIMIT_RSV_EXCL; 17358c2ecf20Sopenharmony_ci qgroup->rsv_excl = 0; 17368c2ecf20Sopenharmony_ci } else { 17378c2ecf20Sopenharmony_ci qgroup->rsv_excl = limit->rsv_excl; 17388c2ecf20Sopenharmony_ci } 17398c2ecf20Sopenharmony_ci } 17408c2ecf20Sopenharmony_ci qgroup->lim_flags |= limit->flags; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci ret = update_qgroup_limit_item(trans, qgroup); 17458c2ecf20Sopenharmony_ci if (ret) { 17468c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 17478c2ecf20Sopenharmony_ci btrfs_info(fs_info, "unable to update quota limit for %llu", 17488c2ecf20Sopenharmony_ci qgroupid); 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ciout: 17528c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 17538c2ecf20Sopenharmony_ci return ret; 17548c2ecf20Sopenharmony_ci} 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ciint btrfs_qgroup_trace_extent_nolock(struct btrfs_fs_info *fs_info, 17578c2ecf20Sopenharmony_ci struct btrfs_delayed_ref_root *delayed_refs, 17588c2ecf20Sopenharmony_ci struct btrfs_qgroup_extent_record *record) 17598c2ecf20Sopenharmony_ci{ 17608c2ecf20Sopenharmony_ci struct rb_node **p = &delayed_refs->dirty_extent_root.rb_node; 17618c2ecf20Sopenharmony_ci struct rb_node *parent_node = NULL; 17628c2ecf20Sopenharmony_ci struct btrfs_qgroup_extent_record *entry; 17638c2ecf20Sopenharmony_ci u64 bytenr = record->bytenr; 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci lockdep_assert_held(&delayed_refs->lock); 17668c2ecf20Sopenharmony_ci trace_btrfs_qgroup_trace_extent(fs_info, record); 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci while (*p) { 17698c2ecf20Sopenharmony_ci parent_node = *p; 17708c2ecf20Sopenharmony_ci entry = rb_entry(parent_node, struct btrfs_qgroup_extent_record, 17718c2ecf20Sopenharmony_ci node); 17728c2ecf20Sopenharmony_ci if (bytenr < entry->bytenr) { 17738c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 17748c2ecf20Sopenharmony_ci } else if (bytenr > entry->bytenr) { 17758c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 17768c2ecf20Sopenharmony_ci } else { 17778c2ecf20Sopenharmony_ci if (record->data_rsv && !entry->data_rsv) { 17788c2ecf20Sopenharmony_ci entry->data_rsv = record->data_rsv; 17798c2ecf20Sopenharmony_ci entry->data_rsv_refroot = 17808c2ecf20Sopenharmony_ci record->data_rsv_refroot; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci return 1; 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci } 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci rb_link_node(&record->node, parent_node, p); 17878c2ecf20Sopenharmony_ci rb_insert_color(&record->node, &delayed_refs->dirty_extent_root); 17888c2ecf20Sopenharmony_ci return 0; 17898c2ecf20Sopenharmony_ci} 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ciint btrfs_qgroup_trace_extent_post(struct btrfs_fs_info *fs_info, 17928c2ecf20Sopenharmony_ci struct btrfs_qgroup_extent_record *qrecord) 17938c2ecf20Sopenharmony_ci{ 17948c2ecf20Sopenharmony_ci struct ulist *old_root; 17958c2ecf20Sopenharmony_ci u64 bytenr = qrecord->bytenr; 17968c2ecf20Sopenharmony_ci int ret; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci ret = btrfs_find_all_roots(NULL, fs_info, bytenr, 0, &old_root, false); 17998c2ecf20Sopenharmony_ci if (ret < 0) { 18008c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 18018c2ecf20Sopenharmony_ci btrfs_warn(fs_info, 18028c2ecf20Sopenharmony_ci"error accounting new delayed refs extent (err code: %d), quota inconsistent", 18038c2ecf20Sopenharmony_ci ret); 18048c2ecf20Sopenharmony_ci return 0; 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci /* 18088c2ecf20Sopenharmony_ci * Here we don't need to get the lock of 18098c2ecf20Sopenharmony_ci * trans->transaction->delayed_refs, since inserted qrecord won't 18108c2ecf20Sopenharmony_ci * be deleted, only qrecord->node may be modified (new qrecord insert) 18118c2ecf20Sopenharmony_ci * 18128c2ecf20Sopenharmony_ci * So modifying qrecord->old_roots is safe here 18138c2ecf20Sopenharmony_ci */ 18148c2ecf20Sopenharmony_ci qrecord->old_roots = old_root; 18158c2ecf20Sopenharmony_ci return 0; 18168c2ecf20Sopenharmony_ci} 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ciint btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr, 18198c2ecf20Sopenharmony_ci u64 num_bytes, gfp_t gfp_flag) 18208c2ecf20Sopenharmony_ci{ 18218c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 18228c2ecf20Sopenharmony_ci struct btrfs_qgroup_extent_record *record; 18238c2ecf20Sopenharmony_ci struct btrfs_delayed_ref_root *delayed_refs; 18248c2ecf20Sopenharmony_ci int ret; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) 18278c2ecf20Sopenharmony_ci || bytenr == 0 || num_bytes == 0) 18288c2ecf20Sopenharmony_ci return 0; 18298c2ecf20Sopenharmony_ci record = kzalloc(sizeof(*record), gfp_flag); 18308c2ecf20Sopenharmony_ci if (!record) 18318c2ecf20Sopenharmony_ci return -ENOMEM; 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci delayed_refs = &trans->transaction->delayed_refs; 18348c2ecf20Sopenharmony_ci record->bytenr = bytenr; 18358c2ecf20Sopenharmony_ci record->num_bytes = num_bytes; 18368c2ecf20Sopenharmony_ci record->old_roots = NULL; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci spin_lock(&delayed_refs->lock); 18398c2ecf20Sopenharmony_ci ret = btrfs_qgroup_trace_extent_nolock(fs_info, delayed_refs, record); 18408c2ecf20Sopenharmony_ci spin_unlock(&delayed_refs->lock); 18418c2ecf20Sopenharmony_ci if (ret > 0) { 18428c2ecf20Sopenharmony_ci kfree(record); 18438c2ecf20Sopenharmony_ci return 0; 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci return btrfs_qgroup_trace_extent_post(fs_info, record); 18468c2ecf20Sopenharmony_ci} 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ciint btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans, 18498c2ecf20Sopenharmony_ci struct extent_buffer *eb) 18508c2ecf20Sopenharmony_ci{ 18518c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 18528c2ecf20Sopenharmony_ci int nr = btrfs_header_nritems(eb); 18538c2ecf20Sopenharmony_ci int i, extent_type, ret; 18548c2ecf20Sopenharmony_ci struct btrfs_key key; 18558c2ecf20Sopenharmony_ci struct btrfs_file_extent_item *fi; 18568c2ecf20Sopenharmony_ci u64 bytenr, num_bytes; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci /* We can be called directly from walk_up_proc() */ 18598c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 18608c2ecf20Sopenharmony_ci return 0; 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 18638c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(eb, &key, i); 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci if (key.type != BTRFS_EXTENT_DATA_KEY) 18668c2ecf20Sopenharmony_ci continue; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci fi = btrfs_item_ptr(eb, i, struct btrfs_file_extent_item); 18698c2ecf20Sopenharmony_ci /* filter out non qgroup-accountable extents */ 18708c2ecf20Sopenharmony_ci extent_type = btrfs_file_extent_type(eb, fi); 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci if (extent_type == BTRFS_FILE_EXTENT_INLINE) 18738c2ecf20Sopenharmony_ci continue; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci bytenr = btrfs_file_extent_disk_bytenr(eb, fi); 18768c2ecf20Sopenharmony_ci if (!bytenr) 18778c2ecf20Sopenharmony_ci continue; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci ret = btrfs_qgroup_trace_extent(trans, bytenr, num_bytes, 18828c2ecf20Sopenharmony_ci GFP_NOFS); 18838c2ecf20Sopenharmony_ci if (ret) 18848c2ecf20Sopenharmony_ci return ret; 18858c2ecf20Sopenharmony_ci } 18868c2ecf20Sopenharmony_ci cond_resched(); 18878c2ecf20Sopenharmony_ci return 0; 18888c2ecf20Sopenharmony_ci} 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci/* 18918c2ecf20Sopenharmony_ci * Walk up the tree from the bottom, freeing leaves and any interior 18928c2ecf20Sopenharmony_ci * nodes which have had all slots visited. If a node (leaf or 18938c2ecf20Sopenharmony_ci * interior) is freed, the node above it will have it's slot 18948c2ecf20Sopenharmony_ci * incremented. The root node will never be freed. 18958c2ecf20Sopenharmony_ci * 18968c2ecf20Sopenharmony_ci * At the end of this function, we should have a path which has all 18978c2ecf20Sopenharmony_ci * slots incremented to the next position for a search. If we need to 18988c2ecf20Sopenharmony_ci * read a new node it will be NULL and the node above it will have the 18998c2ecf20Sopenharmony_ci * correct slot selected for a later read. 19008c2ecf20Sopenharmony_ci * 19018c2ecf20Sopenharmony_ci * If we increment the root nodes slot counter past the number of 19028c2ecf20Sopenharmony_ci * elements, 1 is returned to signal completion of the search. 19038c2ecf20Sopenharmony_ci */ 19048c2ecf20Sopenharmony_cistatic int adjust_slots_upwards(struct btrfs_path *path, int root_level) 19058c2ecf20Sopenharmony_ci{ 19068c2ecf20Sopenharmony_ci int level = 0; 19078c2ecf20Sopenharmony_ci int nr, slot; 19088c2ecf20Sopenharmony_ci struct extent_buffer *eb; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci if (root_level == 0) 19118c2ecf20Sopenharmony_ci return 1; 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci while (level <= root_level) { 19148c2ecf20Sopenharmony_ci eb = path->nodes[level]; 19158c2ecf20Sopenharmony_ci nr = btrfs_header_nritems(eb); 19168c2ecf20Sopenharmony_ci path->slots[level]++; 19178c2ecf20Sopenharmony_ci slot = path->slots[level]; 19188c2ecf20Sopenharmony_ci if (slot >= nr || level == 0) { 19198c2ecf20Sopenharmony_ci /* 19208c2ecf20Sopenharmony_ci * Don't free the root - we will detect this 19218c2ecf20Sopenharmony_ci * condition after our loop and return a 19228c2ecf20Sopenharmony_ci * positive value for caller to stop walking the tree. 19238c2ecf20Sopenharmony_ci */ 19248c2ecf20Sopenharmony_ci if (level != root_level) { 19258c2ecf20Sopenharmony_ci btrfs_tree_unlock_rw(eb, path->locks[level]); 19268c2ecf20Sopenharmony_ci path->locks[level] = 0; 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci free_extent_buffer(eb); 19298c2ecf20Sopenharmony_ci path->nodes[level] = NULL; 19308c2ecf20Sopenharmony_ci path->slots[level] = 0; 19318c2ecf20Sopenharmony_ci } 19328c2ecf20Sopenharmony_ci } else { 19338c2ecf20Sopenharmony_ci /* 19348c2ecf20Sopenharmony_ci * We have a valid slot to walk back down 19358c2ecf20Sopenharmony_ci * from. Stop here so caller can process these 19368c2ecf20Sopenharmony_ci * new nodes. 19378c2ecf20Sopenharmony_ci */ 19388c2ecf20Sopenharmony_ci break; 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci level++; 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci eb = path->nodes[root_level]; 19458c2ecf20Sopenharmony_ci if (path->slots[root_level] >= btrfs_header_nritems(eb)) 19468c2ecf20Sopenharmony_ci return 1; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci return 0; 19498c2ecf20Sopenharmony_ci} 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci/* 19528c2ecf20Sopenharmony_ci * Helper function to trace a subtree tree block swap. 19538c2ecf20Sopenharmony_ci * 19548c2ecf20Sopenharmony_ci * The swap will happen in highest tree block, but there may be a lot of 19558c2ecf20Sopenharmony_ci * tree blocks involved. 19568c2ecf20Sopenharmony_ci * 19578c2ecf20Sopenharmony_ci * For example: 19588c2ecf20Sopenharmony_ci * OO = Old tree blocks 19598c2ecf20Sopenharmony_ci * NN = New tree blocks allocated during balance 19608c2ecf20Sopenharmony_ci * 19618c2ecf20Sopenharmony_ci * File tree (257) Reloc tree for 257 19628c2ecf20Sopenharmony_ci * L2 OO NN 19638c2ecf20Sopenharmony_ci * / \ / \ 19648c2ecf20Sopenharmony_ci * L1 OO OO (a) OO NN (a) 19658c2ecf20Sopenharmony_ci * / \ / \ / \ / \ 19668c2ecf20Sopenharmony_ci * L0 OO OO OO OO OO OO NN NN 19678c2ecf20Sopenharmony_ci * (b) (c) (b) (c) 19688c2ecf20Sopenharmony_ci * 19698c2ecf20Sopenharmony_ci * When calling qgroup_trace_extent_swap(), we will pass: 19708c2ecf20Sopenharmony_ci * @src_eb = OO(a) 19718c2ecf20Sopenharmony_ci * @dst_path = [ nodes[1] = NN(a), nodes[0] = NN(c) ] 19728c2ecf20Sopenharmony_ci * @dst_level = 0 19738c2ecf20Sopenharmony_ci * @root_level = 1 19748c2ecf20Sopenharmony_ci * 19758c2ecf20Sopenharmony_ci * In that case, qgroup_trace_extent_swap() will search from OO(a) to 19768c2ecf20Sopenharmony_ci * reach OO(c), then mark both OO(c) and NN(c) as qgroup dirty. 19778c2ecf20Sopenharmony_ci * 19788c2ecf20Sopenharmony_ci * The main work of qgroup_trace_extent_swap() can be split into 3 parts: 19798c2ecf20Sopenharmony_ci * 19808c2ecf20Sopenharmony_ci * 1) Tree search from @src_eb 19818c2ecf20Sopenharmony_ci * It should acts as a simplified btrfs_search_slot(). 19828c2ecf20Sopenharmony_ci * The key for search can be extracted from @dst_path->nodes[dst_level] 19838c2ecf20Sopenharmony_ci * (first key). 19848c2ecf20Sopenharmony_ci * 19858c2ecf20Sopenharmony_ci * 2) Mark the final tree blocks in @src_path and @dst_path qgroup dirty 19868c2ecf20Sopenharmony_ci * NOTE: In above case, OO(a) and NN(a) won't be marked qgroup dirty. 19878c2ecf20Sopenharmony_ci * They should be marked during previous (@dst_level = 1) iteration. 19888c2ecf20Sopenharmony_ci * 19898c2ecf20Sopenharmony_ci * 3) Mark file extents in leaves dirty 19908c2ecf20Sopenharmony_ci * We don't have good way to pick out new file extents only. 19918c2ecf20Sopenharmony_ci * So we still follow the old method by scanning all file extents in 19928c2ecf20Sopenharmony_ci * the leave. 19938c2ecf20Sopenharmony_ci * 19948c2ecf20Sopenharmony_ci * This function can free us from keeping two paths, thus later we only need 19958c2ecf20Sopenharmony_ci * to care about how to iterate all new tree blocks in reloc tree. 19968c2ecf20Sopenharmony_ci */ 19978c2ecf20Sopenharmony_cistatic int qgroup_trace_extent_swap(struct btrfs_trans_handle* trans, 19988c2ecf20Sopenharmony_ci struct extent_buffer *src_eb, 19998c2ecf20Sopenharmony_ci struct btrfs_path *dst_path, 20008c2ecf20Sopenharmony_ci int dst_level, int root_level, 20018c2ecf20Sopenharmony_ci bool trace_leaf) 20028c2ecf20Sopenharmony_ci{ 20038c2ecf20Sopenharmony_ci struct btrfs_key key; 20048c2ecf20Sopenharmony_ci struct btrfs_path *src_path; 20058c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 20068c2ecf20Sopenharmony_ci u32 nodesize = fs_info->nodesize; 20078c2ecf20Sopenharmony_ci int cur_level = root_level; 20088c2ecf20Sopenharmony_ci int ret; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci BUG_ON(dst_level > root_level); 20118c2ecf20Sopenharmony_ci /* Level mismatch */ 20128c2ecf20Sopenharmony_ci if (btrfs_header_level(src_eb) != root_level) 20138c2ecf20Sopenharmony_ci return -EINVAL; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci src_path = btrfs_alloc_path(); 20168c2ecf20Sopenharmony_ci if (!src_path) { 20178c2ecf20Sopenharmony_ci ret = -ENOMEM; 20188c2ecf20Sopenharmony_ci goto out; 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci if (dst_level) 20228c2ecf20Sopenharmony_ci btrfs_node_key_to_cpu(dst_path->nodes[dst_level], &key, 0); 20238c2ecf20Sopenharmony_ci else 20248c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(dst_path->nodes[dst_level], &key, 0); 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci /* For src_path */ 20278c2ecf20Sopenharmony_ci atomic_inc(&src_eb->refs); 20288c2ecf20Sopenharmony_ci src_path->nodes[root_level] = src_eb; 20298c2ecf20Sopenharmony_ci src_path->slots[root_level] = dst_path->slots[root_level]; 20308c2ecf20Sopenharmony_ci src_path->locks[root_level] = 0; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci /* A simplified version of btrfs_search_slot() */ 20338c2ecf20Sopenharmony_ci while (cur_level >= dst_level) { 20348c2ecf20Sopenharmony_ci struct btrfs_key src_key; 20358c2ecf20Sopenharmony_ci struct btrfs_key dst_key; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci if (src_path->nodes[cur_level] == NULL) { 20388c2ecf20Sopenharmony_ci struct btrfs_key first_key; 20398c2ecf20Sopenharmony_ci struct extent_buffer *eb; 20408c2ecf20Sopenharmony_ci int parent_slot; 20418c2ecf20Sopenharmony_ci u64 child_gen; 20428c2ecf20Sopenharmony_ci u64 child_bytenr; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci eb = src_path->nodes[cur_level + 1]; 20458c2ecf20Sopenharmony_ci parent_slot = src_path->slots[cur_level + 1]; 20468c2ecf20Sopenharmony_ci child_bytenr = btrfs_node_blockptr(eb, parent_slot); 20478c2ecf20Sopenharmony_ci child_gen = btrfs_node_ptr_generation(eb, parent_slot); 20488c2ecf20Sopenharmony_ci btrfs_node_key_to_cpu(eb, &first_key, parent_slot); 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci eb = read_tree_block(fs_info, child_bytenr, child_gen, 20518c2ecf20Sopenharmony_ci cur_level, &first_key); 20528c2ecf20Sopenharmony_ci if (IS_ERR(eb)) { 20538c2ecf20Sopenharmony_ci ret = PTR_ERR(eb); 20548c2ecf20Sopenharmony_ci goto out; 20558c2ecf20Sopenharmony_ci } else if (!extent_buffer_uptodate(eb)) { 20568c2ecf20Sopenharmony_ci free_extent_buffer(eb); 20578c2ecf20Sopenharmony_ci ret = -EIO; 20588c2ecf20Sopenharmony_ci goto out; 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci src_path->nodes[cur_level] = eb; 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci btrfs_tree_read_lock(eb); 20648c2ecf20Sopenharmony_ci btrfs_set_lock_blocking_read(eb); 20658c2ecf20Sopenharmony_ci src_path->locks[cur_level] = BTRFS_READ_LOCK_BLOCKING; 20668c2ecf20Sopenharmony_ci } 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci src_path->slots[cur_level] = dst_path->slots[cur_level]; 20698c2ecf20Sopenharmony_ci if (cur_level) { 20708c2ecf20Sopenharmony_ci btrfs_node_key_to_cpu(dst_path->nodes[cur_level], 20718c2ecf20Sopenharmony_ci &dst_key, dst_path->slots[cur_level]); 20728c2ecf20Sopenharmony_ci btrfs_node_key_to_cpu(src_path->nodes[cur_level], 20738c2ecf20Sopenharmony_ci &src_key, src_path->slots[cur_level]); 20748c2ecf20Sopenharmony_ci } else { 20758c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(dst_path->nodes[cur_level], 20768c2ecf20Sopenharmony_ci &dst_key, dst_path->slots[cur_level]); 20778c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(src_path->nodes[cur_level], 20788c2ecf20Sopenharmony_ci &src_key, src_path->slots[cur_level]); 20798c2ecf20Sopenharmony_ci } 20808c2ecf20Sopenharmony_ci /* Content mismatch, something went wrong */ 20818c2ecf20Sopenharmony_ci if (btrfs_comp_cpu_keys(&dst_key, &src_key)) { 20828c2ecf20Sopenharmony_ci ret = -ENOENT; 20838c2ecf20Sopenharmony_ci goto out; 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci cur_level--; 20868c2ecf20Sopenharmony_ci } 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci /* 20898c2ecf20Sopenharmony_ci * Now both @dst_path and @src_path have been populated, record the tree 20908c2ecf20Sopenharmony_ci * blocks for qgroup accounting. 20918c2ecf20Sopenharmony_ci */ 20928c2ecf20Sopenharmony_ci ret = btrfs_qgroup_trace_extent(trans, src_path->nodes[dst_level]->start, 20938c2ecf20Sopenharmony_ci nodesize, GFP_NOFS); 20948c2ecf20Sopenharmony_ci if (ret < 0) 20958c2ecf20Sopenharmony_ci goto out; 20968c2ecf20Sopenharmony_ci ret = btrfs_qgroup_trace_extent(trans, 20978c2ecf20Sopenharmony_ci dst_path->nodes[dst_level]->start, 20988c2ecf20Sopenharmony_ci nodesize, GFP_NOFS); 20998c2ecf20Sopenharmony_ci if (ret < 0) 21008c2ecf20Sopenharmony_ci goto out; 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci /* Record leaf file extents */ 21038c2ecf20Sopenharmony_ci if (dst_level == 0 && trace_leaf) { 21048c2ecf20Sopenharmony_ci ret = btrfs_qgroup_trace_leaf_items(trans, src_path->nodes[0]); 21058c2ecf20Sopenharmony_ci if (ret < 0) 21068c2ecf20Sopenharmony_ci goto out; 21078c2ecf20Sopenharmony_ci ret = btrfs_qgroup_trace_leaf_items(trans, dst_path->nodes[0]); 21088c2ecf20Sopenharmony_ci } 21098c2ecf20Sopenharmony_ciout: 21108c2ecf20Sopenharmony_ci btrfs_free_path(src_path); 21118c2ecf20Sopenharmony_ci return ret; 21128c2ecf20Sopenharmony_ci} 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci/* 21158c2ecf20Sopenharmony_ci * Helper function to do recursive generation-aware depth-first search, to 21168c2ecf20Sopenharmony_ci * locate all new tree blocks in a subtree of reloc tree. 21178c2ecf20Sopenharmony_ci * 21188c2ecf20Sopenharmony_ci * E.g. (OO = Old tree blocks, NN = New tree blocks, whose gen == last_snapshot) 21198c2ecf20Sopenharmony_ci * reloc tree 21208c2ecf20Sopenharmony_ci * L2 NN (a) 21218c2ecf20Sopenharmony_ci * / \ 21228c2ecf20Sopenharmony_ci * L1 OO NN (b) 21238c2ecf20Sopenharmony_ci * / \ / \ 21248c2ecf20Sopenharmony_ci * L0 OO OO OO NN 21258c2ecf20Sopenharmony_ci * (c) (d) 21268c2ecf20Sopenharmony_ci * If we pass: 21278c2ecf20Sopenharmony_ci * @dst_path = [ nodes[1] = NN(b), nodes[0] = NULL ], 21288c2ecf20Sopenharmony_ci * @cur_level = 1 21298c2ecf20Sopenharmony_ci * @root_level = 1 21308c2ecf20Sopenharmony_ci * 21318c2ecf20Sopenharmony_ci * We will iterate through tree blocks NN(b), NN(d) and info qgroup to trace 21328c2ecf20Sopenharmony_ci * above tree blocks along with their counter parts in file tree. 21338c2ecf20Sopenharmony_ci * While during search, old tree blocks OO(c) will be skipped as tree block swap 21348c2ecf20Sopenharmony_ci * won't affect OO(c). 21358c2ecf20Sopenharmony_ci */ 21368c2ecf20Sopenharmony_cistatic int qgroup_trace_new_subtree_blocks(struct btrfs_trans_handle* trans, 21378c2ecf20Sopenharmony_ci struct extent_buffer *src_eb, 21388c2ecf20Sopenharmony_ci struct btrfs_path *dst_path, 21398c2ecf20Sopenharmony_ci int cur_level, int root_level, 21408c2ecf20Sopenharmony_ci u64 last_snapshot, bool trace_leaf) 21418c2ecf20Sopenharmony_ci{ 21428c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 21438c2ecf20Sopenharmony_ci struct extent_buffer *eb; 21448c2ecf20Sopenharmony_ci bool need_cleanup = false; 21458c2ecf20Sopenharmony_ci int ret = 0; 21468c2ecf20Sopenharmony_ci int i; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci /* Level sanity check */ 21498c2ecf20Sopenharmony_ci if (cur_level < 0 || cur_level >= BTRFS_MAX_LEVEL - 1 || 21508c2ecf20Sopenharmony_ci root_level < 0 || root_level >= BTRFS_MAX_LEVEL - 1 || 21518c2ecf20Sopenharmony_ci root_level < cur_level) { 21528c2ecf20Sopenharmony_ci btrfs_err_rl(fs_info, 21538c2ecf20Sopenharmony_ci "%s: bad levels, cur_level=%d root_level=%d", 21548c2ecf20Sopenharmony_ci __func__, cur_level, root_level); 21558c2ecf20Sopenharmony_ci return -EUCLEAN; 21568c2ecf20Sopenharmony_ci } 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci /* Read the tree block if needed */ 21598c2ecf20Sopenharmony_ci if (dst_path->nodes[cur_level] == NULL) { 21608c2ecf20Sopenharmony_ci struct btrfs_key first_key; 21618c2ecf20Sopenharmony_ci int parent_slot; 21628c2ecf20Sopenharmony_ci u64 child_gen; 21638c2ecf20Sopenharmony_ci u64 child_bytenr; 21648c2ecf20Sopenharmony_ci 21658c2ecf20Sopenharmony_ci /* 21668c2ecf20Sopenharmony_ci * dst_path->nodes[root_level] must be initialized before 21678c2ecf20Sopenharmony_ci * calling this function. 21688c2ecf20Sopenharmony_ci */ 21698c2ecf20Sopenharmony_ci if (cur_level == root_level) { 21708c2ecf20Sopenharmony_ci btrfs_err_rl(fs_info, 21718c2ecf20Sopenharmony_ci "%s: dst_path->nodes[%d] not initialized, root_level=%d cur_level=%d", 21728c2ecf20Sopenharmony_ci __func__, root_level, root_level, cur_level); 21738c2ecf20Sopenharmony_ci return -EUCLEAN; 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci /* 21778c2ecf20Sopenharmony_ci * We need to get child blockptr/gen from parent before we can 21788c2ecf20Sopenharmony_ci * read it. 21798c2ecf20Sopenharmony_ci */ 21808c2ecf20Sopenharmony_ci eb = dst_path->nodes[cur_level + 1]; 21818c2ecf20Sopenharmony_ci parent_slot = dst_path->slots[cur_level + 1]; 21828c2ecf20Sopenharmony_ci child_bytenr = btrfs_node_blockptr(eb, parent_slot); 21838c2ecf20Sopenharmony_ci child_gen = btrfs_node_ptr_generation(eb, parent_slot); 21848c2ecf20Sopenharmony_ci btrfs_node_key_to_cpu(eb, &first_key, parent_slot); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci /* This node is old, no need to trace */ 21878c2ecf20Sopenharmony_ci if (child_gen < last_snapshot) 21888c2ecf20Sopenharmony_ci goto out; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci eb = read_tree_block(fs_info, child_bytenr, child_gen, 21918c2ecf20Sopenharmony_ci cur_level, &first_key); 21928c2ecf20Sopenharmony_ci if (IS_ERR(eb)) { 21938c2ecf20Sopenharmony_ci ret = PTR_ERR(eb); 21948c2ecf20Sopenharmony_ci goto out; 21958c2ecf20Sopenharmony_ci } else if (!extent_buffer_uptodate(eb)) { 21968c2ecf20Sopenharmony_ci free_extent_buffer(eb); 21978c2ecf20Sopenharmony_ci ret = -EIO; 21988c2ecf20Sopenharmony_ci goto out; 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci dst_path->nodes[cur_level] = eb; 22028c2ecf20Sopenharmony_ci dst_path->slots[cur_level] = 0; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci btrfs_tree_read_lock(eb); 22058c2ecf20Sopenharmony_ci btrfs_set_lock_blocking_read(eb); 22068c2ecf20Sopenharmony_ci dst_path->locks[cur_level] = BTRFS_READ_LOCK_BLOCKING; 22078c2ecf20Sopenharmony_ci need_cleanup = true; 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci /* Now record this tree block and its counter part for qgroups */ 22118c2ecf20Sopenharmony_ci ret = qgroup_trace_extent_swap(trans, src_eb, dst_path, cur_level, 22128c2ecf20Sopenharmony_ci root_level, trace_leaf); 22138c2ecf20Sopenharmony_ci if (ret < 0) 22148c2ecf20Sopenharmony_ci goto cleanup; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci eb = dst_path->nodes[cur_level]; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci if (cur_level > 0) { 22198c2ecf20Sopenharmony_ci /* Iterate all child tree blocks */ 22208c2ecf20Sopenharmony_ci for (i = 0; i < btrfs_header_nritems(eb); i++) { 22218c2ecf20Sopenharmony_ci /* Skip old tree blocks as they won't be swapped */ 22228c2ecf20Sopenharmony_ci if (btrfs_node_ptr_generation(eb, i) < last_snapshot) 22238c2ecf20Sopenharmony_ci continue; 22248c2ecf20Sopenharmony_ci dst_path->slots[cur_level] = i; 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_ci /* Recursive call (at most 7 times) */ 22278c2ecf20Sopenharmony_ci ret = qgroup_trace_new_subtree_blocks(trans, src_eb, 22288c2ecf20Sopenharmony_ci dst_path, cur_level - 1, root_level, 22298c2ecf20Sopenharmony_ci last_snapshot, trace_leaf); 22308c2ecf20Sopenharmony_ci if (ret < 0) 22318c2ecf20Sopenharmony_ci goto cleanup; 22328c2ecf20Sopenharmony_ci } 22338c2ecf20Sopenharmony_ci } 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_cicleanup: 22368c2ecf20Sopenharmony_ci if (need_cleanup) { 22378c2ecf20Sopenharmony_ci /* Clean up */ 22388c2ecf20Sopenharmony_ci btrfs_tree_unlock_rw(dst_path->nodes[cur_level], 22398c2ecf20Sopenharmony_ci dst_path->locks[cur_level]); 22408c2ecf20Sopenharmony_ci free_extent_buffer(dst_path->nodes[cur_level]); 22418c2ecf20Sopenharmony_ci dst_path->nodes[cur_level] = NULL; 22428c2ecf20Sopenharmony_ci dst_path->slots[cur_level] = 0; 22438c2ecf20Sopenharmony_ci dst_path->locks[cur_level] = 0; 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ciout: 22468c2ecf20Sopenharmony_ci return ret; 22478c2ecf20Sopenharmony_ci} 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_cistatic int qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans, 22508c2ecf20Sopenharmony_ci struct extent_buffer *src_eb, 22518c2ecf20Sopenharmony_ci struct extent_buffer *dst_eb, 22528c2ecf20Sopenharmony_ci u64 last_snapshot, bool trace_leaf) 22538c2ecf20Sopenharmony_ci{ 22548c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 22558c2ecf20Sopenharmony_ci struct btrfs_path *dst_path = NULL; 22568c2ecf20Sopenharmony_ci int level; 22578c2ecf20Sopenharmony_ci int ret; 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 22608c2ecf20Sopenharmony_ci return 0; 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci /* Wrong parameter order */ 22638c2ecf20Sopenharmony_ci if (btrfs_header_generation(src_eb) > btrfs_header_generation(dst_eb)) { 22648c2ecf20Sopenharmony_ci btrfs_err_rl(fs_info, 22658c2ecf20Sopenharmony_ci "%s: bad parameter order, src_gen=%llu dst_gen=%llu", __func__, 22668c2ecf20Sopenharmony_ci btrfs_header_generation(src_eb), 22678c2ecf20Sopenharmony_ci btrfs_header_generation(dst_eb)); 22688c2ecf20Sopenharmony_ci return -EUCLEAN; 22698c2ecf20Sopenharmony_ci } 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci if (!extent_buffer_uptodate(src_eb) || !extent_buffer_uptodate(dst_eb)) { 22728c2ecf20Sopenharmony_ci ret = -EIO; 22738c2ecf20Sopenharmony_ci goto out; 22748c2ecf20Sopenharmony_ci } 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci level = btrfs_header_level(dst_eb); 22778c2ecf20Sopenharmony_ci dst_path = btrfs_alloc_path(); 22788c2ecf20Sopenharmony_ci if (!dst_path) { 22798c2ecf20Sopenharmony_ci ret = -ENOMEM; 22808c2ecf20Sopenharmony_ci goto out; 22818c2ecf20Sopenharmony_ci } 22828c2ecf20Sopenharmony_ci /* For dst_path */ 22838c2ecf20Sopenharmony_ci atomic_inc(&dst_eb->refs); 22848c2ecf20Sopenharmony_ci dst_path->nodes[level] = dst_eb; 22858c2ecf20Sopenharmony_ci dst_path->slots[level] = 0; 22868c2ecf20Sopenharmony_ci dst_path->locks[level] = 0; 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci /* Do the generation aware breadth-first search */ 22898c2ecf20Sopenharmony_ci ret = qgroup_trace_new_subtree_blocks(trans, src_eb, dst_path, level, 22908c2ecf20Sopenharmony_ci level, last_snapshot, trace_leaf); 22918c2ecf20Sopenharmony_ci if (ret < 0) 22928c2ecf20Sopenharmony_ci goto out; 22938c2ecf20Sopenharmony_ci ret = 0; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ciout: 22968c2ecf20Sopenharmony_ci btrfs_free_path(dst_path); 22978c2ecf20Sopenharmony_ci if (ret < 0) 22988c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 22998c2ecf20Sopenharmony_ci return ret; 23008c2ecf20Sopenharmony_ci} 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ciint btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, 23038c2ecf20Sopenharmony_ci struct extent_buffer *root_eb, 23048c2ecf20Sopenharmony_ci u64 root_gen, int root_level) 23058c2ecf20Sopenharmony_ci{ 23068c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 23078c2ecf20Sopenharmony_ci int ret = 0; 23088c2ecf20Sopenharmony_ci int level; 23098c2ecf20Sopenharmony_ci struct extent_buffer *eb = root_eb; 23108c2ecf20Sopenharmony_ci struct btrfs_path *path = NULL; 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci BUG_ON(root_level < 0 || root_level >= BTRFS_MAX_LEVEL); 23138c2ecf20Sopenharmony_ci BUG_ON(root_eb == NULL); 23148c2ecf20Sopenharmony_ci 23158c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 23168c2ecf20Sopenharmony_ci return 0; 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci if (!extent_buffer_uptodate(root_eb)) { 23198c2ecf20Sopenharmony_ci ret = btrfs_read_buffer(root_eb, root_gen, root_level, NULL); 23208c2ecf20Sopenharmony_ci if (ret) 23218c2ecf20Sopenharmony_ci goto out; 23228c2ecf20Sopenharmony_ci } 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci if (root_level == 0) { 23258c2ecf20Sopenharmony_ci ret = btrfs_qgroup_trace_leaf_items(trans, root_eb); 23268c2ecf20Sopenharmony_ci goto out; 23278c2ecf20Sopenharmony_ci } 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 23308c2ecf20Sopenharmony_ci if (!path) 23318c2ecf20Sopenharmony_ci return -ENOMEM; 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci /* 23348c2ecf20Sopenharmony_ci * Walk down the tree. Missing extent blocks are filled in as 23358c2ecf20Sopenharmony_ci * we go. Metadata is accounted every time we read a new 23368c2ecf20Sopenharmony_ci * extent block. 23378c2ecf20Sopenharmony_ci * 23388c2ecf20Sopenharmony_ci * When we reach a leaf, we account for file extent items in it, 23398c2ecf20Sopenharmony_ci * walk back up the tree (adjusting slot pointers as we go) 23408c2ecf20Sopenharmony_ci * and restart the search process. 23418c2ecf20Sopenharmony_ci */ 23428c2ecf20Sopenharmony_ci atomic_inc(&root_eb->refs); /* For path */ 23438c2ecf20Sopenharmony_ci path->nodes[root_level] = root_eb; 23448c2ecf20Sopenharmony_ci path->slots[root_level] = 0; 23458c2ecf20Sopenharmony_ci path->locks[root_level] = 0; /* so release_path doesn't try to unlock */ 23468c2ecf20Sopenharmony_ciwalk_down: 23478c2ecf20Sopenharmony_ci level = root_level; 23488c2ecf20Sopenharmony_ci while (level >= 0) { 23498c2ecf20Sopenharmony_ci if (path->nodes[level] == NULL) { 23508c2ecf20Sopenharmony_ci struct btrfs_key first_key; 23518c2ecf20Sopenharmony_ci int parent_slot; 23528c2ecf20Sopenharmony_ci u64 child_gen; 23538c2ecf20Sopenharmony_ci u64 child_bytenr; 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci /* 23568c2ecf20Sopenharmony_ci * We need to get child blockptr/gen from parent before 23578c2ecf20Sopenharmony_ci * we can read it. 23588c2ecf20Sopenharmony_ci */ 23598c2ecf20Sopenharmony_ci eb = path->nodes[level + 1]; 23608c2ecf20Sopenharmony_ci parent_slot = path->slots[level + 1]; 23618c2ecf20Sopenharmony_ci child_bytenr = btrfs_node_blockptr(eb, parent_slot); 23628c2ecf20Sopenharmony_ci child_gen = btrfs_node_ptr_generation(eb, parent_slot); 23638c2ecf20Sopenharmony_ci btrfs_node_key_to_cpu(eb, &first_key, parent_slot); 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci eb = read_tree_block(fs_info, child_bytenr, child_gen, 23668c2ecf20Sopenharmony_ci level, &first_key); 23678c2ecf20Sopenharmony_ci if (IS_ERR(eb)) { 23688c2ecf20Sopenharmony_ci ret = PTR_ERR(eb); 23698c2ecf20Sopenharmony_ci goto out; 23708c2ecf20Sopenharmony_ci } else if (!extent_buffer_uptodate(eb)) { 23718c2ecf20Sopenharmony_ci free_extent_buffer(eb); 23728c2ecf20Sopenharmony_ci ret = -EIO; 23738c2ecf20Sopenharmony_ci goto out; 23748c2ecf20Sopenharmony_ci } 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci path->nodes[level] = eb; 23778c2ecf20Sopenharmony_ci path->slots[level] = 0; 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci btrfs_tree_read_lock(eb); 23808c2ecf20Sopenharmony_ci btrfs_set_lock_blocking_read(eb); 23818c2ecf20Sopenharmony_ci path->locks[level] = BTRFS_READ_LOCK_BLOCKING; 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci ret = btrfs_qgroup_trace_extent(trans, child_bytenr, 23848c2ecf20Sopenharmony_ci fs_info->nodesize, 23858c2ecf20Sopenharmony_ci GFP_NOFS); 23868c2ecf20Sopenharmony_ci if (ret) 23878c2ecf20Sopenharmony_ci goto out; 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci if (level == 0) { 23918c2ecf20Sopenharmony_ci ret = btrfs_qgroup_trace_leaf_items(trans, 23928c2ecf20Sopenharmony_ci path->nodes[level]); 23938c2ecf20Sopenharmony_ci if (ret) 23948c2ecf20Sopenharmony_ci goto out; 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci /* Nonzero return here means we completed our search */ 23978c2ecf20Sopenharmony_ci ret = adjust_slots_upwards(path, root_level); 23988c2ecf20Sopenharmony_ci if (ret) 23998c2ecf20Sopenharmony_ci break; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci /* Restart search with new slots */ 24028c2ecf20Sopenharmony_ci goto walk_down; 24038c2ecf20Sopenharmony_ci } 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci level--; 24068c2ecf20Sopenharmony_ci } 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci ret = 0; 24098c2ecf20Sopenharmony_ciout: 24108c2ecf20Sopenharmony_ci btrfs_free_path(path); 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci return ret; 24138c2ecf20Sopenharmony_ci} 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci#define UPDATE_NEW 0 24168c2ecf20Sopenharmony_ci#define UPDATE_OLD 1 24178c2ecf20Sopenharmony_ci/* 24188c2ecf20Sopenharmony_ci * Walk all of the roots that points to the bytenr and adjust their refcnts. 24198c2ecf20Sopenharmony_ci */ 24208c2ecf20Sopenharmony_cistatic int qgroup_update_refcnt(struct btrfs_fs_info *fs_info, 24218c2ecf20Sopenharmony_ci struct ulist *roots, struct ulist *tmp, 24228c2ecf20Sopenharmony_ci struct ulist *qgroups, u64 seq, int update_old) 24238c2ecf20Sopenharmony_ci{ 24248c2ecf20Sopenharmony_ci struct ulist_node *unode; 24258c2ecf20Sopenharmony_ci struct ulist_iterator uiter; 24268c2ecf20Sopenharmony_ci struct ulist_node *tmp_unode; 24278c2ecf20Sopenharmony_ci struct ulist_iterator tmp_uiter; 24288c2ecf20Sopenharmony_ci struct btrfs_qgroup *qg; 24298c2ecf20Sopenharmony_ci int ret = 0; 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci if (!roots) 24328c2ecf20Sopenharmony_ci return 0; 24338c2ecf20Sopenharmony_ci ULIST_ITER_INIT(&uiter); 24348c2ecf20Sopenharmony_ci while ((unode = ulist_next(roots, &uiter))) { 24358c2ecf20Sopenharmony_ci qg = find_qgroup_rb(fs_info, unode->val); 24368c2ecf20Sopenharmony_ci if (!qg) 24378c2ecf20Sopenharmony_ci continue; 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_ci ulist_reinit(tmp); 24408c2ecf20Sopenharmony_ci ret = ulist_add(qgroups, qg->qgroupid, qgroup_to_aux(qg), 24418c2ecf20Sopenharmony_ci GFP_ATOMIC); 24428c2ecf20Sopenharmony_ci if (ret < 0) 24438c2ecf20Sopenharmony_ci return ret; 24448c2ecf20Sopenharmony_ci ret = ulist_add(tmp, qg->qgroupid, qgroup_to_aux(qg), GFP_ATOMIC); 24458c2ecf20Sopenharmony_ci if (ret < 0) 24468c2ecf20Sopenharmony_ci return ret; 24478c2ecf20Sopenharmony_ci ULIST_ITER_INIT(&tmp_uiter); 24488c2ecf20Sopenharmony_ci while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) { 24498c2ecf20Sopenharmony_ci struct btrfs_qgroup_list *glist; 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci qg = unode_aux_to_qgroup(tmp_unode); 24528c2ecf20Sopenharmony_ci if (update_old) 24538c2ecf20Sopenharmony_ci btrfs_qgroup_update_old_refcnt(qg, seq, 1); 24548c2ecf20Sopenharmony_ci else 24558c2ecf20Sopenharmony_ci btrfs_qgroup_update_new_refcnt(qg, seq, 1); 24568c2ecf20Sopenharmony_ci list_for_each_entry(glist, &qg->groups, next_group) { 24578c2ecf20Sopenharmony_ci ret = ulist_add(qgroups, glist->group->qgroupid, 24588c2ecf20Sopenharmony_ci qgroup_to_aux(glist->group), 24598c2ecf20Sopenharmony_ci GFP_ATOMIC); 24608c2ecf20Sopenharmony_ci if (ret < 0) 24618c2ecf20Sopenharmony_ci return ret; 24628c2ecf20Sopenharmony_ci ret = ulist_add(tmp, glist->group->qgroupid, 24638c2ecf20Sopenharmony_ci qgroup_to_aux(glist->group), 24648c2ecf20Sopenharmony_ci GFP_ATOMIC); 24658c2ecf20Sopenharmony_ci if (ret < 0) 24668c2ecf20Sopenharmony_ci return ret; 24678c2ecf20Sopenharmony_ci } 24688c2ecf20Sopenharmony_ci } 24698c2ecf20Sopenharmony_ci } 24708c2ecf20Sopenharmony_ci return 0; 24718c2ecf20Sopenharmony_ci} 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci/* 24748c2ecf20Sopenharmony_ci * Update qgroup rfer/excl counters. 24758c2ecf20Sopenharmony_ci * Rfer update is easy, codes can explain themselves. 24768c2ecf20Sopenharmony_ci * 24778c2ecf20Sopenharmony_ci * Excl update is tricky, the update is split into 2 parts. 24788c2ecf20Sopenharmony_ci * Part 1: Possible exclusive <-> sharing detect: 24798c2ecf20Sopenharmony_ci * | A | !A | 24808c2ecf20Sopenharmony_ci * ------------------------------------- 24818c2ecf20Sopenharmony_ci * B | * | - | 24828c2ecf20Sopenharmony_ci * ------------------------------------- 24838c2ecf20Sopenharmony_ci * !B | + | ** | 24848c2ecf20Sopenharmony_ci * ------------------------------------- 24858c2ecf20Sopenharmony_ci * 24868c2ecf20Sopenharmony_ci * Conditions: 24878c2ecf20Sopenharmony_ci * A: cur_old_roots < nr_old_roots (not exclusive before) 24888c2ecf20Sopenharmony_ci * !A: cur_old_roots == nr_old_roots (possible exclusive before) 24898c2ecf20Sopenharmony_ci * B: cur_new_roots < nr_new_roots (not exclusive now) 24908c2ecf20Sopenharmony_ci * !B: cur_new_roots == nr_new_roots (possible exclusive now) 24918c2ecf20Sopenharmony_ci * 24928c2ecf20Sopenharmony_ci * Results: 24938c2ecf20Sopenharmony_ci * +: Possible sharing -> exclusive -: Possible exclusive -> sharing 24948c2ecf20Sopenharmony_ci * *: Definitely not changed. **: Possible unchanged. 24958c2ecf20Sopenharmony_ci * 24968c2ecf20Sopenharmony_ci * For !A and !B condition, the exception is cur_old/new_roots == 0 case. 24978c2ecf20Sopenharmony_ci * 24988c2ecf20Sopenharmony_ci * To make the logic clear, we first use condition A and B to split 24998c2ecf20Sopenharmony_ci * combination into 4 results. 25008c2ecf20Sopenharmony_ci * 25018c2ecf20Sopenharmony_ci * Then, for result "+" and "-", check old/new_roots == 0 case, as in them 25028c2ecf20Sopenharmony_ci * only on variant maybe 0. 25038c2ecf20Sopenharmony_ci * 25048c2ecf20Sopenharmony_ci * Lastly, check result **, since there are 2 variants maybe 0, split them 25058c2ecf20Sopenharmony_ci * again(2x2). 25068c2ecf20Sopenharmony_ci * But this time we don't need to consider other things, the codes and logic 25078c2ecf20Sopenharmony_ci * is easy to understand now. 25088c2ecf20Sopenharmony_ci */ 25098c2ecf20Sopenharmony_cistatic int qgroup_update_counters(struct btrfs_fs_info *fs_info, 25108c2ecf20Sopenharmony_ci struct ulist *qgroups, 25118c2ecf20Sopenharmony_ci u64 nr_old_roots, 25128c2ecf20Sopenharmony_ci u64 nr_new_roots, 25138c2ecf20Sopenharmony_ci u64 num_bytes, u64 seq) 25148c2ecf20Sopenharmony_ci{ 25158c2ecf20Sopenharmony_ci struct ulist_node *unode; 25168c2ecf20Sopenharmony_ci struct ulist_iterator uiter; 25178c2ecf20Sopenharmony_ci struct btrfs_qgroup *qg; 25188c2ecf20Sopenharmony_ci u64 cur_new_count, cur_old_count; 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci ULIST_ITER_INIT(&uiter); 25218c2ecf20Sopenharmony_ci while ((unode = ulist_next(qgroups, &uiter))) { 25228c2ecf20Sopenharmony_ci bool dirty = false; 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci qg = unode_aux_to_qgroup(unode); 25258c2ecf20Sopenharmony_ci cur_old_count = btrfs_qgroup_get_old_refcnt(qg, seq); 25268c2ecf20Sopenharmony_ci cur_new_count = btrfs_qgroup_get_new_refcnt(qg, seq); 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci trace_qgroup_update_counters(fs_info, qg, cur_old_count, 25298c2ecf20Sopenharmony_ci cur_new_count); 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci /* Rfer update part */ 25328c2ecf20Sopenharmony_ci if (cur_old_count == 0 && cur_new_count > 0) { 25338c2ecf20Sopenharmony_ci qg->rfer += num_bytes; 25348c2ecf20Sopenharmony_ci qg->rfer_cmpr += num_bytes; 25358c2ecf20Sopenharmony_ci dirty = true; 25368c2ecf20Sopenharmony_ci } 25378c2ecf20Sopenharmony_ci if (cur_old_count > 0 && cur_new_count == 0) { 25388c2ecf20Sopenharmony_ci qg->rfer -= num_bytes; 25398c2ecf20Sopenharmony_ci qg->rfer_cmpr -= num_bytes; 25408c2ecf20Sopenharmony_ci dirty = true; 25418c2ecf20Sopenharmony_ci } 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_ci /* Excl update part */ 25448c2ecf20Sopenharmony_ci /* Exclusive/none -> shared case */ 25458c2ecf20Sopenharmony_ci if (cur_old_count == nr_old_roots && 25468c2ecf20Sopenharmony_ci cur_new_count < nr_new_roots) { 25478c2ecf20Sopenharmony_ci /* Exclusive -> shared */ 25488c2ecf20Sopenharmony_ci if (cur_old_count != 0) { 25498c2ecf20Sopenharmony_ci qg->excl -= num_bytes; 25508c2ecf20Sopenharmony_ci qg->excl_cmpr -= num_bytes; 25518c2ecf20Sopenharmony_ci dirty = true; 25528c2ecf20Sopenharmony_ci } 25538c2ecf20Sopenharmony_ci } 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci /* Shared -> exclusive/none case */ 25568c2ecf20Sopenharmony_ci if (cur_old_count < nr_old_roots && 25578c2ecf20Sopenharmony_ci cur_new_count == nr_new_roots) { 25588c2ecf20Sopenharmony_ci /* Shared->exclusive */ 25598c2ecf20Sopenharmony_ci if (cur_new_count != 0) { 25608c2ecf20Sopenharmony_ci qg->excl += num_bytes; 25618c2ecf20Sopenharmony_ci qg->excl_cmpr += num_bytes; 25628c2ecf20Sopenharmony_ci dirty = true; 25638c2ecf20Sopenharmony_ci } 25648c2ecf20Sopenharmony_ci } 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci /* Exclusive/none -> exclusive/none case */ 25678c2ecf20Sopenharmony_ci if (cur_old_count == nr_old_roots && 25688c2ecf20Sopenharmony_ci cur_new_count == nr_new_roots) { 25698c2ecf20Sopenharmony_ci if (cur_old_count == 0) { 25708c2ecf20Sopenharmony_ci /* None -> exclusive/none */ 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci if (cur_new_count != 0) { 25738c2ecf20Sopenharmony_ci /* None -> exclusive */ 25748c2ecf20Sopenharmony_ci qg->excl += num_bytes; 25758c2ecf20Sopenharmony_ci qg->excl_cmpr += num_bytes; 25768c2ecf20Sopenharmony_ci dirty = true; 25778c2ecf20Sopenharmony_ci } 25788c2ecf20Sopenharmony_ci /* None -> none, nothing changed */ 25798c2ecf20Sopenharmony_ci } else { 25808c2ecf20Sopenharmony_ci /* Exclusive -> exclusive/none */ 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci if (cur_new_count == 0) { 25838c2ecf20Sopenharmony_ci /* Exclusive -> none */ 25848c2ecf20Sopenharmony_ci qg->excl -= num_bytes; 25858c2ecf20Sopenharmony_ci qg->excl_cmpr -= num_bytes; 25868c2ecf20Sopenharmony_ci dirty = true; 25878c2ecf20Sopenharmony_ci } 25888c2ecf20Sopenharmony_ci /* Exclusive -> exclusive, nothing changed */ 25898c2ecf20Sopenharmony_ci } 25908c2ecf20Sopenharmony_ci } 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci if (dirty) 25938c2ecf20Sopenharmony_ci qgroup_dirty(fs_info, qg); 25948c2ecf20Sopenharmony_ci } 25958c2ecf20Sopenharmony_ci return 0; 25968c2ecf20Sopenharmony_ci} 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ci/* 25998c2ecf20Sopenharmony_ci * Check if the @roots potentially is a list of fs tree roots 26008c2ecf20Sopenharmony_ci * 26018c2ecf20Sopenharmony_ci * Return 0 for definitely not a fs/subvol tree roots ulist 26028c2ecf20Sopenharmony_ci * Return 1 for possible fs/subvol tree roots in the list (considering an empty 26038c2ecf20Sopenharmony_ci * one as well) 26048c2ecf20Sopenharmony_ci */ 26058c2ecf20Sopenharmony_cistatic int maybe_fs_roots(struct ulist *roots) 26068c2ecf20Sopenharmony_ci{ 26078c2ecf20Sopenharmony_ci struct ulist_node *unode; 26088c2ecf20Sopenharmony_ci struct ulist_iterator uiter; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci /* Empty one, still possible for fs roots */ 26118c2ecf20Sopenharmony_ci if (!roots || roots->nnodes == 0) 26128c2ecf20Sopenharmony_ci return 1; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci ULIST_ITER_INIT(&uiter); 26158c2ecf20Sopenharmony_ci unode = ulist_next(roots, &uiter); 26168c2ecf20Sopenharmony_ci if (!unode) 26178c2ecf20Sopenharmony_ci return 1; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci /* 26208c2ecf20Sopenharmony_ci * If it contains fs tree roots, then it must belong to fs/subvol 26218c2ecf20Sopenharmony_ci * trees. 26228c2ecf20Sopenharmony_ci * If it contains a non-fs tree, it won't be shared with fs/subvol trees. 26238c2ecf20Sopenharmony_ci */ 26248c2ecf20Sopenharmony_ci return is_fstree(unode->val); 26258c2ecf20Sopenharmony_ci} 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ciint btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, 26288c2ecf20Sopenharmony_ci u64 num_bytes, struct ulist *old_roots, 26298c2ecf20Sopenharmony_ci struct ulist *new_roots) 26308c2ecf20Sopenharmony_ci{ 26318c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 26328c2ecf20Sopenharmony_ci struct ulist *qgroups = NULL; 26338c2ecf20Sopenharmony_ci struct ulist *tmp = NULL; 26348c2ecf20Sopenharmony_ci u64 seq; 26358c2ecf20Sopenharmony_ci u64 nr_new_roots = 0; 26368c2ecf20Sopenharmony_ci u64 nr_old_roots = 0; 26378c2ecf20Sopenharmony_ci int ret = 0; 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci /* 26408c2ecf20Sopenharmony_ci * If quotas get disabled meanwhile, the resouces need to be freed and 26418c2ecf20Sopenharmony_ci * we can't just exit here. 26428c2ecf20Sopenharmony_ci */ 26438c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 26448c2ecf20Sopenharmony_ci goto out_free; 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci if (new_roots) { 26478c2ecf20Sopenharmony_ci if (!maybe_fs_roots(new_roots)) 26488c2ecf20Sopenharmony_ci goto out_free; 26498c2ecf20Sopenharmony_ci nr_new_roots = new_roots->nnodes; 26508c2ecf20Sopenharmony_ci } 26518c2ecf20Sopenharmony_ci if (old_roots) { 26528c2ecf20Sopenharmony_ci if (!maybe_fs_roots(old_roots)) 26538c2ecf20Sopenharmony_ci goto out_free; 26548c2ecf20Sopenharmony_ci nr_old_roots = old_roots->nnodes; 26558c2ecf20Sopenharmony_ci } 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci /* Quick exit, either not fs tree roots, or won't affect any qgroup */ 26588c2ecf20Sopenharmony_ci if (nr_old_roots == 0 && nr_new_roots == 0) 26598c2ecf20Sopenharmony_ci goto out_free; 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci BUG_ON(!fs_info->quota_root); 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci trace_btrfs_qgroup_account_extent(fs_info, trans->transid, bytenr, 26648c2ecf20Sopenharmony_ci num_bytes, nr_old_roots, nr_new_roots); 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci qgroups = ulist_alloc(GFP_NOFS); 26678c2ecf20Sopenharmony_ci if (!qgroups) { 26688c2ecf20Sopenharmony_ci ret = -ENOMEM; 26698c2ecf20Sopenharmony_ci goto out_free; 26708c2ecf20Sopenharmony_ci } 26718c2ecf20Sopenharmony_ci tmp = ulist_alloc(GFP_NOFS); 26728c2ecf20Sopenharmony_ci if (!tmp) { 26738c2ecf20Sopenharmony_ci ret = -ENOMEM; 26748c2ecf20Sopenharmony_ci goto out_free; 26758c2ecf20Sopenharmony_ci } 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 26788c2ecf20Sopenharmony_ci if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { 26798c2ecf20Sopenharmony_ci if (fs_info->qgroup_rescan_progress.objectid <= bytenr) { 26808c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 26818c2ecf20Sopenharmony_ci ret = 0; 26828c2ecf20Sopenharmony_ci goto out_free; 26838c2ecf20Sopenharmony_ci } 26848c2ecf20Sopenharmony_ci } 26858c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 26888c2ecf20Sopenharmony_ci seq = fs_info->qgroup_seq; 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci /* Update old refcnts using old_roots */ 26918c2ecf20Sopenharmony_ci ret = qgroup_update_refcnt(fs_info, old_roots, tmp, qgroups, seq, 26928c2ecf20Sopenharmony_ci UPDATE_OLD); 26938c2ecf20Sopenharmony_ci if (ret < 0) 26948c2ecf20Sopenharmony_ci goto out; 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci /* Update new refcnts using new_roots */ 26978c2ecf20Sopenharmony_ci ret = qgroup_update_refcnt(fs_info, new_roots, tmp, qgroups, seq, 26988c2ecf20Sopenharmony_ci UPDATE_NEW); 26998c2ecf20Sopenharmony_ci if (ret < 0) 27008c2ecf20Sopenharmony_ci goto out; 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_ci qgroup_update_counters(fs_info, qgroups, nr_old_roots, nr_new_roots, 27038c2ecf20Sopenharmony_ci num_bytes, seq); 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_ci /* 27068c2ecf20Sopenharmony_ci * Bump qgroup_seq to avoid seq overlap 27078c2ecf20Sopenharmony_ci */ 27088c2ecf20Sopenharmony_ci fs_info->qgroup_seq += max(nr_old_roots, nr_new_roots) + 1; 27098c2ecf20Sopenharmony_ciout: 27108c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 27118c2ecf20Sopenharmony_ciout_free: 27128c2ecf20Sopenharmony_ci ulist_free(tmp); 27138c2ecf20Sopenharmony_ci ulist_free(qgroups); 27148c2ecf20Sopenharmony_ci ulist_free(old_roots); 27158c2ecf20Sopenharmony_ci ulist_free(new_roots); 27168c2ecf20Sopenharmony_ci return ret; 27178c2ecf20Sopenharmony_ci} 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ciint btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans) 27208c2ecf20Sopenharmony_ci{ 27218c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 27228c2ecf20Sopenharmony_ci struct btrfs_qgroup_extent_record *record; 27238c2ecf20Sopenharmony_ci struct btrfs_delayed_ref_root *delayed_refs; 27248c2ecf20Sopenharmony_ci struct ulist *new_roots = NULL; 27258c2ecf20Sopenharmony_ci struct rb_node *node; 27268c2ecf20Sopenharmony_ci u64 num_dirty_extents = 0; 27278c2ecf20Sopenharmony_ci u64 qgroup_to_skip; 27288c2ecf20Sopenharmony_ci int ret = 0; 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci delayed_refs = &trans->transaction->delayed_refs; 27318c2ecf20Sopenharmony_ci qgroup_to_skip = delayed_refs->qgroup_to_skip; 27328c2ecf20Sopenharmony_ci while ((node = rb_first(&delayed_refs->dirty_extent_root))) { 27338c2ecf20Sopenharmony_ci record = rb_entry(node, struct btrfs_qgroup_extent_record, 27348c2ecf20Sopenharmony_ci node); 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci num_dirty_extents++; 27378c2ecf20Sopenharmony_ci trace_btrfs_qgroup_account_extents(fs_info, record); 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci if (!ret) { 27408c2ecf20Sopenharmony_ci /* 27418c2ecf20Sopenharmony_ci * Old roots should be searched when inserting qgroup 27428c2ecf20Sopenharmony_ci * extent record 27438c2ecf20Sopenharmony_ci */ 27448c2ecf20Sopenharmony_ci if (WARN_ON(!record->old_roots)) { 27458c2ecf20Sopenharmony_ci /* Search commit root to find old_roots */ 27468c2ecf20Sopenharmony_ci ret = btrfs_find_all_roots(NULL, fs_info, 27478c2ecf20Sopenharmony_ci record->bytenr, 0, 27488c2ecf20Sopenharmony_ci &record->old_roots, false); 27498c2ecf20Sopenharmony_ci if (ret < 0) 27508c2ecf20Sopenharmony_ci goto cleanup; 27518c2ecf20Sopenharmony_ci } 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci /* Free the reserved data space */ 27548c2ecf20Sopenharmony_ci btrfs_qgroup_free_refroot(fs_info, 27558c2ecf20Sopenharmony_ci record->data_rsv_refroot, 27568c2ecf20Sopenharmony_ci record->data_rsv, 27578c2ecf20Sopenharmony_ci BTRFS_QGROUP_RSV_DATA); 27588c2ecf20Sopenharmony_ci /* 27598c2ecf20Sopenharmony_ci * Use SEQ_LAST as time_seq to do special search, which 27608c2ecf20Sopenharmony_ci * doesn't lock tree or delayed_refs and search current 27618c2ecf20Sopenharmony_ci * root. It's safe inside commit_transaction(). 27628c2ecf20Sopenharmony_ci */ 27638c2ecf20Sopenharmony_ci ret = btrfs_find_all_roots(trans, fs_info, 27648c2ecf20Sopenharmony_ci record->bytenr, SEQ_LAST, &new_roots, false); 27658c2ecf20Sopenharmony_ci if (ret < 0) 27668c2ecf20Sopenharmony_ci goto cleanup; 27678c2ecf20Sopenharmony_ci if (qgroup_to_skip) { 27688c2ecf20Sopenharmony_ci ulist_del(new_roots, qgroup_to_skip, 0); 27698c2ecf20Sopenharmony_ci ulist_del(record->old_roots, qgroup_to_skip, 27708c2ecf20Sopenharmony_ci 0); 27718c2ecf20Sopenharmony_ci } 27728c2ecf20Sopenharmony_ci ret = btrfs_qgroup_account_extent(trans, record->bytenr, 27738c2ecf20Sopenharmony_ci record->num_bytes, 27748c2ecf20Sopenharmony_ci record->old_roots, 27758c2ecf20Sopenharmony_ci new_roots); 27768c2ecf20Sopenharmony_ci record->old_roots = NULL; 27778c2ecf20Sopenharmony_ci new_roots = NULL; 27788c2ecf20Sopenharmony_ci } 27798c2ecf20Sopenharmony_cicleanup: 27808c2ecf20Sopenharmony_ci ulist_free(record->old_roots); 27818c2ecf20Sopenharmony_ci ulist_free(new_roots); 27828c2ecf20Sopenharmony_ci new_roots = NULL; 27838c2ecf20Sopenharmony_ci rb_erase(node, &delayed_refs->dirty_extent_root); 27848c2ecf20Sopenharmony_ci kfree(record); 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci } 27878c2ecf20Sopenharmony_ci trace_qgroup_num_dirty_extents(fs_info, trans->transid, 27888c2ecf20Sopenharmony_ci num_dirty_extents); 27898c2ecf20Sopenharmony_ci return ret; 27908c2ecf20Sopenharmony_ci} 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci/* 27938c2ecf20Sopenharmony_ci * Writes all changed qgroups to disk. 27948c2ecf20Sopenharmony_ci * Called by the transaction commit path and the qgroup assign ioctl. 27958c2ecf20Sopenharmony_ci */ 27968c2ecf20Sopenharmony_ciint btrfs_run_qgroups(struct btrfs_trans_handle *trans) 27978c2ecf20Sopenharmony_ci{ 27988c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 27998c2ecf20Sopenharmony_ci int ret = 0; 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci /* 28028c2ecf20Sopenharmony_ci * In case we are called from the qgroup assign ioctl, assert that we 28038c2ecf20Sopenharmony_ci * are holding the qgroup_ioctl_lock, otherwise we can race with a quota 28048c2ecf20Sopenharmony_ci * disable operation (ioctl) and access a freed quota root. 28058c2ecf20Sopenharmony_ci */ 28068c2ecf20Sopenharmony_ci if (trans->transaction->state != TRANS_STATE_COMMIT_DOING) 28078c2ecf20Sopenharmony_ci lockdep_assert_held(&fs_info->qgroup_ioctl_lock); 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci if (!fs_info->quota_root) 28108c2ecf20Sopenharmony_ci return ret; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 28138c2ecf20Sopenharmony_ci while (!list_empty(&fs_info->dirty_qgroups)) { 28148c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 28158c2ecf20Sopenharmony_ci qgroup = list_first_entry(&fs_info->dirty_qgroups, 28168c2ecf20Sopenharmony_ci struct btrfs_qgroup, dirty); 28178c2ecf20Sopenharmony_ci list_del_init(&qgroup->dirty); 28188c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 28198c2ecf20Sopenharmony_ci ret = update_qgroup_info_item(trans, qgroup); 28208c2ecf20Sopenharmony_ci if (ret) 28218c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= 28228c2ecf20Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 28238c2ecf20Sopenharmony_ci ret = update_qgroup_limit_item(trans, qgroup); 28248c2ecf20Sopenharmony_ci if (ret) 28258c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= 28268c2ecf20Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 28278c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 28288c2ecf20Sopenharmony_ci } 28298c2ecf20Sopenharmony_ci if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 28308c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_ON; 28318c2ecf20Sopenharmony_ci else 28328c2ecf20Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON; 28338c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci ret = update_qgroup_status_item(trans); 28368c2ecf20Sopenharmony_ci if (ret) 28378c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci return ret; 28408c2ecf20Sopenharmony_ci} 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci/* 28438c2ecf20Sopenharmony_ci * Copy the accounting information between qgroups. This is necessary 28448c2ecf20Sopenharmony_ci * when a snapshot or a subvolume is created. Throwing an error will 28458c2ecf20Sopenharmony_ci * cause a transaction abort so we take extra care here to only error 28468c2ecf20Sopenharmony_ci * when a readonly fs is a reasonable outcome. 28478c2ecf20Sopenharmony_ci */ 28488c2ecf20Sopenharmony_ciint btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, 28498c2ecf20Sopenharmony_ci u64 objectid, struct btrfs_qgroup_inherit *inherit) 28508c2ecf20Sopenharmony_ci{ 28518c2ecf20Sopenharmony_ci int ret = 0; 28528c2ecf20Sopenharmony_ci int i; 28538c2ecf20Sopenharmony_ci u64 *i_qgroups; 28548c2ecf20Sopenharmony_ci bool committing = false; 28558c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 28568c2ecf20Sopenharmony_ci struct btrfs_root *quota_root; 28578c2ecf20Sopenharmony_ci struct btrfs_qgroup *srcgroup; 28588c2ecf20Sopenharmony_ci struct btrfs_qgroup *dstgroup; 28598c2ecf20Sopenharmony_ci bool need_rescan = false; 28608c2ecf20Sopenharmony_ci u32 level_size = 0; 28618c2ecf20Sopenharmony_ci u64 nums; 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci /* 28648c2ecf20Sopenharmony_ci * There are only two callers of this function. 28658c2ecf20Sopenharmony_ci * 28668c2ecf20Sopenharmony_ci * One in create_subvol() in the ioctl context, which needs to hold 28678c2ecf20Sopenharmony_ci * the qgroup_ioctl_lock. 28688c2ecf20Sopenharmony_ci * 28698c2ecf20Sopenharmony_ci * The other one in create_pending_snapshot() where no other qgroup 28708c2ecf20Sopenharmony_ci * code can modify the fs as they all need to either start a new trans 28718c2ecf20Sopenharmony_ci * or hold a trans handler, thus we don't need to hold 28728c2ecf20Sopenharmony_ci * qgroup_ioctl_lock. 28738c2ecf20Sopenharmony_ci * This would avoid long and complex lock chain and make lockdep happy. 28748c2ecf20Sopenharmony_ci */ 28758c2ecf20Sopenharmony_ci spin_lock(&fs_info->trans_lock); 28768c2ecf20Sopenharmony_ci if (trans->transaction->state == TRANS_STATE_COMMIT_DOING) 28778c2ecf20Sopenharmony_ci committing = true; 28788c2ecf20Sopenharmony_ci spin_unlock(&fs_info->trans_lock); 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ci if (!committing) 28818c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 28828c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 28838c2ecf20Sopenharmony_ci goto out; 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_ci quota_root = fs_info->quota_root; 28868c2ecf20Sopenharmony_ci if (!quota_root) { 28878c2ecf20Sopenharmony_ci ret = -EINVAL; 28888c2ecf20Sopenharmony_ci goto out; 28898c2ecf20Sopenharmony_ci } 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci if (inherit) { 28928c2ecf20Sopenharmony_ci i_qgroups = (u64 *)(inherit + 1); 28938c2ecf20Sopenharmony_ci nums = inherit->num_qgroups + 2 * inherit->num_ref_copies + 28948c2ecf20Sopenharmony_ci 2 * inherit->num_excl_copies; 28958c2ecf20Sopenharmony_ci for (i = 0; i < nums; ++i) { 28968c2ecf20Sopenharmony_ci srcgroup = find_qgroup_rb(fs_info, *i_qgroups); 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci /* 28998c2ecf20Sopenharmony_ci * Zero out invalid groups so we can ignore 29008c2ecf20Sopenharmony_ci * them later. 29018c2ecf20Sopenharmony_ci */ 29028c2ecf20Sopenharmony_ci if (!srcgroup || 29038c2ecf20Sopenharmony_ci ((srcgroup->qgroupid >> 48) <= (objectid >> 48))) 29048c2ecf20Sopenharmony_ci *i_qgroups = 0ULL; 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci ++i_qgroups; 29078c2ecf20Sopenharmony_ci } 29088c2ecf20Sopenharmony_ci } 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci /* 29118c2ecf20Sopenharmony_ci * create a tracking group for the subvol itself 29128c2ecf20Sopenharmony_ci */ 29138c2ecf20Sopenharmony_ci ret = add_qgroup_item(trans, quota_root, objectid); 29148c2ecf20Sopenharmony_ci if (ret) 29158c2ecf20Sopenharmony_ci goto out; 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci /* 29188c2ecf20Sopenharmony_ci * add qgroup to all inherited groups 29198c2ecf20Sopenharmony_ci */ 29208c2ecf20Sopenharmony_ci if (inherit) { 29218c2ecf20Sopenharmony_ci i_qgroups = (u64 *)(inherit + 1); 29228c2ecf20Sopenharmony_ci for (i = 0; i < inherit->num_qgroups; ++i, ++i_qgroups) { 29238c2ecf20Sopenharmony_ci if (*i_qgroups == 0) 29248c2ecf20Sopenharmony_ci continue; 29258c2ecf20Sopenharmony_ci ret = add_qgroup_relation_item(trans, objectid, 29268c2ecf20Sopenharmony_ci *i_qgroups); 29278c2ecf20Sopenharmony_ci if (ret && ret != -EEXIST) 29288c2ecf20Sopenharmony_ci goto out; 29298c2ecf20Sopenharmony_ci ret = add_qgroup_relation_item(trans, *i_qgroups, 29308c2ecf20Sopenharmony_ci objectid); 29318c2ecf20Sopenharmony_ci if (ret && ret != -EEXIST) 29328c2ecf20Sopenharmony_ci goto out; 29338c2ecf20Sopenharmony_ci } 29348c2ecf20Sopenharmony_ci ret = 0; 29358c2ecf20Sopenharmony_ci } 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci dstgroup = add_qgroup_rb(fs_info, objectid); 29418c2ecf20Sopenharmony_ci if (IS_ERR(dstgroup)) { 29428c2ecf20Sopenharmony_ci ret = PTR_ERR(dstgroup); 29438c2ecf20Sopenharmony_ci goto unlock; 29448c2ecf20Sopenharmony_ci } 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci if (inherit && inherit->flags & BTRFS_QGROUP_INHERIT_SET_LIMITS) { 29478c2ecf20Sopenharmony_ci dstgroup->lim_flags = inherit->lim.flags; 29488c2ecf20Sopenharmony_ci dstgroup->max_rfer = inherit->lim.max_rfer; 29498c2ecf20Sopenharmony_ci dstgroup->max_excl = inherit->lim.max_excl; 29508c2ecf20Sopenharmony_ci dstgroup->rsv_rfer = inherit->lim.rsv_rfer; 29518c2ecf20Sopenharmony_ci dstgroup->rsv_excl = inherit->lim.rsv_excl; 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci qgroup_dirty(fs_info, dstgroup); 29548c2ecf20Sopenharmony_ci } 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci if (srcid) { 29578c2ecf20Sopenharmony_ci srcgroup = find_qgroup_rb(fs_info, srcid); 29588c2ecf20Sopenharmony_ci if (!srcgroup) 29598c2ecf20Sopenharmony_ci goto unlock; 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci /* 29628c2ecf20Sopenharmony_ci * We call inherit after we clone the root in order to make sure 29638c2ecf20Sopenharmony_ci * our counts don't go crazy, so at this point the only 29648c2ecf20Sopenharmony_ci * difference between the two roots should be the root node. 29658c2ecf20Sopenharmony_ci */ 29668c2ecf20Sopenharmony_ci level_size = fs_info->nodesize; 29678c2ecf20Sopenharmony_ci dstgroup->rfer = srcgroup->rfer; 29688c2ecf20Sopenharmony_ci dstgroup->rfer_cmpr = srcgroup->rfer_cmpr; 29698c2ecf20Sopenharmony_ci dstgroup->excl = level_size; 29708c2ecf20Sopenharmony_ci dstgroup->excl_cmpr = level_size; 29718c2ecf20Sopenharmony_ci srcgroup->excl = level_size; 29728c2ecf20Sopenharmony_ci srcgroup->excl_cmpr = level_size; 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci /* inherit the limit info */ 29758c2ecf20Sopenharmony_ci dstgroup->lim_flags = srcgroup->lim_flags; 29768c2ecf20Sopenharmony_ci dstgroup->max_rfer = srcgroup->max_rfer; 29778c2ecf20Sopenharmony_ci dstgroup->max_excl = srcgroup->max_excl; 29788c2ecf20Sopenharmony_ci dstgroup->rsv_rfer = srcgroup->rsv_rfer; 29798c2ecf20Sopenharmony_ci dstgroup->rsv_excl = srcgroup->rsv_excl; 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci qgroup_dirty(fs_info, dstgroup); 29828c2ecf20Sopenharmony_ci qgroup_dirty(fs_info, srcgroup); 29838c2ecf20Sopenharmony_ci } 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_ci if (!inherit) 29868c2ecf20Sopenharmony_ci goto unlock; 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci i_qgroups = (u64 *)(inherit + 1); 29898c2ecf20Sopenharmony_ci for (i = 0; i < inherit->num_qgroups; ++i) { 29908c2ecf20Sopenharmony_ci if (*i_qgroups) { 29918c2ecf20Sopenharmony_ci ret = add_relation_rb(fs_info, objectid, *i_qgroups); 29928c2ecf20Sopenharmony_ci if (ret) 29938c2ecf20Sopenharmony_ci goto unlock; 29948c2ecf20Sopenharmony_ci } 29958c2ecf20Sopenharmony_ci ++i_qgroups; 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci /* 29988c2ecf20Sopenharmony_ci * If we're doing a snapshot, and adding the snapshot to a new 29998c2ecf20Sopenharmony_ci * qgroup, the numbers are guaranteed to be incorrect. 30008c2ecf20Sopenharmony_ci */ 30018c2ecf20Sopenharmony_ci if (srcid) 30028c2ecf20Sopenharmony_ci need_rescan = true; 30038c2ecf20Sopenharmony_ci } 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci for (i = 0; i < inherit->num_ref_copies; ++i, i_qgroups += 2) { 30068c2ecf20Sopenharmony_ci struct btrfs_qgroup *src; 30078c2ecf20Sopenharmony_ci struct btrfs_qgroup *dst; 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci if (!i_qgroups[0] || !i_qgroups[1]) 30108c2ecf20Sopenharmony_ci continue; 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci src = find_qgroup_rb(fs_info, i_qgroups[0]); 30138c2ecf20Sopenharmony_ci dst = find_qgroup_rb(fs_info, i_qgroups[1]); 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci if (!src || !dst) { 30168c2ecf20Sopenharmony_ci ret = -EINVAL; 30178c2ecf20Sopenharmony_ci goto unlock; 30188c2ecf20Sopenharmony_ci } 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci dst->rfer = src->rfer - level_size; 30218c2ecf20Sopenharmony_ci dst->rfer_cmpr = src->rfer_cmpr - level_size; 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci /* Manually tweaking numbers certainly needs a rescan */ 30248c2ecf20Sopenharmony_ci need_rescan = true; 30258c2ecf20Sopenharmony_ci } 30268c2ecf20Sopenharmony_ci for (i = 0; i < inherit->num_excl_copies; ++i, i_qgroups += 2) { 30278c2ecf20Sopenharmony_ci struct btrfs_qgroup *src; 30288c2ecf20Sopenharmony_ci struct btrfs_qgroup *dst; 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci if (!i_qgroups[0] || !i_qgroups[1]) 30318c2ecf20Sopenharmony_ci continue; 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci src = find_qgroup_rb(fs_info, i_qgroups[0]); 30348c2ecf20Sopenharmony_ci dst = find_qgroup_rb(fs_info, i_qgroups[1]); 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci if (!src || !dst) { 30378c2ecf20Sopenharmony_ci ret = -EINVAL; 30388c2ecf20Sopenharmony_ci goto unlock; 30398c2ecf20Sopenharmony_ci } 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci dst->excl = src->excl + level_size; 30428c2ecf20Sopenharmony_ci dst->excl_cmpr = src->excl_cmpr + level_size; 30438c2ecf20Sopenharmony_ci need_rescan = true; 30448c2ecf20Sopenharmony_ci } 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ciunlock: 30478c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 30488c2ecf20Sopenharmony_ci if (!ret) 30498c2ecf20Sopenharmony_ci ret = btrfs_sysfs_add_one_qgroup(fs_info, dstgroup); 30508c2ecf20Sopenharmony_ciout: 30518c2ecf20Sopenharmony_ci if (!committing) 30528c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 30538c2ecf20Sopenharmony_ci if (need_rescan) 30548c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 30558c2ecf20Sopenharmony_ci return ret; 30568c2ecf20Sopenharmony_ci} 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_cistatic bool qgroup_check_limits(const struct btrfs_qgroup *qg, u64 num_bytes) 30598c2ecf20Sopenharmony_ci{ 30608c2ecf20Sopenharmony_ci if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) && 30618c2ecf20Sopenharmony_ci qgroup_rsv_total(qg) + (s64)qg->rfer + num_bytes > qg->max_rfer) 30628c2ecf20Sopenharmony_ci return false; 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_ci if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) && 30658c2ecf20Sopenharmony_ci qgroup_rsv_total(qg) + (s64)qg->excl + num_bytes > qg->max_excl) 30668c2ecf20Sopenharmony_ci return false; 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci return true; 30698c2ecf20Sopenharmony_ci} 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_cistatic int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce, 30728c2ecf20Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 30738c2ecf20Sopenharmony_ci{ 30748c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 30758c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 30768c2ecf20Sopenharmony_ci u64 ref_root = root->root_key.objectid; 30778c2ecf20Sopenharmony_ci int ret = 0; 30788c2ecf20Sopenharmony_ci struct ulist_node *unode; 30798c2ecf20Sopenharmony_ci struct ulist_iterator uiter; 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci if (!is_fstree(ref_root)) 30828c2ecf20Sopenharmony_ci return 0; 30838c2ecf20Sopenharmony_ci 30848c2ecf20Sopenharmony_ci if (num_bytes == 0) 30858c2ecf20Sopenharmony_ci return 0; 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci if (test_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags) && 30888c2ecf20Sopenharmony_ci capable(CAP_SYS_RESOURCE)) 30898c2ecf20Sopenharmony_ci enforce = false; 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 30928c2ecf20Sopenharmony_ci if (!fs_info->quota_root) 30938c2ecf20Sopenharmony_ci goto out; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, ref_root); 30968c2ecf20Sopenharmony_ci if (!qgroup) 30978c2ecf20Sopenharmony_ci goto out; 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci /* 31008c2ecf20Sopenharmony_ci * in a first step, we check all affected qgroups if any limits would 31018c2ecf20Sopenharmony_ci * be exceeded 31028c2ecf20Sopenharmony_ci */ 31038c2ecf20Sopenharmony_ci ulist_reinit(fs_info->qgroup_ulist); 31048c2ecf20Sopenharmony_ci ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid, 31058c2ecf20Sopenharmony_ci qgroup_to_aux(qgroup), GFP_ATOMIC); 31068c2ecf20Sopenharmony_ci if (ret < 0) 31078c2ecf20Sopenharmony_ci goto out; 31088c2ecf20Sopenharmony_ci ULIST_ITER_INIT(&uiter); 31098c2ecf20Sopenharmony_ci while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { 31108c2ecf20Sopenharmony_ci struct btrfs_qgroup *qg; 31118c2ecf20Sopenharmony_ci struct btrfs_qgroup_list *glist; 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci qg = unode_aux_to_qgroup(unode); 31148c2ecf20Sopenharmony_ci 31158c2ecf20Sopenharmony_ci if (enforce && !qgroup_check_limits(qg, num_bytes)) { 31168c2ecf20Sopenharmony_ci ret = -EDQUOT; 31178c2ecf20Sopenharmony_ci goto out; 31188c2ecf20Sopenharmony_ci } 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci list_for_each_entry(glist, &qg->groups, next_group) { 31218c2ecf20Sopenharmony_ci ret = ulist_add(fs_info->qgroup_ulist, 31228c2ecf20Sopenharmony_ci glist->group->qgroupid, 31238c2ecf20Sopenharmony_ci qgroup_to_aux(glist->group), GFP_ATOMIC); 31248c2ecf20Sopenharmony_ci if (ret < 0) 31258c2ecf20Sopenharmony_ci goto out; 31268c2ecf20Sopenharmony_ci } 31278c2ecf20Sopenharmony_ci } 31288c2ecf20Sopenharmony_ci ret = 0; 31298c2ecf20Sopenharmony_ci /* 31308c2ecf20Sopenharmony_ci * no limits exceeded, now record the reservation into all qgroups 31318c2ecf20Sopenharmony_ci */ 31328c2ecf20Sopenharmony_ci ULIST_ITER_INIT(&uiter); 31338c2ecf20Sopenharmony_ci while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { 31348c2ecf20Sopenharmony_ci struct btrfs_qgroup *qg; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci qg = unode_aux_to_qgroup(unode); 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci qgroup_rsv_add(fs_info, qg, num_bytes, type); 31398c2ecf20Sopenharmony_ci } 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ciout: 31428c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 31438c2ecf20Sopenharmony_ci return ret; 31448c2ecf20Sopenharmony_ci} 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci/* 31478c2ecf20Sopenharmony_ci * Free @num_bytes of reserved space with @type for qgroup. (Normally level 0 31488c2ecf20Sopenharmony_ci * qgroup). 31498c2ecf20Sopenharmony_ci * 31508c2ecf20Sopenharmony_ci * Will handle all higher level qgroup too. 31518c2ecf20Sopenharmony_ci * 31528c2ecf20Sopenharmony_ci * NOTE: If @num_bytes is (u64)-1, this means to free all bytes of this qgroup. 31538c2ecf20Sopenharmony_ci * This special case is only used for META_PERTRANS type. 31548c2ecf20Sopenharmony_ci */ 31558c2ecf20Sopenharmony_civoid btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info, 31568c2ecf20Sopenharmony_ci u64 ref_root, u64 num_bytes, 31578c2ecf20Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 31588c2ecf20Sopenharmony_ci{ 31598c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 31608c2ecf20Sopenharmony_ci struct ulist_node *unode; 31618c2ecf20Sopenharmony_ci struct ulist_iterator uiter; 31628c2ecf20Sopenharmony_ci int ret = 0; 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ci if (!is_fstree(ref_root)) 31658c2ecf20Sopenharmony_ci return; 31668c2ecf20Sopenharmony_ci 31678c2ecf20Sopenharmony_ci if (num_bytes == 0) 31688c2ecf20Sopenharmony_ci return; 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_ci if (num_bytes == (u64)-1 && type != BTRFS_QGROUP_RSV_META_PERTRANS) { 31718c2ecf20Sopenharmony_ci WARN(1, "%s: Invalid type to free", __func__); 31728c2ecf20Sopenharmony_ci return; 31738c2ecf20Sopenharmony_ci } 31748c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci if (!fs_info->quota_root) 31778c2ecf20Sopenharmony_ci goto out; 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, ref_root); 31808c2ecf20Sopenharmony_ci if (!qgroup) 31818c2ecf20Sopenharmony_ci goto out; 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci if (num_bytes == (u64)-1) 31848c2ecf20Sopenharmony_ci /* 31858c2ecf20Sopenharmony_ci * We're freeing all pertrans rsv, get reserved value from 31868c2ecf20Sopenharmony_ci * level 0 qgroup as real num_bytes to free. 31878c2ecf20Sopenharmony_ci */ 31888c2ecf20Sopenharmony_ci num_bytes = qgroup->rsv.values[type]; 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci ulist_reinit(fs_info->qgroup_ulist); 31918c2ecf20Sopenharmony_ci ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid, 31928c2ecf20Sopenharmony_ci qgroup_to_aux(qgroup), GFP_ATOMIC); 31938c2ecf20Sopenharmony_ci if (ret < 0) 31948c2ecf20Sopenharmony_ci goto out; 31958c2ecf20Sopenharmony_ci ULIST_ITER_INIT(&uiter); 31968c2ecf20Sopenharmony_ci while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { 31978c2ecf20Sopenharmony_ci struct btrfs_qgroup *qg; 31988c2ecf20Sopenharmony_ci struct btrfs_qgroup_list *glist; 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_ci qg = unode_aux_to_qgroup(unode); 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci qgroup_rsv_release(fs_info, qg, num_bytes, type); 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci list_for_each_entry(glist, &qg->groups, next_group) { 32058c2ecf20Sopenharmony_ci ret = ulist_add(fs_info->qgroup_ulist, 32068c2ecf20Sopenharmony_ci glist->group->qgroupid, 32078c2ecf20Sopenharmony_ci qgroup_to_aux(glist->group), GFP_ATOMIC); 32088c2ecf20Sopenharmony_ci if (ret < 0) 32098c2ecf20Sopenharmony_ci goto out; 32108c2ecf20Sopenharmony_ci } 32118c2ecf20Sopenharmony_ci } 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ciout: 32148c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 32158c2ecf20Sopenharmony_ci} 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci/* 32188c2ecf20Sopenharmony_ci * Check if the leaf is the last leaf. Which means all node pointers 32198c2ecf20Sopenharmony_ci * are at their last position. 32208c2ecf20Sopenharmony_ci */ 32218c2ecf20Sopenharmony_cistatic bool is_last_leaf(struct btrfs_path *path) 32228c2ecf20Sopenharmony_ci{ 32238c2ecf20Sopenharmony_ci int i; 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci for (i = 1; i < BTRFS_MAX_LEVEL && path->nodes[i]; i++) { 32268c2ecf20Sopenharmony_ci if (path->slots[i] != btrfs_header_nritems(path->nodes[i]) - 1) 32278c2ecf20Sopenharmony_ci return false; 32288c2ecf20Sopenharmony_ci } 32298c2ecf20Sopenharmony_ci return true; 32308c2ecf20Sopenharmony_ci} 32318c2ecf20Sopenharmony_ci 32328c2ecf20Sopenharmony_ci/* 32338c2ecf20Sopenharmony_ci * returns < 0 on error, 0 when more leafs are to be scanned. 32348c2ecf20Sopenharmony_ci * returns 1 when done. 32358c2ecf20Sopenharmony_ci */ 32368c2ecf20Sopenharmony_cistatic int qgroup_rescan_leaf(struct btrfs_trans_handle *trans, 32378c2ecf20Sopenharmony_ci struct btrfs_path *path) 32388c2ecf20Sopenharmony_ci{ 32398c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 32408c2ecf20Sopenharmony_ci struct btrfs_key found; 32418c2ecf20Sopenharmony_ci struct extent_buffer *scratch_leaf = NULL; 32428c2ecf20Sopenharmony_ci struct ulist *roots = NULL; 32438c2ecf20Sopenharmony_ci u64 num_bytes; 32448c2ecf20Sopenharmony_ci bool done; 32458c2ecf20Sopenharmony_ci int slot; 32468c2ecf20Sopenharmony_ci int ret; 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 32498c2ecf20Sopenharmony_ci ret = btrfs_search_slot_for_read(fs_info->extent_root, 32508c2ecf20Sopenharmony_ci &fs_info->qgroup_rescan_progress, 32518c2ecf20Sopenharmony_ci path, 1, 0); 32528c2ecf20Sopenharmony_ci 32538c2ecf20Sopenharmony_ci btrfs_debug(fs_info, 32548c2ecf20Sopenharmony_ci "current progress key (%llu %u %llu), search_slot ret %d", 32558c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid, 32568c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_progress.type, 32578c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_progress.offset, ret); 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci if (ret) { 32608c2ecf20Sopenharmony_ci /* 32618c2ecf20Sopenharmony_ci * The rescan is about to end, we will not be scanning any 32628c2ecf20Sopenharmony_ci * further blocks. We cannot unset the RESCAN flag here, because 32638c2ecf20Sopenharmony_ci * we want to commit the transaction if everything went well. 32648c2ecf20Sopenharmony_ci * To make the live accounting work in this phase, we set our 32658c2ecf20Sopenharmony_ci * scan progress pointer such that every real extent objectid 32668c2ecf20Sopenharmony_ci * will be smaller. 32678c2ecf20Sopenharmony_ci */ 32688c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid = (u64)-1; 32698c2ecf20Sopenharmony_ci btrfs_release_path(path); 32708c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 32718c2ecf20Sopenharmony_ci return ret; 32728c2ecf20Sopenharmony_ci } 32738c2ecf20Sopenharmony_ci done = is_last_leaf(path); 32748c2ecf20Sopenharmony_ci 32758c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(path->nodes[0], &found, 32768c2ecf20Sopenharmony_ci btrfs_header_nritems(path->nodes[0]) - 1); 32778c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid = found.objectid + 1; 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci scratch_leaf = btrfs_clone_extent_buffer(path->nodes[0]); 32808c2ecf20Sopenharmony_ci if (!scratch_leaf) { 32818c2ecf20Sopenharmony_ci ret = -ENOMEM; 32828c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 32838c2ecf20Sopenharmony_ci goto out; 32848c2ecf20Sopenharmony_ci } 32858c2ecf20Sopenharmony_ci slot = path->slots[0]; 32868c2ecf20Sopenharmony_ci btrfs_release_path(path); 32878c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci for (; slot < btrfs_header_nritems(scratch_leaf); ++slot) { 32908c2ecf20Sopenharmony_ci btrfs_item_key_to_cpu(scratch_leaf, &found, slot); 32918c2ecf20Sopenharmony_ci if (found.type != BTRFS_EXTENT_ITEM_KEY && 32928c2ecf20Sopenharmony_ci found.type != BTRFS_METADATA_ITEM_KEY) 32938c2ecf20Sopenharmony_ci continue; 32948c2ecf20Sopenharmony_ci if (found.type == BTRFS_METADATA_ITEM_KEY) 32958c2ecf20Sopenharmony_ci num_bytes = fs_info->nodesize; 32968c2ecf20Sopenharmony_ci else 32978c2ecf20Sopenharmony_ci num_bytes = found.offset; 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ci ret = btrfs_find_all_roots(NULL, fs_info, found.objectid, 0, 33008c2ecf20Sopenharmony_ci &roots, false); 33018c2ecf20Sopenharmony_ci if (ret < 0) 33028c2ecf20Sopenharmony_ci goto out; 33038c2ecf20Sopenharmony_ci /* For rescan, just pass old_roots as NULL */ 33048c2ecf20Sopenharmony_ci ret = btrfs_qgroup_account_extent(trans, found.objectid, 33058c2ecf20Sopenharmony_ci num_bytes, NULL, roots); 33068c2ecf20Sopenharmony_ci if (ret < 0) 33078c2ecf20Sopenharmony_ci goto out; 33088c2ecf20Sopenharmony_ci } 33098c2ecf20Sopenharmony_ciout: 33108c2ecf20Sopenharmony_ci if (scratch_leaf) 33118c2ecf20Sopenharmony_ci free_extent_buffer(scratch_leaf); 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_ci if (done && !ret) { 33148c2ecf20Sopenharmony_ci ret = 1; 33158c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid = (u64)-1; 33168c2ecf20Sopenharmony_ci } 33178c2ecf20Sopenharmony_ci return ret; 33188c2ecf20Sopenharmony_ci} 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_cistatic bool rescan_should_stop(struct btrfs_fs_info *fs_info) 33218c2ecf20Sopenharmony_ci{ 33228c2ecf20Sopenharmony_ci return btrfs_fs_closing(fs_info) || 33238c2ecf20Sopenharmony_ci test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state) || 33248c2ecf20Sopenharmony_ci !test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); 33258c2ecf20Sopenharmony_ci} 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_cistatic void btrfs_qgroup_rescan_worker(struct btrfs_work *work) 33288c2ecf20Sopenharmony_ci{ 33298c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = container_of(work, struct btrfs_fs_info, 33308c2ecf20Sopenharmony_ci qgroup_rescan_work); 33318c2ecf20Sopenharmony_ci struct btrfs_path *path; 33328c2ecf20Sopenharmony_ci struct btrfs_trans_handle *trans = NULL; 33338c2ecf20Sopenharmony_ci int err = -ENOMEM; 33348c2ecf20Sopenharmony_ci int ret = 0; 33358c2ecf20Sopenharmony_ci bool stopped = false; 33368c2ecf20Sopenharmony_ci bool did_leaf_rescans = false; 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_ci path = btrfs_alloc_path(); 33398c2ecf20Sopenharmony_ci if (!path) 33408c2ecf20Sopenharmony_ci goto out; 33418c2ecf20Sopenharmony_ci /* 33428c2ecf20Sopenharmony_ci * Rescan should only search for commit root, and any later difference 33438c2ecf20Sopenharmony_ci * should be recorded by qgroup 33448c2ecf20Sopenharmony_ci */ 33458c2ecf20Sopenharmony_ci path->search_commit_root = 1; 33468c2ecf20Sopenharmony_ci path->skip_locking = 1; 33478c2ecf20Sopenharmony_ci 33488c2ecf20Sopenharmony_ci err = 0; 33498c2ecf20Sopenharmony_ci while (!err && !(stopped = rescan_should_stop(fs_info))) { 33508c2ecf20Sopenharmony_ci trans = btrfs_start_transaction(fs_info->fs_root, 0); 33518c2ecf20Sopenharmony_ci if (IS_ERR(trans)) { 33528c2ecf20Sopenharmony_ci err = PTR_ERR(trans); 33538c2ecf20Sopenharmony_ci break; 33548c2ecf20Sopenharmony_ci } 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_ci err = qgroup_rescan_leaf(trans, path); 33578c2ecf20Sopenharmony_ci did_leaf_rescans = true; 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ci if (err > 0) 33608c2ecf20Sopenharmony_ci btrfs_commit_transaction(trans); 33618c2ecf20Sopenharmony_ci else 33628c2ecf20Sopenharmony_ci btrfs_end_transaction(trans); 33638c2ecf20Sopenharmony_ci } 33648c2ecf20Sopenharmony_ci 33658c2ecf20Sopenharmony_ciout: 33668c2ecf20Sopenharmony_ci btrfs_free_path(path); 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 33698c2ecf20Sopenharmony_ci if (err > 0 && 33708c2ecf20Sopenharmony_ci fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) { 33718c2ecf20Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 33728c2ecf20Sopenharmony_ci } else if (err < 0 || stopped) { 33738c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 33748c2ecf20Sopenharmony_ci } 33758c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci /* 33788c2ecf20Sopenharmony_ci * Only update status, since the previous part has already updated the 33798c2ecf20Sopenharmony_ci * qgroup info, and only if we did any actual work. This also prevents 33808c2ecf20Sopenharmony_ci * race with a concurrent quota disable, which has already set 33818c2ecf20Sopenharmony_ci * fs_info->quota_root to NULL and cleared BTRFS_FS_QUOTA_ENABLED at 33828c2ecf20Sopenharmony_ci * btrfs_quota_disable(). 33838c2ecf20Sopenharmony_ci */ 33848c2ecf20Sopenharmony_ci if (did_leaf_rescans) { 33858c2ecf20Sopenharmony_ci trans = btrfs_start_transaction(fs_info->quota_root, 1); 33868c2ecf20Sopenharmony_ci if (IS_ERR(trans)) { 33878c2ecf20Sopenharmony_ci err = PTR_ERR(trans); 33888c2ecf20Sopenharmony_ci trans = NULL; 33898c2ecf20Sopenharmony_ci btrfs_err(fs_info, 33908c2ecf20Sopenharmony_ci "fail to start transaction for status update: %d", 33918c2ecf20Sopenharmony_ci err); 33928c2ecf20Sopenharmony_ci } 33938c2ecf20Sopenharmony_ci } else { 33948c2ecf20Sopenharmony_ci trans = NULL; 33958c2ecf20Sopenharmony_ci } 33968c2ecf20Sopenharmony_ci 33978c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 33988c2ecf20Sopenharmony_ci if (!stopped) 33998c2ecf20Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; 34008c2ecf20Sopenharmony_ci if (trans) { 34018c2ecf20Sopenharmony_ci ret = update_qgroup_status_item(trans); 34028c2ecf20Sopenharmony_ci if (ret < 0) { 34038c2ecf20Sopenharmony_ci err = ret; 34048c2ecf20Sopenharmony_ci btrfs_err(fs_info, "fail to update qgroup status: %d", 34058c2ecf20Sopenharmony_ci err); 34068c2ecf20Sopenharmony_ci } 34078c2ecf20Sopenharmony_ci } 34088c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_running = false; 34098c2ecf20Sopenharmony_ci complete_all(&fs_info->qgroup_rescan_completion); 34108c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 34118c2ecf20Sopenharmony_ci 34128c2ecf20Sopenharmony_ci if (!trans) 34138c2ecf20Sopenharmony_ci return; 34148c2ecf20Sopenharmony_ci 34158c2ecf20Sopenharmony_ci btrfs_end_transaction(trans); 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci if (stopped) { 34188c2ecf20Sopenharmony_ci btrfs_info(fs_info, "qgroup scan paused"); 34198c2ecf20Sopenharmony_ci } else if (err >= 0) { 34208c2ecf20Sopenharmony_ci btrfs_info(fs_info, "qgroup scan completed%s", 34218c2ecf20Sopenharmony_ci err > 0 ? " (inconsistency flag cleared)" : ""); 34228c2ecf20Sopenharmony_ci } else { 34238c2ecf20Sopenharmony_ci btrfs_err(fs_info, "qgroup scan failed with %d", err); 34248c2ecf20Sopenharmony_ci } 34258c2ecf20Sopenharmony_ci} 34268c2ecf20Sopenharmony_ci 34278c2ecf20Sopenharmony_ci/* 34288c2ecf20Sopenharmony_ci * Checks that (a) no rescan is running and (b) quota is enabled. Allocates all 34298c2ecf20Sopenharmony_ci * memory required for the rescan context. 34308c2ecf20Sopenharmony_ci */ 34318c2ecf20Sopenharmony_cistatic int 34328c2ecf20Sopenharmony_ciqgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, 34338c2ecf20Sopenharmony_ci int init_flags) 34348c2ecf20Sopenharmony_ci{ 34358c2ecf20Sopenharmony_ci int ret = 0; 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci if (!init_flags) { 34388c2ecf20Sopenharmony_ci /* we're resuming qgroup rescan at mount time */ 34398c2ecf20Sopenharmony_ci if (!(fs_info->qgroup_flags & 34408c2ecf20Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAG_RESCAN)) { 34418c2ecf20Sopenharmony_ci btrfs_warn(fs_info, 34428c2ecf20Sopenharmony_ci "qgroup rescan init failed, qgroup rescan is not queued"); 34438c2ecf20Sopenharmony_ci ret = -EINVAL; 34448c2ecf20Sopenharmony_ci } else if (!(fs_info->qgroup_flags & 34458c2ecf20Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAG_ON)) { 34468c2ecf20Sopenharmony_ci btrfs_warn(fs_info, 34478c2ecf20Sopenharmony_ci "qgroup rescan init failed, qgroup is not enabled"); 34488c2ecf20Sopenharmony_ci ret = -EINVAL; 34498c2ecf20Sopenharmony_ci } 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci if (ret) 34528c2ecf20Sopenharmony_ci return ret; 34538c2ecf20Sopenharmony_ci } 34548c2ecf20Sopenharmony_ci 34558c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci if (init_flags) { 34588c2ecf20Sopenharmony_ci if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { 34598c2ecf20Sopenharmony_ci btrfs_warn(fs_info, 34608c2ecf20Sopenharmony_ci "qgroup rescan is already in progress"); 34618c2ecf20Sopenharmony_ci ret = -EINPROGRESS; 34628c2ecf20Sopenharmony_ci } else if (!(fs_info->qgroup_flags & 34638c2ecf20Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAG_ON)) { 34648c2ecf20Sopenharmony_ci btrfs_warn(fs_info, 34658c2ecf20Sopenharmony_ci "qgroup rescan init failed, qgroup is not enabled"); 34668c2ecf20Sopenharmony_ci ret = -EINVAL; 34678c2ecf20Sopenharmony_ci } else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) { 34688c2ecf20Sopenharmony_ci /* Quota disable is in progress */ 34698c2ecf20Sopenharmony_ci ret = -EBUSY; 34708c2ecf20Sopenharmony_ci } 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci if (ret) { 34738c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 34748c2ecf20Sopenharmony_ci return ret; 34758c2ecf20Sopenharmony_ci } 34768c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_RESCAN; 34778c2ecf20Sopenharmony_ci } 34788c2ecf20Sopenharmony_ci 34798c2ecf20Sopenharmony_ci memset(&fs_info->qgroup_rescan_progress, 0, 34808c2ecf20Sopenharmony_ci sizeof(fs_info->qgroup_rescan_progress)); 34818c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid = progress_objectid; 34828c2ecf20Sopenharmony_ci init_completion(&fs_info->qgroup_rescan_completion); 34838c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 34848c2ecf20Sopenharmony_ci 34858c2ecf20Sopenharmony_ci btrfs_init_work(&fs_info->qgroup_rescan_work, 34868c2ecf20Sopenharmony_ci btrfs_qgroup_rescan_worker, NULL, NULL); 34878c2ecf20Sopenharmony_ci return 0; 34888c2ecf20Sopenharmony_ci} 34898c2ecf20Sopenharmony_ci 34908c2ecf20Sopenharmony_cistatic void 34918c2ecf20Sopenharmony_ciqgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info) 34928c2ecf20Sopenharmony_ci{ 34938c2ecf20Sopenharmony_ci struct rb_node *n; 34948c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 34978c2ecf20Sopenharmony_ci /* clear all current qgroup tracking information */ 34988c2ecf20Sopenharmony_ci for (n = rb_first(&fs_info->qgroup_tree); n; n = rb_next(n)) { 34998c2ecf20Sopenharmony_ci qgroup = rb_entry(n, struct btrfs_qgroup, node); 35008c2ecf20Sopenharmony_ci qgroup->rfer = 0; 35018c2ecf20Sopenharmony_ci qgroup->rfer_cmpr = 0; 35028c2ecf20Sopenharmony_ci qgroup->excl = 0; 35038c2ecf20Sopenharmony_ci qgroup->excl_cmpr = 0; 35048c2ecf20Sopenharmony_ci qgroup_dirty(fs_info, qgroup); 35058c2ecf20Sopenharmony_ci } 35068c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 35078c2ecf20Sopenharmony_ci} 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ciint 35108c2ecf20Sopenharmony_cibtrfs_qgroup_rescan(struct btrfs_fs_info *fs_info) 35118c2ecf20Sopenharmony_ci{ 35128c2ecf20Sopenharmony_ci int ret = 0; 35138c2ecf20Sopenharmony_ci struct btrfs_trans_handle *trans; 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_ci ret = qgroup_rescan_init(fs_info, 0, 1); 35168c2ecf20Sopenharmony_ci if (ret) 35178c2ecf20Sopenharmony_ci return ret; 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_ci /* 35208c2ecf20Sopenharmony_ci * We have set the rescan_progress to 0, which means no more 35218c2ecf20Sopenharmony_ci * delayed refs will be accounted by btrfs_qgroup_account_ref. 35228c2ecf20Sopenharmony_ci * However, btrfs_qgroup_account_ref may be right after its call 35238c2ecf20Sopenharmony_ci * to btrfs_find_all_roots, in which case it would still do the 35248c2ecf20Sopenharmony_ci * accounting. 35258c2ecf20Sopenharmony_ci * To solve this, we're committing the transaction, which will 35268c2ecf20Sopenharmony_ci * ensure we run all delayed refs and only after that, we are 35278c2ecf20Sopenharmony_ci * going to clear all tracking information for a clean start. 35288c2ecf20Sopenharmony_ci */ 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_ci trans = btrfs_join_transaction(fs_info->fs_root); 35318c2ecf20Sopenharmony_ci if (IS_ERR(trans)) { 35328c2ecf20Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; 35338c2ecf20Sopenharmony_ci return PTR_ERR(trans); 35348c2ecf20Sopenharmony_ci } 35358c2ecf20Sopenharmony_ci ret = btrfs_commit_transaction(trans); 35368c2ecf20Sopenharmony_ci if (ret) { 35378c2ecf20Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; 35388c2ecf20Sopenharmony_ci return ret; 35398c2ecf20Sopenharmony_ci } 35408c2ecf20Sopenharmony_ci 35418c2ecf20Sopenharmony_ci qgroup_rescan_zero_tracking(fs_info); 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 35448c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_running = true; 35458c2ecf20Sopenharmony_ci btrfs_queue_work(fs_info->qgroup_rescan_workers, 35468c2ecf20Sopenharmony_ci &fs_info->qgroup_rescan_work); 35478c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 35488c2ecf20Sopenharmony_ci 35498c2ecf20Sopenharmony_ci return 0; 35508c2ecf20Sopenharmony_ci} 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_ciint btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info, 35538c2ecf20Sopenharmony_ci bool interruptible) 35548c2ecf20Sopenharmony_ci{ 35558c2ecf20Sopenharmony_ci int running; 35568c2ecf20Sopenharmony_ci int ret = 0; 35578c2ecf20Sopenharmony_ci 35588c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 35598c2ecf20Sopenharmony_ci running = fs_info->qgroup_rescan_running; 35608c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ci if (!running) 35638c2ecf20Sopenharmony_ci return 0; 35648c2ecf20Sopenharmony_ci 35658c2ecf20Sopenharmony_ci if (interruptible) 35668c2ecf20Sopenharmony_ci ret = wait_for_completion_interruptible( 35678c2ecf20Sopenharmony_ci &fs_info->qgroup_rescan_completion); 35688c2ecf20Sopenharmony_ci else 35698c2ecf20Sopenharmony_ci wait_for_completion(&fs_info->qgroup_rescan_completion); 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci return ret; 35728c2ecf20Sopenharmony_ci} 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci/* 35758c2ecf20Sopenharmony_ci * this is only called from open_ctree where we're still single threaded, thus 35768c2ecf20Sopenharmony_ci * locking is omitted here. 35778c2ecf20Sopenharmony_ci */ 35788c2ecf20Sopenharmony_civoid 35798c2ecf20Sopenharmony_cibtrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info) 35808c2ecf20Sopenharmony_ci{ 35818c2ecf20Sopenharmony_ci if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { 35828c2ecf20Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 35838c2ecf20Sopenharmony_ci fs_info->qgroup_rescan_running = true; 35848c2ecf20Sopenharmony_ci btrfs_queue_work(fs_info->qgroup_rescan_workers, 35858c2ecf20Sopenharmony_ci &fs_info->qgroup_rescan_work); 35868c2ecf20Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 35878c2ecf20Sopenharmony_ci } 35888c2ecf20Sopenharmony_ci} 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci#define rbtree_iterate_from_safe(node, next, start) \ 35918c2ecf20Sopenharmony_ci for (node = start; node && ({ next = rb_next(node); 1;}); node = next) 35928c2ecf20Sopenharmony_ci 35938c2ecf20Sopenharmony_cistatic int qgroup_unreserve_range(struct btrfs_inode *inode, 35948c2ecf20Sopenharmony_ci struct extent_changeset *reserved, u64 start, 35958c2ecf20Sopenharmony_ci u64 len) 35968c2ecf20Sopenharmony_ci{ 35978c2ecf20Sopenharmony_ci struct rb_node *node; 35988c2ecf20Sopenharmony_ci struct rb_node *next; 35998c2ecf20Sopenharmony_ci struct ulist_node *entry; 36008c2ecf20Sopenharmony_ci int ret = 0; 36018c2ecf20Sopenharmony_ci 36028c2ecf20Sopenharmony_ci node = reserved->range_changed.root.rb_node; 36038c2ecf20Sopenharmony_ci if (!node) 36048c2ecf20Sopenharmony_ci return 0; 36058c2ecf20Sopenharmony_ci while (node) { 36068c2ecf20Sopenharmony_ci entry = rb_entry(node, struct ulist_node, rb_node); 36078c2ecf20Sopenharmony_ci if (entry->val < start) 36088c2ecf20Sopenharmony_ci node = node->rb_right; 36098c2ecf20Sopenharmony_ci else 36108c2ecf20Sopenharmony_ci node = node->rb_left; 36118c2ecf20Sopenharmony_ci } 36128c2ecf20Sopenharmony_ci 36138c2ecf20Sopenharmony_ci if (entry->val > start && rb_prev(&entry->rb_node)) 36148c2ecf20Sopenharmony_ci entry = rb_entry(rb_prev(&entry->rb_node), struct ulist_node, 36158c2ecf20Sopenharmony_ci rb_node); 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci rbtree_iterate_from_safe(node, next, &entry->rb_node) { 36188c2ecf20Sopenharmony_ci u64 entry_start; 36198c2ecf20Sopenharmony_ci u64 entry_end; 36208c2ecf20Sopenharmony_ci u64 entry_len; 36218c2ecf20Sopenharmony_ci int clear_ret; 36228c2ecf20Sopenharmony_ci 36238c2ecf20Sopenharmony_ci entry = rb_entry(node, struct ulist_node, rb_node); 36248c2ecf20Sopenharmony_ci entry_start = entry->val; 36258c2ecf20Sopenharmony_ci entry_end = entry->aux; 36268c2ecf20Sopenharmony_ci entry_len = entry_end - entry_start + 1; 36278c2ecf20Sopenharmony_ci 36288c2ecf20Sopenharmony_ci if (entry_start >= start + len) 36298c2ecf20Sopenharmony_ci break; 36308c2ecf20Sopenharmony_ci if (entry_start + entry_len <= start) 36318c2ecf20Sopenharmony_ci continue; 36328c2ecf20Sopenharmony_ci /* 36338c2ecf20Sopenharmony_ci * Now the entry is in [start, start + len), revert the 36348c2ecf20Sopenharmony_ci * EXTENT_QGROUP_RESERVED bit. 36358c2ecf20Sopenharmony_ci */ 36368c2ecf20Sopenharmony_ci clear_ret = clear_extent_bits(&inode->io_tree, entry_start, 36378c2ecf20Sopenharmony_ci entry_end, EXTENT_QGROUP_RESERVED); 36388c2ecf20Sopenharmony_ci if (!ret && clear_ret < 0) 36398c2ecf20Sopenharmony_ci ret = clear_ret; 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_ci ulist_del(&reserved->range_changed, entry->val, entry->aux); 36428c2ecf20Sopenharmony_ci if (likely(reserved->bytes_changed >= entry_len)) { 36438c2ecf20Sopenharmony_ci reserved->bytes_changed -= entry_len; 36448c2ecf20Sopenharmony_ci } else { 36458c2ecf20Sopenharmony_ci WARN_ON(1); 36468c2ecf20Sopenharmony_ci reserved->bytes_changed = 0; 36478c2ecf20Sopenharmony_ci } 36488c2ecf20Sopenharmony_ci } 36498c2ecf20Sopenharmony_ci 36508c2ecf20Sopenharmony_ci return ret; 36518c2ecf20Sopenharmony_ci} 36528c2ecf20Sopenharmony_ci 36538c2ecf20Sopenharmony_ci/* 36548c2ecf20Sopenharmony_ci * Try to free some space for qgroup. 36558c2ecf20Sopenharmony_ci * 36568c2ecf20Sopenharmony_ci * For qgroup, there are only 3 ways to free qgroup space: 36578c2ecf20Sopenharmony_ci * - Flush nodatacow write 36588c2ecf20Sopenharmony_ci * Any nodatacow write will free its reserved data space at run_delalloc_range(). 36598c2ecf20Sopenharmony_ci * In theory, we should only flush nodatacow inodes, but it's not yet 36608c2ecf20Sopenharmony_ci * possible, so we need to flush the whole root. 36618c2ecf20Sopenharmony_ci * 36628c2ecf20Sopenharmony_ci * - Wait for ordered extents 36638c2ecf20Sopenharmony_ci * When ordered extents are finished, their reserved metadata is finally 36648c2ecf20Sopenharmony_ci * converted to per_trans status, which can be freed by later commit 36658c2ecf20Sopenharmony_ci * transaction. 36668c2ecf20Sopenharmony_ci * 36678c2ecf20Sopenharmony_ci * - Commit transaction 36688c2ecf20Sopenharmony_ci * This would free the meta_per_trans space. 36698c2ecf20Sopenharmony_ci * In theory this shouldn't provide much space, but any more qgroup space 36708c2ecf20Sopenharmony_ci * is needed. 36718c2ecf20Sopenharmony_ci */ 36728c2ecf20Sopenharmony_cistatic int try_flush_qgroup(struct btrfs_root *root) 36738c2ecf20Sopenharmony_ci{ 36748c2ecf20Sopenharmony_ci struct btrfs_trans_handle *trans; 36758c2ecf20Sopenharmony_ci int ret; 36768c2ecf20Sopenharmony_ci bool can_commit = true; 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci /* 36798c2ecf20Sopenharmony_ci * If current process holds a transaction, we shouldn't flush, as we 36808c2ecf20Sopenharmony_ci * assume all space reservation happens before a transaction handle is 36818c2ecf20Sopenharmony_ci * held. 36828c2ecf20Sopenharmony_ci * 36838c2ecf20Sopenharmony_ci * But there are cases like btrfs_delayed_item_reserve_metadata() where 36848c2ecf20Sopenharmony_ci * we try to reserve space with one transction handle already held. 36858c2ecf20Sopenharmony_ci * In that case we can't commit transaction, but at least try to end it 36868c2ecf20Sopenharmony_ci * and hope the started data writes can free some space. 36878c2ecf20Sopenharmony_ci */ 36888c2ecf20Sopenharmony_ci if (current->journal_info && 36898c2ecf20Sopenharmony_ci current->journal_info != BTRFS_SEND_TRANS_STUB) 36908c2ecf20Sopenharmony_ci can_commit = false; 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci /* 36938c2ecf20Sopenharmony_ci * We don't want to run flush again and again, so if there is a running 36948c2ecf20Sopenharmony_ci * one, we won't try to start a new flush, but exit directly. 36958c2ecf20Sopenharmony_ci */ 36968c2ecf20Sopenharmony_ci if (test_and_set_bit(BTRFS_ROOT_QGROUP_FLUSHING, &root->state)) { 36978c2ecf20Sopenharmony_ci /* 36988c2ecf20Sopenharmony_ci * We are already holding a transaction, thus we can block other 36998c2ecf20Sopenharmony_ci * threads from flushing. So exit right now. This increases 37008c2ecf20Sopenharmony_ci * the chance of EDQUOT for heavy load and near limit cases. 37018c2ecf20Sopenharmony_ci * But we can argue that if we're already near limit, EDQUOT is 37028c2ecf20Sopenharmony_ci * unavoidable anyway. 37038c2ecf20Sopenharmony_ci */ 37048c2ecf20Sopenharmony_ci if (!can_commit) 37058c2ecf20Sopenharmony_ci return 0; 37068c2ecf20Sopenharmony_ci 37078c2ecf20Sopenharmony_ci wait_event(root->qgroup_flush_wait, 37088c2ecf20Sopenharmony_ci !test_bit(BTRFS_ROOT_QGROUP_FLUSHING, &root->state)); 37098c2ecf20Sopenharmony_ci return 0; 37108c2ecf20Sopenharmony_ci } 37118c2ecf20Sopenharmony_ci 37128c2ecf20Sopenharmony_ci ret = btrfs_start_delalloc_snapshot(root); 37138c2ecf20Sopenharmony_ci if (ret < 0) 37148c2ecf20Sopenharmony_ci goto out; 37158c2ecf20Sopenharmony_ci btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1); 37168c2ecf20Sopenharmony_ci 37178c2ecf20Sopenharmony_ci trans = btrfs_join_transaction(root); 37188c2ecf20Sopenharmony_ci if (IS_ERR(trans)) { 37198c2ecf20Sopenharmony_ci ret = PTR_ERR(trans); 37208c2ecf20Sopenharmony_ci goto out; 37218c2ecf20Sopenharmony_ci } 37228c2ecf20Sopenharmony_ci 37238c2ecf20Sopenharmony_ci if (can_commit) 37248c2ecf20Sopenharmony_ci ret = btrfs_commit_transaction(trans); 37258c2ecf20Sopenharmony_ci else 37268c2ecf20Sopenharmony_ci ret = btrfs_end_transaction(trans); 37278c2ecf20Sopenharmony_ciout: 37288c2ecf20Sopenharmony_ci clear_bit(BTRFS_ROOT_QGROUP_FLUSHING, &root->state); 37298c2ecf20Sopenharmony_ci wake_up(&root->qgroup_flush_wait); 37308c2ecf20Sopenharmony_ci return ret; 37318c2ecf20Sopenharmony_ci} 37328c2ecf20Sopenharmony_ci 37338c2ecf20Sopenharmony_cistatic int qgroup_reserve_data(struct btrfs_inode *inode, 37348c2ecf20Sopenharmony_ci struct extent_changeset **reserved_ret, u64 start, 37358c2ecf20Sopenharmony_ci u64 len) 37368c2ecf20Sopenharmony_ci{ 37378c2ecf20Sopenharmony_ci struct btrfs_root *root = inode->root; 37388c2ecf20Sopenharmony_ci struct extent_changeset *reserved; 37398c2ecf20Sopenharmony_ci bool new_reserved = false; 37408c2ecf20Sopenharmony_ci u64 orig_reserved; 37418c2ecf20Sopenharmony_ci u64 to_reserve; 37428c2ecf20Sopenharmony_ci int ret; 37438c2ecf20Sopenharmony_ci 37448c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags) || 37458c2ecf20Sopenharmony_ci !is_fstree(root->root_key.objectid) || len == 0) 37468c2ecf20Sopenharmony_ci return 0; 37478c2ecf20Sopenharmony_ci 37488c2ecf20Sopenharmony_ci /* @reserved parameter is mandatory for qgroup */ 37498c2ecf20Sopenharmony_ci if (WARN_ON(!reserved_ret)) 37508c2ecf20Sopenharmony_ci return -EINVAL; 37518c2ecf20Sopenharmony_ci if (!*reserved_ret) { 37528c2ecf20Sopenharmony_ci new_reserved = true; 37538c2ecf20Sopenharmony_ci *reserved_ret = extent_changeset_alloc(); 37548c2ecf20Sopenharmony_ci if (!*reserved_ret) 37558c2ecf20Sopenharmony_ci return -ENOMEM; 37568c2ecf20Sopenharmony_ci } 37578c2ecf20Sopenharmony_ci reserved = *reserved_ret; 37588c2ecf20Sopenharmony_ci /* Record already reserved space */ 37598c2ecf20Sopenharmony_ci orig_reserved = reserved->bytes_changed; 37608c2ecf20Sopenharmony_ci ret = set_record_extent_bits(&inode->io_tree, start, 37618c2ecf20Sopenharmony_ci start + len -1, EXTENT_QGROUP_RESERVED, reserved); 37628c2ecf20Sopenharmony_ci 37638c2ecf20Sopenharmony_ci /* Newly reserved space */ 37648c2ecf20Sopenharmony_ci to_reserve = reserved->bytes_changed - orig_reserved; 37658c2ecf20Sopenharmony_ci trace_btrfs_qgroup_reserve_data(&inode->vfs_inode, start, len, 37668c2ecf20Sopenharmony_ci to_reserve, QGROUP_RESERVE); 37678c2ecf20Sopenharmony_ci if (ret < 0) 37688c2ecf20Sopenharmony_ci goto out; 37698c2ecf20Sopenharmony_ci ret = qgroup_reserve(root, to_reserve, true, BTRFS_QGROUP_RSV_DATA); 37708c2ecf20Sopenharmony_ci if (ret < 0) 37718c2ecf20Sopenharmony_ci goto cleanup; 37728c2ecf20Sopenharmony_ci 37738c2ecf20Sopenharmony_ci return ret; 37748c2ecf20Sopenharmony_ci 37758c2ecf20Sopenharmony_cicleanup: 37768c2ecf20Sopenharmony_ci qgroup_unreserve_range(inode, reserved, start, len); 37778c2ecf20Sopenharmony_ciout: 37788c2ecf20Sopenharmony_ci if (new_reserved) { 37798c2ecf20Sopenharmony_ci extent_changeset_release(reserved); 37808c2ecf20Sopenharmony_ci kfree(reserved); 37818c2ecf20Sopenharmony_ci *reserved_ret = NULL; 37828c2ecf20Sopenharmony_ci } 37838c2ecf20Sopenharmony_ci return ret; 37848c2ecf20Sopenharmony_ci} 37858c2ecf20Sopenharmony_ci 37868c2ecf20Sopenharmony_ci/* 37878c2ecf20Sopenharmony_ci * Reserve qgroup space for range [start, start + len). 37888c2ecf20Sopenharmony_ci * 37898c2ecf20Sopenharmony_ci * This function will either reserve space from related qgroups or do nothing 37908c2ecf20Sopenharmony_ci * if the range is already reserved. 37918c2ecf20Sopenharmony_ci * 37928c2ecf20Sopenharmony_ci * Return 0 for successful reservation 37938c2ecf20Sopenharmony_ci * Return <0 for error (including -EQUOT) 37948c2ecf20Sopenharmony_ci * 37958c2ecf20Sopenharmony_ci * NOTE: This function may sleep for memory allocation, dirty page flushing and 37968c2ecf20Sopenharmony_ci * commit transaction. So caller should not hold any dirty page locked. 37978c2ecf20Sopenharmony_ci */ 37988c2ecf20Sopenharmony_ciint btrfs_qgroup_reserve_data(struct btrfs_inode *inode, 37998c2ecf20Sopenharmony_ci struct extent_changeset **reserved_ret, u64 start, 38008c2ecf20Sopenharmony_ci u64 len) 38018c2ecf20Sopenharmony_ci{ 38028c2ecf20Sopenharmony_ci int ret; 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci ret = qgroup_reserve_data(inode, reserved_ret, start, len); 38058c2ecf20Sopenharmony_ci if (ret <= 0 && ret != -EDQUOT) 38068c2ecf20Sopenharmony_ci return ret; 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci ret = try_flush_qgroup(inode->root); 38098c2ecf20Sopenharmony_ci if (ret < 0) 38108c2ecf20Sopenharmony_ci return ret; 38118c2ecf20Sopenharmony_ci return qgroup_reserve_data(inode, reserved_ret, start, len); 38128c2ecf20Sopenharmony_ci} 38138c2ecf20Sopenharmony_ci 38148c2ecf20Sopenharmony_ci/* Free ranges specified by @reserved, normally in error path */ 38158c2ecf20Sopenharmony_cistatic int qgroup_free_reserved_data(struct btrfs_inode *inode, 38168c2ecf20Sopenharmony_ci struct extent_changeset *reserved, u64 start, u64 len) 38178c2ecf20Sopenharmony_ci{ 38188c2ecf20Sopenharmony_ci struct btrfs_root *root = inode->root; 38198c2ecf20Sopenharmony_ci struct ulist_node *unode; 38208c2ecf20Sopenharmony_ci struct ulist_iterator uiter; 38218c2ecf20Sopenharmony_ci struct extent_changeset changeset; 38228c2ecf20Sopenharmony_ci int freed = 0; 38238c2ecf20Sopenharmony_ci int ret; 38248c2ecf20Sopenharmony_ci 38258c2ecf20Sopenharmony_ci extent_changeset_init(&changeset); 38268c2ecf20Sopenharmony_ci len = round_up(start + len, root->fs_info->sectorsize); 38278c2ecf20Sopenharmony_ci start = round_down(start, root->fs_info->sectorsize); 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci ULIST_ITER_INIT(&uiter); 38308c2ecf20Sopenharmony_ci while ((unode = ulist_next(&reserved->range_changed, &uiter))) { 38318c2ecf20Sopenharmony_ci u64 range_start = unode->val; 38328c2ecf20Sopenharmony_ci /* unode->aux is the inclusive end */ 38338c2ecf20Sopenharmony_ci u64 range_len = unode->aux - range_start + 1; 38348c2ecf20Sopenharmony_ci u64 free_start; 38358c2ecf20Sopenharmony_ci u64 free_len; 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci extent_changeset_release(&changeset); 38388c2ecf20Sopenharmony_ci 38398c2ecf20Sopenharmony_ci /* Only free range in range [start, start + len) */ 38408c2ecf20Sopenharmony_ci if (range_start >= start + len || 38418c2ecf20Sopenharmony_ci range_start + range_len <= start) 38428c2ecf20Sopenharmony_ci continue; 38438c2ecf20Sopenharmony_ci free_start = max(range_start, start); 38448c2ecf20Sopenharmony_ci free_len = min(start + len, range_start + range_len) - 38458c2ecf20Sopenharmony_ci free_start; 38468c2ecf20Sopenharmony_ci /* 38478c2ecf20Sopenharmony_ci * TODO: To also modify reserved->ranges_reserved to reflect 38488c2ecf20Sopenharmony_ci * the modification. 38498c2ecf20Sopenharmony_ci * 38508c2ecf20Sopenharmony_ci * However as long as we free qgroup reserved according to 38518c2ecf20Sopenharmony_ci * EXTENT_QGROUP_RESERVED, we won't double free. 38528c2ecf20Sopenharmony_ci * So not need to rush. 38538c2ecf20Sopenharmony_ci */ 38548c2ecf20Sopenharmony_ci ret = clear_record_extent_bits(&inode->io_tree, free_start, 38558c2ecf20Sopenharmony_ci free_start + free_len - 1, 38568c2ecf20Sopenharmony_ci EXTENT_QGROUP_RESERVED, &changeset); 38578c2ecf20Sopenharmony_ci if (ret < 0) 38588c2ecf20Sopenharmony_ci goto out; 38598c2ecf20Sopenharmony_ci freed += changeset.bytes_changed; 38608c2ecf20Sopenharmony_ci } 38618c2ecf20Sopenharmony_ci btrfs_qgroup_free_refroot(root->fs_info, root->root_key.objectid, freed, 38628c2ecf20Sopenharmony_ci BTRFS_QGROUP_RSV_DATA); 38638c2ecf20Sopenharmony_ci ret = freed; 38648c2ecf20Sopenharmony_ciout: 38658c2ecf20Sopenharmony_ci extent_changeset_release(&changeset); 38668c2ecf20Sopenharmony_ci return ret; 38678c2ecf20Sopenharmony_ci} 38688c2ecf20Sopenharmony_ci 38698c2ecf20Sopenharmony_cistatic int __btrfs_qgroup_release_data(struct btrfs_inode *inode, 38708c2ecf20Sopenharmony_ci struct extent_changeset *reserved, u64 start, u64 len, 38718c2ecf20Sopenharmony_ci int free) 38728c2ecf20Sopenharmony_ci{ 38738c2ecf20Sopenharmony_ci struct extent_changeset changeset; 38748c2ecf20Sopenharmony_ci int trace_op = QGROUP_RELEASE; 38758c2ecf20Sopenharmony_ci int ret; 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &inode->root->fs_info->flags)) 38788c2ecf20Sopenharmony_ci return 0; 38798c2ecf20Sopenharmony_ci 38808c2ecf20Sopenharmony_ci /* In release case, we shouldn't have @reserved */ 38818c2ecf20Sopenharmony_ci WARN_ON(!free && reserved); 38828c2ecf20Sopenharmony_ci if (free && reserved) 38838c2ecf20Sopenharmony_ci return qgroup_free_reserved_data(inode, reserved, start, len); 38848c2ecf20Sopenharmony_ci extent_changeset_init(&changeset); 38858c2ecf20Sopenharmony_ci ret = clear_record_extent_bits(&inode->io_tree, start, start + len -1, 38868c2ecf20Sopenharmony_ci EXTENT_QGROUP_RESERVED, &changeset); 38878c2ecf20Sopenharmony_ci if (ret < 0) 38888c2ecf20Sopenharmony_ci goto out; 38898c2ecf20Sopenharmony_ci 38908c2ecf20Sopenharmony_ci if (free) 38918c2ecf20Sopenharmony_ci trace_op = QGROUP_FREE; 38928c2ecf20Sopenharmony_ci trace_btrfs_qgroup_release_data(&inode->vfs_inode, start, len, 38938c2ecf20Sopenharmony_ci changeset.bytes_changed, trace_op); 38948c2ecf20Sopenharmony_ci if (free) 38958c2ecf20Sopenharmony_ci btrfs_qgroup_free_refroot(inode->root->fs_info, 38968c2ecf20Sopenharmony_ci inode->root->root_key.objectid, 38978c2ecf20Sopenharmony_ci changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA); 38988c2ecf20Sopenharmony_ci ret = changeset.bytes_changed; 38998c2ecf20Sopenharmony_ciout: 39008c2ecf20Sopenharmony_ci extent_changeset_release(&changeset); 39018c2ecf20Sopenharmony_ci return ret; 39028c2ecf20Sopenharmony_ci} 39038c2ecf20Sopenharmony_ci 39048c2ecf20Sopenharmony_ci/* 39058c2ecf20Sopenharmony_ci * Free a reserved space range from io_tree and related qgroups 39068c2ecf20Sopenharmony_ci * 39078c2ecf20Sopenharmony_ci * Should be called when a range of pages get invalidated before reaching disk. 39088c2ecf20Sopenharmony_ci * Or for error cleanup case. 39098c2ecf20Sopenharmony_ci * if @reserved is given, only reserved range in [@start, @start + @len) will 39108c2ecf20Sopenharmony_ci * be freed. 39118c2ecf20Sopenharmony_ci * 39128c2ecf20Sopenharmony_ci * For data written to disk, use btrfs_qgroup_release_data(). 39138c2ecf20Sopenharmony_ci * 39148c2ecf20Sopenharmony_ci * NOTE: This function may sleep for memory allocation. 39158c2ecf20Sopenharmony_ci */ 39168c2ecf20Sopenharmony_ciint btrfs_qgroup_free_data(struct btrfs_inode *inode, 39178c2ecf20Sopenharmony_ci struct extent_changeset *reserved, u64 start, u64 len) 39188c2ecf20Sopenharmony_ci{ 39198c2ecf20Sopenharmony_ci return __btrfs_qgroup_release_data(inode, reserved, start, len, 1); 39208c2ecf20Sopenharmony_ci} 39218c2ecf20Sopenharmony_ci 39228c2ecf20Sopenharmony_ci/* 39238c2ecf20Sopenharmony_ci * Release a reserved space range from io_tree only. 39248c2ecf20Sopenharmony_ci * 39258c2ecf20Sopenharmony_ci * Should be called when a range of pages get written to disk and corresponding 39268c2ecf20Sopenharmony_ci * FILE_EXTENT is inserted into corresponding root. 39278c2ecf20Sopenharmony_ci * 39288c2ecf20Sopenharmony_ci * Since new qgroup accounting framework will only update qgroup numbers at 39298c2ecf20Sopenharmony_ci * commit_transaction() time, its reserved space shouldn't be freed from 39308c2ecf20Sopenharmony_ci * related qgroups. 39318c2ecf20Sopenharmony_ci * 39328c2ecf20Sopenharmony_ci * But we should release the range from io_tree, to allow further write to be 39338c2ecf20Sopenharmony_ci * COWed. 39348c2ecf20Sopenharmony_ci * 39358c2ecf20Sopenharmony_ci * NOTE: This function may sleep for memory allocation. 39368c2ecf20Sopenharmony_ci */ 39378c2ecf20Sopenharmony_ciint btrfs_qgroup_release_data(struct btrfs_inode *inode, u64 start, u64 len) 39388c2ecf20Sopenharmony_ci{ 39398c2ecf20Sopenharmony_ci return __btrfs_qgroup_release_data(inode, NULL, start, len, 0); 39408c2ecf20Sopenharmony_ci} 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_cistatic void add_root_meta_rsv(struct btrfs_root *root, int num_bytes, 39438c2ecf20Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 39448c2ecf20Sopenharmony_ci{ 39458c2ecf20Sopenharmony_ci if (type != BTRFS_QGROUP_RSV_META_PREALLOC && 39468c2ecf20Sopenharmony_ci type != BTRFS_QGROUP_RSV_META_PERTRANS) 39478c2ecf20Sopenharmony_ci return; 39488c2ecf20Sopenharmony_ci if (num_bytes == 0) 39498c2ecf20Sopenharmony_ci return; 39508c2ecf20Sopenharmony_ci 39518c2ecf20Sopenharmony_ci spin_lock(&root->qgroup_meta_rsv_lock); 39528c2ecf20Sopenharmony_ci if (type == BTRFS_QGROUP_RSV_META_PREALLOC) 39538c2ecf20Sopenharmony_ci root->qgroup_meta_rsv_prealloc += num_bytes; 39548c2ecf20Sopenharmony_ci else 39558c2ecf20Sopenharmony_ci root->qgroup_meta_rsv_pertrans += num_bytes; 39568c2ecf20Sopenharmony_ci spin_unlock(&root->qgroup_meta_rsv_lock); 39578c2ecf20Sopenharmony_ci} 39588c2ecf20Sopenharmony_ci 39598c2ecf20Sopenharmony_cistatic int sub_root_meta_rsv(struct btrfs_root *root, int num_bytes, 39608c2ecf20Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 39618c2ecf20Sopenharmony_ci{ 39628c2ecf20Sopenharmony_ci if (type != BTRFS_QGROUP_RSV_META_PREALLOC && 39638c2ecf20Sopenharmony_ci type != BTRFS_QGROUP_RSV_META_PERTRANS) 39648c2ecf20Sopenharmony_ci return 0; 39658c2ecf20Sopenharmony_ci if (num_bytes == 0) 39668c2ecf20Sopenharmony_ci return 0; 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci spin_lock(&root->qgroup_meta_rsv_lock); 39698c2ecf20Sopenharmony_ci if (type == BTRFS_QGROUP_RSV_META_PREALLOC) { 39708c2ecf20Sopenharmony_ci num_bytes = min_t(u64, root->qgroup_meta_rsv_prealloc, 39718c2ecf20Sopenharmony_ci num_bytes); 39728c2ecf20Sopenharmony_ci root->qgroup_meta_rsv_prealloc -= num_bytes; 39738c2ecf20Sopenharmony_ci } else { 39748c2ecf20Sopenharmony_ci num_bytes = min_t(u64, root->qgroup_meta_rsv_pertrans, 39758c2ecf20Sopenharmony_ci num_bytes); 39768c2ecf20Sopenharmony_ci root->qgroup_meta_rsv_pertrans -= num_bytes; 39778c2ecf20Sopenharmony_ci } 39788c2ecf20Sopenharmony_ci spin_unlock(&root->qgroup_meta_rsv_lock); 39798c2ecf20Sopenharmony_ci return num_bytes; 39808c2ecf20Sopenharmony_ci} 39818c2ecf20Sopenharmony_ci 39828c2ecf20Sopenharmony_ciint btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, 39838c2ecf20Sopenharmony_ci enum btrfs_qgroup_rsv_type type, bool enforce) 39848c2ecf20Sopenharmony_ci{ 39858c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 39868c2ecf20Sopenharmony_ci int ret; 39878c2ecf20Sopenharmony_ci 39888c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || 39898c2ecf20Sopenharmony_ci !is_fstree(root->root_key.objectid) || num_bytes == 0) 39908c2ecf20Sopenharmony_ci return 0; 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize)); 39938c2ecf20Sopenharmony_ci trace_qgroup_meta_reserve(root, (s64)num_bytes, type); 39948c2ecf20Sopenharmony_ci ret = qgroup_reserve(root, num_bytes, enforce, type); 39958c2ecf20Sopenharmony_ci if (ret < 0) 39968c2ecf20Sopenharmony_ci return ret; 39978c2ecf20Sopenharmony_ci /* 39988c2ecf20Sopenharmony_ci * Record what we have reserved into root. 39998c2ecf20Sopenharmony_ci * 40008c2ecf20Sopenharmony_ci * To avoid quota disabled->enabled underflow. 40018c2ecf20Sopenharmony_ci * In that case, we may try to free space we haven't reserved 40028c2ecf20Sopenharmony_ci * (since quota was disabled), so record what we reserved into root. 40038c2ecf20Sopenharmony_ci * And ensure later release won't underflow this number. 40048c2ecf20Sopenharmony_ci */ 40058c2ecf20Sopenharmony_ci add_root_meta_rsv(root, num_bytes, type); 40068c2ecf20Sopenharmony_ci return ret; 40078c2ecf20Sopenharmony_ci} 40088c2ecf20Sopenharmony_ci 40098c2ecf20Sopenharmony_ciint __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, 40108c2ecf20Sopenharmony_ci enum btrfs_qgroup_rsv_type type, bool enforce) 40118c2ecf20Sopenharmony_ci{ 40128c2ecf20Sopenharmony_ci int ret; 40138c2ecf20Sopenharmony_ci 40148c2ecf20Sopenharmony_ci ret = btrfs_qgroup_reserve_meta(root, num_bytes, type, enforce); 40158c2ecf20Sopenharmony_ci if (ret <= 0 && ret != -EDQUOT) 40168c2ecf20Sopenharmony_ci return ret; 40178c2ecf20Sopenharmony_ci 40188c2ecf20Sopenharmony_ci ret = try_flush_qgroup(root); 40198c2ecf20Sopenharmony_ci if (ret < 0) 40208c2ecf20Sopenharmony_ci return ret; 40218c2ecf20Sopenharmony_ci return btrfs_qgroup_reserve_meta(root, num_bytes, type, enforce); 40228c2ecf20Sopenharmony_ci} 40238c2ecf20Sopenharmony_ci 40248c2ecf20Sopenharmony_civoid btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root) 40258c2ecf20Sopenharmony_ci{ 40268c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || 40298c2ecf20Sopenharmony_ci !is_fstree(root->root_key.objectid)) 40308c2ecf20Sopenharmony_ci return; 40318c2ecf20Sopenharmony_ci 40328c2ecf20Sopenharmony_ci /* TODO: Update trace point to handle such free */ 40338c2ecf20Sopenharmony_ci trace_qgroup_meta_free_all_pertrans(root); 40348c2ecf20Sopenharmony_ci /* Special value -1 means to free all reserved space */ 40358c2ecf20Sopenharmony_ci btrfs_qgroup_free_refroot(fs_info, root->root_key.objectid, (u64)-1, 40368c2ecf20Sopenharmony_ci BTRFS_QGROUP_RSV_META_PERTRANS); 40378c2ecf20Sopenharmony_ci} 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_civoid __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes, 40408c2ecf20Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 40418c2ecf20Sopenharmony_ci{ 40428c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || 40458c2ecf20Sopenharmony_ci !is_fstree(root->root_key.objectid)) 40468c2ecf20Sopenharmony_ci return; 40478c2ecf20Sopenharmony_ci 40488c2ecf20Sopenharmony_ci /* 40498c2ecf20Sopenharmony_ci * reservation for META_PREALLOC can happen before quota is enabled, 40508c2ecf20Sopenharmony_ci * which can lead to underflow. 40518c2ecf20Sopenharmony_ci * Here ensure we will only free what we really have reserved. 40528c2ecf20Sopenharmony_ci */ 40538c2ecf20Sopenharmony_ci num_bytes = sub_root_meta_rsv(root, num_bytes, type); 40548c2ecf20Sopenharmony_ci BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize)); 40558c2ecf20Sopenharmony_ci trace_qgroup_meta_reserve(root, -(s64)num_bytes, type); 40568c2ecf20Sopenharmony_ci btrfs_qgroup_free_refroot(fs_info, root->root_key.objectid, 40578c2ecf20Sopenharmony_ci num_bytes, type); 40588c2ecf20Sopenharmony_ci} 40598c2ecf20Sopenharmony_ci 40608c2ecf20Sopenharmony_cistatic void qgroup_convert_meta(struct btrfs_fs_info *fs_info, u64 ref_root, 40618c2ecf20Sopenharmony_ci int num_bytes) 40628c2ecf20Sopenharmony_ci{ 40638c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 40648c2ecf20Sopenharmony_ci struct ulist_node *unode; 40658c2ecf20Sopenharmony_ci struct ulist_iterator uiter; 40668c2ecf20Sopenharmony_ci int ret = 0; 40678c2ecf20Sopenharmony_ci 40688c2ecf20Sopenharmony_ci if (num_bytes == 0) 40698c2ecf20Sopenharmony_ci return; 40708c2ecf20Sopenharmony_ci if (!fs_info->quota_root) 40718c2ecf20Sopenharmony_ci return; 40728c2ecf20Sopenharmony_ci 40738c2ecf20Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 40748c2ecf20Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, ref_root); 40758c2ecf20Sopenharmony_ci if (!qgroup) 40768c2ecf20Sopenharmony_ci goto out; 40778c2ecf20Sopenharmony_ci ulist_reinit(fs_info->qgroup_ulist); 40788c2ecf20Sopenharmony_ci ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid, 40798c2ecf20Sopenharmony_ci qgroup_to_aux(qgroup), GFP_ATOMIC); 40808c2ecf20Sopenharmony_ci if (ret < 0) 40818c2ecf20Sopenharmony_ci goto out; 40828c2ecf20Sopenharmony_ci ULIST_ITER_INIT(&uiter); 40838c2ecf20Sopenharmony_ci while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { 40848c2ecf20Sopenharmony_ci struct btrfs_qgroup *qg; 40858c2ecf20Sopenharmony_ci struct btrfs_qgroup_list *glist; 40868c2ecf20Sopenharmony_ci 40878c2ecf20Sopenharmony_ci qg = unode_aux_to_qgroup(unode); 40888c2ecf20Sopenharmony_ci 40898c2ecf20Sopenharmony_ci qgroup_rsv_release(fs_info, qg, num_bytes, 40908c2ecf20Sopenharmony_ci BTRFS_QGROUP_RSV_META_PREALLOC); 40918c2ecf20Sopenharmony_ci qgroup_rsv_add(fs_info, qg, num_bytes, 40928c2ecf20Sopenharmony_ci BTRFS_QGROUP_RSV_META_PERTRANS); 40938c2ecf20Sopenharmony_ci list_for_each_entry(glist, &qg->groups, next_group) { 40948c2ecf20Sopenharmony_ci ret = ulist_add(fs_info->qgroup_ulist, 40958c2ecf20Sopenharmony_ci glist->group->qgroupid, 40968c2ecf20Sopenharmony_ci qgroup_to_aux(glist->group), GFP_ATOMIC); 40978c2ecf20Sopenharmony_ci if (ret < 0) 40988c2ecf20Sopenharmony_ci goto out; 40998c2ecf20Sopenharmony_ci } 41008c2ecf20Sopenharmony_ci } 41018c2ecf20Sopenharmony_ciout: 41028c2ecf20Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 41038c2ecf20Sopenharmony_ci} 41048c2ecf20Sopenharmony_ci 41058c2ecf20Sopenharmony_civoid btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes) 41068c2ecf20Sopenharmony_ci{ 41078c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 41088c2ecf20Sopenharmony_ci 41098c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || 41108c2ecf20Sopenharmony_ci !is_fstree(root->root_key.objectid)) 41118c2ecf20Sopenharmony_ci return; 41128c2ecf20Sopenharmony_ci /* Same as btrfs_qgroup_free_meta_prealloc() */ 41138c2ecf20Sopenharmony_ci num_bytes = sub_root_meta_rsv(root, num_bytes, 41148c2ecf20Sopenharmony_ci BTRFS_QGROUP_RSV_META_PREALLOC); 41158c2ecf20Sopenharmony_ci trace_qgroup_meta_convert(root, num_bytes); 41168c2ecf20Sopenharmony_ci qgroup_convert_meta(fs_info, root->root_key.objectid, num_bytes); 41178c2ecf20Sopenharmony_ci} 41188c2ecf20Sopenharmony_ci 41198c2ecf20Sopenharmony_ci/* 41208c2ecf20Sopenharmony_ci * Check qgroup reserved space leaking, normally at destroy inode 41218c2ecf20Sopenharmony_ci * time 41228c2ecf20Sopenharmony_ci */ 41238c2ecf20Sopenharmony_civoid btrfs_qgroup_check_reserved_leak(struct btrfs_inode *inode) 41248c2ecf20Sopenharmony_ci{ 41258c2ecf20Sopenharmony_ci struct extent_changeset changeset; 41268c2ecf20Sopenharmony_ci struct ulist_node *unode; 41278c2ecf20Sopenharmony_ci struct ulist_iterator iter; 41288c2ecf20Sopenharmony_ci int ret; 41298c2ecf20Sopenharmony_ci 41308c2ecf20Sopenharmony_ci extent_changeset_init(&changeset); 41318c2ecf20Sopenharmony_ci ret = clear_record_extent_bits(&inode->io_tree, 0, (u64)-1, 41328c2ecf20Sopenharmony_ci EXTENT_QGROUP_RESERVED, &changeset); 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_ci WARN_ON(ret < 0); 41358c2ecf20Sopenharmony_ci if (WARN_ON(changeset.bytes_changed)) { 41368c2ecf20Sopenharmony_ci ULIST_ITER_INIT(&iter); 41378c2ecf20Sopenharmony_ci while ((unode = ulist_next(&changeset.range_changed, &iter))) { 41388c2ecf20Sopenharmony_ci btrfs_warn(inode->root->fs_info, 41398c2ecf20Sopenharmony_ci "leaking qgroup reserved space, ino: %llu, start: %llu, end: %llu", 41408c2ecf20Sopenharmony_ci btrfs_ino(inode), unode->val, unode->aux); 41418c2ecf20Sopenharmony_ci } 41428c2ecf20Sopenharmony_ci btrfs_qgroup_free_refroot(inode->root->fs_info, 41438c2ecf20Sopenharmony_ci inode->root->root_key.objectid, 41448c2ecf20Sopenharmony_ci changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA); 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci } 41478c2ecf20Sopenharmony_ci extent_changeset_release(&changeset); 41488c2ecf20Sopenharmony_ci} 41498c2ecf20Sopenharmony_ci 41508c2ecf20Sopenharmony_civoid btrfs_qgroup_init_swapped_blocks( 41518c2ecf20Sopenharmony_ci struct btrfs_qgroup_swapped_blocks *swapped_blocks) 41528c2ecf20Sopenharmony_ci{ 41538c2ecf20Sopenharmony_ci int i; 41548c2ecf20Sopenharmony_ci 41558c2ecf20Sopenharmony_ci spin_lock_init(&swapped_blocks->lock); 41568c2ecf20Sopenharmony_ci for (i = 0; i < BTRFS_MAX_LEVEL; i++) 41578c2ecf20Sopenharmony_ci swapped_blocks->blocks[i] = RB_ROOT; 41588c2ecf20Sopenharmony_ci swapped_blocks->swapped = false; 41598c2ecf20Sopenharmony_ci} 41608c2ecf20Sopenharmony_ci 41618c2ecf20Sopenharmony_ci/* 41628c2ecf20Sopenharmony_ci * Delete all swapped blocks record of @root. 41638c2ecf20Sopenharmony_ci * Every record here means we skipped a full subtree scan for qgroup. 41648c2ecf20Sopenharmony_ci * 41658c2ecf20Sopenharmony_ci * Gets called when committing one transaction. 41668c2ecf20Sopenharmony_ci */ 41678c2ecf20Sopenharmony_civoid btrfs_qgroup_clean_swapped_blocks(struct btrfs_root *root) 41688c2ecf20Sopenharmony_ci{ 41698c2ecf20Sopenharmony_ci struct btrfs_qgroup_swapped_blocks *swapped_blocks; 41708c2ecf20Sopenharmony_ci int i; 41718c2ecf20Sopenharmony_ci 41728c2ecf20Sopenharmony_ci swapped_blocks = &root->swapped_blocks; 41738c2ecf20Sopenharmony_ci 41748c2ecf20Sopenharmony_ci spin_lock(&swapped_blocks->lock); 41758c2ecf20Sopenharmony_ci if (!swapped_blocks->swapped) 41768c2ecf20Sopenharmony_ci goto out; 41778c2ecf20Sopenharmony_ci for (i = 0; i < BTRFS_MAX_LEVEL; i++) { 41788c2ecf20Sopenharmony_ci struct rb_root *cur_root = &swapped_blocks->blocks[i]; 41798c2ecf20Sopenharmony_ci struct btrfs_qgroup_swapped_block *entry; 41808c2ecf20Sopenharmony_ci struct btrfs_qgroup_swapped_block *next; 41818c2ecf20Sopenharmony_ci 41828c2ecf20Sopenharmony_ci rbtree_postorder_for_each_entry_safe(entry, next, cur_root, 41838c2ecf20Sopenharmony_ci node) 41848c2ecf20Sopenharmony_ci kfree(entry); 41858c2ecf20Sopenharmony_ci swapped_blocks->blocks[i] = RB_ROOT; 41868c2ecf20Sopenharmony_ci } 41878c2ecf20Sopenharmony_ci swapped_blocks->swapped = false; 41888c2ecf20Sopenharmony_ciout: 41898c2ecf20Sopenharmony_ci spin_unlock(&swapped_blocks->lock); 41908c2ecf20Sopenharmony_ci} 41918c2ecf20Sopenharmony_ci 41928c2ecf20Sopenharmony_ci/* 41938c2ecf20Sopenharmony_ci * Add subtree roots record into @subvol_root. 41948c2ecf20Sopenharmony_ci * 41958c2ecf20Sopenharmony_ci * @subvol_root: tree root of the subvolume tree get swapped 41968c2ecf20Sopenharmony_ci * @bg: block group under balance 41978c2ecf20Sopenharmony_ci * @subvol_parent/slot: pointer to the subtree root in subvolume tree 41988c2ecf20Sopenharmony_ci * @reloc_parent/slot: pointer to the subtree root in reloc tree 41998c2ecf20Sopenharmony_ci * BOTH POINTERS ARE BEFORE TREE SWAP 42008c2ecf20Sopenharmony_ci * @last_snapshot: last snapshot generation of the subvolume tree 42018c2ecf20Sopenharmony_ci */ 42028c2ecf20Sopenharmony_ciint btrfs_qgroup_add_swapped_blocks(struct btrfs_trans_handle *trans, 42038c2ecf20Sopenharmony_ci struct btrfs_root *subvol_root, 42048c2ecf20Sopenharmony_ci struct btrfs_block_group *bg, 42058c2ecf20Sopenharmony_ci struct extent_buffer *subvol_parent, int subvol_slot, 42068c2ecf20Sopenharmony_ci struct extent_buffer *reloc_parent, int reloc_slot, 42078c2ecf20Sopenharmony_ci u64 last_snapshot) 42088c2ecf20Sopenharmony_ci{ 42098c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = subvol_root->fs_info; 42108c2ecf20Sopenharmony_ci struct btrfs_qgroup_swapped_blocks *blocks = &subvol_root->swapped_blocks; 42118c2ecf20Sopenharmony_ci struct btrfs_qgroup_swapped_block *block; 42128c2ecf20Sopenharmony_ci struct rb_node **cur; 42138c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 42148c2ecf20Sopenharmony_ci int level = btrfs_header_level(subvol_parent) - 1; 42158c2ecf20Sopenharmony_ci int ret = 0; 42168c2ecf20Sopenharmony_ci 42178c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 42188c2ecf20Sopenharmony_ci return 0; 42198c2ecf20Sopenharmony_ci 42208c2ecf20Sopenharmony_ci if (btrfs_node_ptr_generation(subvol_parent, subvol_slot) > 42218c2ecf20Sopenharmony_ci btrfs_node_ptr_generation(reloc_parent, reloc_slot)) { 42228c2ecf20Sopenharmony_ci btrfs_err_rl(fs_info, 42238c2ecf20Sopenharmony_ci "%s: bad parameter order, subvol_gen=%llu reloc_gen=%llu", 42248c2ecf20Sopenharmony_ci __func__, 42258c2ecf20Sopenharmony_ci btrfs_node_ptr_generation(subvol_parent, subvol_slot), 42268c2ecf20Sopenharmony_ci btrfs_node_ptr_generation(reloc_parent, reloc_slot)); 42278c2ecf20Sopenharmony_ci return -EUCLEAN; 42288c2ecf20Sopenharmony_ci } 42298c2ecf20Sopenharmony_ci 42308c2ecf20Sopenharmony_ci block = kmalloc(sizeof(*block), GFP_NOFS); 42318c2ecf20Sopenharmony_ci if (!block) { 42328c2ecf20Sopenharmony_ci ret = -ENOMEM; 42338c2ecf20Sopenharmony_ci goto out; 42348c2ecf20Sopenharmony_ci } 42358c2ecf20Sopenharmony_ci 42368c2ecf20Sopenharmony_ci /* 42378c2ecf20Sopenharmony_ci * @reloc_parent/slot is still before swap, while @block is going to 42388c2ecf20Sopenharmony_ci * record the bytenr after swap, so we do the swap here. 42398c2ecf20Sopenharmony_ci */ 42408c2ecf20Sopenharmony_ci block->subvol_bytenr = btrfs_node_blockptr(reloc_parent, reloc_slot); 42418c2ecf20Sopenharmony_ci block->subvol_generation = btrfs_node_ptr_generation(reloc_parent, 42428c2ecf20Sopenharmony_ci reloc_slot); 42438c2ecf20Sopenharmony_ci block->reloc_bytenr = btrfs_node_blockptr(subvol_parent, subvol_slot); 42448c2ecf20Sopenharmony_ci block->reloc_generation = btrfs_node_ptr_generation(subvol_parent, 42458c2ecf20Sopenharmony_ci subvol_slot); 42468c2ecf20Sopenharmony_ci block->last_snapshot = last_snapshot; 42478c2ecf20Sopenharmony_ci block->level = level; 42488c2ecf20Sopenharmony_ci 42498c2ecf20Sopenharmony_ci /* 42508c2ecf20Sopenharmony_ci * If we have bg == NULL, we're called from btrfs_recover_relocation(), 42518c2ecf20Sopenharmony_ci * no one else can modify tree blocks thus we qgroup will not change 42528c2ecf20Sopenharmony_ci * no matter the value of trace_leaf. 42538c2ecf20Sopenharmony_ci */ 42548c2ecf20Sopenharmony_ci if (bg && bg->flags & BTRFS_BLOCK_GROUP_DATA) 42558c2ecf20Sopenharmony_ci block->trace_leaf = true; 42568c2ecf20Sopenharmony_ci else 42578c2ecf20Sopenharmony_ci block->trace_leaf = false; 42588c2ecf20Sopenharmony_ci btrfs_node_key_to_cpu(reloc_parent, &block->first_key, reloc_slot); 42598c2ecf20Sopenharmony_ci 42608c2ecf20Sopenharmony_ci /* Insert @block into @blocks */ 42618c2ecf20Sopenharmony_ci spin_lock(&blocks->lock); 42628c2ecf20Sopenharmony_ci cur = &blocks->blocks[level].rb_node; 42638c2ecf20Sopenharmony_ci while (*cur) { 42648c2ecf20Sopenharmony_ci struct btrfs_qgroup_swapped_block *entry; 42658c2ecf20Sopenharmony_ci 42668c2ecf20Sopenharmony_ci parent = *cur; 42678c2ecf20Sopenharmony_ci entry = rb_entry(parent, struct btrfs_qgroup_swapped_block, 42688c2ecf20Sopenharmony_ci node); 42698c2ecf20Sopenharmony_ci 42708c2ecf20Sopenharmony_ci if (entry->subvol_bytenr < block->subvol_bytenr) { 42718c2ecf20Sopenharmony_ci cur = &(*cur)->rb_left; 42728c2ecf20Sopenharmony_ci } else if (entry->subvol_bytenr > block->subvol_bytenr) { 42738c2ecf20Sopenharmony_ci cur = &(*cur)->rb_right; 42748c2ecf20Sopenharmony_ci } else { 42758c2ecf20Sopenharmony_ci if (entry->subvol_generation != 42768c2ecf20Sopenharmony_ci block->subvol_generation || 42778c2ecf20Sopenharmony_ci entry->reloc_bytenr != block->reloc_bytenr || 42788c2ecf20Sopenharmony_ci entry->reloc_generation != 42798c2ecf20Sopenharmony_ci block->reloc_generation) { 42808c2ecf20Sopenharmony_ci /* 42818c2ecf20Sopenharmony_ci * Duplicated but mismatch entry found. 42828c2ecf20Sopenharmony_ci * Shouldn't happen. 42838c2ecf20Sopenharmony_ci * 42848c2ecf20Sopenharmony_ci * Marking qgroup inconsistent should be enough 42858c2ecf20Sopenharmony_ci * for end users. 42868c2ecf20Sopenharmony_ci */ 42878c2ecf20Sopenharmony_ci WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG)); 42888c2ecf20Sopenharmony_ci ret = -EEXIST; 42898c2ecf20Sopenharmony_ci } 42908c2ecf20Sopenharmony_ci kfree(block); 42918c2ecf20Sopenharmony_ci goto out_unlock; 42928c2ecf20Sopenharmony_ci } 42938c2ecf20Sopenharmony_ci } 42948c2ecf20Sopenharmony_ci rb_link_node(&block->node, parent, cur); 42958c2ecf20Sopenharmony_ci rb_insert_color(&block->node, &blocks->blocks[level]); 42968c2ecf20Sopenharmony_ci blocks->swapped = true; 42978c2ecf20Sopenharmony_ciout_unlock: 42988c2ecf20Sopenharmony_ci spin_unlock(&blocks->lock); 42998c2ecf20Sopenharmony_ciout: 43008c2ecf20Sopenharmony_ci if (ret < 0) 43018c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= 43028c2ecf20Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 43038c2ecf20Sopenharmony_ci return ret; 43048c2ecf20Sopenharmony_ci} 43058c2ecf20Sopenharmony_ci 43068c2ecf20Sopenharmony_ci/* 43078c2ecf20Sopenharmony_ci * Check if the tree block is a subtree root, and if so do the needed 43088c2ecf20Sopenharmony_ci * delayed subtree trace for qgroup. 43098c2ecf20Sopenharmony_ci * 43108c2ecf20Sopenharmony_ci * This is called during btrfs_cow_block(). 43118c2ecf20Sopenharmony_ci */ 43128c2ecf20Sopenharmony_ciint btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans, 43138c2ecf20Sopenharmony_ci struct btrfs_root *root, 43148c2ecf20Sopenharmony_ci struct extent_buffer *subvol_eb) 43158c2ecf20Sopenharmony_ci{ 43168c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 43178c2ecf20Sopenharmony_ci struct btrfs_qgroup_swapped_blocks *blocks = &root->swapped_blocks; 43188c2ecf20Sopenharmony_ci struct btrfs_qgroup_swapped_block *block; 43198c2ecf20Sopenharmony_ci struct extent_buffer *reloc_eb = NULL; 43208c2ecf20Sopenharmony_ci struct rb_node *node; 43218c2ecf20Sopenharmony_ci bool found = false; 43228c2ecf20Sopenharmony_ci bool swapped = false; 43238c2ecf20Sopenharmony_ci int level = btrfs_header_level(subvol_eb); 43248c2ecf20Sopenharmony_ci int ret = 0; 43258c2ecf20Sopenharmony_ci int i; 43268c2ecf20Sopenharmony_ci 43278c2ecf20Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 43288c2ecf20Sopenharmony_ci return 0; 43298c2ecf20Sopenharmony_ci if (!is_fstree(root->root_key.objectid) || !root->reloc_root) 43308c2ecf20Sopenharmony_ci return 0; 43318c2ecf20Sopenharmony_ci 43328c2ecf20Sopenharmony_ci spin_lock(&blocks->lock); 43338c2ecf20Sopenharmony_ci if (!blocks->swapped) { 43348c2ecf20Sopenharmony_ci spin_unlock(&blocks->lock); 43358c2ecf20Sopenharmony_ci return 0; 43368c2ecf20Sopenharmony_ci } 43378c2ecf20Sopenharmony_ci node = blocks->blocks[level].rb_node; 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci while (node) { 43408c2ecf20Sopenharmony_ci block = rb_entry(node, struct btrfs_qgroup_swapped_block, node); 43418c2ecf20Sopenharmony_ci if (block->subvol_bytenr < subvol_eb->start) { 43428c2ecf20Sopenharmony_ci node = node->rb_left; 43438c2ecf20Sopenharmony_ci } else if (block->subvol_bytenr > subvol_eb->start) { 43448c2ecf20Sopenharmony_ci node = node->rb_right; 43458c2ecf20Sopenharmony_ci } else { 43468c2ecf20Sopenharmony_ci found = true; 43478c2ecf20Sopenharmony_ci break; 43488c2ecf20Sopenharmony_ci } 43498c2ecf20Sopenharmony_ci } 43508c2ecf20Sopenharmony_ci if (!found) { 43518c2ecf20Sopenharmony_ci spin_unlock(&blocks->lock); 43528c2ecf20Sopenharmony_ci goto out; 43538c2ecf20Sopenharmony_ci } 43548c2ecf20Sopenharmony_ci /* Found one, remove it from @blocks first and update blocks->swapped */ 43558c2ecf20Sopenharmony_ci rb_erase(&block->node, &blocks->blocks[level]); 43568c2ecf20Sopenharmony_ci for (i = 0; i < BTRFS_MAX_LEVEL; i++) { 43578c2ecf20Sopenharmony_ci if (RB_EMPTY_ROOT(&blocks->blocks[i])) { 43588c2ecf20Sopenharmony_ci swapped = true; 43598c2ecf20Sopenharmony_ci break; 43608c2ecf20Sopenharmony_ci } 43618c2ecf20Sopenharmony_ci } 43628c2ecf20Sopenharmony_ci blocks->swapped = swapped; 43638c2ecf20Sopenharmony_ci spin_unlock(&blocks->lock); 43648c2ecf20Sopenharmony_ci 43658c2ecf20Sopenharmony_ci /* Read out reloc subtree root */ 43668c2ecf20Sopenharmony_ci reloc_eb = read_tree_block(fs_info, block->reloc_bytenr, 43678c2ecf20Sopenharmony_ci block->reloc_generation, block->level, 43688c2ecf20Sopenharmony_ci &block->first_key); 43698c2ecf20Sopenharmony_ci if (IS_ERR(reloc_eb)) { 43708c2ecf20Sopenharmony_ci ret = PTR_ERR(reloc_eb); 43718c2ecf20Sopenharmony_ci reloc_eb = NULL; 43728c2ecf20Sopenharmony_ci goto free_out; 43738c2ecf20Sopenharmony_ci } 43748c2ecf20Sopenharmony_ci if (!extent_buffer_uptodate(reloc_eb)) { 43758c2ecf20Sopenharmony_ci ret = -EIO; 43768c2ecf20Sopenharmony_ci goto free_out; 43778c2ecf20Sopenharmony_ci } 43788c2ecf20Sopenharmony_ci 43798c2ecf20Sopenharmony_ci ret = qgroup_trace_subtree_swap(trans, reloc_eb, subvol_eb, 43808c2ecf20Sopenharmony_ci block->last_snapshot, block->trace_leaf); 43818c2ecf20Sopenharmony_cifree_out: 43828c2ecf20Sopenharmony_ci kfree(block); 43838c2ecf20Sopenharmony_ci free_extent_buffer(reloc_eb); 43848c2ecf20Sopenharmony_ciout: 43858c2ecf20Sopenharmony_ci if (ret < 0) { 43868c2ecf20Sopenharmony_ci btrfs_err_rl(fs_info, 43878c2ecf20Sopenharmony_ci "failed to account subtree at bytenr %llu: %d", 43888c2ecf20Sopenharmony_ci subvol_eb->start, ret); 43898c2ecf20Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 43908c2ecf20Sopenharmony_ci } 43918c2ecf20Sopenharmony_ci return ret; 43928c2ecf20Sopenharmony_ci} 43938c2ecf20Sopenharmony_ci 43948c2ecf20Sopenharmony_civoid btrfs_qgroup_destroy_extent_records(struct btrfs_transaction *trans) 43958c2ecf20Sopenharmony_ci{ 43968c2ecf20Sopenharmony_ci struct btrfs_qgroup_extent_record *entry; 43978c2ecf20Sopenharmony_ci struct btrfs_qgroup_extent_record *next; 43988c2ecf20Sopenharmony_ci struct rb_root *root; 43998c2ecf20Sopenharmony_ci 44008c2ecf20Sopenharmony_ci root = &trans->delayed_refs.dirty_extent_root; 44018c2ecf20Sopenharmony_ci rbtree_postorder_for_each_entry_safe(entry, next, root, node) { 44028c2ecf20Sopenharmony_ci ulist_free(entry->old_roots); 44038c2ecf20Sopenharmony_ci kfree(entry); 44048c2ecf20Sopenharmony_ci } 44058c2ecf20Sopenharmony_ci *root = RB_ROOT; 44068c2ecf20Sopenharmony_ci} 4407