162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2011 STRATO. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/sched.h> 762306a36Sopenharmony_ci#include <linux/pagemap.h> 862306a36Sopenharmony_ci#include <linux/writeback.h> 962306a36Sopenharmony_ci#include <linux/blkdev.h> 1062306a36Sopenharmony_ci#include <linux/rbtree.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/workqueue.h> 1362306a36Sopenharmony_ci#include <linux/btrfs.h> 1462306a36Sopenharmony_ci#include <linux/sched/mm.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "ctree.h" 1762306a36Sopenharmony_ci#include "transaction.h" 1862306a36Sopenharmony_ci#include "disk-io.h" 1962306a36Sopenharmony_ci#include "locking.h" 2062306a36Sopenharmony_ci#include "ulist.h" 2162306a36Sopenharmony_ci#include "backref.h" 2262306a36Sopenharmony_ci#include "extent_io.h" 2362306a36Sopenharmony_ci#include "qgroup.h" 2462306a36Sopenharmony_ci#include "block-group.h" 2562306a36Sopenharmony_ci#include "sysfs.h" 2662306a36Sopenharmony_ci#include "tree-mod-log.h" 2762306a36Sopenharmony_ci#include "fs.h" 2862306a36Sopenharmony_ci#include "accessors.h" 2962306a36Sopenharmony_ci#include "extent-tree.h" 3062306a36Sopenharmony_ci#include "root-tree.h" 3162306a36Sopenharmony_ci#include "tree-checker.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * Helpers to access qgroup reservation 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * Callers should ensure the lock context and type are valid 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic u64 qgroup_rsv_total(const struct btrfs_qgroup *qgroup) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci u64 ret = 0; 4262306a36Sopenharmony_ci int i; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++) 4562306a36Sopenharmony_ci ret += qgroup->rsv.values[i]; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci return ret; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#ifdef CONFIG_BTRFS_DEBUG 5162306a36Sopenharmony_cistatic const char *qgroup_rsv_type_str(enum btrfs_qgroup_rsv_type type) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci if (type == BTRFS_QGROUP_RSV_DATA) 5462306a36Sopenharmony_ci return "data"; 5562306a36Sopenharmony_ci if (type == BTRFS_QGROUP_RSV_META_PERTRANS) 5662306a36Sopenharmony_ci return "meta_pertrans"; 5762306a36Sopenharmony_ci if (type == BTRFS_QGROUP_RSV_META_PREALLOC) 5862306a36Sopenharmony_ci return "meta_prealloc"; 5962306a36Sopenharmony_ci return NULL; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci#endif 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void qgroup_rsv_add(struct btrfs_fs_info *fs_info, 6462306a36Sopenharmony_ci struct btrfs_qgroup *qgroup, u64 num_bytes, 6562306a36Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci trace_qgroup_update_reserve(fs_info, qgroup, num_bytes, type); 6862306a36Sopenharmony_ci qgroup->rsv.values[type] += num_bytes; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void qgroup_rsv_release(struct btrfs_fs_info *fs_info, 7262306a36Sopenharmony_ci struct btrfs_qgroup *qgroup, u64 num_bytes, 7362306a36Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci trace_qgroup_update_reserve(fs_info, qgroup, -(s64)num_bytes, type); 7662306a36Sopenharmony_ci if (qgroup->rsv.values[type] >= num_bytes) { 7762306a36Sopenharmony_ci qgroup->rsv.values[type] -= num_bytes; 7862306a36Sopenharmony_ci return; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci#ifdef CONFIG_BTRFS_DEBUG 8162306a36Sopenharmony_ci WARN_RATELIMIT(1, 8262306a36Sopenharmony_ci "qgroup %llu %s reserved space underflow, have %llu to free %llu", 8362306a36Sopenharmony_ci qgroup->qgroupid, qgroup_rsv_type_str(type), 8462306a36Sopenharmony_ci qgroup->rsv.values[type], num_bytes); 8562306a36Sopenharmony_ci#endif 8662306a36Sopenharmony_ci qgroup->rsv.values[type] = 0; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void qgroup_rsv_add_by_qgroup(struct btrfs_fs_info *fs_info, 9062306a36Sopenharmony_ci struct btrfs_qgroup *dest, 9162306a36Sopenharmony_ci struct btrfs_qgroup *src) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci int i; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++) 9662306a36Sopenharmony_ci qgroup_rsv_add(fs_info, dest, src->rsv.values[i], i); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void qgroup_rsv_release_by_qgroup(struct btrfs_fs_info *fs_info, 10062306a36Sopenharmony_ci struct btrfs_qgroup *dest, 10162306a36Sopenharmony_ci struct btrfs_qgroup *src) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci int i; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++) 10662306a36Sopenharmony_ci qgroup_rsv_release(fs_info, dest, src->rsv.values[i], i); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void btrfs_qgroup_update_old_refcnt(struct btrfs_qgroup *qg, u64 seq, 11062306a36Sopenharmony_ci int mod) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci if (qg->old_refcnt < seq) 11362306a36Sopenharmony_ci qg->old_refcnt = seq; 11462306a36Sopenharmony_ci qg->old_refcnt += mod; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void btrfs_qgroup_update_new_refcnt(struct btrfs_qgroup *qg, u64 seq, 11862306a36Sopenharmony_ci int mod) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci if (qg->new_refcnt < seq) 12162306a36Sopenharmony_ci qg->new_refcnt = seq; 12262306a36Sopenharmony_ci qg->new_refcnt += mod; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic inline u64 btrfs_qgroup_get_old_refcnt(struct btrfs_qgroup *qg, u64 seq) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci if (qg->old_refcnt < seq) 12862306a36Sopenharmony_ci return 0; 12962306a36Sopenharmony_ci return qg->old_refcnt - seq; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic inline u64 btrfs_qgroup_get_new_refcnt(struct btrfs_qgroup *qg, u64 seq) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci if (qg->new_refcnt < seq) 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci return qg->new_refcnt - seq; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* 14062306a36Sopenharmony_ci * glue structure to represent the relations between qgroups. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_cistruct btrfs_qgroup_list { 14362306a36Sopenharmony_ci struct list_head next_group; 14462306a36Sopenharmony_ci struct list_head next_member; 14562306a36Sopenharmony_ci struct btrfs_qgroup *group; 14662306a36Sopenharmony_ci struct btrfs_qgroup *member; 14762306a36Sopenharmony_ci}; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic inline u64 qgroup_to_aux(struct btrfs_qgroup *qg) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci return (u64)(uintptr_t)qg; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic inline struct btrfs_qgroup* unode_aux_to_qgroup(struct ulist_node *n) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci return (struct btrfs_qgroup *)(uintptr_t)n->aux; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic int 16062306a36Sopenharmony_ciqgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, 16162306a36Sopenharmony_ci int init_flags); 16262306a36Sopenharmony_cistatic void qgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* must be called with qgroup_ioctl_lock held */ 16562306a36Sopenharmony_cistatic struct btrfs_qgroup *find_qgroup_rb(struct btrfs_fs_info *fs_info, 16662306a36Sopenharmony_ci u64 qgroupid) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct rb_node *n = fs_info->qgroup_tree.rb_node; 16962306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci while (n) { 17262306a36Sopenharmony_ci qgroup = rb_entry(n, struct btrfs_qgroup, node); 17362306a36Sopenharmony_ci if (qgroup->qgroupid < qgroupid) 17462306a36Sopenharmony_ci n = n->rb_left; 17562306a36Sopenharmony_ci else if (qgroup->qgroupid > qgroupid) 17662306a36Sopenharmony_ci n = n->rb_right; 17762306a36Sopenharmony_ci else 17862306a36Sopenharmony_ci return qgroup; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci return NULL; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* must be called with qgroup_lock held */ 18462306a36Sopenharmony_cistatic struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info, 18562306a36Sopenharmony_ci u64 qgroupid) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct rb_node **p = &fs_info->qgroup_tree.rb_node; 18862306a36Sopenharmony_ci struct rb_node *parent = NULL; 18962306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci while (*p) { 19262306a36Sopenharmony_ci parent = *p; 19362306a36Sopenharmony_ci qgroup = rb_entry(parent, struct btrfs_qgroup, node); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (qgroup->qgroupid < qgroupid) 19662306a36Sopenharmony_ci p = &(*p)->rb_left; 19762306a36Sopenharmony_ci else if (qgroup->qgroupid > qgroupid) 19862306a36Sopenharmony_ci p = &(*p)->rb_right; 19962306a36Sopenharmony_ci else 20062306a36Sopenharmony_ci return qgroup; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci qgroup = kzalloc(sizeof(*qgroup), GFP_ATOMIC); 20462306a36Sopenharmony_ci if (!qgroup) 20562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci qgroup->qgroupid = qgroupid; 20862306a36Sopenharmony_ci INIT_LIST_HEAD(&qgroup->groups); 20962306a36Sopenharmony_ci INIT_LIST_HEAD(&qgroup->members); 21062306a36Sopenharmony_ci INIT_LIST_HEAD(&qgroup->dirty); 21162306a36Sopenharmony_ci INIT_LIST_HEAD(&qgroup->iterator); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci rb_link_node(&qgroup->node, parent, p); 21462306a36Sopenharmony_ci rb_insert_color(&qgroup->node, &fs_info->qgroup_tree); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return qgroup; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic void __del_qgroup_rb(struct btrfs_fs_info *fs_info, 22062306a36Sopenharmony_ci struct btrfs_qgroup *qgroup) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct btrfs_qgroup_list *list; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci list_del(&qgroup->dirty); 22562306a36Sopenharmony_ci while (!list_empty(&qgroup->groups)) { 22662306a36Sopenharmony_ci list = list_first_entry(&qgroup->groups, 22762306a36Sopenharmony_ci struct btrfs_qgroup_list, next_group); 22862306a36Sopenharmony_ci list_del(&list->next_group); 22962306a36Sopenharmony_ci list_del(&list->next_member); 23062306a36Sopenharmony_ci kfree(list); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci while (!list_empty(&qgroup->members)) { 23462306a36Sopenharmony_ci list = list_first_entry(&qgroup->members, 23562306a36Sopenharmony_ci struct btrfs_qgroup_list, next_member); 23662306a36Sopenharmony_ci list_del(&list->next_group); 23762306a36Sopenharmony_ci list_del(&list->next_member); 23862306a36Sopenharmony_ci kfree(list); 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* must be called with qgroup_lock held */ 24362306a36Sopenharmony_cistatic int del_qgroup_rb(struct btrfs_fs_info *fs_info, u64 qgroupid) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct btrfs_qgroup *qgroup = find_qgroup_rb(fs_info, qgroupid); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (!qgroup) 24862306a36Sopenharmony_ci return -ENOENT; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci rb_erase(&qgroup->node, &fs_info->qgroup_tree); 25162306a36Sopenharmony_ci __del_qgroup_rb(fs_info, qgroup); 25262306a36Sopenharmony_ci return 0; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/* 25662306a36Sopenharmony_ci * Add relation specified by two qgroups. 25762306a36Sopenharmony_ci * 25862306a36Sopenharmony_ci * Must be called with qgroup_lock held. 25962306a36Sopenharmony_ci * 26062306a36Sopenharmony_ci * Return: 0 on success 26162306a36Sopenharmony_ci * -ENOENT if one of the qgroups is NULL 26262306a36Sopenharmony_ci * <0 other errors 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_cistatic int __add_relation_rb(struct btrfs_qgroup *member, struct btrfs_qgroup *parent) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct btrfs_qgroup_list *list; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!member || !parent) 26962306a36Sopenharmony_ci return -ENOENT; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci list = kzalloc(sizeof(*list), GFP_ATOMIC); 27262306a36Sopenharmony_ci if (!list) 27362306a36Sopenharmony_ci return -ENOMEM; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci list->group = parent; 27662306a36Sopenharmony_ci list->member = member; 27762306a36Sopenharmony_ci list_add_tail(&list->next_group, &member->groups); 27862306a36Sopenharmony_ci list_add_tail(&list->next_member, &parent->members); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* 28462306a36Sopenharmony_ci * Add relation specified by two qgroup ids. 28562306a36Sopenharmony_ci * 28662306a36Sopenharmony_ci * Must be called with qgroup_lock held. 28762306a36Sopenharmony_ci * 28862306a36Sopenharmony_ci * Return: 0 on success 28962306a36Sopenharmony_ci * -ENOENT if one of the ids does not exist 29062306a36Sopenharmony_ci * <0 other errors 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_cistatic int add_relation_rb(struct btrfs_fs_info *fs_info, u64 memberid, u64 parentid) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct btrfs_qgroup *member; 29562306a36Sopenharmony_ci struct btrfs_qgroup *parent; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci member = find_qgroup_rb(fs_info, memberid); 29862306a36Sopenharmony_ci parent = find_qgroup_rb(fs_info, parentid); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci return __add_relation_rb(member, parent); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci/* Must be called with qgroup_lock held */ 30462306a36Sopenharmony_cistatic int del_relation_rb(struct btrfs_fs_info *fs_info, 30562306a36Sopenharmony_ci u64 memberid, u64 parentid) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct btrfs_qgroup *member; 30862306a36Sopenharmony_ci struct btrfs_qgroup *parent; 30962306a36Sopenharmony_ci struct btrfs_qgroup_list *list; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci member = find_qgroup_rb(fs_info, memberid); 31262306a36Sopenharmony_ci parent = find_qgroup_rb(fs_info, parentid); 31362306a36Sopenharmony_ci if (!member || !parent) 31462306a36Sopenharmony_ci return -ENOENT; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci list_for_each_entry(list, &member->groups, next_group) { 31762306a36Sopenharmony_ci if (list->group == parent) { 31862306a36Sopenharmony_ci list_del(&list->next_group); 31962306a36Sopenharmony_ci list_del(&list->next_member); 32062306a36Sopenharmony_ci kfree(list); 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci return -ENOENT; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 32862306a36Sopenharmony_ciint btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid, 32962306a36Sopenharmony_ci u64 rfer, u64 excl) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, qgroupid); 33462306a36Sopenharmony_ci if (!qgroup) 33562306a36Sopenharmony_ci return -EINVAL; 33662306a36Sopenharmony_ci if (qgroup->rfer != rfer || qgroup->excl != excl) 33762306a36Sopenharmony_ci return -EINVAL; 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci#endif 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic void qgroup_mark_inconsistent(struct btrfs_fs_info *fs_info) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci fs_info->qgroup_flags |= (BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT | 34562306a36Sopenharmony_ci BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN | 34662306a36Sopenharmony_ci BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/* 35062306a36Sopenharmony_ci * The full config is read in one go, only called from open_ctree() 35162306a36Sopenharmony_ci * It doesn't use any locking, as at this point we're still single-threaded 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ciint btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct btrfs_key key; 35662306a36Sopenharmony_ci struct btrfs_key found_key; 35762306a36Sopenharmony_ci struct btrfs_root *quota_root = fs_info->quota_root; 35862306a36Sopenharmony_ci struct btrfs_path *path = NULL; 35962306a36Sopenharmony_ci struct extent_buffer *l; 36062306a36Sopenharmony_ci int slot; 36162306a36Sopenharmony_ci int ret = 0; 36262306a36Sopenharmony_ci u64 flags = 0; 36362306a36Sopenharmony_ci u64 rescan_progress = 0; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 36662306a36Sopenharmony_ci return 0; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci fs_info->qgroup_ulist = ulist_alloc(GFP_KERNEL); 36962306a36Sopenharmony_ci if (!fs_info->qgroup_ulist) { 37062306a36Sopenharmony_ci ret = -ENOMEM; 37162306a36Sopenharmony_ci goto out; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci path = btrfs_alloc_path(); 37562306a36Sopenharmony_ci if (!path) { 37662306a36Sopenharmony_ci ret = -ENOMEM; 37762306a36Sopenharmony_ci goto out; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci ret = btrfs_sysfs_add_qgroups(fs_info); 38162306a36Sopenharmony_ci if (ret < 0) 38262306a36Sopenharmony_ci goto out; 38362306a36Sopenharmony_ci /* default this to quota off, in case no status key is found */ 38462306a36Sopenharmony_ci fs_info->qgroup_flags = 0; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* 38762306a36Sopenharmony_ci * pass 1: read status, all qgroup infos and limits 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci key.objectid = 0; 39062306a36Sopenharmony_ci key.type = 0; 39162306a36Sopenharmony_ci key.offset = 0; 39262306a36Sopenharmony_ci ret = btrfs_search_slot_for_read(quota_root, &key, path, 1, 1); 39362306a36Sopenharmony_ci if (ret) 39462306a36Sopenharmony_ci goto out; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci while (1) { 39762306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci slot = path->slots[0]; 40062306a36Sopenharmony_ci l = path->nodes[0]; 40162306a36Sopenharmony_ci btrfs_item_key_to_cpu(l, &found_key, slot); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (found_key.type == BTRFS_QGROUP_STATUS_KEY) { 40462306a36Sopenharmony_ci struct btrfs_qgroup_status_item *ptr; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci ptr = btrfs_item_ptr(l, slot, 40762306a36Sopenharmony_ci struct btrfs_qgroup_status_item); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (btrfs_qgroup_status_version(l, ptr) != 41062306a36Sopenharmony_ci BTRFS_QGROUP_STATUS_VERSION) { 41162306a36Sopenharmony_ci btrfs_err(fs_info, 41262306a36Sopenharmony_ci "old qgroup version, quota disabled"); 41362306a36Sopenharmony_ci goto out; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci if (btrfs_qgroup_status_generation(l, ptr) != 41662306a36Sopenharmony_ci fs_info->generation) { 41762306a36Sopenharmony_ci qgroup_mark_inconsistent(fs_info); 41862306a36Sopenharmony_ci btrfs_err(fs_info, 41962306a36Sopenharmony_ci "qgroup generation mismatch, marked as inconsistent"); 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, 42262306a36Sopenharmony_ci ptr); 42362306a36Sopenharmony_ci rescan_progress = btrfs_qgroup_status_rescan(l, ptr); 42462306a36Sopenharmony_ci goto next1; 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (found_key.type != BTRFS_QGROUP_INFO_KEY && 42862306a36Sopenharmony_ci found_key.type != BTRFS_QGROUP_LIMIT_KEY) 42962306a36Sopenharmony_ci goto next1; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, found_key.offset); 43262306a36Sopenharmony_ci if ((qgroup && found_key.type == BTRFS_QGROUP_INFO_KEY) || 43362306a36Sopenharmony_ci (!qgroup && found_key.type == BTRFS_QGROUP_LIMIT_KEY)) { 43462306a36Sopenharmony_ci btrfs_err(fs_info, "inconsistent qgroup config"); 43562306a36Sopenharmony_ci qgroup_mark_inconsistent(fs_info); 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci if (!qgroup) { 43862306a36Sopenharmony_ci qgroup = add_qgroup_rb(fs_info, found_key.offset); 43962306a36Sopenharmony_ci if (IS_ERR(qgroup)) { 44062306a36Sopenharmony_ci ret = PTR_ERR(qgroup); 44162306a36Sopenharmony_ci goto out; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup); 44562306a36Sopenharmony_ci if (ret < 0) 44662306a36Sopenharmony_ci goto out; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci switch (found_key.type) { 44962306a36Sopenharmony_ci case BTRFS_QGROUP_INFO_KEY: { 45062306a36Sopenharmony_ci struct btrfs_qgroup_info_item *ptr; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci ptr = btrfs_item_ptr(l, slot, 45362306a36Sopenharmony_ci struct btrfs_qgroup_info_item); 45462306a36Sopenharmony_ci qgroup->rfer = btrfs_qgroup_info_rfer(l, ptr); 45562306a36Sopenharmony_ci qgroup->rfer_cmpr = btrfs_qgroup_info_rfer_cmpr(l, ptr); 45662306a36Sopenharmony_ci qgroup->excl = btrfs_qgroup_info_excl(l, ptr); 45762306a36Sopenharmony_ci qgroup->excl_cmpr = btrfs_qgroup_info_excl_cmpr(l, ptr); 45862306a36Sopenharmony_ci /* generation currently unused */ 45962306a36Sopenharmony_ci break; 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci case BTRFS_QGROUP_LIMIT_KEY: { 46262306a36Sopenharmony_ci struct btrfs_qgroup_limit_item *ptr; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci ptr = btrfs_item_ptr(l, slot, 46562306a36Sopenharmony_ci struct btrfs_qgroup_limit_item); 46662306a36Sopenharmony_ci qgroup->lim_flags = btrfs_qgroup_limit_flags(l, ptr); 46762306a36Sopenharmony_ci qgroup->max_rfer = btrfs_qgroup_limit_max_rfer(l, ptr); 46862306a36Sopenharmony_ci qgroup->max_excl = btrfs_qgroup_limit_max_excl(l, ptr); 46962306a36Sopenharmony_ci qgroup->rsv_rfer = btrfs_qgroup_limit_rsv_rfer(l, ptr); 47062306a36Sopenharmony_ci qgroup->rsv_excl = btrfs_qgroup_limit_rsv_excl(l, ptr); 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_cinext1: 47562306a36Sopenharmony_ci ret = btrfs_next_item(quota_root, path); 47662306a36Sopenharmony_ci if (ret < 0) 47762306a36Sopenharmony_ci goto out; 47862306a36Sopenharmony_ci if (ret) 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci btrfs_release_path(path); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci /* 48462306a36Sopenharmony_ci * pass 2: read all qgroup relations 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci key.objectid = 0; 48762306a36Sopenharmony_ci key.type = BTRFS_QGROUP_RELATION_KEY; 48862306a36Sopenharmony_ci key.offset = 0; 48962306a36Sopenharmony_ci ret = btrfs_search_slot_for_read(quota_root, &key, path, 1, 0); 49062306a36Sopenharmony_ci if (ret) 49162306a36Sopenharmony_ci goto out; 49262306a36Sopenharmony_ci while (1) { 49362306a36Sopenharmony_ci slot = path->slots[0]; 49462306a36Sopenharmony_ci l = path->nodes[0]; 49562306a36Sopenharmony_ci btrfs_item_key_to_cpu(l, &found_key, slot); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (found_key.type != BTRFS_QGROUP_RELATION_KEY) 49862306a36Sopenharmony_ci goto next2; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (found_key.objectid > found_key.offset) { 50162306a36Sopenharmony_ci /* parent <- member, not needed to build config */ 50262306a36Sopenharmony_ci /* FIXME should we omit the key completely? */ 50362306a36Sopenharmony_ci goto next2; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci ret = add_relation_rb(fs_info, found_key.objectid, 50762306a36Sopenharmony_ci found_key.offset); 50862306a36Sopenharmony_ci if (ret == -ENOENT) { 50962306a36Sopenharmony_ci btrfs_warn(fs_info, 51062306a36Sopenharmony_ci "orphan qgroup relation 0x%llx->0x%llx", 51162306a36Sopenharmony_ci found_key.objectid, found_key.offset); 51262306a36Sopenharmony_ci ret = 0; /* ignore the error */ 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci if (ret) 51562306a36Sopenharmony_ci goto out; 51662306a36Sopenharmony_cinext2: 51762306a36Sopenharmony_ci ret = btrfs_next_item(quota_root, path); 51862306a36Sopenharmony_ci if (ret < 0) 51962306a36Sopenharmony_ci goto out; 52062306a36Sopenharmony_ci if (ret) 52162306a36Sopenharmony_ci break; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ciout: 52462306a36Sopenharmony_ci btrfs_free_path(path); 52562306a36Sopenharmony_ci fs_info->qgroup_flags |= flags; 52662306a36Sopenharmony_ci if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) 52762306a36Sopenharmony_ci clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); 52862306a36Sopenharmony_ci else if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN && 52962306a36Sopenharmony_ci ret >= 0) 53062306a36Sopenharmony_ci ret = qgroup_rescan_init(fs_info, rescan_progress, 0); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (ret < 0) { 53362306a36Sopenharmony_ci ulist_free(fs_info->qgroup_ulist); 53462306a36Sopenharmony_ci fs_info->qgroup_ulist = NULL; 53562306a36Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; 53662306a36Sopenharmony_ci btrfs_sysfs_del_qgroups(fs_info); 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci return ret < 0 ? ret : 0; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/* 54362306a36Sopenharmony_ci * Called in close_ctree() when quota is still enabled. This verifies we don't 54462306a36Sopenharmony_ci * leak some reserved space. 54562306a36Sopenharmony_ci * 54662306a36Sopenharmony_ci * Return false if no reserved space is left. 54762306a36Sopenharmony_ci * Return true if some reserved space is leaked. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_cibool btrfs_check_quota_leak(struct btrfs_fs_info *fs_info) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct rb_node *node; 55262306a36Sopenharmony_ci bool ret = false; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 55562306a36Sopenharmony_ci return ret; 55662306a36Sopenharmony_ci /* 55762306a36Sopenharmony_ci * Since we're unmounting, there is no race and no need to grab qgroup 55862306a36Sopenharmony_ci * lock. And here we don't go post-order to provide a more user 55962306a36Sopenharmony_ci * friendly sorted result. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ci for (node = rb_first(&fs_info->qgroup_tree); node; node = rb_next(node)) { 56262306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 56362306a36Sopenharmony_ci int i; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci qgroup = rb_entry(node, struct btrfs_qgroup, node); 56662306a36Sopenharmony_ci for (i = 0; i < BTRFS_QGROUP_RSV_LAST; i++) { 56762306a36Sopenharmony_ci if (qgroup->rsv.values[i]) { 56862306a36Sopenharmony_ci ret = true; 56962306a36Sopenharmony_ci btrfs_warn(fs_info, 57062306a36Sopenharmony_ci "qgroup %hu/%llu has unreleased space, type %d rsv %llu", 57162306a36Sopenharmony_ci btrfs_qgroup_level(qgroup->qgroupid), 57262306a36Sopenharmony_ci btrfs_qgroup_subvolid(qgroup->qgroupid), 57362306a36Sopenharmony_ci i, qgroup->rsv.values[i]); 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci return ret; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci/* 58162306a36Sopenharmony_ci * This is called from close_ctree() or open_ctree() or btrfs_quota_disable(), 58262306a36Sopenharmony_ci * first two are in single-threaded paths.And for the third one, we have set 58362306a36Sopenharmony_ci * quota_root to be null with qgroup_lock held before, so it is safe to clean 58462306a36Sopenharmony_ci * up the in-memory structures without qgroup_lock held. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_civoid btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct rb_node *n; 58962306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci while ((n = rb_first(&fs_info->qgroup_tree))) { 59262306a36Sopenharmony_ci qgroup = rb_entry(n, struct btrfs_qgroup, node); 59362306a36Sopenharmony_ci rb_erase(n, &fs_info->qgroup_tree); 59462306a36Sopenharmony_ci __del_qgroup_rb(fs_info, qgroup); 59562306a36Sopenharmony_ci btrfs_sysfs_del_one_qgroup(fs_info, qgroup); 59662306a36Sopenharmony_ci kfree(qgroup); 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci /* 59962306a36Sopenharmony_ci * We call btrfs_free_qgroup_config() when unmounting 60062306a36Sopenharmony_ci * filesystem and disabling quota, so we set qgroup_ulist 60162306a36Sopenharmony_ci * to be null here to avoid double free. 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_ci ulist_free(fs_info->qgroup_ulist); 60462306a36Sopenharmony_ci fs_info->qgroup_ulist = NULL; 60562306a36Sopenharmony_ci btrfs_sysfs_del_qgroups(fs_info); 60662306a36Sopenharmony_ci} 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic int add_qgroup_relation_item(struct btrfs_trans_handle *trans, u64 src, 60962306a36Sopenharmony_ci u64 dst) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci int ret; 61262306a36Sopenharmony_ci struct btrfs_root *quota_root = trans->fs_info->quota_root; 61362306a36Sopenharmony_ci struct btrfs_path *path; 61462306a36Sopenharmony_ci struct btrfs_key key; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci path = btrfs_alloc_path(); 61762306a36Sopenharmony_ci if (!path) 61862306a36Sopenharmony_ci return -ENOMEM; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci key.objectid = src; 62162306a36Sopenharmony_ci key.type = BTRFS_QGROUP_RELATION_KEY; 62262306a36Sopenharmony_ci key.offset = dst; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci ret = btrfs_insert_empty_item(trans, quota_root, path, &key, 0); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci btrfs_mark_buffer_dirty(trans, path->nodes[0]); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci btrfs_free_path(path); 62962306a36Sopenharmony_ci return ret; 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic int del_qgroup_relation_item(struct btrfs_trans_handle *trans, u64 src, 63362306a36Sopenharmony_ci u64 dst) 63462306a36Sopenharmony_ci{ 63562306a36Sopenharmony_ci int ret; 63662306a36Sopenharmony_ci struct btrfs_root *quota_root = trans->fs_info->quota_root; 63762306a36Sopenharmony_ci struct btrfs_path *path; 63862306a36Sopenharmony_ci struct btrfs_key key; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci path = btrfs_alloc_path(); 64162306a36Sopenharmony_ci if (!path) 64262306a36Sopenharmony_ci return -ENOMEM; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci key.objectid = src; 64562306a36Sopenharmony_ci key.type = BTRFS_QGROUP_RELATION_KEY; 64662306a36Sopenharmony_ci key.offset = dst; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1); 64962306a36Sopenharmony_ci if (ret < 0) 65062306a36Sopenharmony_ci goto out; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci if (ret > 0) { 65362306a36Sopenharmony_ci ret = -ENOENT; 65462306a36Sopenharmony_ci goto out; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci ret = btrfs_del_item(trans, quota_root, path); 65862306a36Sopenharmony_ciout: 65962306a36Sopenharmony_ci btrfs_free_path(path); 66062306a36Sopenharmony_ci return ret; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic int add_qgroup_item(struct btrfs_trans_handle *trans, 66462306a36Sopenharmony_ci struct btrfs_root *quota_root, u64 qgroupid) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci int ret; 66762306a36Sopenharmony_ci struct btrfs_path *path; 66862306a36Sopenharmony_ci struct btrfs_qgroup_info_item *qgroup_info; 66962306a36Sopenharmony_ci struct btrfs_qgroup_limit_item *qgroup_limit; 67062306a36Sopenharmony_ci struct extent_buffer *leaf; 67162306a36Sopenharmony_ci struct btrfs_key key; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (btrfs_is_testing(quota_root->fs_info)) 67462306a36Sopenharmony_ci return 0; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci path = btrfs_alloc_path(); 67762306a36Sopenharmony_ci if (!path) 67862306a36Sopenharmony_ci return -ENOMEM; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci key.objectid = 0; 68162306a36Sopenharmony_ci key.type = BTRFS_QGROUP_INFO_KEY; 68262306a36Sopenharmony_ci key.offset = qgroupid; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* 68562306a36Sopenharmony_ci * Avoid a transaction abort by catching -EEXIST here. In that 68662306a36Sopenharmony_ci * case, we proceed by re-initializing the existing structure 68762306a36Sopenharmony_ci * on disk. 68862306a36Sopenharmony_ci */ 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci ret = btrfs_insert_empty_item(trans, quota_root, path, &key, 69162306a36Sopenharmony_ci sizeof(*qgroup_info)); 69262306a36Sopenharmony_ci if (ret && ret != -EEXIST) 69362306a36Sopenharmony_ci goto out; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci leaf = path->nodes[0]; 69662306a36Sopenharmony_ci qgroup_info = btrfs_item_ptr(leaf, path->slots[0], 69762306a36Sopenharmony_ci struct btrfs_qgroup_info_item); 69862306a36Sopenharmony_ci btrfs_set_qgroup_info_generation(leaf, qgroup_info, trans->transid); 69962306a36Sopenharmony_ci btrfs_set_qgroup_info_rfer(leaf, qgroup_info, 0); 70062306a36Sopenharmony_ci btrfs_set_qgroup_info_rfer_cmpr(leaf, qgroup_info, 0); 70162306a36Sopenharmony_ci btrfs_set_qgroup_info_excl(leaf, qgroup_info, 0); 70262306a36Sopenharmony_ci btrfs_set_qgroup_info_excl_cmpr(leaf, qgroup_info, 0); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci btrfs_mark_buffer_dirty(trans, leaf); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci btrfs_release_path(path); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci key.type = BTRFS_QGROUP_LIMIT_KEY; 70962306a36Sopenharmony_ci ret = btrfs_insert_empty_item(trans, quota_root, path, &key, 71062306a36Sopenharmony_ci sizeof(*qgroup_limit)); 71162306a36Sopenharmony_ci if (ret && ret != -EEXIST) 71262306a36Sopenharmony_ci goto out; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci leaf = path->nodes[0]; 71562306a36Sopenharmony_ci qgroup_limit = btrfs_item_ptr(leaf, path->slots[0], 71662306a36Sopenharmony_ci struct btrfs_qgroup_limit_item); 71762306a36Sopenharmony_ci btrfs_set_qgroup_limit_flags(leaf, qgroup_limit, 0); 71862306a36Sopenharmony_ci btrfs_set_qgroup_limit_max_rfer(leaf, qgroup_limit, 0); 71962306a36Sopenharmony_ci btrfs_set_qgroup_limit_max_excl(leaf, qgroup_limit, 0); 72062306a36Sopenharmony_ci btrfs_set_qgroup_limit_rsv_rfer(leaf, qgroup_limit, 0); 72162306a36Sopenharmony_ci btrfs_set_qgroup_limit_rsv_excl(leaf, qgroup_limit, 0); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci btrfs_mark_buffer_dirty(trans, leaf); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci ret = 0; 72662306a36Sopenharmony_ciout: 72762306a36Sopenharmony_ci btrfs_free_path(path); 72862306a36Sopenharmony_ci return ret; 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic int del_qgroup_item(struct btrfs_trans_handle *trans, u64 qgroupid) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci int ret; 73462306a36Sopenharmony_ci struct btrfs_root *quota_root = trans->fs_info->quota_root; 73562306a36Sopenharmony_ci struct btrfs_path *path; 73662306a36Sopenharmony_ci struct btrfs_key key; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci path = btrfs_alloc_path(); 73962306a36Sopenharmony_ci if (!path) 74062306a36Sopenharmony_ci return -ENOMEM; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci key.objectid = 0; 74362306a36Sopenharmony_ci key.type = BTRFS_QGROUP_INFO_KEY; 74462306a36Sopenharmony_ci key.offset = qgroupid; 74562306a36Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1); 74662306a36Sopenharmony_ci if (ret < 0) 74762306a36Sopenharmony_ci goto out; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (ret > 0) { 75062306a36Sopenharmony_ci ret = -ENOENT; 75162306a36Sopenharmony_ci goto out; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ret = btrfs_del_item(trans, quota_root, path); 75562306a36Sopenharmony_ci if (ret) 75662306a36Sopenharmony_ci goto out; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci btrfs_release_path(path); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci key.type = BTRFS_QGROUP_LIMIT_KEY; 76162306a36Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1); 76262306a36Sopenharmony_ci if (ret < 0) 76362306a36Sopenharmony_ci goto out; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci if (ret > 0) { 76662306a36Sopenharmony_ci ret = -ENOENT; 76762306a36Sopenharmony_ci goto out; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci ret = btrfs_del_item(trans, quota_root, path); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ciout: 77362306a36Sopenharmony_ci btrfs_free_path(path); 77462306a36Sopenharmony_ci return ret; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic int update_qgroup_limit_item(struct btrfs_trans_handle *trans, 77862306a36Sopenharmony_ci struct btrfs_qgroup *qgroup) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci struct btrfs_root *quota_root = trans->fs_info->quota_root; 78162306a36Sopenharmony_ci struct btrfs_path *path; 78262306a36Sopenharmony_ci struct btrfs_key key; 78362306a36Sopenharmony_ci struct extent_buffer *l; 78462306a36Sopenharmony_ci struct btrfs_qgroup_limit_item *qgroup_limit; 78562306a36Sopenharmony_ci int ret; 78662306a36Sopenharmony_ci int slot; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci key.objectid = 0; 78962306a36Sopenharmony_ci key.type = BTRFS_QGROUP_LIMIT_KEY; 79062306a36Sopenharmony_ci key.offset = qgroup->qgroupid; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci path = btrfs_alloc_path(); 79362306a36Sopenharmony_ci if (!path) 79462306a36Sopenharmony_ci return -ENOMEM; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, 0, 1); 79762306a36Sopenharmony_ci if (ret > 0) 79862306a36Sopenharmony_ci ret = -ENOENT; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (ret) 80162306a36Sopenharmony_ci goto out; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci l = path->nodes[0]; 80462306a36Sopenharmony_ci slot = path->slots[0]; 80562306a36Sopenharmony_ci qgroup_limit = btrfs_item_ptr(l, slot, struct btrfs_qgroup_limit_item); 80662306a36Sopenharmony_ci btrfs_set_qgroup_limit_flags(l, qgroup_limit, qgroup->lim_flags); 80762306a36Sopenharmony_ci btrfs_set_qgroup_limit_max_rfer(l, qgroup_limit, qgroup->max_rfer); 80862306a36Sopenharmony_ci btrfs_set_qgroup_limit_max_excl(l, qgroup_limit, qgroup->max_excl); 80962306a36Sopenharmony_ci btrfs_set_qgroup_limit_rsv_rfer(l, qgroup_limit, qgroup->rsv_rfer); 81062306a36Sopenharmony_ci btrfs_set_qgroup_limit_rsv_excl(l, qgroup_limit, qgroup->rsv_excl); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci btrfs_mark_buffer_dirty(trans, l); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ciout: 81562306a36Sopenharmony_ci btrfs_free_path(path); 81662306a36Sopenharmony_ci return ret; 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cistatic int update_qgroup_info_item(struct btrfs_trans_handle *trans, 82062306a36Sopenharmony_ci struct btrfs_qgroup *qgroup) 82162306a36Sopenharmony_ci{ 82262306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 82362306a36Sopenharmony_ci struct btrfs_root *quota_root = fs_info->quota_root; 82462306a36Sopenharmony_ci struct btrfs_path *path; 82562306a36Sopenharmony_ci struct btrfs_key key; 82662306a36Sopenharmony_ci struct extent_buffer *l; 82762306a36Sopenharmony_ci struct btrfs_qgroup_info_item *qgroup_info; 82862306a36Sopenharmony_ci int ret; 82962306a36Sopenharmony_ci int slot; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (btrfs_is_testing(fs_info)) 83262306a36Sopenharmony_ci return 0; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci key.objectid = 0; 83562306a36Sopenharmony_ci key.type = BTRFS_QGROUP_INFO_KEY; 83662306a36Sopenharmony_ci key.offset = qgroup->qgroupid; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci path = btrfs_alloc_path(); 83962306a36Sopenharmony_ci if (!path) 84062306a36Sopenharmony_ci return -ENOMEM; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, 0, 1); 84362306a36Sopenharmony_ci if (ret > 0) 84462306a36Sopenharmony_ci ret = -ENOENT; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci if (ret) 84762306a36Sopenharmony_ci goto out; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci l = path->nodes[0]; 85062306a36Sopenharmony_ci slot = path->slots[0]; 85162306a36Sopenharmony_ci qgroup_info = btrfs_item_ptr(l, slot, struct btrfs_qgroup_info_item); 85262306a36Sopenharmony_ci btrfs_set_qgroup_info_generation(l, qgroup_info, trans->transid); 85362306a36Sopenharmony_ci btrfs_set_qgroup_info_rfer(l, qgroup_info, qgroup->rfer); 85462306a36Sopenharmony_ci btrfs_set_qgroup_info_rfer_cmpr(l, qgroup_info, qgroup->rfer_cmpr); 85562306a36Sopenharmony_ci btrfs_set_qgroup_info_excl(l, qgroup_info, qgroup->excl); 85662306a36Sopenharmony_ci btrfs_set_qgroup_info_excl_cmpr(l, qgroup_info, qgroup->excl_cmpr); 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci btrfs_mark_buffer_dirty(trans, l); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ciout: 86162306a36Sopenharmony_ci btrfs_free_path(path); 86262306a36Sopenharmony_ci return ret; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic int update_qgroup_status_item(struct btrfs_trans_handle *trans) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 86862306a36Sopenharmony_ci struct btrfs_root *quota_root = fs_info->quota_root; 86962306a36Sopenharmony_ci struct btrfs_path *path; 87062306a36Sopenharmony_ci struct btrfs_key key; 87162306a36Sopenharmony_ci struct extent_buffer *l; 87262306a36Sopenharmony_ci struct btrfs_qgroup_status_item *ptr; 87362306a36Sopenharmony_ci int ret; 87462306a36Sopenharmony_ci int slot; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci key.objectid = 0; 87762306a36Sopenharmony_ci key.type = BTRFS_QGROUP_STATUS_KEY; 87862306a36Sopenharmony_ci key.offset = 0; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci path = btrfs_alloc_path(); 88162306a36Sopenharmony_ci if (!path) 88262306a36Sopenharmony_ci return -ENOMEM; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci ret = btrfs_search_slot(trans, quota_root, &key, path, 0, 1); 88562306a36Sopenharmony_ci if (ret > 0) 88662306a36Sopenharmony_ci ret = -ENOENT; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci if (ret) 88962306a36Sopenharmony_ci goto out; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci l = path->nodes[0]; 89262306a36Sopenharmony_ci slot = path->slots[0]; 89362306a36Sopenharmony_ci ptr = btrfs_item_ptr(l, slot, struct btrfs_qgroup_status_item); 89462306a36Sopenharmony_ci btrfs_set_qgroup_status_flags(l, ptr, fs_info->qgroup_flags & 89562306a36Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAGS_MASK); 89662306a36Sopenharmony_ci btrfs_set_qgroup_status_generation(l, ptr, trans->transid); 89762306a36Sopenharmony_ci btrfs_set_qgroup_status_rescan(l, ptr, 89862306a36Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci btrfs_mark_buffer_dirty(trans, l); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ciout: 90362306a36Sopenharmony_ci btrfs_free_path(path); 90462306a36Sopenharmony_ci return ret; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci/* 90862306a36Sopenharmony_ci * called with qgroup_lock held 90962306a36Sopenharmony_ci */ 91062306a36Sopenharmony_cistatic int btrfs_clean_quota_tree(struct btrfs_trans_handle *trans, 91162306a36Sopenharmony_ci struct btrfs_root *root) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci struct btrfs_path *path; 91462306a36Sopenharmony_ci struct btrfs_key key; 91562306a36Sopenharmony_ci struct extent_buffer *leaf = NULL; 91662306a36Sopenharmony_ci int ret; 91762306a36Sopenharmony_ci int nr = 0; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci path = btrfs_alloc_path(); 92062306a36Sopenharmony_ci if (!path) 92162306a36Sopenharmony_ci return -ENOMEM; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci key.objectid = 0; 92462306a36Sopenharmony_ci key.offset = 0; 92562306a36Sopenharmony_ci key.type = 0; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci while (1) { 92862306a36Sopenharmony_ci ret = btrfs_search_slot(trans, root, &key, path, -1, 1); 92962306a36Sopenharmony_ci if (ret < 0) 93062306a36Sopenharmony_ci goto out; 93162306a36Sopenharmony_ci leaf = path->nodes[0]; 93262306a36Sopenharmony_ci nr = btrfs_header_nritems(leaf); 93362306a36Sopenharmony_ci if (!nr) 93462306a36Sopenharmony_ci break; 93562306a36Sopenharmony_ci /* 93662306a36Sopenharmony_ci * delete the leaf one by one 93762306a36Sopenharmony_ci * since the whole tree is going 93862306a36Sopenharmony_ci * to be deleted. 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_ci path->slots[0] = 0; 94162306a36Sopenharmony_ci ret = btrfs_del_items(trans, root, path, 0, nr); 94262306a36Sopenharmony_ci if (ret) 94362306a36Sopenharmony_ci goto out; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci btrfs_release_path(path); 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci ret = 0; 94862306a36Sopenharmony_ciout: 94962306a36Sopenharmony_ci btrfs_free_path(path); 95062306a36Sopenharmony_ci return ret; 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ciint btrfs_quota_enable(struct btrfs_fs_info *fs_info) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci struct btrfs_root *quota_root; 95662306a36Sopenharmony_ci struct btrfs_root *tree_root = fs_info->tree_root; 95762306a36Sopenharmony_ci struct btrfs_path *path = NULL; 95862306a36Sopenharmony_ci struct btrfs_qgroup_status_item *ptr; 95962306a36Sopenharmony_ci struct extent_buffer *leaf; 96062306a36Sopenharmony_ci struct btrfs_key key; 96162306a36Sopenharmony_ci struct btrfs_key found_key; 96262306a36Sopenharmony_ci struct btrfs_qgroup *qgroup = NULL; 96362306a36Sopenharmony_ci struct btrfs_trans_handle *trans = NULL; 96462306a36Sopenharmony_ci struct ulist *ulist = NULL; 96562306a36Sopenharmony_ci int ret = 0; 96662306a36Sopenharmony_ci int slot; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* 96962306a36Sopenharmony_ci * We need to have subvol_sem write locked, to prevent races between 97062306a36Sopenharmony_ci * concurrent tasks trying to enable quotas, because we will unlock 97162306a36Sopenharmony_ci * and relock qgroup_ioctl_lock before setting fs_info->quota_root 97262306a36Sopenharmony_ci * and before setting BTRFS_FS_QUOTA_ENABLED. 97362306a36Sopenharmony_ci */ 97462306a36Sopenharmony_ci lockdep_assert_held_write(&fs_info->subvol_sem); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci if (btrfs_fs_incompat(fs_info, EXTENT_TREE_V2)) { 97762306a36Sopenharmony_ci btrfs_err(fs_info, 97862306a36Sopenharmony_ci "qgroups are currently unsupported in extent tree v2"); 97962306a36Sopenharmony_ci return -EINVAL; 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 98362306a36Sopenharmony_ci if (fs_info->quota_root) 98462306a36Sopenharmony_ci goto out; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci ulist = ulist_alloc(GFP_KERNEL); 98762306a36Sopenharmony_ci if (!ulist) { 98862306a36Sopenharmony_ci ret = -ENOMEM; 98962306a36Sopenharmony_ci goto out; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci ret = btrfs_sysfs_add_qgroups(fs_info); 99362306a36Sopenharmony_ci if (ret < 0) 99462306a36Sopenharmony_ci goto out; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* 99762306a36Sopenharmony_ci * Unlock qgroup_ioctl_lock before starting the transaction. This is to 99862306a36Sopenharmony_ci * avoid lock acquisition inversion problems (reported by lockdep) between 99962306a36Sopenharmony_ci * qgroup_ioctl_lock and the vfs freeze semaphores, acquired when we 100062306a36Sopenharmony_ci * start a transaction. 100162306a36Sopenharmony_ci * After we started the transaction lock qgroup_ioctl_lock again and 100262306a36Sopenharmony_ci * check if someone else created the quota root in the meanwhile. If so, 100362306a36Sopenharmony_ci * just return success and release the transaction handle. 100462306a36Sopenharmony_ci * 100562306a36Sopenharmony_ci * Also we don't need to worry about someone else calling 100662306a36Sopenharmony_ci * btrfs_sysfs_add_qgroups() after we unlock and getting an error because 100762306a36Sopenharmony_ci * that function returns 0 (success) when the sysfs entries already exist. 100862306a36Sopenharmony_ci */ 100962306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci /* 101262306a36Sopenharmony_ci * 1 for quota root item 101362306a36Sopenharmony_ci * 1 for BTRFS_QGROUP_STATUS item 101462306a36Sopenharmony_ci * 101562306a36Sopenharmony_ci * Yet we also need 2*n items for a QGROUP_INFO/QGROUP_LIMIT items 101662306a36Sopenharmony_ci * per subvolume. However those are not currently reserved since it 101762306a36Sopenharmony_ci * would be a lot of overkill. 101862306a36Sopenharmony_ci */ 101962306a36Sopenharmony_ci trans = btrfs_start_transaction(tree_root, 2); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 102262306a36Sopenharmony_ci if (IS_ERR(trans)) { 102362306a36Sopenharmony_ci ret = PTR_ERR(trans); 102462306a36Sopenharmony_ci trans = NULL; 102562306a36Sopenharmony_ci goto out; 102662306a36Sopenharmony_ci } 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci if (fs_info->quota_root) 102962306a36Sopenharmony_ci goto out; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci fs_info->qgroup_ulist = ulist; 103262306a36Sopenharmony_ci ulist = NULL; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci /* 103562306a36Sopenharmony_ci * initially create the quota tree 103662306a36Sopenharmony_ci */ 103762306a36Sopenharmony_ci quota_root = btrfs_create_tree(trans, BTRFS_QUOTA_TREE_OBJECTID); 103862306a36Sopenharmony_ci if (IS_ERR(quota_root)) { 103962306a36Sopenharmony_ci ret = PTR_ERR(quota_root); 104062306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 104162306a36Sopenharmony_ci goto out; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci path = btrfs_alloc_path(); 104562306a36Sopenharmony_ci if (!path) { 104662306a36Sopenharmony_ci ret = -ENOMEM; 104762306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 104862306a36Sopenharmony_ci goto out_free_root; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci key.objectid = 0; 105262306a36Sopenharmony_ci key.type = BTRFS_QGROUP_STATUS_KEY; 105362306a36Sopenharmony_ci key.offset = 0; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci ret = btrfs_insert_empty_item(trans, quota_root, path, &key, 105662306a36Sopenharmony_ci sizeof(*ptr)); 105762306a36Sopenharmony_ci if (ret) { 105862306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 105962306a36Sopenharmony_ci goto out_free_path; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci leaf = path->nodes[0]; 106362306a36Sopenharmony_ci ptr = btrfs_item_ptr(leaf, path->slots[0], 106462306a36Sopenharmony_ci struct btrfs_qgroup_status_item); 106562306a36Sopenharmony_ci btrfs_set_qgroup_status_generation(leaf, ptr, trans->transid); 106662306a36Sopenharmony_ci btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_STATUS_VERSION); 106762306a36Sopenharmony_ci fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON | 106862306a36Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 106962306a36Sopenharmony_ci btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags & 107062306a36Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAGS_MASK); 107162306a36Sopenharmony_ci btrfs_set_qgroup_status_rescan(leaf, ptr, 0); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci btrfs_mark_buffer_dirty(trans, leaf); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci key.objectid = 0; 107662306a36Sopenharmony_ci key.type = BTRFS_ROOT_REF_KEY; 107762306a36Sopenharmony_ci key.offset = 0; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci btrfs_release_path(path); 108062306a36Sopenharmony_ci ret = btrfs_search_slot_for_read(tree_root, &key, path, 1, 0); 108162306a36Sopenharmony_ci if (ret > 0) 108262306a36Sopenharmony_ci goto out_add_root; 108362306a36Sopenharmony_ci if (ret < 0) { 108462306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 108562306a36Sopenharmony_ci goto out_free_path; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci while (1) { 108962306a36Sopenharmony_ci slot = path->slots[0]; 109062306a36Sopenharmony_ci leaf = path->nodes[0]; 109162306a36Sopenharmony_ci btrfs_item_key_to_cpu(leaf, &found_key, slot); 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci if (found_key.type == BTRFS_ROOT_REF_KEY) { 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci /* Release locks on tree_root before we access quota_root */ 109662306a36Sopenharmony_ci btrfs_release_path(path); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci ret = add_qgroup_item(trans, quota_root, 109962306a36Sopenharmony_ci found_key.offset); 110062306a36Sopenharmony_ci if (ret) { 110162306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 110262306a36Sopenharmony_ci goto out_free_path; 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci qgroup = add_qgroup_rb(fs_info, found_key.offset); 110662306a36Sopenharmony_ci if (IS_ERR(qgroup)) { 110762306a36Sopenharmony_ci ret = PTR_ERR(qgroup); 110862306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 110962306a36Sopenharmony_ci goto out_free_path; 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup); 111262306a36Sopenharmony_ci if (ret < 0) { 111362306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 111462306a36Sopenharmony_ci goto out_free_path; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci ret = btrfs_search_slot_for_read(tree_root, &found_key, 111762306a36Sopenharmony_ci path, 1, 0); 111862306a36Sopenharmony_ci if (ret < 0) { 111962306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 112062306a36Sopenharmony_ci goto out_free_path; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci if (ret > 0) { 112362306a36Sopenharmony_ci /* 112462306a36Sopenharmony_ci * Shouldn't happen, but in case it does we 112562306a36Sopenharmony_ci * don't need to do the btrfs_next_item, just 112662306a36Sopenharmony_ci * continue. 112762306a36Sopenharmony_ci */ 112862306a36Sopenharmony_ci continue; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci ret = btrfs_next_item(tree_root, path); 113262306a36Sopenharmony_ci if (ret < 0) { 113362306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 113462306a36Sopenharmony_ci goto out_free_path; 113562306a36Sopenharmony_ci } 113662306a36Sopenharmony_ci if (ret) 113762306a36Sopenharmony_ci break; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ciout_add_root: 114162306a36Sopenharmony_ci btrfs_release_path(path); 114262306a36Sopenharmony_ci ret = add_qgroup_item(trans, quota_root, BTRFS_FS_TREE_OBJECTID); 114362306a36Sopenharmony_ci if (ret) { 114462306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 114562306a36Sopenharmony_ci goto out_free_path; 114662306a36Sopenharmony_ci } 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci qgroup = add_qgroup_rb(fs_info, BTRFS_FS_TREE_OBJECTID); 114962306a36Sopenharmony_ci if (IS_ERR(qgroup)) { 115062306a36Sopenharmony_ci ret = PTR_ERR(qgroup); 115162306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 115262306a36Sopenharmony_ci goto out_free_path; 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup); 115562306a36Sopenharmony_ci if (ret < 0) { 115662306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 115762306a36Sopenharmony_ci goto out_free_path; 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 116162306a36Sopenharmony_ci /* 116262306a36Sopenharmony_ci * Commit the transaction while not holding qgroup_ioctl_lock, to avoid 116362306a36Sopenharmony_ci * a deadlock with tasks concurrently doing other qgroup operations, such 116462306a36Sopenharmony_ci * adding/removing qgroups or adding/deleting qgroup relations for example, 116562306a36Sopenharmony_ci * because all qgroup operations first start or join a transaction and then 116662306a36Sopenharmony_ci * lock the qgroup_ioctl_lock mutex. 116762306a36Sopenharmony_ci * We are safe from a concurrent task trying to enable quotas, by calling 116862306a36Sopenharmony_ci * this function, since we are serialized by fs_info->subvol_sem. 116962306a36Sopenharmony_ci */ 117062306a36Sopenharmony_ci ret = btrfs_commit_transaction(trans); 117162306a36Sopenharmony_ci trans = NULL; 117262306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 117362306a36Sopenharmony_ci if (ret) 117462306a36Sopenharmony_ci goto out_free_path; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci /* 117762306a36Sopenharmony_ci * Set quota enabled flag after committing the transaction, to avoid 117862306a36Sopenharmony_ci * deadlocks on fs_info->qgroup_ioctl_lock with concurrent snapshot 117962306a36Sopenharmony_ci * creation. 118062306a36Sopenharmony_ci */ 118162306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 118262306a36Sopenharmony_ci fs_info->quota_root = quota_root; 118362306a36Sopenharmony_ci set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); 118462306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci ret = qgroup_rescan_init(fs_info, 0, 1); 118762306a36Sopenharmony_ci if (!ret) { 118862306a36Sopenharmony_ci qgroup_rescan_zero_tracking(fs_info); 118962306a36Sopenharmony_ci fs_info->qgroup_rescan_running = true; 119062306a36Sopenharmony_ci btrfs_queue_work(fs_info->qgroup_rescan_workers, 119162306a36Sopenharmony_ci &fs_info->qgroup_rescan_work); 119262306a36Sopenharmony_ci } else { 119362306a36Sopenharmony_ci /* 119462306a36Sopenharmony_ci * We have set both BTRFS_FS_QUOTA_ENABLED and 119562306a36Sopenharmony_ci * BTRFS_QGROUP_STATUS_FLAG_ON, so we can only fail with 119662306a36Sopenharmony_ci * -EINPROGRESS. That can happen because someone started the 119762306a36Sopenharmony_ci * rescan worker by calling quota rescan ioctl before we 119862306a36Sopenharmony_ci * attempted to initialize the rescan worker. Failure due to 119962306a36Sopenharmony_ci * quotas disabled in the meanwhile is not possible, because 120062306a36Sopenharmony_ci * we are holding a write lock on fs_info->subvol_sem, which 120162306a36Sopenharmony_ci * is also acquired when disabling quotas. 120262306a36Sopenharmony_ci * Ignore such error, and any other error would need to undo 120362306a36Sopenharmony_ci * everything we did in the transaction we just committed. 120462306a36Sopenharmony_ci */ 120562306a36Sopenharmony_ci ASSERT(ret == -EINPROGRESS); 120662306a36Sopenharmony_ci ret = 0; 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ciout_free_path: 121062306a36Sopenharmony_ci btrfs_free_path(path); 121162306a36Sopenharmony_ciout_free_root: 121262306a36Sopenharmony_ci if (ret) 121362306a36Sopenharmony_ci btrfs_put_root(quota_root); 121462306a36Sopenharmony_ciout: 121562306a36Sopenharmony_ci if (ret) { 121662306a36Sopenharmony_ci ulist_free(fs_info->qgroup_ulist); 121762306a36Sopenharmony_ci fs_info->qgroup_ulist = NULL; 121862306a36Sopenharmony_ci btrfs_sysfs_del_qgroups(fs_info); 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 122162306a36Sopenharmony_ci if (ret && trans) 122262306a36Sopenharmony_ci btrfs_end_transaction(trans); 122362306a36Sopenharmony_ci else if (trans) 122462306a36Sopenharmony_ci ret = btrfs_end_transaction(trans); 122562306a36Sopenharmony_ci ulist_free(ulist); 122662306a36Sopenharmony_ci return ret; 122762306a36Sopenharmony_ci} 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ciint btrfs_quota_disable(struct btrfs_fs_info *fs_info) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci struct btrfs_root *quota_root; 123262306a36Sopenharmony_ci struct btrfs_trans_handle *trans = NULL; 123362306a36Sopenharmony_ci int ret = 0; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* 123662306a36Sopenharmony_ci * We need to have subvol_sem write locked to prevent races with 123762306a36Sopenharmony_ci * snapshot creation. 123862306a36Sopenharmony_ci */ 123962306a36Sopenharmony_ci lockdep_assert_held_write(&fs_info->subvol_sem); 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci /* 124262306a36Sopenharmony_ci * Lock the cleaner mutex to prevent races with concurrent relocation, 124362306a36Sopenharmony_ci * because relocation may be building backrefs for blocks of the quota 124462306a36Sopenharmony_ci * root while we are deleting the root. This is like dropping fs roots 124562306a36Sopenharmony_ci * of deleted snapshots/subvolumes, we need the same protection. 124662306a36Sopenharmony_ci * 124762306a36Sopenharmony_ci * This also prevents races between concurrent tasks trying to disable 124862306a36Sopenharmony_ci * quotas, because we will unlock and relock qgroup_ioctl_lock across 124962306a36Sopenharmony_ci * BTRFS_FS_QUOTA_ENABLED changes. 125062306a36Sopenharmony_ci */ 125162306a36Sopenharmony_ci mutex_lock(&fs_info->cleaner_mutex); 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 125462306a36Sopenharmony_ci if (!fs_info->quota_root) 125562306a36Sopenharmony_ci goto out; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci /* 125862306a36Sopenharmony_ci * Unlock the qgroup_ioctl_lock mutex before waiting for the rescan worker to 125962306a36Sopenharmony_ci * complete. Otherwise we can deadlock because btrfs_remove_qgroup() needs 126062306a36Sopenharmony_ci * to lock that mutex while holding a transaction handle and the rescan 126162306a36Sopenharmony_ci * worker needs to commit a transaction. 126262306a36Sopenharmony_ci */ 126362306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci /* 126662306a36Sopenharmony_ci * Request qgroup rescan worker to complete and wait for it. This wait 126762306a36Sopenharmony_ci * must be done before transaction start for quota disable since it may 126862306a36Sopenharmony_ci * deadlock with transaction by the qgroup rescan worker. 126962306a36Sopenharmony_ci */ 127062306a36Sopenharmony_ci clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); 127162306a36Sopenharmony_ci btrfs_qgroup_wait_for_completion(fs_info, false); 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci /* 127462306a36Sopenharmony_ci * 1 For the root item 127562306a36Sopenharmony_ci * 127662306a36Sopenharmony_ci * We should also reserve enough items for the quota tree deletion in 127762306a36Sopenharmony_ci * btrfs_clean_quota_tree but this is not done. 127862306a36Sopenharmony_ci * 127962306a36Sopenharmony_ci * Also, we must always start a transaction without holding the mutex 128062306a36Sopenharmony_ci * qgroup_ioctl_lock, see btrfs_quota_enable(). 128162306a36Sopenharmony_ci */ 128262306a36Sopenharmony_ci trans = btrfs_start_transaction(fs_info->tree_root, 1); 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 128562306a36Sopenharmony_ci if (IS_ERR(trans)) { 128662306a36Sopenharmony_ci ret = PTR_ERR(trans); 128762306a36Sopenharmony_ci trans = NULL; 128862306a36Sopenharmony_ci set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); 128962306a36Sopenharmony_ci goto out; 129062306a36Sopenharmony_ci } 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci if (!fs_info->quota_root) 129362306a36Sopenharmony_ci goto out; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 129662306a36Sopenharmony_ci quota_root = fs_info->quota_root; 129762306a36Sopenharmony_ci fs_info->quota_root = NULL; 129862306a36Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON; 129962306a36Sopenharmony_ci fs_info->qgroup_drop_subtree_thres = BTRFS_MAX_LEVEL; 130062306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci btrfs_free_qgroup_config(fs_info); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci ret = btrfs_clean_quota_tree(trans, quota_root); 130562306a36Sopenharmony_ci if (ret) { 130662306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 130762306a36Sopenharmony_ci goto out; 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci ret = btrfs_del_root(trans, "a_root->root_key); 131162306a36Sopenharmony_ci if (ret) { 131262306a36Sopenharmony_ci btrfs_abort_transaction(trans, ret); 131362306a36Sopenharmony_ci goto out; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci spin_lock(&fs_info->trans_lock); 131762306a36Sopenharmony_ci list_del("a_root->dirty_list); 131862306a36Sopenharmony_ci spin_unlock(&fs_info->trans_lock); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci btrfs_tree_lock(quota_root->node); 132162306a36Sopenharmony_ci btrfs_clear_buffer_dirty(trans, quota_root->node); 132262306a36Sopenharmony_ci btrfs_tree_unlock(quota_root->node); 132362306a36Sopenharmony_ci btrfs_free_tree_block(trans, btrfs_root_id(quota_root), 132462306a36Sopenharmony_ci quota_root->node, 0, 1); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci btrfs_put_root(quota_root); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ciout: 132962306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 133062306a36Sopenharmony_ci if (ret && trans) 133162306a36Sopenharmony_ci btrfs_end_transaction(trans); 133262306a36Sopenharmony_ci else if (trans) 133362306a36Sopenharmony_ci ret = btrfs_end_transaction(trans); 133462306a36Sopenharmony_ci mutex_unlock(&fs_info->cleaner_mutex); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci return ret; 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_cistatic void qgroup_dirty(struct btrfs_fs_info *fs_info, 134062306a36Sopenharmony_ci struct btrfs_qgroup *qgroup) 134162306a36Sopenharmony_ci{ 134262306a36Sopenharmony_ci if (list_empty(&qgroup->dirty)) 134362306a36Sopenharmony_ci list_add(&qgroup->dirty, &fs_info->dirty_qgroups); 134462306a36Sopenharmony_ci} 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_cistatic void qgroup_iterator_add(struct list_head *head, struct btrfs_qgroup *qgroup) 134762306a36Sopenharmony_ci{ 134862306a36Sopenharmony_ci if (!list_empty(&qgroup->iterator)) 134962306a36Sopenharmony_ci return; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci list_add_tail(&qgroup->iterator, head); 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cistatic void qgroup_iterator_clean(struct list_head *head) 135562306a36Sopenharmony_ci{ 135662306a36Sopenharmony_ci while (!list_empty(head)) { 135762306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci qgroup = list_first_entry(head, struct btrfs_qgroup, iterator); 136062306a36Sopenharmony_ci list_del_init(&qgroup->iterator); 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci} 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci/* 136562306a36Sopenharmony_ci * The easy accounting, we're updating qgroup relationship whose child qgroup 136662306a36Sopenharmony_ci * only has exclusive extents. 136762306a36Sopenharmony_ci * 136862306a36Sopenharmony_ci * In this case, all exclusive extents will also be exclusive for parent, so 136962306a36Sopenharmony_ci * excl/rfer just get added/removed. 137062306a36Sopenharmony_ci * 137162306a36Sopenharmony_ci * So is qgroup reservation space, which should also be added/removed to 137262306a36Sopenharmony_ci * parent. 137362306a36Sopenharmony_ci * Or when child tries to release reservation space, parent will underflow its 137462306a36Sopenharmony_ci * reservation (for relationship adding case). 137562306a36Sopenharmony_ci * 137662306a36Sopenharmony_ci * Caller should hold fs_info->qgroup_lock. 137762306a36Sopenharmony_ci */ 137862306a36Sopenharmony_cistatic int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, 137962306a36Sopenharmony_ci struct ulist *tmp, u64 ref_root, 138062306a36Sopenharmony_ci struct btrfs_qgroup *src, int sign) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 138362306a36Sopenharmony_ci struct btrfs_qgroup_list *glist; 138462306a36Sopenharmony_ci struct ulist_node *unode; 138562306a36Sopenharmony_ci struct ulist_iterator uiter; 138662306a36Sopenharmony_ci u64 num_bytes = src->excl; 138762306a36Sopenharmony_ci int ret = 0; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, ref_root); 139062306a36Sopenharmony_ci if (!qgroup) 139162306a36Sopenharmony_ci goto out; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci qgroup->rfer += sign * num_bytes; 139462306a36Sopenharmony_ci qgroup->rfer_cmpr += sign * num_bytes; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci WARN_ON(sign < 0 && qgroup->excl < num_bytes); 139762306a36Sopenharmony_ci qgroup->excl += sign * num_bytes; 139862306a36Sopenharmony_ci qgroup->excl_cmpr += sign * num_bytes; 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci if (sign > 0) 140162306a36Sopenharmony_ci qgroup_rsv_add_by_qgroup(fs_info, qgroup, src); 140262306a36Sopenharmony_ci else 140362306a36Sopenharmony_ci qgroup_rsv_release_by_qgroup(fs_info, qgroup, src); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci qgroup_dirty(fs_info, qgroup); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci /* Get all of the parent groups that contain this qgroup */ 140862306a36Sopenharmony_ci list_for_each_entry(glist, &qgroup->groups, next_group) { 140962306a36Sopenharmony_ci ret = ulist_add(tmp, glist->group->qgroupid, 141062306a36Sopenharmony_ci qgroup_to_aux(glist->group), GFP_ATOMIC); 141162306a36Sopenharmony_ci if (ret < 0) 141262306a36Sopenharmony_ci goto out; 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci /* Iterate all of the parents and adjust their reference counts */ 141662306a36Sopenharmony_ci ULIST_ITER_INIT(&uiter); 141762306a36Sopenharmony_ci while ((unode = ulist_next(tmp, &uiter))) { 141862306a36Sopenharmony_ci qgroup = unode_aux_to_qgroup(unode); 141962306a36Sopenharmony_ci qgroup->rfer += sign * num_bytes; 142062306a36Sopenharmony_ci qgroup->rfer_cmpr += sign * num_bytes; 142162306a36Sopenharmony_ci WARN_ON(sign < 0 && qgroup->excl < num_bytes); 142262306a36Sopenharmony_ci qgroup->excl += sign * num_bytes; 142362306a36Sopenharmony_ci if (sign > 0) 142462306a36Sopenharmony_ci qgroup_rsv_add_by_qgroup(fs_info, qgroup, src); 142562306a36Sopenharmony_ci else 142662306a36Sopenharmony_ci qgroup_rsv_release_by_qgroup(fs_info, qgroup, src); 142762306a36Sopenharmony_ci qgroup->excl_cmpr += sign * num_bytes; 142862306a36Sopenharmony_ci qgroup_dirty(fs_info, qgroup); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* Add any parents of the parents */ 143162306a36Sopenharmony_ci list_for_each_entry(glist, &qgroup->groups, next_group) { 143262306a36Sopenharmony_ci ret = ulist_add(tmp, glist->group->qgroupid, 143362306a36Sopenharmony_ci qgroup_to_aux(glist->group), GFP_ATOMIC); 143462306a36Sopenharmony_ci if (ret < 0) 143562306a36Sopenharmony_ci goto out; 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci ret = 0; 143962306a36Sopenharmony_ciout: 144062306a36Sopenharmony_ci return ret; 144162306a36Sopenharmony_ci} 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci/* 144562306a36Sopenharmony_ci * Quick path for updating qgroup with only excl refs. 144662306a36Sopenharmony_ci * 144762306a36Sopenharmony_ci * In that case, just update all parent will be enough. 144862306a36Sopenharmony_ci * Or we needs to do a full rescan. 144962306a36Sopenharmony_ci * Caller should also hold fs_info->qgroup_lock. 145062306a36Sopenharmony_ci * 145162306a36Sopenharmony_ci * Return 0 for quick update, return >0 for need to full rescan 145262306a36Sopenharmony_ci * and mark INCONSISTENT flag. 145362306a36Sopenharmony_ci * Return < 0 for other error. 145462306a36Sopenharmony_ci */ 145562306a36Sopenharmony_cistatic int quick_update_accounting(struct btrfs_fs_info *fs_info, 145662306a36Sopenharmony_ci struct ulist *tmp, u64 src, u64 dst, 145762306a36Sopenharmony_ci int sign) 145862306a36Sopenharmony_ci{ 145962306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 146062306a36Sopenharmony_ci int ret = 1; 146162306a36Sopenharmony_ci int err = 0; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, src); 146462306a36Sopenharmony_ci if (!qgroup) 146562306a36Sopenharmony_ci goto out; 146662306a36Sopenharmony_ci if (qgroup->excl == qgroup->rfer) { 146762306a36Sopenharmony_ci ret = 0; 146862306a36Sopenharmony_ci err = __qgroup_excl_accounting(fs_info, tmp, dst, 146962306a36Sopenharmony_ci qgroup, sign); 147062306a36Sopenharmony_ci if (err < 0) { 147162306a36Sopenharmony_ci ret = err; 147262306a36Sopenharmony_ci goto out; 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ciout: 147662306a36Sopenharmony_ci if (ret) 147762306a36Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 147862306a36Sopenharmony_ci return ret; 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ciint btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, 148262306a36Sopenharmony_ci u64 dst) 148362306a36Sopenharmony_ci{ 148462306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 148562306a36Sopenharmony_ci struct btrfs_qgroup *parent; 148662306a36Sopenharmony_ci struct btrfs_qgroup *member; 148762306a36Sopenharmony_ci struct btrfs_qgroup_list *list; 148862306a36Sopenharmony_ci struct ulist *tmp; 148962306a36Sopenharmony_ci unsigned int nofs_flag; 149062306a36Sopenharmony_ci int ret = 0; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci /* Check the level of src and dst first */ 149362306a36Sopenharmony_ci if (btrfs_qgroup_level(src) >= btrfs_qgroup_level(dst)) 149462306a36Sopenharmony_ci return -EINVAL; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci /* We hold a transaction handle open, must do a NOFS allocation. */ 149762306a36Sopenharmony_ci nofs_flag = memalloc_nofs_save(); 149862306a36Sopenharmony_ci tmp = ulist_alloc(GFP_KERNEL); 149962306a36Sopenharmony_ci memalloc_nofs_restore(nofs_flag); 150062306a36Sopenharmony_ci if (!tmp) 150162306a36Sopenharmony_ci return -ENOMEM; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 150462306a36Sopenharmony_ci if (!fs_info->quota_root) { 150562306a36Sopenharmony_ci ret = -ENOTCONN; 150662306a36Sopenharmony_ci goto out; 150762306a36Sopenharmony_ci } 150862306a36Sopenharmony_ci member = find_qgroup_rb(fs_info, src); 150962306a36Sopenharmony_ci parent = find_qgroup_rb(fs_info, dst); 151062306a36Sopenharmony_ci if (!member || !parent) { 151162306a36Sopenharmony_ci ret = -EINVAL; 151262306a36Sopenharmony_ci goto out; 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci /* check if such qgroup relation exist firstly */ 151662306a36Sopenharmony_ci list_for_each_entry(list, &member->groups, next_group) { 151762306a36Sopenharmony_ci if (list->group == parent) { 151862306a36Sopenharmony_ci ret = -EEXIST; 151962306a36Sopenharmony_ci goto out; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci ret = add_qgroup_relation_item(trans, src, dst); 152462306a36Sopenharmony_ci if (ret) 152562306a36Sopenharmony_ci goto out; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci ret = add_qgroup_relation_item(trans, dst, src); 152862306a36Sopenharmony_ci if (ret) { 152962306a36Sopenharmony_ci del_qgroup_relation_item(trans, src, dst); 153062306a36Sopenharmony_ci goto out; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 153462306a36Sopenharmony_ci ret = __add_relation_rb(member, parent); 153562306a36Sopenharmony_ci if (ret < 0) { 153662306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 153762306a36Sopenharmony_ci goto out; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci ret = quick_update_accounting(fs_info, tmp, src, dst, 1); 154062306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 154162306a36Sopenharmony_ciout: 154262306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 154362306a36Sopenharmony_ci ulist_free(tmp); 154462306a36Sopenharmony_ci return ret; 154562306a36Sopenharmony_ci} 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_cistatic int __del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, 154862306a36Sopenharmony_ci u64 dst) 154962306a36Sopenharmony_ci{ 155062306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 155162306a36Sopenharmony_ci struct btrfs_qgroup *parent; 155262306a36Sopenharmony_ci struct btrfs_qgroup *member; 155362306a36Sopenharmony_ci struct btrfs_qgroup_list *list; 155462306a36Sopenharmony_ci struct ulist *tmp; 155562306a36Sopenharmony_ci bool found = false; 155662306a36Sopenharmony_ci unsigned int nofs_flag; 155762306a36Sopenharmony_ci int ret = 0; 155862306a36Sopenharmony_ci int ret2; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci /* We hold a transaction handle open, must do a NOFS allocation. */ 156162306a36Sopenharmony_ci nofs_flag = memalloc_nofs_save(); 156262306a36Sopenharmony_ci tmp = ulist_alloc(GFP_KERNEL); 156362306a36Sopenharmony_ci memalloc_nofs_restore(nofs_flag); 156462306a36Sopenharmony_ci if (!tmp) 156562306a36Sopenharmony_ci return -ENOMEM; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (!fs_info->quota_root) { 156862306a36Sopenharmony_ci ret = -ENOTCONN; 156962306a36Sopenharmony_ci goto out; 157062306a36Sopenharmony_ci } 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci member = find_qgroup_rb(fs_info, src); 157362306a36Sopenharmony_ci parent = find_qgroup_rb(fs_info, dst); 157462306a36Sopenharmony_ci /* 157562306a36Sopenharmony_ci * The parent/member pair doesn't exist, then try to delete the dead 157662306a36Sopenharmony_ci * relation items only. 157762306a36Sopenharmony_ci */ 157862306a36Sopenharmony_ci if (!member || !parent) 157962306a36Sopenharmony_ci goto delete_item; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci /* check if such qgroup relation exist firstly */ 158262306a36Sopenharmony_ci list_for_each_entry(list, &member->groups, next_group) { 158362306a36Sopenharmony_ci if (list->group == parent) { 158462306a36Sopenharmony_ci found = true; 158562306a36Sopenharmony_ci break; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_cidelete_item: 159062306a36Sopenharmony_ci ret = del_qgroup_relation_item(trans, src, dst); 159162306a36Sopenharmony_ci if (ret < 0 && ret != -ENOENT) 159262306a36Sopenharmony_ci goto out; 159362306a36Sopenharmony_ci ret2 = del_qgroup_relation_item(trans, dst, src); 159462306a36Sopenharmony_ci if (ret2 < 0 && ret2 != -ENOENT) 159562306a36Sopenharmony_ci goto out; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci /* At least one deletion succeeded, return 0 */ 159862306a36Sopenharmony_ci if (!ret || !ret2) 159962306a36Sopenharmony_ci ret = 0; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (found) { 160262306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 160362306a36Sopenharmony_ci del_relation_rb(fs_info, src, dst); 160462306a36Sopenharmony_ci ret = quick_update_accounting(fs_info, tmp, src, dst, -1); 160562306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 160662306a36Sopenharmony_ci } 160762306a36Sopenharmony_ciout: 160862306a36Sopenharmony_ci ulist_free(tmp); 160962306a36Sopenharmony_ci return ret; 161062306a36Sopenharmony_ci} 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ciint btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, u64 src, 161362306a36Sopenharmony_ci u64 dst) 161462306a36Sopenharmony_ci{ 161562306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 161662306a36Sopenharmony_ci int ret = 0; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 161962306a36Sopenharmony_ci ret = __del_qgroup_relation(trans, src, dst); 162062306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci return ret; 162362306a36Sopenharmony_ci} 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ciint btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) 162662306a36Sopenharmony_ci{ 162762306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 162862306a36Sopenharmony_ci struct btrfs_root *quota_root; 162962306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 163062306a36Sopenharmony_ci int ret = 0; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 163362306a36Sopenharmony_ci if (!fs_info->quota_root) { 163462306a36Sopenharmony_ci ret = -ENOTCONN; 163562306a36Sopenharmony_ci goto out; 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci quota_root = fs_info->quota_root; 163862306a36Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, qgroupid); 163962306a36Sopenharmony_ci if (qgroup) { 164062306a36Sopenharmony_ci ret = -EEXIST; 164162306a36Sopenharmony_ci goto out; 164262306a36Sopenharmony_ci } 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci ret = add_qgroup_item(trans, quota_root, qgroupid); 164562306a36Sopenharmony_ci if (ret) 164662306a36Sopenharmony_ci goto out; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 164962306a36Sopenharmony_ci qgroup = add_qgroup_rb(fs_info, qgroupid); 165062306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci if (IS_ERR(qgroup)) { 165362306a36Sopenharmony_ci ret = PTR_ERR(qgroup); 165462306a36Sopenharmony_ci goto out; 165562306a36Sopenharmony_ci } 165662306a36Sopenharmony_ci ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup); 165762306a36Sopenharmony_ciout: 165862306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 165962306a36Sopenharmony_ci return ret; 166062306a36Sopenharmony_ci} 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_cistatic bool qgroup_has_usage(struct btrfs_qgroup *qgroup) 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci return (qgroup->rfer > 0 || qgroup->rfer_cmpr > 0 || 166562306a36Sopenharmony_ci qgroup->excl > 0 || qgroup->excl_cmpr > 0 || 166662306a36Sopenharmony_ci qgroup->rsv.values[BTRFS_QGROUP_RSV_DATA] > 0 || 166762306a36Sopenharmony_ci qgroup->rsv.values[BTRFS_QGROUP_RSV_META_PREALLOC] > 0 || 166862306a36Sopenharmony_ci qgroup->rsv.values[BTRFS_QGROUP_RSV_META_PERTRANS] > 0); 166962306a36Sopenharmony_ci} 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ciint btrfs_remove_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid) 167262306a36Sopenharmony_ci{ 167362306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 167462306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 167562306a36Sopenharmony_ci struct btrfs_qgroup_list *list; 167662306a36Sopenharmony_ci int ret = 0; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 167962306a36Sopenharmony_ci if (!fs_info->quota_root) { 168062306a36Sopenharmony_ci ret = -ENOTCONN; 168162306a36Sopenharmony_ci goto out; 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, qgroupid); 168562306a36Sopenharmony_ci if (!qgroup) { 168662306a36Sopenharmony_ci ret = -ENOENT; 168762306a36Sopenharmony_ci goto out; 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_ci if (is_fstree(qgroupid) && qgroup_has_usage(qgroup)) { 169162306a36Sopenharmony_ci ret = -EBUSY; 169262306a36Sopenharmony_ci goto out; 169362306a36Sopenharmony_ci } 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci /* Check if there are no children of this qgroup */ 169662306a36Sopenharmony_ci if (!list_empty(&qgroup->members)) { 169762306a36Sopenharmony_ci ret = -EBUSY; 169862306a36Sopenharmony_ci goto out; 169962306a36Sopenharmony_ci } 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci ret = del_qgroup_item(trans, qgroupid); 170262306a36Sopenharmony_ci if (ret && ret != -ENOENT) 170362306a36Sopenharmony_ci goto out; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci while (!list_empty(&qgroup->groups)) { 170662306a36Sopenharmony_ci list = list_first_entry(&qgroup->groups, 170762306a36Sopenharmony_ci struct btrfs_qgroup_list, next_group); 170862306a36Sopenharmony_ci ret = __del_qgroup_relation(trans, qgroupid, 170962306a36Sopenharmony_ci list->group->qgroupid); 171062306a36Sopenharmony_ci if (ret) 171162306a36Sopenharmony_ci goto out; 171262306a36Sopenharmony_ci } 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 171562306a36Sopenharmony_ci del_qgroup_rb(fs_info, qgroupid); 171662306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci /* 171962306a36Sopenharmony_ci * Remove the qgroup from sysfs now without holding the qgroup_lock 172062306a36Sopenharmony_ci * spinlock, since the sysfs_remove_group() function needs to take 172162306a36Sopenharmony_ci * the mutex kernfs_mutex through kernfs_remove_by_name_ns(). 172262306a36Sopenharmony_ci */ 172362306a36Sopenharmony_ci btrfs_sysfs_del_one_qgroup(fs_info, qgroup); 172462306a36Sopenharmony_ci kfree(qgroup); 172562306a36Sopenharmony_ciout: 172662306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 172762306a36Sopenharmony_ci return ret; 172862306a36Sopenharmony_ci} 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ciint btrfs_limit_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid, 173162306a36Sopenharmony_ci struct btrfs_qgroup_limit *limit) 173262306a36Sopenharmony_ci{ 173362306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 173462306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 173562306a36Sopenharmony_ci int ret = 0; 173662306a36Sopenharmony_ci /* Sometimes we would want to clear the limit on this qgroup. 173762306a36Sopenharmony_ci * To meet this requirement, we treat the -1 as a special value 173862306a36Sopenharmony_ci * which tell kernel to clear the limit on this qgroup. 173962306a36Sopenharmony_ci */ 174062306a36Sopenharmony_ci const u64 CLEAR_VALUE = -1; 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 174362306a36Sopenharmony_ci if (!fs_info->quota_root) { 174462306a36Sopenharmony_ci ret = -ENOTCONN; 174562306a36Sopenharmony_ci goto out; 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, qgroupid); 174962306a36Sopenharmony_ci if (!qgroup) { 175062306a36Sopenharmony_ci ret = -ENOENT; 175162306a36Sopenharmony_ci goto out; 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 175562306a36Sopenharmony_ci if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_RFER) { 175662306a36Sopenharmony_ci if (limit->max_rfer == CLEAR_VALUE) { 175762306a36Sopenharmony_ci qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_MAX_RFER; 175862306a36Sopenharmony_ci limit->flags &= ~BTRFS_QGROUP_LIMIT_MAX_RFER; 175962306a36Sopenharmony_ci qgroup->max_rfer = 0; 176062306a36Sopenharmony_ci } else { 176162306a36Sopenharmony_ci qgroup->max_rfer = limit->max_rfer; 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci } 176462306a36Sopenharmony_ci if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) { 176562306a36Sopenharmony_ci if (limit->max_excl == CLEAR_VALUE) { 176662306a36Sopenharmony_ci qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_MAX_EXCL; 176762306a36Sopenharmony_ci limit->flags &= ~BTRFS_QGROUP_LIMIT_MAX_EXCL; 176862306a36Sopenharmony_ci qgroup->max_excl = 0; 176962306a36Sopenharmony_ci } else { 177062306a36Sopenharmony_ci qgroup->max_excl = limit->max_excl; 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci } 177362306a36Sopenharmony_ci if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_RFER) { 177462306a36Sopenharmony_ci if (limit->rsv_rfer == CLEAR_VALUE) { 177562306a36Sopenharmony_ci qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_RSV_RFER; 177662306a36Sopenharmony_ci limit->flags &= ~BTRFS_QGROUP_LIMIT_RSV_RFER; 177762306a36Sopenharmony_ci qgroup->rsv_rfer = 0; 177862306a36Sopenharmony_ci } else { 177962306a36Sopenharmony_ci qgroup->rsv_rfer = limit->rsv_rfer; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci } 178262306a36Sopenharmony_ci if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_EXCL) { 178362306a36Sopenharmony_ci if (limit->rsv_excl == CLEAR_VALUE) { 178462306a36Sopenharmony_ci qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_RSV_EXCL; 178562306a36Sopenharmony_ci limit->flags &= ~BTRFS_QGROUP_LIMIT_RSV_EXCL; 178662306a36Sopenharmony_ci qgroup->rsv_excl = 0; 178762306a36Sopenharmony_ci } else { 178862306a36Sopenharmony_ci qgroup->rsv_excl = limit->rsv_excl; 178962306a36Sopenharmony_ci } 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci qgroup->lim_flags |= limit->flags; 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci ret = update_qgroup_limit_item(trans, qgroup); 179662306a36Sopenharmony_ci if (ret) { 179762306a36Sopenharmony_ci qgroup_mark_inconsistent(fs_info); 179862306a36Sopenharmony_ci btrfs_info(fs_info, "unable to update quota limit for %llu", 179962306a36Sopenharmony_ci qgroupid); 180062306a36Sopenharmony_ci } 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ciout: 180362306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 180462306a36Sopenharmony_ci return ret; 180562306a36Sopenharmony_ci} 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ciint btrfs_qgroup_trace_extent_nolock(struct btrfs_fs_info *fs_info, 180862306a36Sopenharmony_ci struct btrfs_delayed_ref_root *delayed_refs, 180962306a36Sopenharmony_ci struct btrfs_qgroup_extent_record *record) 181062306a36Sopenharmony_ci{ 181162306a36Sopenharmony_ci struct rb_node **p = &delayed_refs->dirty_extent_root.rb_node; 181262306a36Sopenharmony_ci struct rb_node *parent_node = NULL; 181362306a36Sopenharmony_ci struct btrfs_qgroup_extent_record *entry; 181462306a36Sopenharmony_ci u64 bytenr = record->bytenr; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci lockdep_assert_held(&delayed_refs->lock); 181762306a36Sopenharmony_ci trace_btrfs_qgroup_trace_extent(fs_info, record); 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci while (*p) { 182062306a36Sopenharmony_ci parent_node = *p; 182162306a36Sopenharmony_ci entry = rb_entry(parent_node, struct btrfs_qgroup_extent_record, 182262306a36Sopenharmony_ci node); 182362306a36Sopenharmony_ci if (bytenr < entry->bytenr) { 182462306a36Sopenharmony_ci p = &(*p)->rb_left; 182562306a36Sopenharmony_ci } else if (bytenr > entry->bytenr) { 182662306a36Sopenharmony_ci p = &(*p)->rb_right; 182762306a36Sopenharmony_ci } else { 182862306a36Sopenharmony_ci if (record->data_rsv && !entry->data_rsv) { 182962306a36Sopenharmony_ci entry->data_rsv = record->data_rsv; 183062306a36Sopenharmony_ci entry->data_rsv_refroot = 183162306a36Sopenharmony_ci record->data_rsv_refroot; 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci return 1; 183462306a36Sopenharmony_ci } 183562306a36Sopenharmony_ci } 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci rb_link_node(&record->node, parent_node, p); 183862306a36Sopenharmony_ci rb_insert_color(&record->node, &delayed_refs->dirty_extent_root); 183962306a36Sopenharmony_ci return 0; 184062306a36Sopenharmony_ci} 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ciint btrfs_qgroup_trace_extent_post(struct btrfs_trans_handle *trans, 184362306a36Sopenharmony_ci struct btrfs_qgroup_extent_record *qrecord) 184462306a36Sopenharmony_ci{ 184562306a36Sopenharmony_ci struct btrfs_backref_walk_ctx ctx = { 0 }; 184662306a36Sopenharmony_ci int ret; 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci /* 184962306a36Sopenharmony_ci * We are always called in a context where we are already holding a 185062306a36Sopenharmony_ci * transaction handle. Often we are called when adding a data delayed 185162306a36Sopenharmony_ci * reference from btrfs_truncate_inode_items() (truncating or unlinking), 185262306a36Sopenharmony_ci * in which case we will be holding a write lock on extent buffer from a 185362306a36Sopenharmony_ci * subvolume tree. In this case we can't allow btrfs_find_all_roots() to 185462306a36Sopenharmony_ci * acquire fs_info->commit_root_sem, because that is a higher level lock 185562306a36Sopenharmony_ci * that must be acquired before locking any extent buffers. 185662306a36Sopenharmony_ci * 185762306a36Sopenharmony_ci * So we want btrfs_find_all_roots() to not acquire the commit_root_sem 185862306a36Sopenharmony_ci * but we can't pass it a non-NULL transaction handle, because otherwise 185962306a36Sopenharmony_ci * it would not use commit roots and would lock extent buffers, causing 186062306a36Sopenharmony_ci * a deadlock if it ends up trying to read lock the same extent buffer 186162306a36Sopenharmony_ci * that was previously write locked at btrfs_truncate_inode_items(). 186262306a36Sopenharmony_ci * 186362306a36Sopenharmony_ci * So pass a NULL transaction handle to btrfs_find_all_roots() and 186462306a36Sopenharmony_ci * explicitly tell it to not acquire the commit_root_sem - if we are 186562306a36Sopenharmony_ci * holding a transaction handle we don't need its protection. 186662306a36Sopenharmony_ci */ 186762306a36Sopenharmony_ci ASSERT(trans != NULL); 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci if (trans->fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING) 187062306a36Sopenharmony_ci return 0; 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci ctx.bytenr = qrecord->bytenr; 187362306a36Sopenharmony_ci ctx.fs_info = trans->fs_info; 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, true); 187662306a36Sopenharmony_ci if (ret < 0) { 187762306a36Sopenharmony_ci qgroup_mark_inconsistent(trans->fs_info); 187862306a36Sopenharmony_ci btrfs_warn(trans->fs_info, 187962306a36Sopenharmony_ci"error accounting new delayed refs extent (err code: %d), quota inconsistent", 188062306a36Sopenharmony_ci ret); 188162306a36Sopenharmony_ci return 0; 188262306a36Sopenharmony_ci } 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci /* 188562306a36Sopenharmony_ci * Here we don't need to get the lock of 188662306a36Sopenharmony_ci * trans->transaction->delayed_refs, since inserted qrecord won't 188762306a36Sopenharmony_ci * be deleted, only qrecord->node may be modified (new qrecord insert) 188862306a36Sopenharmony_ci * 188962306a36Sopenharmony_ci * So modifying qrecord->old_roots is safe here 189062306a36Sopenharmony_ci */ 189162306a36Sopenharmony_ci qrecord->old_roots = ctx.roots; 189262306a36Sopenharmony_ci return 0; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ciint btrfs_qgroup_trace_extent(struct btrfs_trans_handle *trans, u64 bytenr, 189662306a36Sopenharmony_ci u64 num_bytes) 189762306a36Sopenharmony_ci{ 189862306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 189962306a36Sopenharmony_ci struct btrfs_qgroup_extent_record *record; 190062306a36Sopenharmony_ci struct btrfs_delayed_ref_root *delayed_refs; 190162306a36Sopenharmony_ci int ret; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) 190462306a36Sopenharmony_ci || bytenr == 0 || num_bytes == 0) 190562306a36Sopenharmony_ci return 0; 190662306a36Sopenharmony_ci record = kzalloc(sizeof(*record), GFP_NOFS); 190762306a36Sopenharmony_ci if (!record) 190862306a36Sopenharmony_ci return -ENOMEM; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci delayed_refs = &trans->transaction->delayed_refs; 191162306a36Sopenharmony_ci record->bytenr = bytenr; 191262306a36Sopenharmony_ci record->num_bytes = num_bytes; 191362306a36Sopenharmony_ci record->old_roots = NULL; 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci spin_lock(&delayed_refs->lock); 191662306a36Sopenharmony_ci ret = btrfs_qgroup_trace_extent_nolock(fs_info, delayed_refs, record); 191762306a36Sopenharmony_ci spin_unlock(&delayed_refs->lock); 191862306a36Sopenharmony_ci if (ret > 0) { 191962306a36Sopenharmony_ci kfree(record); 192062306a36Sopenharmony_ci return 0; 192162306a36Sopenharmony_ci } 192262306a36Sopenharmony_ci return btrfs_qgroup_trace_extent_post(trans, record); 192362306a36Sopenharmony_ci} 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ciint btrfs_qgroup_trace_leaf_items(struct btrfs_trans_handle *trans, 192662306a36Sopenharmony_ci struct extent_buffer *eb) 192762306a36Sopenharmony_ci{ 192862306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 192962306a36Sopenharmony_ci int nr = btrfs_header_nritems(eb); 193062306a36Sopenharmony_ci int i, extent_type, ret; 193162306a36Sopenharmony_ci struct btrfs_key key; 193262306a36Sopenharmony_ci struct btrfs_file_extent_item *fi; 193362306a36Sopenharmony_ci u64 bytenr, num_bytes; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci /* We can be called directly from walk_up_proc() */ 193662306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 193762306a36Sopenharmony_ci return 0; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 194062306a36Sopenharmony_ci btrfs_item_key_to_cpu(eb, &key, i); 194162306a36Sopenharmony_ci 194262306a36Sopenharmony_ci if (key.type != BTRFS_EXTENT_DATA_KEY) 194362306a36Sopenharmony_ci continue; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci fi = btrfs_item_ptr(eb, i, struct btrfs_file_extent_item); 194662306a36Sopenharmony_ci /* filter out non qgroup-accountable extents */ 194762306a36Sopenharmony_ci extent_type = btrfs_file_extent_type(eb, fi); 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci if (extent_type == BTRFS_FILE_EXTENT_INLINE) 195062306a36Sopenharmony_ci continue; 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci bytenr = btrfs_file_extent_disk_bytenr(eb, fi); 195362306a36Sopenharmony_ci if (!bytenr) 195462306a36Sopenharmony_ci continue; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi); 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci ret = btrfs_qgroup_trace_extent(trans, bytenr, num_bytes); 195962306a36Sopenharmony_ci if (ret) 196062306a36Sopenharmony_ci return ret; 196162306a36Sopenharmony_ci } 196262306a36Sopenharmony_ci cond_resched(); 196362306a36Sopenharmony_ci return 0; 196462306a36Sopenharmony_ci} 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci/* 196762306a36Sopenharmony_ci * Walk up the tree from the bottom, freeing leaves and any interior 196862306a36Sopenharmony_ci * nodes which have had all slots visited. If a node (leaf or 196962306a36Sopenharmony_ci * interior) is freed, the node above it will have it's slot 197062306a36Sopenharmony_ci * incremented. The root node will never be freed. 197162306a36Sopenharmony_ci * 197262306a36Sopenharmony_ci * At the end of this function, we should have a path which has all 197362306a36Sopenharmony_ci * slots incremented to the next position for a search. If we need to 197462306a36Sopenharmony_ci * read a new node it will be NULL and the node above it will have the 197562306a36Sopenharmony_ci * correct slot selected for a later read. 197662306a36Sopenharmony_ci * 197762306a36Sopenharmony_ci * If we increment the root nodes slot counter past the number of 197862306a36Sopenharmony_ci * elements, 1 is returned to signal completion of the search. 197962306a36Sopenharmony_ci */ 198062306a36Sopenharmony_cistatic int adjust_slots_upwards(struct btrfs_path *path, int root_level) 198162306a36Sopenharmony_ci{ 198262306a36Sopenharmony_ci int level = 0; 198362306a36Sopenharmony_ci int nr, slot; 198462306a36Sopenharmony_ci struct extent_buffer *eb; 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci if (root_level == 0) 198762306a36Sopenharmony_ci return 1; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci while (level <= root_level) { 199062306a36Sopenharmony_ci eb = path->nodes[level]; 199162306a36Sopenharmony_ci nr = btrfs_header_nritems(eb); 199262306a36Sopenharmony_ci path->slots[level]++; 199362306a36Sopenharmony_ci slot = path->slots[level]; 199462306a36Sopenharmony_ci if (slot >= nr || level == 0) { 199562306a36Sopenharmony_ci /* 199662306a36Sopenharmony_ci * Don't free the root - we will detect this 199762306a36Sopenharmony_ci * condition after our loop and return a 199862306a36Sopenharmony_ci * positive value for caller to stop walking the tree. 199962306a36Sopenharmony_ci */ 200062306a36Sopenharmony_ci if (level != root_level) { 200162306a36Sopenharmony_ci btrfs_tree_unlock_rw(eb, path->locks[level]); 200262306a36Sopenharmony_ci path->locks[level] = 0; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci free_extent_buffer(eb); 200562306a36Sopenharmony_ci path->nodes[level] = NULL; 200662306a36Sopenharmony_ci path->slots[level] = 0; 200762306a36Sopenharmony_ci } 200862306a36Sopenharmony_ci } else { 200962306a36Sopenharmony_ci /* 201062306a36Sopenharmony_ci * We have a valid slot to walk back down 201162306a36Sopenharmony_ci * from. Stop here so caller can process these 201262306a36Sopenharmony_ci * new nodes. 201362306a36Sopenharmony_ci */ 201462306a36Sopenharmony_ci break; 201562306a36Sopenharmony_ci } 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci level++; 201862306a36Sopenharmony_ci } 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci eb = path->nodes[root_level]; 202162306a36Sopenharmony_ci if (path->slots[root_level] >= btrfs_header_nritems(eb)) 202262306a36Sopenharmony_ci return 1; 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci return 0; 202562306a36Sopenharmony_ci} 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci/* 202862306a36Sopenharmony_ci * Helper function to trace a subtree tree block swap. 202962306a36Sopenharmony_ci * 203062306a36Sopenharmony_ci * The swap will happen in highest tree block, but there may be a lot of 203162306a36Sopenharmony_ci * tree blocks involved. 203262306a36Sopenharmony_ci * 203362306a36Sopenharmony_ci * For example: 203462306a36Sopenharmony_ci * OO = Old tree blocks 203562306a36Sopenharmony_ci * NN = New tree blocks allocated during balance 203662306a36Sopenharmony_ci * 203762306a36Sopenharmony_ci * File tree (257) Reloc tree for 257 203862306a36Sopenharmony_ci * L2 OO NN 203962306a36Sopenharmony_ci * / \ / \ 204062306a36Sopenharmony_ci * L1 OO OO (a) OO NN (a) 204162306a36Sopenharmony_ci * / \ / \ / \ / \ 204262306a36Sopenharmony_ci * L0 OO OO OO OO OO OO NN NN 204362306a36Sopenharmony_ci * (b) (c) (b) (c) 204462306a36Sopenharmony_ci * 204562306a36Sopenharmony_ci * When calling qgroup_trace_extent_swap(), we will pass: 204662306a36Sopenharmony_ci * @src_eb = OO(a) 204762306a36Sopenharmony_ci * @dst_path = [ nodes[1] = NN(a), nodes[0] = NN(c) ] 204862306a36Sopenharmony_ci * @dst_level = 0 204962306a36Sopenharmony_ci * @root_level = 1 205062306a36Sopenharmony_ci * 205162306a36Sopenharmony_ci * In that case, qgroup_trace_extent_swap() will search from OO(a) to 205262306a36Sopenharmony_ci * reach OO(c), then mark both OO(c) and NN(c) as qgroup dirty. 205362306a36Sopenharmony_ci * 205462306a36Sopenharmony_ci * The main work of qgroup_trace_extent_swap() can be split into 3 parts: 205562306a36Sopenharmony_ci * 205662306a36Sopenharmony_ci * 1) Tree search from @src_eb 205762306a36Sopenharmony_ci * It should acts as a simplified btrfs_search_slot(). 205862306a36Sopenharmony_ci * The key for search can be extracted from @dst_path->nodes[dst_level] 205962306a36Sopenharmony_ci * (first key). 206062306a36Sopenharmony_ci * 206162306a36Sopenharmony_ci * 2) Mark the final tree blocks in @src_path and @dst_path qgroup dirty 206262306a36Sopenharmony_ci * NOTE: In above case, OO(a) and NN(a) won't be marked qgroup dirty. 206362306a36Sopenharmony_ci * They should be marked during previous (@dst_level = 1) iteration. 206462306a36Sopenharmony_ci * 206562306a36Sopenharmony_ci * 3) Mark file extents in leaves dirty 206662306a36Sopenharmony_ci * We don't have good way to pick out new file extents only. 206762306a36Sopenharmony_ci * So we still follow the old method by scanning all file extents in 206862306a36Sopenharmony_ci * the leave. 206962306a36Sopenharmony_ci * 207062306a36Sopenharmony_ci * This function can free us from keeping two paths, thus later we only need 207162306a36Sopenharmony_ci * to care about how to iterate all new tree blocks in reloc tree. 207262306a36Sopenharmony_ci */ 207362306a36Sopenharmony_cistatic int qgroup_trace_extent_swap(struct btrfs_trans_handle* trans, 207462306a36Sopenharmony_ci struct extent_buffer *src_eb, 207562306a36Sopenharmony_ci struct btrfs_path *dst_path, 207662306a36Sopenharmony_ci int dst_level, int root_level, 207762306a36Sopenharmony_ci bool trace_leaf) 207862306a36Sopenharmony_ci{ 207962306a36Sopenharmony_ci struct btrfs_key key; 208062306a36Sopenharmony_ci struct btrfs_path *src_path; 208162306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 208262306a36Sopenharmony_ci u32 nodesize = fs_info->nodesize; 208362306a36Sopenharmony_ci int cur_level = root_level; 208462306a36Sopenharmony_ci int ret; 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci BUG_ON(dst_level > root_level); 208762306a36Sopenharmony_ci /* Level mismatch */ 208862306a36Sopenharmony_ci if (btrfs_header_level(src_eb) != root_level) 208962306a36Sopenharmony_ci return -EINVAL; 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci src_path = btrfs_alloc_path(); 209262306a36Sopenharmony_ci if (!src_path) { 209362306a36Sopenharmony_ci ret = -ENOMEM; 209462306a36Sopenharmony_ci goto out; 209562306a36Sopenharmony_ci } 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci if (dst_level) 209862306a36Sopenharmony_ci btrfs_node_key_to_cpu(dst_path->nodes[dst_level], &key, 0); 209962306a36Sopenharmony_ci else 210062306a36Sopenharmony_ci btrfs_item_key_to_cpu(dst_path->nodes[dst_level], &key, 0); 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci /* For src_path */ 210362306a36Sopenharmony_ci atomic_inc(&src_eb->refs); 210462306a36Sopenharmony_ci src_path->nodes[root_level] = src_eb; 210562306a36Sopenharmony_ci src_path->slots[root_level] = dst_path->slots[root_level]; 210662306a36Sopenharmony_ci src_path->locks[root_level] = 0; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci /* A simplified version of btrfs_search_slot() */ 210962306a36Sopenharmony_ci while (cur_level >= dst_level) { 211062306a36Sopenharmony_ci struct btrfs_key src_key; 211162306a36Sopenharmony_ci struct btrfs_key dst_key; 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci if (src_path->nodes[cur_level] == NULL) { 211462306a36Sopenharmony_ci struct extent_buffer *eb; 211562306a36Sopenharmony_ci int parent_slot; 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci eb = src_path->nodes[cur_level + 1]; 211862306a36Sopenharmony_ci parent_slot = src_path->slots[cur_level + 1]; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci eb = btrfs_read_node_slot(eb, parent_slot); 212162306a36Sopenharmony_ci if (IS_ERR(eb)) { 212262306a36Sopenharmony_ci ret = PTR_ERR(eb); 212362306a36Sopenharmony_ci goto out; 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci src_path->nodes[cur_level] = eb; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci btrfs_tree_read_lock(eb); 212962306a36Sopenharmony_ci src_path->locks[cur_level] = BTRFS_READ_LOCK; 213062306a36Sopenharmony_ci } 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci src_path->slots[cur_level] = dst_path->slots[cur_level]; 213362306a36Sopenharmony_ci if (cur_level) { 213462306a36Sopenharmony_ci btrfs_node_key_to_cpu(dst_path->nodes[cur_level], 213562306a36Sopenharmony_ci &dst_key, dst_path->slots[cur_level]); 213662306a36Sopenharmony_ci btrfs_node_key_to_cpu(src_path->nodes[cur_level], 213762306a36Sopenharmony_ci &src_key, src_path->slots[cur_level]); 213862306a36Sopenharmony_ci } else { 213962306a36Sopenharmony_ci btrfs_item_key_to_cpu(dst_path->nodes[cur_level], 214062306a36Sopenharmony_ci &dst_key, dst_path->slots[cur_level]); 214162306a36Sopenharmony_ci btrfs_item_key_to_cpu(src_path->nodes[cur_level], 214262306a36Sopenharmony_ci &src_key, src_path->slots[cur_level]); 214362306a36Sopenharmony_ci } 214462306a36Sopenharmony_ci /* Content mismatch, something went wrong */ 214562306a36Sopenharmony_ci if (btrfs_comp_cpu_keys(&dst_key, &src_key)) { 214662306a36Sopenharmony_ci ret = -ENOENT; 214762306a36Sopenharmony_ci goto out; 214862306a36Sopenharmony_ci } 214962306a36Sopenharmony_ci cur_level--; 215062306a36Sopenharmony_ci } 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_ci /* 215362306a36Sopenharmony_ci * Now both @dst_path and @src_path have been populated, record the tree 215462306a36Sopenharmony_ci * blocks for qgroup accounting. 215562306a36Sopenharmony_ci */ 215662306a36Sopenharmony_ci ret = btrfs_qgroup_trace_extent(trans, src_path->nodes[dst_level]->start, 215762306a36Sopenharmony_ci nodesize); 215862306a36Sopenharmony_ci if (ret < 0) 215962306a36Sopenharmony_ci goto out; 216062306a36Sopenharmony_ci ret = btrfs_qgroup_trace_extent(trans, dst_path->nodes[dst_level]->start, 216162306a36Sopenharmony_ci nodesize); 216262306a36Sopenharmony_ci if (ret < 0) 216362306a36Sopenharmony_ci goto out; 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci /* Record leaf file extents */ 216662306a36Sopenharmony_ci if (dst_level == 0 && trace_leaf) { 216762306a36Sopenharmony_ci ret = btrfs_qgroup_trace_leaf_items(trans, src_path->nodes[0]); 216862306a36Sopenharmony_ci if (ret < 0) 216962306a36Sopenharmony_ci goto out; 217062306a36Sopenharmony_ci ret = btrfs_qgroup_trace_leaf_items(trans, dst_path->nodes[0]); 217162306a36Sopenharmony_ci } 217262306a36Sopenharmony_ciout: 217362306a36Sopenharmony_ci btrfs_free_path(src_path); 217462306a36Sopenharmony_ci return ret; 217562306a36Sopenharmony_ci} 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci/* 217862306a36Sopenharmony_ci * Helper function to do recursive generation-aware depth-first search, to 217962306a36Sopenharmony_ci * locate all new tree blocks in a subtree of reloc tree. 218062306a36Sopenharmony_ci * 218162306a36Sopenharmony_ci * E.g. (OO = Old tree blocks, NN = New tree blocks, whose gen == last_snapshot) 218262306a36Sopenharmony_ci * reloc tree 218362306a36Sopenharmony_ci * L2 NN (a) 218462306a36Sopenharmony_ci * / \ 218562306a36Sopenharmony_ci * L1 OO NN (b) 218662306a36Sopenharmony_ci * / \ / \ 218762306a36Sopenharmony_ci * L0 OO OO OO NN 218862306a36Sopenharmony_ci * (c) (d) 218962306a36Sopenharmony_ci * If we pass: 219062306a36Sopenharmony_ci * @dst_path = [ nodes[1] = NN(b), nodes[0] = NULL ], 219162306a36Sopenharmony_ci * @cur_level = 1 219262306a36Sopenharmony_ci * @root_level = 1 219362306a36Sopenharmony_ci * 219462306a36Sopenharmony_ci * We will iterate through tree blocks NN(b), NN(d) and info qgroup to trace 219562306a36Sopenharmony_ci * above tree blocks along with their counter parts in file tree. 219662306a36Sopenharmony_ci * While during search, old tree blocks OO(c) will be skipped as tree block swap 219762306a36Sopenharmony_ci * won't affect OO(c). 219862306a36Sopenharmony_ci */ 219962306a36Sopenharmony_cistatic int qgroup_trace_new_subtree_blocks(struct btrfs_trans_handle* trans, 220062306a36Sopenharmony_ci struct extent_buffer *src_eb, 220162306a36Sopenharmony_ci struct btrfs_path *dst_path, 220262306a36Sopenharmony_ci int cur_level, int root_level, 220362306a36Sopenharmony_ci u64 last_snapshot, bool trace_leaf) 220462306a36Sopenharmony_ci{ 220562306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 220662306a36Sopenharmony_ci struct extent_buffer *eb; 220762306a36Sopenharmony_ci bool need_cleanup = false; 220862306a36Sopenharmony_ci int ret = 0; 220962306a36Sopenharmony_ci int i; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci /* Level sanity check */ 221262306a36Sopenharmony_ci if (cur_level < 0 || cur_level >= BTRFS_MAX_LEVEL - 1 || 221362306a36Sopenharmony_ci root_level < 0 || root_level >= BTRFS_MAX_LEVEL - 1 || 221462306a36Sopenharmony_ci root_level < cur_level) { 221562306a36Sopenharmony_ci btrfs_err_rl(fs_info, 221662306a36Sopenharmony_ci "%s: bad levels, cur_level=%d root_level=%d", 221762306a36Sopenharmony_ci __func__, cur_level, root_level); 221862306a36Sopenharmony_ci return -EUCLEAN; 221962306a36Sopenharmony_ci } 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci /* Read the tree block if needed */ 222262306a36Sopenharmony_ci if (dst_path->nodes[cur_level] == NULL) { 222362306a36Sopenharmony_ci int parent_slot; 222462306a36Sopenharmony_ci u64 child_gen; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci /* 222762306a36Sopenharmony_ci * dst_path->nodes[root_level] must be initialized before 222862306a36Sopenharmony_ci * calling this function. 222962306a36Sopenharmony_ci */ 223062306a36Sopenharmony_ci if (cur_level == root_level) { 223162306a36Sopenharmony_ci btrfs_err_rl(fs_info, 223262306a36Sopenharmony_ci "%s: dst_path->nodes[%d] not initialized, root_level=%d cur_level=%d", 223362306a36Sopenharmony_ci __func__, root_level, root_level, cur_level); 223462306a36Sopenharmony_ci return -EUCLEAN; 223562306a36Sopenharmony_ci } 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci /* 223862306a36Sopenharmony_ci * We need to get child blockptr/gen from parent before we can 223962306a36Sopenharmony_ci * read it. 224062306a36Sopenharmony_ci */ 224162306a36Sopenharmony_ci eb = dst_path->nodes[cur_level + 1]; 224262306a36Sopenharmony_ci parent_slot = dst_path->slots[cur_level + 1]; 224362306a36Sopenharmony_ci child_gen = btrfs_node_ptr_generation(eb, parent_slot); 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci /* This node is old, no need to trace */ 224662306a36Sopenharmony_ci if (child_gen < last_snapshot) 224762306a36Sopenharmony_ci goto out; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci eb = btrfs_read_node_slot(eb, parent_slot); 225062306a36Sopenharmony_ci if (IS_ERR(eb)) { 225162306a36Sopenharmony_ci ret = PTR_ERR(eb); 225262306a36Sopenharmony_ci goto out; 225362306a36Sopenharmony_ci } 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci dst_path->nodes[cur_level] = eb; 225662306a36Sopenharmony_ci dst_path->slots[cur_level] = 0; 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci btrfs_tree_read_lock(eb); 225962306a36Sopenharmony_ci dst_path->locks[cur_level] = BTRFS_READ_LOCK; 226062306a36Sopenharmony_ci need_cleanup = true; 226162306a36Sopenharmony_ci } 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci /* Now record this tree block and its counter part for qgroups */ 226462306a36Sopenharmony_ci ret = qgroup_trace_extent_swap(trans, src_eb, dst_path, cur_level, 226562306a36Sopenharmony_ci root_level, trace_leaf); 226662306a36Sopenharmony_ci if (ret < 0) 226762306a36Sopenharmony_ci goto cleanup; 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci eb = dst_path->nodes[cur_level]; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci if (cur_level > 0) { 227262306a36Sopenharmony_ci /* Iterate all child tree blocks */ 227362306a36Sopenharmony_ci for (i = 0; i < btrfs_header_nritems(eb); i++) { 227462306a36Sopenharmony_ci /* Skip old tree blocks as they won't be swapped */ 227562306a36Sopenharmony_ci if (btrfs_node_ptr_generation(eb, i) < last_snapshot) 227662306a36Sopenharmony_ci continue; 227762306a36Sopenharmony_ci dst_path->slots[cur_level] = i; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci /* Recursive call (at most 7 times) */ 228062306a36Sopenharmony_ci ret = qgroup_trace_new_subtree_blocks(trans, src_eb, 228162306a36Sopenharmony_ci dst_path, cur_level - 1, root_level, 228262306a36Sopenharmony_ci last_snapshot, trace_leaf); 228362306a36Sopenharmony_ci if (ret < 0) 228462306a36Sopenharmony_ci goto cleanup; 228562306a36Sopenharmony_ci } 228662306a36Sopenharmony_ci } 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_cicleanup: 228962306a36Sopenharmony_ci if (need_cleanup) { 229062306a36Sopenharmony_ci /* Clean up */ 229162306a36Sopenharmony_ci btrfs_tree_unlock_rw(dst_path->nodes[cur_level], 229262306a36Sopenharmony_ci dst_path->locks[cur_level]); 229362306a36Sopenharmony_ci free_extent_buffer(dst_path->nodes[cur_level]); 229462306a36Sopenharmony_ci dst_path->nodes[cur_level] = NULL; 229562306a36Sopenharmony_ci dst_path->slots[cur_level] = 0; 229662306a36Sopenharmony_ci dst_path->locks[cur_level] = 0; 229762306a36Sopenharmony_ci } 229862306a36Sopenharmony_ciout: 229962306a36Sopenharmony_ci return ret; 230062306a36Sopenharmony_ci} 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_cistatic int qgroup_trace_subtree_swap(struct btrfs_trans_handle *trans, 230362306a36Sopenharmony_ci struct extent_buffer *src_eb, 230462306a36Sopenharmony_ci struct extent_buffer *dst_eb, 230562306a36Sopenharmony_ci u64 last_snapshot, bool trace_leaf) 230662306a36Sopenharmony_ci{ 230762306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 230862306a36Sopenharmony_ci struct btrfs_path *dst_path = NULL; 230962306a36Sopenharmony_ci int level; 231062306a36Sopenharmony_ci int ret; 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 231362306a36Sopenharmony_ci return 0; 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci /* Wrong parameter order */ 231662306a36Sopenharmony_ci if (btrfs_header_generation(src_eb) > btrfs_header_generation(dst_eb)) { 231762306a36Sopenharmony_ci btrfs_err_rl(fs_info, 231862306a36Sopenharmony_ci "%s: bad parameter order, src_gen=%llu dst_gen=%llu", __func__, 231962306a36Sopenharmony_ci btrfs_header_generation(src_eb), 232062306a36Sopenharmony_ci btrfs_header_generation(dst_eb)); 232162306a36Sopenharmony_ci return -EUCLEAN; 232262306a36Sopenharmony_ci } 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci if (!extent_buffer_uptodate(src_eb) || !extent_buffer_uptodate(dst_eb)) { 232562306a36Sopenharmony_ci ret = -EIO; 232662306a36Sopenharmony_ci goto out; 232762306a36Sopenharmony_ci } 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci level = btrfs_header_level(dst_eb); 233062306a36Sopenharmony_ci dst_path = btrfs_alloc_path(); 233162306a36Sopenharmony_ci if (!dst_path) { 233262306a36Sopenharmony_ci ret = -ENOMEM; 233362306a36Sopenharmony_ci goto out; 233462306a36Sopenharmony_ci } 233562306a36Sopenharmony_ci /* For dst_path */ 233662306a36Sopenharmony_ci atomic_inc(&dst_eb->refs); 233762306a36Sopenharmony_ci dst_path->nodes[level] = dst_eb; 233862306a36Sopenharmony_ci dst_path->slots[level] = 0; 233962306a36Sopenharmony_ci dst_path->locks[level] = 0; 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci /* Do the generation aware breadth-first search */ 234262306a36Sopenharmony_ci ret = qgroup_trace_new_subtree_blocks(trans, src_eb, dst_path, level, 234362306a36Sopenharmony_ci level, last_snapshot, trace_leaf); 234462306a36Sopenharmony_ci if (ret < 0) 234562306a36Sopenharmony_ci goto out; 234662306a36Sopenharmony_ci ret = 0; 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ciout: 234962306a36Sopenharmony_ci btrfs_free_path(dst_path); 235062306a36Sopenharmony_ci if (ret < 0) 235162306a36Sopenharmony_ci qgroup_mark_inconsistent(fs_info); 235262306a36Sopenharmony_ci return ret; 235362306a36Sopenharmony_ci} 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ciint btrfs_qgroup_trace_subtree(struct btrfs_trans_handle *trans, 235662306a36Sopenharmony_ci struct extent_buffer *root_eb, 235762306a36Sopenharmony_ci u64 root_gen, int root_level) 235862306a36Sopenharmony_ci{ 235962306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 236062306a36Sopenharmony_ci int ret = 0; 236162306a36Sopenharmony_ci int level; 236262306a36Sopenharmony_ci u8 drop_subptree_thres; 236362306a36Sopenharmony_ci struct extent_buffer *eb = root_eb; 236462306a36Sopenharmony_ci struct btrfs_path *path = NULL; 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci BUG_ON(root_level < 0 || root_level >= BTRFS_MAX_LEVEL); 236762306a36Sopenharmony_ci BUG_ON(root_eb == NULL); 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 237062306a36Sopenharmony_ci return 0; 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 237362306a36Sopenharmony_ci drop_subptree_thres = fs_info->qgroup_drop_subtree_thres; 237462306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci /* 237762306a36Sopenharmony_ci * This function only gets called for snapshot drop, if we hit a high 237862306a36Sopenharmony_ci * node here, it means we are going to change ownership for quite a lot 237962306a36Sopenharmony_ci * of extents, which will greatly slow down btrfs_commit_transaction(). 238062306a36Sopenharmony_ci * 238162306a36Sopenharmony_ci * So here if we find a high tree here, we just skip the accounting and 238262306a36Sopenharmony_ci * mark qgroup inconsistent. 238362306a36Sopenharmony_ci */ 238462306a36Sopenharmony_ci if (root_level >= drop_subptree_thres) { 238562306a36Sopenharmony_ci qgroup_mark_inconsistent(fs_info); 238662306a36Sopenharmony_ci return 0; 238762306a36Sopenharmony_ci } 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci if (!extent_buffer_uptodate(root_eb)) { 239062306a36Sopenharmony_ci struct btrfs_tree_parent_check check = { 239162306a36Sopenharmony_ci .has_first_key = false, 239262306a36Sopenharmony_ci .transid = root_gen, 239362306a36Sopenharmony_ci .level = root_level 239462306a36Sopenharmony_ci }; 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci ret = btrfs_read_extent_buffer(root_eb, &check); 239762306a36Sopenharmony_ci if (ret) 239862306a36Sopenharmony_ci goto out; 239962306a36Sopenharmony_ci } 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci if (root_level == 0) { 240262306a36Sopenharmony_ci ret = btrfs_qgroup_trace_leaf_items(trans, root_eb); 240362306a36Sopenharmony_ci goto out; 240462306a36Sopenharmony_ci } 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci path = btrfs_alloc_path(); 240762306a36Sopenharmony_ci if (!path) 240862306a36Sopenharmony_ci return -ENOMEM; 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci /* 241162306a36Sopenharmony_ci * Walk down the tree. Missing extent blocks are filled in as 241262306a36Sopenharmony_ci * we go. Metadata is accounted every time we read a new 241362306a36Sopenharmony_ci * extent block. 241462306a36Sopenharmony_ci * 241562306a36Sopenharmony_ci * When we reach a leaf, we account for file extent items in it, 241662306a36Sopenharmony_ci * walk back up the tree (adjusting slot pointers as we go) 241762306a36Sopenharmony_ci * and restart the search process. 241862306a36Sopenharmony_ci */ 241962306a36Sopenharmony_ci atomic_inc(&root_eb->refs); /* For path */ 242062306a36Sopenharmony_ci path->nodes[root_level] = root_eb; 242162306a36Sopenharmony_ci path->slots[root_level] = 0; 242262306a36Sopenharmony_ci path->locks[root_level] = 0; /* so release_path doesn't try to unlock */ 242362306a36Sopenharmony_ciwalk_down: 242462306a36Sopenharmony_ci level = root_level; 242562306a36Sopenharmony_ci while (level >= 0) { 242662306a36Sopenharmony_ci if (path->nodes[level] == NULL) { 242762306a36Sopenharmony_ci int parent_slot; 242862306a36Sopenharmony_ci u64 child_bytenr; 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci /* 243162306a36Sopenharmony_ci * We need to get child blockptr from parent before we 243262306a36Sopenharmony_ci * can read it. 243362306a36Sopenharmony_ci */ 243462306a36Sopenharmony_ci eb = path->nodes[level + 1]; 243562306a36Sopenharmony_ci parent_slot = path->slots[level + 1]; 243662306a36Sopenharmony_ci child_bytenr = btrfs_node_blockptr(eb, parent_slot); 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_ci eb = btrfs_read_node_slot(eb, parent_slot); 243962306a36Sopenharmony_ci if (IS_ERR(eb)) { 244062306a36Sopenharmony_ci ret = PTR_ERR(eb); 244162306a36Sopenharmony_ci goto out; 244262306a36Sopenharmony_ci } 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci path->nodes[level] = eb; 244562306a36Sopenharmony_ci path->slots[level] = 0; 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci btrfs_tree_read_lock(eb); 244862306a36Sopenharmony_ci path->locks[level] = BTRFS_READ_LOCK; 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci ret = btrfs_qgroup_trace_extent(trans, child_bytenr, 245162306a36Sopenharmony_ci fs_info->nodesize); 245262306a36Sopenharmony_ci if (ret) 245362306a36Sopenharmony_ci goto out; 245462306a36Sopenharmony_ci } 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci if (level == 0) { 245762306a36Sopenharmony_ci ret = btrfs_qgroup_trace_leaf_items(trans, 245862306a36Sopenharmony_ci path->nodes[level]); 245962306a36Sopenharmony_ci if (ret) 246062306a36Sopenharmony_ci goto out; 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci /* Nonzero return here means we completed our search */ 246362306a36Sopenharmony_ci ret = adjust_slots_upwards(path, root_level); 246462306a36Sopenharmony_ci if (ret) 246562306a36Sopenharmony_ci break; 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci /* Restart search with new slots */ 246862306a36Sopenharmony_ci goto walk_down; 246962306a36Sopenharmony_ci } 247062306a36Sopenharmony_ci 247162306a36Sopenharmony_ci level--; 247262306a36Sopenharmony_ci } 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci ret = 0; 247562306a36Sopenharmony_ciout: 247662306a36Sopenharmony_ci btrfs_free_path(path); 247762306a36Sopenharmony_ci 247862306a36Sopenharmony_ci return ret; 247962306a36Sopenharmony_ci} 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci#define UPDATE_NEW 0 248262306a36Sopenharmony_ci#define UPDATE_OLD 1 248362306a36Sopenharmony_ci/* 248462306a36Sopenharmony_ci * Walk all of the roots that points to the bytenr and adjust their refcnts. 248562306a36Sopenharmony_ci */ 248662306a36Sopenharmony_cistatic int qgroup_update_refcnt(struct btrfs_fs_info *fs_info, 248762306a36Sopenharmony_ci struct ulist *roots, struct ulist *tmp, 248862306a36Sopenharmony_ci struct ulist *qgroups, u64 seq, int update_old) 248962306a36Sopenharmony_ci{ 249062306a36Sopenharmony_ci struct ulist_node *unode; 249162306a36Sopenharmony_ci struct ulist_iterator uiter; 249262306a36Sopenharmony_ci struct ulist_node *tmp_unode; 249362306a36Sopenharmony_ci struct ulist_iterator tmp_uiter; 249462306a36Sopenharmony_ci struct btrfs_qgroup *qg; 249562306a36Sopenharmony_ci int ret = 0; 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci if (!roots) 249862306a36Sopenharmony_ci return 0; 249962306a36Sopenharmony_ci ULIST_ITER_INIT(&uiter); 250062306a36Sopenharmony_ci while ((unode = ulist_next(roots, &uiter))) { 250162306a36Sopenharmony_ci qg = find_qgroup_rb(fs_info, unode->val); 250262306a36Sopenharmony_ci if (!qg) 250362306a36Sopenharmony_ci continue; 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci ulist_reinit(tmp); 250662306a36Sopenharmony_ci ret = ulist_add(qgroups, qg->qgroupid, qgroup_to_aux(qg), 250762306a36Sopenharmony_ci GFP_ATOMIC); 250862306a36Sopenharmony_ci if (ret < 0) 250962306a36Sopenharmony_ci return ret; 251062306a36Sopenharmony_ci ret = ulist_add(tmp, qg->qgroupid, qgroup_to_aux(qg), GFP_ATOMIC); 251162306a36Sopenharmony_ci if (ret < 0) 251262306a36Sopenharmony_ci return ret; 251362306a36Sopenharmony_ci ULIST_ITER_INIT(&tmp_uiter); 251462306a36Sopenharmony_ci while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) { 251562306a36Sopenharmony_ci struct btrfs_qgroup_list *glist; 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci qg = unode_aux_to_qgroup(tmp_unode); 251862306a36Sopenharmony_ci if (update_old) 251962306a36Sopenharmony_ci btrfs_qgroup_update_old_refcnt(qg, seq, 1); 252062306a36Sopenharmony_ci else 252162306a36Sopenharmony_ci btrfs_qgroup_update_new_refcnt(qg, seq, 1); 252262306a36Sopenharmony_ci list_for_each_entry(glist, &qg->groups, next_group) { 252362306a36Sopenharmony_ci ret = ulist_add(qgroups, glist->group->qgroupid, 252462306a36Sopenharmony_ci qgroup_to_aux(glist->group), 252562306a36Sopenharmony_ci GFP_ATOMIC); 252662306a36Sopenharmony_ci if (ret < 0) 252762306a36Sopenharmony_ci return ret; 252862306a36Sopenharmony_ci ret = ulist_add(tmp, glist->group->qgroupid, 252962306a36Sopenharmony_ci qgroup_to_aux(glist->group), 253062306a36Sopenharmony_ci GFP_ATOMIC); 253162306a36Sopenharmony_ci if (ret < 0) 253262306a36Sopenharmony_ci return ret; 253362306a36Sopenharmony_ci } 253462306a36Sopenharmony_ci } 253562306a36Sopenharmony_ci } 253662306a36Sopenharmony_ci return 0; 253762306a36Sopenharmony_ci} 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci/* 254062306a36Sopenharmony_ci * Update qgroup rfer/excl counters. 254162306a36Sopenharmony_ci * Rfer update is easy, codes can explain themselves. 254262306a36Sopenharmony_ci * 254362306a36Sopenharmony_ci * Excl update is tricky, the update is split into 2 parts. 254462306a36Sopenharmony_ci * Part 1: Possible exclusive <-> sharing detect: 254562306a36Sopenharmony_ci * | A | !A | 254662306a36Sopenharmony_ci * ------------------------------------- 254762306a36Sopenharmony_ci * B | * | - | 254862306a36Sopenharmony_ci * ------------------------------------- 254962306a36Sopenharmony_ci * !B | + | ** | 255062306a36Sopenharmony_ci * ------------------------------------- 255162306a36Sopenharmony_ci * 255262306a36Sopenharmony_ci * Conditions: 255362306a36Sopenharmony_ci * A: cur_old_roots < nr_old_roots (not exclusive before) 255462306a36Sopenharmony_ci * !A: cur_old_roots == nr_old_roots (possible exclusive before) 255562306a36Sopenharmony_ci * B: cur_new_roots < nr_new_roots (not exclusive now) 255662306a36Sopenharmony_ci * !B: cur_new_roots == nr_new_roots (possible exclusive now) 255762306a36Sopenharmony_ci * 255862306a36Sopenharmony_ci * Results: 255962306a36Sopenharmony_ci * +: Possible sharing -> exclusive -: Possible exclusive -> sharing 256062306a36Sopenharmony_ci * *: Definitely not changed. **: Possible unchanged. 256162306a36Sopenharmony_ci * 256262306a36Sopenharmony_ci * For !A and !B condition, the exception is cur_old/new_roots == 0 case. 256362306a36Sopenharmony_ci * 256462306a36Sopenharmony_ci * To make the logic clear, we first use condition A and B to split 256562306a36Sopenharmony_ci * combination into 4 results. 256662306a36Sopenharmony_ci * 256762306a36Sopenharmony_ci * Then, for result "+" and "-", check old/new_roots == 0 case, as in them 256862306a36Sopenharmony_ci * only on variant maybe 0. 256962306a36Sopenharmony_ci * 257062306a36Sopenharmony_ci * Lastly, check result **, since there are 2 variants maybe 0, split them 257162306a36Sopenharmony_ci * again(2x2). 257262306a36Sopenharmony_ci * But this time we don't need to consider other things, the codes and logic 257362306a36Sopenharmony_ci * is easy to understand now. 257462306a36Sopenharmony_ci */ 257562306a36Sopenharmony_cistatic int qgroup_update_counters(struct btrfs_fs_info *fs_info, 257662306a36Sopenharmony_ci struct ulist *qgroups, 257762306a36Sopenharmony_ci u64 nr_old_roots, 257862306a36Sopenharmony_ci u64 nr_new_roots, 257962306a36Sopenharmony_ci u64 num_bytes, u64 seq) 258062306a36Sopenharmony_ci{ 258162306a36Sopenharmony_ci struct ulist_node *unode; 258262306a36Sopenharmony_ci struct ulist_iterator uiter; 258362306a36Sopenharmony_ci struct btrfs_qgroup *qg; 258462306a36Sopenharmony_ci u64 cur_new_count, cur_old_count; 258562306a36Sopenharmony_ci 258662306a36Sopenharmony_ci ULIST_ITER_INIT(&uiter); 258762306a36Sopenharmony_ci while ((unode = ulist_next(qgroups, &uiter))) { 258862306a36Sopenharmony_ci bool dirty = false; 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci qg = unode_aux_to_qgroup(unode); 259162306a36Sopenharmony_ci cur_old_count = btrfs_qgroup_get_old_refcnt(qg, seq); 259262306a36Sopenharmony_ci cur_new_count = btrfs_qgroup_get_new_refcnt(qg, seq); 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_ci trace_qgroup_update_counters(fs_info, qg, cur_old_count, 259562306a36Sopenharmony_ci cur_new_count); 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci /* Rfer update part */ 259862306a36Sopenharmony_ci if (cur_old_count == 0 && cur_new_count > 0) { 259962306a36Sopenharmony_ci qg->rfer += num_bytes; 260062306a36Sopenharmony_ci qg->rfer_cmpr += num_bytes; 260162306a36Sopenharmony_ci dirty = true; 260262306a36Sopenharmony_ci } 260362306a36Sopenharmony_ci if (cur_old_count > 0 && cur_new_count == 0) { 260462306a36Sopenharmony_ci qg->rfer -= num_bytes; 260562306a36Sopenharmony_ci qg->rfer_cmpr -= num_bytes; 260662306a36Sopenharmony_ci dirty = true; 260762306a36Sopenharmony_ci } 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci /* Excl update part */ 261062306a36Sopenharmony_ci /* Exclusive/none -> shared case */ 261162306a36Sopenharmony_ci if (cur_old_count == nr_old_roots && 261262306a36Sopenharmony_ci cur_new_count < nr_new_roots) { 261362306a36Sopenharmony_ci /* Exclusive -> shared */ 261462306a36Sopenharmony_ci if (cur_old_count != 0) { 261562306a36Sopenharmony_ci qg->excl -= num_bytes; 261662306a36Sopenharmony_ci qg->excl_cmpr -= num_bytes; 261762306a36Sopenharmony_ci dirty = true; 261862306a36Sopenharmony_ci } 261962306a36Sopenharmony_ci } 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci /* Shared -> exclusive/none case */ 262262306a36Sopenharmony_ci if (cur_old_count < nr_old_roots && 262362306a36Sopenharmony_ci cur_new_count == nr_new_roots) { 262462306a36Sopenharmony_ci /* Shared->exclusive */ 262562306a36Sopenharmony_ci if (cur_new_count != 0) { 262662306a36Sopenharmony_ci qg->excl += num_bytes; 262762306a36Sopenharmony_ci qg->excl_cmpr += num_bytes; 262862306a36Sopenharmony_ci dirty = true; 262962306a36Sopenharmony_ci } 263062306a36Sopenharmony_ci } 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci /* Exclusive/none -> exclusive/none case */ 263362306a36Sopenharmony_ci if (cur_old_count == nr_old_roots && 263462306a36Sopenharmony_ci cur_new_count == nr_new_roots) { 263562306a36Sopenharmony_ci if (cur_old_count == 0) { 263662306a36Sopenharmony_ci /* None -> exclusive/none */ 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci if (cur_new_count != 0) { 263962306a36Sopenharmony_ci /* None -> exclusive */ 264062306a36Sopenharmony_ci qg->excl += num_bytes; 264162306a36Sopenharmony_ci qg->excl_cmpr += num_bytes; 264262306a36Sopenharmony_ci dirty = true; 264362306a36Sopenharmony_ci } 264462306a36Sopenharmony_ci /* None -> none, nothing changed */ 264562306a36Sopenharmony_ci } else { 264662306a36Sopenharmony_ci /* Exclusive -> exclusive/none */ 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci if (cur_new_count == 0) { 264962306a36Sopenharmony_ci /* Exclusive -> none */ 265062306a36Sopenharmony_ci qg->excl -= num_bytes; 265162306a36Sopenharmony_ci qg->excl_cmpr -= num_bytes; 265262306a36Sopenharmony_ci dirty = true; 265362306a36Sopenharmony_ci } 265462306a36Sopenharmony_ci /* Exclusive -> exclusive, nothing changed */ 265562306a36Sopenharmony_ci } 265662306a36Sopenharmony_ci } 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci if (dirty) 265962306a36Sopenharmony_ci qgroup_dirty(fs_info, qg); 266062306a36Sopenharmony_ci } 266162306a36Sopenharmony_ci return 0; 266262306a36Sopenharmony_ci} 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci/* 266562306a36Sopenharmony_ci * Check if the @roots potentially is a list of fs tree roots 266662306a36Sopenharmony_ci * 266762306a36Sopenharmony_ci * Return 0 for definitely not a fs/subvol tree roots ulist 266862306a36Sopenharmony_ci * Return 1 for possible fs/subvol tree roots in the list (considering an empty 266962306a36Sopenharmony_ci * one as well) 267062306a36Sopenharmony_ci */ 267162306a36Sopenharmony_cistatic int maybe_fs_roots(struct ulist *roots) 267262306a36Sopenharmony_ci{ 267362306a36Sopenharmony_ci struct ulist_node *unode; 267462306a36Sopenharmony_ci struct ulist_iterator uiter; 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci /* Empty one, still possible for fs roots */ 267762306a36Sopenharmony_ci if (!roots || roots->nnodes == 0) 267862306a36Sopenharmony_ci return 1; 267962306a36Sopenharmony_ci 268062306a36Sopenharmony_ci ULIST_ITER_INIT(&uiter); 268162306a36Sopenharmony_ci unode = ulist_next(roots, &uiter); 268262306a36Sopenharmony_ci if (!unode) 268362306a36Sopenharmony_ci return 1; 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci /* 268662306a36Sopenharmony_ci * If it contains fs tree roots, then it must belong to fs/subvol 268762306a36Sopenharmony_ci * trees. 268862306a36Sopenharmony_ci * If it contains a non-fs tree, it won't be shared with fs/subvol trees. 268962306a36Sopenharmony_ci */ 269062306a36Sopenharmony_ci return is_fstree(unode->val); 269162306a36Sopenharmony_ci} 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ciint btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, u64 bytenr, 269462306a36Sopenharmony_ci u64 num_bytes, struct ulist *old_roots, 269562306a36Sopenharmony_ci struct ulist *new_roots) 269662306a36Sopenharmony_ci{ 269762306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 269862306a36Sopenharmony_ci struct ulist *qgroups = NULL; 269962306a36Sopenharmony_ci struct ulist *tmp = NULL; 270062306a36Sopenharmony_ci u64 seq; 270162306a36Sopenharmony_ci u64 nr_new_roots = 0; 270262306a36Sopenharmony_ci u64 nr_old_roots = 0; 270362306a36Sopenharmony_ci int ret = 0; 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci /* 270662306a36Sopenharmony_ci * If quotas get disabled meanwhile, the resources need to be freed and 270762306a36Sopenharmony_ci * we can't just exit here. 270862306a36Sopenharmony_ci */ 270962306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || 271062306a36Sopenharmony_ci fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING) 271162306a36Sopenharmony_ci goto out_free; 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_ci if (new_roots) { 271462306a36Sopenharmony_ci if (!maybe_fs_roots(new_roots)) 271562306a36Sopenharmony_ci goto out_free; 271662306a36Sopenharmony_ci nr_new_roots = new_roots->nnodes; 271762306a36Sopenharmony_ci } 271862306a36Sopenharmony_ci if (old_roots) { 271962306a36Sopenharmony_ci if (!maybe_fs_roots(old_roots)) 272062306a36Sopenharmony_ci goto out_free; 272162306a36Sopenharmony_ci nr_old_roots = old_roots->nnodes; 272262306a36Sopenharmony_ci } 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci /* Quick exit, either not fs tree roots, or won't affect any qgroup */ 272562306a36Sopenharmony_ci if (nr_old_roots == 0 && nr_new_roots == 0) 272662306a36Sopenharmony_ci goto out_free; 272762306a36Sopenharmony_ci 272862306a36Sopenharmony_ci BUG_ON(!fs_info->quota_root); 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci trace_btrfs_qgroup_account_extent(fs_info, trans->transid, bytenr, 273162306a36Sopenharmony_ci num_bytes, nr_old_roots, nr_new_roots); 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci qgroups = ulist_alloc(GFP_NOFS); 273462306a36Sopenharmony_ci if (!qgroups) { 273562306a36Sopenharmony_ci ret = -ENOMEM; 273662306a36Sopenharmony_ci goto out_free; 273762306a36Sopenharmony_ci } 273862306a36Sopenharmony_ci tmp = ulist_alloc(GFP_NOFS); 273962306a36Sopenharmony_ci if (!tmp) { 274062306a36Sopenharmony_ci ret = -ENOMEM; 274162306a36Sopenharmony_ci goto out_free; 274262306a36Sopenharmony_ci } 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 274562306a36Sopenharmony_ci if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { 274662306a36Sopenharmony_ci if (fs_info->qgroup_rescan_progress.objectid <= bytenr) { 274762306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 274862306a36Sopenharmony_ci ret = 0; 274962306a36Sopenharmony_ci goto out_free; 275062306a36Sopenharmony_ci } 275162306a36Sopenharmony_ci } 275262306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 275562306a36Sopenharmony_ci seq = fs_info->qgroup_seq; 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci /* Update old refcnts using old_roots */ 275862306a36Sopenharmony_ci ret = qgroup_update_refcnt(fs_info, old_roots, tmp, qgroups, seq, 275962306a36Sopenharmony_ci UPDATE_OLD); 276062306a36Sopenharmony_ci if (ret < 0) 276162306a36Sopenharmony_ci goto out; 276262306a36Sopenharmony_ci 276362306a36Sopenharmony_ci /* Update new refcnts using new_roots */ 276462306a36Sopenharmony_ci ret = qgroup_update_refcnt(fs_info, new_roots, tmp, qgroups, seq, 276562306a36Sopenharmony_ci UPDATE_NEW); 276662306a36Sopenharmony_ci if (ret < 0) 276762306a36Sopenharmony_ci goto out; 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci qgroup_update_counters(fs_info, qgroups, nr_old_roots, nr_new_roots, 277062306a36Sopenharmony_ci num_bytes, seq); 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci /* 277362306a36Sopenharmony_ci * Bump qgroup_seq to avoid seq overlap 277462306a36Sopenharmony_ci */ 277562306a36Sopenharmony_ci fs_info->qgroup_seq += max(nr_old_roots, nr_new_roots) + 1; 277662306a36Sopenharmony_ciout: 277762306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 277862306a36Sopenharmony_ciout_free: 277962306a36Sopenharmony_ci ulist_free(tmp); 278062306a36Sopenharmony_ci ulist_free(qgroups); 278162306a36Sopenharmony_ci ulist_free(old_roots); 278262306a36Sopenharmony_ci ulist_free(new_roots); 278362306a36Sopenharmony_ci return ret; 278462306a36Sopenharmony_ci} 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ciint btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans) 278762306a36Sopenharmony_ci{ 278862306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 278962306a36Sopenharmony_ci struct btrfs_qgroup_extent_record *record; 279062306a36Sopenharmony_ci struct btrfs_delayed_ref_root *delayed_refs; 279162306a36Sopenharmony_ci struct ulist *new_roots = NULL; 279262306a36Sopenharmony_ci struct rb_node *node; 279362306a36Sopenharmony_ci u64 num_dirty_extents = 0; 279462306a36Sopenharmony_ci u64 qgroup_to_skip; 279562306a36Sopenharmony_ci int ret = 0; 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ci delayed_refs = &trans->transaction->delayed_refs; 279862306a36Sopenharmony_ci qgroup_to_skip = delayed_refs->qgroup_to_skip; 279962306a36Sopenharmony_ci while ((node = rb_first(&delayed_refs->dirty_extent_root))) { 280062306a36Sopenharmony_ci record = rb_entry(node, struct btrfs_qgroup_extent_record, 280162306a36Sopenharmony_ci node); 280262306a36Sopenharmony_ci 280362306a36Sopenharmony_ci num_dirty_extents++; 280462306a36Sopenharmony_ci trace_btrfs_qgroup_account_extents(fs_info, record); 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci if (!ret && !(fs_info->qgroup_flags & 280762306a36Sopenharmony_ci BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING)) { 280862306a36Sopenharmony_ci struct btrfs_backref_walk_ctx ctx = { 0 }; 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_ci ctx.bytenr = record->bytenr; 281162306a36Sopenharmony_ci ctx.fs_info = fs_info; 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_ci /* 281462306a36Sopenharmony_ci * Old roots should be searched when inserting qgroup 281562306a36Sopenharmony_ci * extent record. 281662306a36Sopenharmony_ci * 281762306a36Sopenharmony_ci * But for INCONSISTENT (NO_ACCOUNTING) -> rescan case, 281862306a36Sopenharmony_ci * we may have some record inserted during 281962306a36Sopenharmony_ci * NO_ACCOUNTING (thus no old_roots populated), but 282062306a36Sopenharmony_ci * later we start rescan, which clears NO_ACCOUNTING, 282162306a36Sopenharmony_ci * leaving some inserted records without old_roots 282262306a36Sopenharmony_ci * populated. 282362306a36Sopenharmony_ci * 282462306a36Sopenharmony_ci * Those cases are rare and should not cause too much 282562306a36Sopenharmony_ci * time spent during commit_transaction(). 282662306a36Sopenharmony_ci */ 282762306a36Sopenharmony_ci if (!record->old_roots) { 282862306a36Sopenharmony_ci /* Search commit root to find old_roots */ 282962306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 283062306a36Sopenharmony_ci if (ret < 0) 283162306a36Sopenharmony_ci goto cleanup; 283262306a36Sopenharmony_ci record->old_roots = ctx.roots; 283362306a36Sopenharmony_ci ctx.roots = NULL; 283462306a36Sopenharmony_ci } 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ci /* 283762306a36Sopenharmony_ci * Use BTRFS_SEQ_LAST as time_seq to do special search, 283862306a36Sopenharmony_ci * which doesn't lock tree or delayed_refs and search 283962306a36Sopenharmony_ci * current root. It's safe inside commit_transaction(). 284062306a36Sopenharmony_ci */ 284162306a36Sopenharmony_ci ctx.trans = trans; 284262306a36Sopenharmony_ci ctx.time_seq = BTRFS_SEQ_LAST; 284362306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 284462306a36Sopenharmony_ci if (ret < 0) 284562306a36Sopenharmony_ci goto cleanup; 284662306a36Sopenharmony_ci new_roots = ctx.roots; 284762306a36Sopenharmony_ci if (qgroup_to_skip) { 284862306a36Sopenharmony_ci ulist_del(new_roots, qgroup_to_skip, 0); 284962306a36Sopenharmony_ci ulist_del(record->old_roots, qgroup_to_skip, 285062306a36Sopenharmony_ci 0); 285162306a36Sopenharmony_ci } 285262306a36Sopenharmony_ci ret = btrfs_qgroup_account_extent(trans, record->bytenr, 285362306a36Sopenharmony_ci record->num_bytes, 285462306a36Sopenharmony_ci record->old_roots, 285562306a36Sopenharmony_ci new_roots); 285662306a36Sopenharmony_ci record->old_roots = NULL; 285762306a36Sopenharmony_ci new_roots = NULL; 285862306a36Sopenharmony_ci } 285962306a36Sopenharmony_ci /* Free the reserved data space */ 286062306a36Sopenharmony_ci btrfs_qgroup_free_refroot(fs_info, 286162306a36Sopenharmony_ci record->data_rsv_refroot, 286262306a36Sopenharmony_ci record->data_rsv, 286362306a36Sopenharmony_ci BTRFS_QGROUP_RSV_DATA); 286462306a36Sopenharmony_cicleanup: 286562306a36Sopenharmony_ci ulist_free(record->old_roots); 286662306a36Sopenharmony_ci ulist_free(new_roots); 286762306a36Sopenharmony_ci new_roots = NULL; 286862306a36Sopenharmony_ci rb_erase(node, &delayed_refs->dirty_extent_root); 286962306a36Sopenharmony_ci kfree(record); 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci } 287262306a36Sopenharmony_ci trace_qgroup_num_dirty_extents(fs_info, trans->transid, 287362306a36Sopenharmony_ci num_dirty_extents); 287462306a36Sopenharmony_ci return ret; 287562306a36Sopenharmony_ci} 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci/* 287862306a36Sopenharmony_ci * Writes all changed qgroups to disk. 287962306a36Sopenharmony_ci * Called by the transaction commit path and the qgroup assign ioctl. 288062306a36Sopenharmony_ci */ 288162306a36Sopenharmony_ciint btrfs_run_qgroups(struct btrfs_trans_handle *trans) 288262306a36Sopenharmony_ci{ 288362306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 288462306a36Sopenharmony_ci int ret = 0; 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci /* 288762306a36Sopenharmony_ci * In case we are called from the qgroup assign ioctl, assert that we 288862306a36Sopenharmony_ci * are holding the qgroup_ioctl_lock, otherwise we can race with a quota 288962306a36Sopenharmony_ci * disable operation (ioctl) and access a freed quota root. 289062306a36Sopenharmony_ci */ 289162306a36Sopenharmony_ci if (trans->transaction->state != TRANS_STATE_COMMIT_DOING) 289262306a36Sopenharmony_ci lockdep_assert_held(&fs_info->qgroup_ioctl_lock); 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci if (!fs_info->quota_root) 289562306a36Sopenharmony_ci return ret; 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 289862306a36Sopenharmony_ci while (!list_empty(&fs_info->dirty_qgroups)) { 289962306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 290062306a36Sopenharmony_ci qgroup = list_first_entry(&fs_info->dirty_qgroups, 290162306a36Sopenharmony_ci struct btrfs_qgroup, dirty); 290262306a36Sopenharmony_ci list_del_init(&qgroup->dirty); 290362306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 290462306a36Sopenharmony_ci ret = update_qgroup_info_item(trans, qgroup); 290562306a36Sopenharmony_ci if (ret) 290662306a36Sopenharmony_ci qgroup_mark_inconsistent(fs_info); 290762306a36Sopenharmony_ci ret = update_qgroup_limit_item(trans, qgroup); 290862306a36Sopenharmony_ci if (ret) 290962306a36Sopenharmony_ci qgroup_mark_inconsistent(fs_info); 291062306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 291162306a36Sopenharmony_ci } 291262306a36Sopenharmony_ci if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 291362306a36Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_ON; 291462306a36Sopenharmony_ci else 291562306a36Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON; 291662306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci ret = update_qgroup_status_item(trans); 291962306a36Sopenharmony_ci if (ret) 292062306a36Sopenharmony_ci qgroup_mark_inconsistent(fs_info); 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci return ret; 292362306a36Sopenharmony_ci} 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci/* 292662306a36Sopenharmony_ci * Copy the accounting information between qgroups. This is necessary 292762306a36Sopenharmony_ci * when a snapshot or a subvolume is created. Throwing an error will 292862306a36Sopenharmony_ci * cause a transaction abort so we take extra care here to only error 292962306a36Sopenharmony_ci * when a readonly fs is a reasonable outcome. 293062306a36Sopenharmony_ci */ 293162306a36Sopenharmony_ciint btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, 293262306a36Sopenharmony_ci u64 objectid, struct btrfs_qgroup_inherit *inherit) 293362306a36Sopenharmony_ci{ 293462306a36Sopenharmony_ci int ret = 0; 293562306a36Sopenharmony_ci int i; 293662306a36Sopenharmony_ci u64 *i_qgroups; 293762306a36Sopenharmony_ci bool committing = false; 293862306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 293962306a36Sopenharmony_ci struct btrfs_root *quota_root; 294062306a36Sopenharmony_ci struct btrfs_qgroup *srcgroup; 294162306a36Sopenharmony_ci struct btrfs_qgroup *dstgroup; 294262306a36Sopenharmony_ci bool need_rescan = false; 294362306a36Sopenharmony_ci u32 level_size = 0; 294462306a36Sopenharmony_ci u64 nums; 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci /* 294762306a36Sopenharmony_ci * There are only two callers of this function. 294862306a36Sopenharmony_ci * 294962306a36Sopenharmony_ci * One in create_subvol() in the ioctl context, which needs to hold 295062306a36Sopenharmony_ci * the qgroup_ioctl_lock. 295162306a36Sopenharmony_ci * 295262306a36Sopenharmony_ci * The other one in create_pending_snapshot() where no other qgroup 295362306a36Sopenharmony_ci * code can modify the fs as they all need to either start a new trans 295462306a36Sopenharmony_ci * or hold a trans handler, thus we don't need to hold 295562306a36Sopenharmony_ci * qgroup_ioctl_lock. 295662306a36Sopenharmony_ci * This would avoid long and complex lock chain and make lockdep happy. 295762306a36Sopenharmony_ci */ 295862306a36Sopenharmony_ci spin_lock(&fs_info->trans_lock); 295962306a36Sopenharmony_ci if (trans->transaction->state == TRANS_STATE_COMMIT_DOING) 296062306a36Sopenharmony_ci committing = true; 296162306a36Sopenharmony_ci spin_unlock(&fs_info->trans_lock); 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ci if (!committing) 296462306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_ioctl_lock); 296562306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 296662306a36Sopenharmony_ci goto out; 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_ci quota_root = fs_info->quota_root; 296962306a36Sopenharmony_ci if (!quota_root) { 297062306a36Sopenharmony_ci ret = -EINVAL; 297162306a36Sopenharmony_ci goto out; 297262306a36Sopenharmony_ci } 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci if (inherit) { 297562306a36Sopenharmony_ci i_qgroups = (u64 *)(inherit + 1); 297662306a36Sopenharmony_ci nums = inherit->num_qgroups + 2 * inherit->num_ref_copies + 297762306a36Sopenharmony_ci 2 * inherit->num_excl_copies; 297862306a36Sopenharmony_ci for (i = 0; i < nums; ++i) { 297962306a36Sopenharmony_ci srcgroup = find_qgroup_rb(fs_info, *i_qgroups); 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci /* 298262306a36Sopenharmony_ci * Zero out invalid groups so we can ignore 298362306a36Sopenharmony_ci * them later. 298462306a36Sopenharmony_ci */ 298562306a36Sopenharmony_ci if (!srcgroup || 298662306a36Sopenharmony_ci ((srcgroup->qgroupid >> 48) <= (objectid >> 48))) 298762306a36Sopenharmony_ci *i_qgroups = 0ULL; 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_ci ++i_qgroups; 299062306a36Sopenharmony_ci } 299162306a36Sopenharmony_ci } 299262306a36Sopenharmony_ci 299362306a36Sopenharmony_ci /* 299462306a36Sopenharmony_ci * create a tracking group for the subvol itself 299562306a36Sopenharmony_ci */ 299662306a36Sopenharmony_ci ret = add_qgroup_item(trans, quota_root, objectid); 299762306a36Sopenharmony_ci if (ret) 299862306a36Sopenharmony_ci goto out; 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_ci /* 300162306a36Sopenharmony_ci * add qgroup to all inherited groups 300262306a36Sopenharmony_ci */ 300362306a36Sopenharmony_ci if (inherit) { 300462306a36Sopenharmony_ci i_qgroups = (u64 *)(inherit + 1); 300562306a36Sopenharmony_ci for (i = 0; i < inherit->num_qgroups; ++i, ++i_qgroups) { 300662306a36Sopenharmony_ci if (*i_qgroups == 0) 300762306a36Sopenharmony_ci continue; 300862306a36Sopenharmony_ci ret = add_qgroup_relation_item(trans, objectid, 300962306a36Sopenharmony_ci *i_qgroups); 301062306a36Sopenharmony_ci if (ret && ret != -EEXIST) 301162306a36Sopenharmony_ci goto out; 301262306a36Sopenharmony_ci ret = add_qgroup_relation_item(trans, *i_qgroups, 301362306a36Sopenharmony_ci objectid); 301462306a36Sopenharmony_ci if (ret && ret != -EEXIST) 301562306a36Sopenharmony_ci goto out; 301662306a36Sopenharmony_ci } 301762306a36Sopenharmony_ci ret = 0; 301862306a36Sopenharmony_ci } 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci dstgroup = add_qgroup_rb(fs_info, objectid); 302462306a36Sopenharmony_ci if (IS_ERR(dstgroup)) { 302562306a36Sopenharmony_ci ret = PTR_ERR(dstgroup); 302662306a36Sopenharmony_ci goto unlock; 302762306a36Sopenharmony_ci } 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_ci if (inherit && inherit->flags & BTRFS_QGROUP_INHERIT_SET_LIMITS) { 303062306a36Sopenharmony_ci dstgroup->lim_flags = inherit->lim.flags; 303162306a36Sopenharmony_ci dstgroup->max_rfer = inherit->lim.max_rfer; 303262306a36Sopenharmony_ci dstgroup->max_excl = inherit->lim.max_excl; 303362306a36Sopenharmony_ci dstgroup->rsv_rfer = inherit->lim.rsv_rfer; 303462306a36Sopenharmony_ci dstgroup->rsv_excl = inherit->lim.rsv_excl; 303562306a36Sopenharmony_ci 303662306a36Sopenharmony_ci qgroup_dirty(fs_info, dstgroup); 303762306a36Sopenharmony_ci } 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci if (srcid) { 304062306a36Sopenharmony_ci srcgroup = find_qgroup_rb(fs_info, srcid); 304162306a36Sopenharmony_ci if (!srcgroup) 304262306a36Sopenharmony_ci goto unlock; 304362306a36Sopenharmony_ci 304462306a36Sopenharmony_ci /* 304562306a36Sopenharmony_ci * We call inherit after we clone the root in order to make sure 304662306a36Sopenharmony_ci * our counts don't go crazy, so at this point the only 304762306a36Sopenharmony_ci * difference between the two roots should be the root node. 304862306a36Sopenharmony_ci */ 304962306a36Sopenharmony_ci level_size = fs_info->nodesize; 305062306a36Sopenharmony_ci dstgroup->rfer = srcgroup->rfer; 305162306a36Sopenharmony_ci dstgroup->rfer_cmpr = srcgroup->rfer_cmpr; 305262306a36Sopenharmony_ci dstgroup->excl = level_size; 305362306a36Sopenharmony_ci dstgroup->excl_cmpr = level_size; 305462306a36Sopenharmony_ci srcgroup->excl = level_size; 305562306a36Sopenharmony_ci srcgroup->excl_cmpr = level_size; 305662306a36Sopenharmony_ci 305762306a36Sopenharmony_ci /* inherit the limit info */ 305862306a36Sopenharmony_ci dstgroup->lim_flags = srcgroup->lim_flags; 305962306a36Sopenharmony_ci dstgroup->max_rfer = srcgroup->max_rfer; 306062306a36Sopenharmony_ci dstgroup->max_excl = srcgroup->max_excl; 306162306a36Sopenharmony_ci dstgroup->rsv_rfer = srcgroup->rsv_rfer; 306262306a36Sopenharmony_ci dstgroup->rsv_excl = srcgroup->rsv_excl; 306362306a36Sopenharmony_ci 306462306a36Sopenharmony_ci qgroup_dirty(fs_info, dstgroup); 306562306a36Sopenharmony_ci qgroup_dirty(fs_info, srcgroup); 306662306a36Sopenharmony_ci } 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci if (!inherit) 306962306a36Sopenharmony_ci goto unlock; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci i_qgroups = (u64 *)(inherit + 1); 307262306a36Sopenharmony_ci for (i = 0; i < inherit->num_qgroups; ++i) { 307362306a36Sopenharmony_ci if (*i_qgroups) { 307462306a36Sopenharmony_ci ret = add_relation_rb(fs_info, objectid, *i_qgroups); 307562306a36Sopenharmony_ci if (ret) 307662306a36Sopenharmony_ci goto unlock; 307762306a36Sopenharmony_ci } 307862306a36Sopenharmony_ci ++i_qgroups; 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_ci /* 308162306a36Sopenharmony_ci * If we're doing a snapshot, and adding the snapshot to a new 308262306a36Sopenharmony_ci * qgroup, the numbers are guaranteed to be incorrect. 308362306a36Sopenharmony_ci */ 308462306a36Sopenharmony_ci if (srcid) 308562306a36Sopenharmony_ci need_rescan = true; 308662306a36Sopenharmony_ci } 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_ci for (i = 0; i < inherit->num_ref_copies; ++i, i_qgroups += 2) { 308962306a36Sopenharmony_ci struct btrfs_qgroup *src; 309062306a36Sopenharmony_ci struct btrfs_qgroup *dst; 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci if (!i_qgroups[0] || !i_qgroups[1]) 309362306a36Sopenharmony_ci continue; 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci src = find_qgroup_rb(fs_info, i_qgroups[0]); 309662306a36Sopenharmony_ci dst = find_qgroup_rb(fs_info, i_qgroups[1]); 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci if (!src || !dst) { 309962306a36Sopenharmony_ci ret = -EINVAL; 310062306a36Sopenharmony_ci goto unlock; 310162306a36Sopenharmony_ci } 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci dst->rfer = src->rfer - level_size; 310462306a36Sopenharmony_ci dst->rfer_cmpr = src->rfer_cmpr - level_size; 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci /* Manually tweaking numbers certainly needs a rescan */ 310762306a36Sopenharmony_ci need_rescan = true; 310862306a36Sopenharmony_ci } 310962306a36Sopenharmony_ci for (i = 0; i < inherit->num_excl_copies; ++i, i_qgroups += 2) { 311062306a36Sopenharmony_ci struct btrfs_qgroup *src; 311162306a36Sopenharmony_ci struct btrfs_qgroup *dst; 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_ci if (!i_qgroups[0] || !i_qgroups[1]) 311462306a36Sopenharmony_ci continue; 311562306a36Sopenharmony_ci 311662306a36Sopenharmony_ci src = find_qgroup_rb(fs_info, i_qgroups[0]); 311762306a36Sopenharmony_ci dst = find_qgroup_rb(fs_info, i_qgroups[1]); 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci if (!src || !dst) { 312062306a36Sopenharmony_ci ret = -EINVAL; 312162306a36Sopenharmony_ci goto unlock; 312262306a36Sopenharmony_ci } 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci dst->excl = src->excl + level_size; 312562306a36Sopenharmony_ci dst->excl_cmpr = src->excl_cmpr + level_size; 312662306a36Sopenharmony_ci need_rescan = true; 312762306a36Sopenharmony_ci } 312862306a36Sopenharmony_ci 312962306a36Sopenharmony_ciunlock: 313062306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 313162306a36Sopenharmony_ci if (!ret) 313262306a36Sopenharmony_ci ret = btrfs_sysfs_add_one_qgroup(fs_info, dstgroup); 313362306a36Sopenharmony_ciout: 313462306a36Sopenharmony_ci if (!committing) 313562306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_ioctl_lock); 313662306a36Sopenharmony_ci if (need_rescan) 313762306a36Sopenharmony_ci qgroup_mark_inconsistent(fs_info); 313862306a36Sopenharmony_ci return ret; 313962306a36Sopenharmony_ci} 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_cistatic bool qgroup_check_limits(const struct btrfs_qgroup *qg, u64 num_bytes) 314262306a36Sopenharmony_ci{ 314362306a36Sopenharmony_ci if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) && 314462306a36Sopenharmony_ci qgroup_rsv_total(qg) + (s64)qg->rfer + num_bytes > qg->max_rfer) 314562306a36Sopenharmony_ci return false; 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_ci if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) && 314862306a36Sopenharmony_ci qgroup_rsv_total(qg) + (s64)qg->excl + num_bytes > qg->max_excl) 314962306a36Sopenharmony_ci return false; 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_ci return true; 315262306a36Sopenharmony_ci} 315362306a36Sopenharmony_ci 315462306a36Sopenharmony_cistatic int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce, 315562306a36Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 315662306a36Sopenharmony_ci{ 315762306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 315862306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 315962306a36Sopenharmony_ci u64 ref_root = root->root_key.objectid; 316062306a36Sopenharmony_ci int ret = 0; 316162306a36Sopenharmony_ci LIST_HEAD(qgroup_list); 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_ci if (!is_fstree(ref_root)) 316462306a36Sopenharmony_ci return 0; 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_ci if (num_bytes == 0) 316762306a36Sopenharmony_ci return 0; 316862306a36Sopenharmony_ci 316962306a36Sopenharmony_ci if (test_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags) && 317062306a36Sopenharmony_ci capable(CAP_SYS_RESOURCE)) 317162306a36Sopenharmony_ci enforce = false; 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 317462306a36Sopenharmony_ci if (!fs_info->quota_root) 317562306a36Sopenharmony_ci goto out; 317662306a36Sopenharmony_ci 317762306a36Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, ref_root); 317862306a36Sopenharmony_ci if (!qgroup) 317962306a36Sopenharmony_ci goto out; 318062306a36Sopenharmony_ci 318162306a36Sopenharmony_ci qgroup_iterator_add(&qgroup_list, qgroup); 318262306a36Sopenharmony_ci list_for_each_entry(qgroup, &qgroup_list, iterator) { 318362306a36Sopenharmony_ci struct btrfs_qgroup_list *glist; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci if (enforce && !qgroup_check_limits(qgroup, num_bytes)) { 318662306a36Sopenharmony_ci ret = -EDQUOT; 318762306a36Sopenharmony_ci goto out; 318862306a36Sopenharmony_ci } 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci list_for_each_entry(glist, &qgroup->groups, next_group) 319162306a36Sopenharmony_ci qgroup_iterator_add(&qgroup_list, glist->group); 319262306a36Sopenharmony_ci } 319362306a36Sopenharmony_ci 319462306a36Sopenharmony_ci ret = 0; 319562306a36Sopenharmony_ci /* 319662306a36Sopenharmony_ci * no limits exceeded, now record the reservation into all qgroups 319762306a36Sopenharmony_ci */ 319862306a36Sopenharmony_ci list_for_each_entry(qgroup, &qgroup_list, iterator) 319962306a36Sopenharmony_ci qgroup_rsv_add(fs_info, qgroup, num_bytes, type); 320062306a36Sopenharmony_ci 320162306a36Sopenharmony_ciout: 320262306a36Sopenharmony_ci qgroup_iterator_clean(&qgroup_list); 320362306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 320462306a36Sopenharmony_ci return ret; 320562306a36Sopenharmony_ci} 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_ci/* 320862306a36Sopenharmony_ci * Free @num_bytes of reserved space with @type for qgroup. (Normally level 0 320962306a36Sopenharmony_ci * qgroup). 321062306a36Sopenharmony_ci * 321162306a36Sopenharmony_ci * Will handle all higher level qgroup too. 321262306a36Sopenharmony_ci * 321362306a36Sopenharmony_ci * NOTE: If @num_bytes is (u64)-1, this means to free all bytes of this qgroup. 321462306a36Sopenharmony_ci * This special case is only used for META_PERTRANS type. 321562306a36Sopenharmony_ci */ 321662306a36Sopenharmony_civoid btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info, 321762306a36Sopenharmony_ci u64 ref_root, u64 num_bytes, 321862306a36Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 321962306a36Sopenharmony_ci{ 322062306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 322162306a36Sopenharmony_ci struct ulist_node *unode; 322262306a36Sopenharmony_ci struct ulist_iterator uiter; 322362306a36Sopenharmony_ci int ret = 0; 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci if (!is_fstree(ref_root)) 322662306a36Sopenharmony_ci return; 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci if (num_bytes == 0) 322962306a36Sopenharmony_ci return; 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci if (num_bytes == (u64)-1 && type != BTRFS_QGROUP_RSV_META_PERTRANS) { 323262306a36Sopenharmony_ci WARN(1, "%s: Invalid type to free", __func__); 323362306a36Sopenharmony_ci return; 323462306a36Sopenharmony_ci } 323562306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 323662306a36Sopenharmony_ci 323762306a36Sopenharmony_ci if (!fs_info->quota_root) 323862306a36Sopenharmony_ci goto out; 323962306a36Sopenharmony_ci 324062306a36Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, ref_root); 324162306a36Sopenharmony_ci if (!qgroup) 324262306a36Sopenharmony_ci goto out; 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ci if (num_bytes == (u64)-1) 324562306a36Sopenharmony_ci /* 324662306a36Sopenharmony_ci * We're freeing all pertrans rsv, get reserved value from 324762306a36Sopenharmony_ci * level 0 qgroup as real num_bytes to free. 324862306a36Sopenharmony_ci */ 324962306a36Sopenharmony_ci num_bytes = qgroup->rsv.values[type]; 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci ulist_reinit(fs_info->qgroup_ulist); 325262306a36Sopenharmony_ci ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid, 325362306a36Sopenharmony_ci qgroup_to_aux(qgroup), GFP_ATOMIC); 325462306a36Sopenharmony_ci if (ret < 0) 325562306a36Sopenharmony_ci goto out; 325662306a36Sopenharmony_ci ULIST_ITER_INIT(&uiter); 325762306a36Sopenharmony_ci while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { 325862306a36Sopenharmony_ci struct btrfs_qgroup *qg; 325962306a36Sopenharmony_ci struct btrfs_qgroup_list *glist; 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci qg = unode_aux_to_qgroup(unode); 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ci qgroup_rsv_release(fs_info, qg, num_bytes, type); 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci list_for_each_entry(glist, &qg->groups, next_group) { 326662306a36Sopenharmony_ci ret = ulist_add(fs_info->qgroup_ulist, 326762306a36Sopenharmony_ci glist->group->qgroupid, 326862306a36Sopenharmony_ci qgroup_to_aux(glist->group), GFP_ATOMIC); 326962306a36Sopenharmony_ci if (ret < 0) 327062306a36Sopenharmony_ci goto out; 327162306a36Sopenharmony_ci } 327262306a36Sopenharmony_ci } 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ciout: 327562306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 327662306a36Sopenharmony_ci} 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci/* 327962306a36Sopenharmony_ci * Check if the leaf is the last leaf. Which means all node pointers 328062306a36Sopenharmony_ci * are at their last position. 328162306a36Sopenharmony_ci */ 328262306a36Sopenharmony_cistatic bool is_last_leaf(struct btrfs_path *path) 328362306a36Sopenharmony_ci{ 328462306a36Sopenharmony_ci int i; 328562306a36Sopenharmony_ci 328662306a36Sopenharmony_ci for (i = 1; i < BTRFS_MAX_LEVEL && path->nodes[i]; i++) { 328762306a36Sopenharmony_ci if (path->slots[i] != btrfs_header_nritems(path->nodes[i]) - 1) 328862306a36Sopenharmony_ci return false; 328962306a36Sopenharmony_ci } 329062306a36Sopenharmony_ci return true; 329162306a36Sopenharmony_ci} 329262306a36Sopenharmony_ci 329362306a36Sopenharmony_ci/* 329462306a36Sopenharmony_ci * returns < 0 on error, 0 when more leafs are to be scanned. 329562306a36Sopenharmony_ci * returns 1 when done. 329662306a36Sopenharmony_ci */ 329762306a36Sopenharmony_cistatic int qgroup_rescan_leaf(struct btrfs_trans_handle *trans, 329862306a36Sopenharmony_ci struct btrfs_path *path) 329962306a36Sopenharmony_ci{ 330062306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = trans->fs_info; 330162306a36Sopenharmony_ci struct btrfs_root *extent_root; 330262306a36Sopenharmony_ci struct btrfs_key found; 330362306a36Sopenharmony_ci struct extent_buffer *scratch_leaf = NULL; 330462306a36Sopenharmony_ci u64 num_bytes; 330562306a36Sopenharmony_ci bool done; 330662306a36Sopenharmony_ci int slot; 330762306a36Sopenharmony_ci int ret; 330862306a36Sopenharmony_ci 330962306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 331062306a36Sopenharmony_ci extent_root = btrfs_extent_root(fs_info, 331162306a36Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid); 331262306a36Sopenharmony_ci ret = btrfs_search_slot_for_read(extent_root, 331362306a36Sopenharmony_ci &fs_info->qgroup_rescan_progress, 331462306a36Sopenharmony_ci path, 1, 0); 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_ci btrfs_debug(fs_info, 331762306a36Sopenharmony_ci "current progress key (%llu %u %llu), search_slot ret %d", 331862306a36Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid, 331962306a36Sopenharmony_ci fs_info->qgroup_rescan_progress.type, 332062306a36Sopenharmony_ci fs_info->qgroup_rescan_progress.offset, ret); 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci if (ret) { 332362306a36Sopenharmony_ci /* 332462306a36Sopenharmony_ci * The rescan is about to end, we will not be scanning any 332562306a36Sopenharmony_ci * further blocks. We cannot unset the RESCAN flag here, because 332662306a36Sopenharmony_ci * we want to commit the transaction if everything went well. 332762306a36Sopenharmony_ci * To make the live accounting work in this phase, we set our 332862306a36Sopenharmony_ci * scan progress pointer such that every real extent objectid 332962306a36Sopenharmony_ci * will be smaller. 333062306a36Sopenharmony_ci */ 333162306a36Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid = (u64)-1; 333262306a36Sopenharmony_ci btrfs_release_path(path); 333362306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 333462306a36Sopenharmony_ci return ret; 333562306a36Sopenharmony_ci } 333662306a36Sopenharmony_ci done = is_last_leaf(path); 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci btrfs_item_key_to_cpu(path->nodes[0], &found, 333962306a36Sopenharmony_ci btrfs_header_nritems(path->nodes[0]) - 1); 334062306a36Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid = found.objectid + 1; 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci scratch_leaf = btrfs_clone_extent_buffer(path->nodes[0]); 334362306a36Sopenharmony_ci if (!scratch_leaf) { 334462306a36Sopenharmony_ci ret = -ENOMEM; 334562306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 334662306a36Sopenharmony_ci goto out; 334762306a36Sopenharmony_ci } 334862306a36Sopenharmony_ci slot = path->slots[0]; 334962306a36Sopenharmony_ci btrfs_release_path(path); 335062306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 335162306a36Sopenharmony_ci 335262306a36Sopenharmony_ci for (; slot < btrfs_header_nritems(scratch_leaf); ++slot) { 335362306a36Sopenharmony_ci struct btrfs_backref_walk_ctx ctx = { 0 }; 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci btrfs_item_key_to_cpu(scratch_leaf, &found, slot); 335662306a36Sopenharmony_ci if (found.type != BTRFS_EXTENT_ITEM_KEY && 335762306a36Sopenharmony_ci found.type != BTRFS_METADATA_ITEM_KEY) 335862306a36Sopenharmony_ci continue; 335962306a36Sopenharmony_ci if (found.type == BTRFS_METADATA_ITEM_KEY) 336062306a36Sopenharmony_ci num_bytes = fs_info->nodesize; 336162306a36Sopenharmony_ci else 336262306a36Sopenharmony_ci num_bytes = found.offset; 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci ctx.bytenr = found.objectid; 336562306a36Sopenharmony_ci ctx.fs_info = fs_info; 336662306a36Sopenharmony_ci 336762306a36Sopenharmony_ci ret = btrfs_find_all_roots(&ctx, false); 336862306a36Sopenharmony_ci if (ret < 0) 336962306a36Sopenharmony_ci goto out; 337062306a36Sopenharmony_ci /* For rescan, just pass old_roots as NULL */ 337162306a36Sopenharmony_ci ret = btrfs_qgroup_account_extent(trans, found.objectid, 337262306a36Sopenharmony_ci num_bytes, NULL, ctx.roots); 337362306a36Sopenharmony_ci if (ret < 0) 337462306a36Sopenharmony_ci goto out; 337562306a36Sopenharmony_ci } 337662306a36Sopenharmony_ciout: 337762306a36Sopenharmony_ci if (scratch_leaf) 337862306a36Sopenharmony_ci free_extent_buffer(scratch_leaf); 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci if (done && !ret) { 338162306a36Sopenharmony_ci ret = 1; 338262306a36Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid = (u64)-1; 338362306a36Sopenharmony_ci } 338462306a36Sopenharmony_ci return ret; 338562306a36Sopenharmony_ci} 338662306a36Sopenharmony_ci 338762306a36Sopenharmony_cistatic bool rescan_should_stop(struct btrfs_fs_info *fs_info) 338862306a36Sopenharmony_ci{ 338962306a36Sopenharmony_ci return btrfs_fs_closing(fs_info) || 339062306a36Sopenharmony_ci test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state) || 339162306a36Sopenharmony_ci !test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || 339262306a36Sopenharmony_ci fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN; 339362306a36Sopenharmony_ci} 339462306a36Sopenharmony_ci 339562306a36Sopenharmony_cistatic void btrfs_qgroup_rescan_worker(struct btrfs_work *work) 339662306a36Sopenharmony_ci{ 339762306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = container_of(work, struct btrfs_fs_info, 339862306a36Sopenharmony_ci qgroup_rescan_work); 339962306a36Sopenharmony_ci struct btrfs_path *path; 340062306a36Sopenharmony_ci struct btrfs_trans_handle *trans = NULL; 340162306a36Sopenharmony_ci int err = -ENOMEM; 340262306a36Sopenharmony_ci int ret = 0; 340362306a36Sopenharmony_ci bool stopped = false; 340462306a36Sopenharmony_ci bool did_leaf_rescans = false; 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ci path = btrfs_alloc_path(); 340762306a36Sopenharmony_ci if (!path) 340862306a36Sopenharmony_ci goto out; 340962306a36Sopenharmony_ci /* 341062306a36Sopenharmony_ci * Rescan should only search for commit root, and any later difference 341162306a36Sopenharmony_ci * should be recorded by qgroup 341262306a36Sopenharmony_ci */ 341362306a36Sopenharmony_ci path->search_commit_root = 1; 341462306a36Sopenharmony_ci path->skip_locking = 1; 341562306a36Sopenharmony_ci 341662306a36Sopenharmony_ci err = 0; 341762306a36Sopenharmony_ci while (!err && !(stopped = rescan_should_stop(fs_info))) { 341862306a36Sopenharmony_ci trans = btrfs_start_transaction(fs_info->fs_root, 0); 341962306a36Sopenharmony_ci if (IS_ERR(trans)) { 342062306a36Sopenharmony_ci err = PTR_ERR(trans); 342162306a36Sopenharmony_ci break; 342262306a36Sopenharmony_ci } 342362306a36Sopenharmony_ci 342462306a36Sopenharmony_ci err = qgroup_rescan_leaf(trans, path); 342562306a36Sopenharmony_ci did_leaf_rescans = true; 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci if (err > 0) 342862306a36Sopenharmony_ci btrfs_commit_transaction(trans); 342962306a36Sopenharmony_ci else 343062306a36Sopenharmony_ci btrfs_end_transaction(trans); 343162306a36Sopenharmony_ci } 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ciout: 343462306a36Sopenharmony_ci btrfs_free_path(path); 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 343762306a36Sopenharmony_ci if (err > 0 && 343862306a36Sopenharmony_ci fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) { 343962306a36Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 344062306a36Sopenharmony_ci } else if (err < 0 || stopped) { 344162306a36Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; 344262306a36Sopenharmony_ci } 344362306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci /* 344662306a36Sopenharmony_ci * Only update status, since the previous part has already updated the 344762306a36Sopenharmony_ci * qgroup info, and only if we did any actual work. This also prevents 344862306a36Sopenharmony_ci * race with a concurrent quota disable, which has already set 344962306a36Sopenharmony_ci * fs_info->quota_root to NULL and cleared BTRFS_FS_QUOTA_ENABLED at 345062306a36Sopenharmony_ci * btrfs_quota_disable(). 345162306a36Sopenharmony_ci */ 345262306a36Sopenharmony_ci if (did_leaf_rescans) { 345362306a36Sopenharmony_ci trans = btrfs_start_transaction(fs_info->quota_root, 1); 345462306a36Sopenharmony_ci if (IS_ERR(trans)) { 345562306a36Sopenharmony_ci err = PTR_ERR(trans); 345662306a36Sopenharmony_ci trans = NULL; 345762306a36Sopenharmony_ci btrfs_err(fs_info, 345862306a36Sopenharmony_ci "fail to start transaction for status update: %d", 345962306a36Sopenharmony_ci err); 346062306a36Sopenharmony_ci } 346162306a36Sopenharmony_ci } else { 346262306a36Sopenharmony_ci trans = NULL; 346362306a36Sopenharmony_ci } 346462306a36Sopenharmony_ci 346562306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 346662306a36Sopenharmony_ci if (!stopped || 346762306a36Sopenharmony_ci fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN) 346862306a36Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; 346962306a36Sopenharmony_ci if (trans) { 347062306a36Sopenharmony_ci ret = update_qgroup_status_item(trans); 347162306a36Sopenharmony_ci if (ret < 0) { 347262306a36Sopenharmony_ci err = ret; 347362306a36Sopenharmony_ci btrfs_err(fs_info, "fail to update qgroup status: %d", 347462306a36Sopenharmony_ci err); 347562306a36Sopenharmony_ci } 347662306a36Sopenharmony_ci } 347762306a36Sopenharmony_ci fs_info->qgroup_rescan_running = false; 347862306a36Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN; 347962306a36Sopenharmony_ci complete_all(&fs_info->qgroup_rescan_completion); 348062306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_ci if (!trans) 348362306a36Sopenharmony_ci return; 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_ci btrfs_end_transaction(trans); 348662306a36Sopenharmony_ci 348762306a36Sopenharmony_ci if (stopped) { 348862306a36Sopenharmony_ci btrfs_info(fs_info, "qgroup scan paused"); 348962306a36Sopenharmony_ci } else if (fs_info->qgroup_flags & BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN) { 349062306a36Sopenharmony_ci btrfs_info(fs_info, "qgroup scan cancelled"); 349162306a36Sopenharmony_ci } else if (err >= 0) { 349262306a36Sopenharmony_ci btrfs_info(fs_info, "qgroup scan completed%s", 349362306a36Sopenharmony_ci err > 0 ? " (inconsistency flag cleared)" : ""); 349462306a36Sopenharmony_ci } else { 349562306a36Sopenharmony_ci btrfs_err(fs_info, "qgroup scan failed with %d", err); 349662306a36Sopenharmony_ci } 349762306a36Sopenharmony_ci} 349862306a36Sopenharmony_ci 349962306a36Sopenharmony_ci/* 350062306a36Sopenharmony_ci * Checks that (a) no rescan is running and (b) quota is enabled. Allocates all 350162306a36Sopenharmony_ci * memory required for the rescan context. 350262306a36Sopenharmony_ci */ 350362306a36Sopenharmony_cistatic int 350462306a36Sopenharmony_ciqgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, 350562306a36Sopenharmony_ci int init_flags) 350662306a36Sopenharmony_ci{ 350762306a36Sopenharmony_ci int ret = 0; 350862306a36Sopenharmony_ci 350962306a36Sopenharmony_ci if (!init_flags) { 351062306a36Sopenharmony_ci /* we're resuming qgroup rescan at mount time */ 351162306a36Sopenharmony_ci if (!(fs_info->qgroup_flags & 351262306a36Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAG_RESCAN)) { 351362306a36Sopenharmony_ci btrfs_warn(fs_info, 351462306a36Sopenharmony_ci "qgroup rescan init failed, qgroup rescan is not queued"); 351562306a36Sopenharmony_ci ret = -EINVAL; 351662306a36Sopenharmony_ci } else if (!(fs_info->qgroup_flags & 351762306a36Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAG_ON)) { 351862306a36Sopenharmony_ci btrfs_warn(fs_info, 351962306a36Sopenharmony_ci "qgroup rescan init failed, qgroup is not enabled"); 352062306a36Sopenharmony_ci ret = -EINVAL; 352162306a36Sopenharmony_ci } 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_ci if (ret) 352462306a36Sopenharmony_ci return ret; 352562306a36Sopenharmony_ci } 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 352862306a36Sopenharmony_ci 352962306a36Sopenharmony_ci if (init_flags) { 353062306a36Sopenharmony_ci if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { 353162306a36Sopenharmony_ci btrfs_warn(fs_info, 353262306a36Sopenharmony_ci "qgroup rescan is already in progress"); 353362306a36Sopenharmony_ci ret = -EINPROGRESS; 353462306a36Sopenharmony_ci } else if (!(fs_info->qgroup_flags & 353562306a36Sopenharmony_ci BTRFS_QGROUP_STATUS_FLAG_ON)) { 353662306a36Sopenharmony_ci btrfs_warn(fs_info, 353762306a36Sopenharmony_ci "qgroup rescan init failed, qgroup is not enabled"); 353862306a36Sopenharmony_ci ret = -EINVAL; 353962306a36Sopenharmony_ci } else if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) { 354062306a36Sopenharmony_ci /* Quota disable is in progress */ 354162306a36Sopenharmony_ci ret = -EBUSY; 354262306a36Sopenharmony_ci } 354362306a36Sopenharmony_ci 354462306a36Sopenharmony_ci if (ret) { 354562306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 354662306a36Sopenharmony_ci return ret; 354762306a36Sopenharmony_ci } 354862306a36Sopenharmony_ci fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_RESCAN; 354962306a36Sopenharmony_ci } 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_ci memset(&fs_info->qgroup_rescan_progress, 0, 355262306a36Sopenharmony_ci sizeof(fs_info->qgroup_rescan_progress)); 355362306a36Sopenharmony_ci fs_info->qgroup_flags &= ~(BTRFS_QGROUP_RUNTIME_FLAG_CANCEL_RESCAN | 355462306a36Sopenharmony_ci BTRFS_QGROUP_RUNTIME_FLAG_NO_ACCOUNTING); 355562306a36Sopenharmony_ci fs_info->qgroup_rescan_progress.objectid = progress_objectid; 355662306a36Sopenharmony_ci init_completion(&fs_info->qgroup_rescan_completion); 355762306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 355862306a36Sopenharmony_ci 355962306a36Sopenharmony_ci btrfs_init_work(&fs_info->qgroup_rescan_work, 356062306a36Sopenharmony_ci btrfs_qgroup_rescan_worker, NULL, NULL); 356162306a36Sopenharmony_ci return 0; 356262306a36Sopenharmony_ci} 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_cistatic void 356562306a36Sopenharmony_ciqgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info) 356662306a36Sopenharmony_ci{ 356762306a36Sopenharmony_ci struct rb_node *n; 356862306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 356962306a36Sopenharmony_ci 357062306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 357162306a36Sopenharmony_ci /* clear all current qgroup tracking information */ 357262306a36Sopenharmony_ci for (n = rb_first(&fs_info->qgroup_tree); n; n = rb_next(n)) { 357362306a36Sopenharmony_ci qgroup = rb_entry(n, struct btrfs_qgroup, node); 357462306a36Sopenharmony_ci qgroup->rfer = 0; 357562306a36Sopenharmony_ci qgroup->rfer_cmpr = 0; 357662306a36Sopenharmony_ci qgroup->excl = 0; 357762306a36Sopenharmony_ci qgroup->excl_cmpr = 0; 357862306a36Sopenharmony_ci qgroup_dirty(fs_info, qgroup); 357962306a36Sopenharmony_ci } 358062306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 358162306a36Sopenharmony_ci} 358262306a36Sopenharmony_ci 358362306a36Sopenharmony_ciint 358462306a36Sopenharmony_cibtrfs_qgroup_rescan(struct btrfs_fs_info *fs_info) 358562306a36Sopenharmony_ci{ 358662306a36Sopenharmony_ci int ret = 0; 358762306a36Sopenharmony_ci struct btrfs_trans_handle *trans; 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_ci ret = qgroup_rescan_init(fs_info, 0, 1); 359062306a36Sopenharmony_ci if (ret) 359162306a36Sopenharmony_ci return ret; 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_ci /* 359462306a36Sopenharmony_ci * We have set the rescan_progress to 0, which means no more 359562306a36Sopenharmony_ci * delayed refs will be accounted by btrfs_qgroup_account_ref. 359662306a36Sopenharmony_ci * However, btrfs_qgroup_account_ref may be right after its call 359762306a36Sopenharmony_ci * to btrfs_find_all_roots, in which case it would still do the 359862306a36Sopenharmony_ci * accounting. 359962306a36Sopenharmony_ci * To solve this, we're committing the transaction, which will 360062306a36Sopenharmony_ci * ensure we run all delayed refs and only after that, we are 360162306a36Sopenharmony_ci * going to clear all tracking information for a clean start. 360262306a36Sopenharmony_ci */ 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_ci trans = btrfs_attach_transaction_barrier(fs_info->fs_root); 360562306a36Sopenharmony_ci if (IS_ERR(trans) && trans != ERR_PTR(-ENOENT)) { 360662306a36Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; 360762306a36Sopenharmony_ci return PTR_ERR(trans); 360862306a36Sopenharmony_ci } else if (trans != ERR_PTR(-ENOENT)) { 360962306a36Sopenharmony_ci ret = btrfs_commit_transaction(trans); 361062306a36Sopenharmony_ci if (ret) { 361162306a36Sopenharmony_ci fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; 361262306a36Sopenharmony_ci return ret; 361362306a36Sopenharmony_ci } 361462306a36Sopenharmony_ci } 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ci qgroup_rescan_zero_tracking(fs_info); 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 361962306a36Sopenharmony_ci fs_info->qgroup_rescan_running = true; 362062306a36Sopenharmony_ci btrfs_queue_work(fs_info->qgroup_rescan_workers, 362162306a36Sopenharmony_ci &fs_info->qgroup_rescan_work); 362262306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci return 0; 362562306a36Sopenharmony_ci} 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ciint btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info, 362862306a36Sopenharmony_ci bool interruptible) 362962306a36Sopenharmony_ci{ 363062306a36Sopenharmony_ci int running; 363162306a36Sopenharmony_ci int ret = 0; 363262306a36Sopenharmony_ci 363362306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 363462306a36Sopenharmony_ci running = fs_info->qgroup_rescan_running; 363562306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_ci if (!running) 363862306a36Sopenharmony_ci return 0; 363962306a36Sopenharmony_ci 364062306a36Sopenharmony_ci if (interruptible) 364162306a36Sopenharmony_ci ret = wait_for_completion_interruptible( 364262306a36Sopenharmony_ci &fs_info->qgroup_rescan_completion); 364362306a36Sopenharmony_ci else 364462306a36Sopenharmony_ci wait_for_completion(&fs_info->qgroup_rescan_completion); 364562306a36Sopenharmony_ci 364662306a36Sopenharmony_ci return ret; 364762306a36Sopenharmony_ci} 364862306a36Sopenharmony_ci 364962306a36Sopenharmony_ci/* 365062306a36Sopenharmony_ci * this is only called from open_ctree where we're still single threaded, thus 365162306a36Sopenharmony_ci * locking is omitted here. 365262306a36Sopenharmony_ci */ 365362306a36Sopenharmony_civoid 365462306a36Sopenharmony_cibtrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info) 365562306a36Sopenharmony_ci{ 365662306a36Sopenharmony_ci if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { 365762306a36Sopenharmony_ci mutex_lock(&fs_info->qgroup_rescan_lock); 365862306a36Sopenharmony_ci fs_info->qgroup_rescan_running = true; 365962306a36Sopenharmony_ci btrfs_queue_work(fs_info->qgroup_rescan_workers, 366062306a36Sopenharmony_ci &fs_info->qgroup_rescan_work); 366162306a36Sopenharmony_ci mutex_unlock(&fs_info->qgroup_rescan_lock); 366262306a36Sopenharmony_ci } 366362306a36Sopenharmony_ci} 366462306a36Sopenharmony_ci 366562306a36Sopenharmony_ci#define rbtree_iterate_from_safe(node, next, start) \ 366662306a36Sopenharmony_ci for (node = start; node && ({ next = rb_next(node); 1;}); node = next) 366762306a36Sopenharmony_ci 366862306a36Sopenharmony_cistatic int qgroup_unreserve_range(struct btrfs_inode *inode, 366962306a36Sopenharmony_ci struct extent_changeset *reserved, u64 start, 367062306a36Sopenharmony_ci u64 len) 367162306a36Sopenharmony_ci{ 367262306a36Sopenharmony_ci struct rb_node *node; 367362306a36Sopenharmony_ci struct rb_node *next; 367462306a36Sopenharmony_ci struct ulist_node *entry; 367562306a36Sopenharmony_ci int ret = 0; 367662306a36Sopenharmony_ci 367762306a36Sopenharmony_ci node = reserved->range_changed.root.rb_node; 367862306a36Sopenharmony_ci if (!node) 367962306a36Sopenharmony_ci return 0; 368062306a36Sopenharmony_ci while (node) { 368162306a36Sopenharmony_ci entry = rb_entry(node, struct ulist_node, rb_node); 368262306a36Sopenharmony_ci if (entry->val < start) 368362306a36Sopenharmony_ci node = node->rb_right; 368462306a36Sopenharmony_ci else 368562306a36Sopenharmony_ci node = node->rb_left; 368662306a36Sopenharmony_ci } 368762306a36Sopenharmony_ci 368862306a36Sopenharmony_ci if (entry->val > start && rb_prev(&entry->rb_node)) 368962306a36Sopenharmony_ci entry = rb_entry(rb_prev(&entry->rb_node), struct ulist_node, 369062306a36Sopenharmony_ci rb_node); 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci rbtree_iterate_from_safe(node, next, &entry->rb_node) { 369362306a36Sopenharmony_ci u64 entry_start; 369462306a36Sopenharmony_ci u64 entry_end; 369562306a36Sopenharmony_ci u64 entry_len; 369662306a36Sopenharmony_ci int clear_ret; 369762306a36Sopenharmony_ci 369862306a36Sopenharmony_ci entry = rb_entry(node, struct ulist_node, rb_node); 369962306a36Sopenharmony_ci entry_start = entry->val; 370062306a36Sopenharmony_ci entry_end = entry->aux; 370162306a36Sopenharmony_ci entry_len = entry_end - entry_start + 1; 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci if (entry_start >= start + len) 370462306a36Sopenharmony_ci break; 370562306a36Sopenharmony_ci if (entry_start + entry_len <= start) 370662306a36Sopenharmony_ci continue; 370762306a36Sopenharmony_ci /* 370862306a36Sopenharmony_ci * Now the entry is in [start, start + len), revert the 370962306a36Sopenharmony_ci * EXTENT_QGROUP_RESERVED bit. 371062306a36Sopenharmony_ci */ 371162306a36Sopenharmony_ci clear_ret = clear_extent_bits(&inode->io_tree, entry_start, 371262306a36Sopenharmony_ci entry_end, EXTENT_QGROUP_RESERVED); 371362306a36Sopenharmony_ci if (!ret && clear_ret < 0) 371462306a36Sopenharmony_ci ret = clear_ret; 371562306a36Sopenharmony_ci 371662306a36Sopenharmony_ci ulist_del(&reserved->range_changed, entry->val, entry->aux); 371762306a36Sopenharmony_ci if (likely(reserved->bytes_changed >= entry_len)) { 371862306a36Sopenharmony_ci reserved->bytes_changed -= entry_len; 371962306a36Sopenharmony_ci } else { 372062306a36Sopenharmony_ci WARN_ON(1); 372162306a36Sopenharmony_ci reserved->bytes_changed = 0; 372262306a36Sopenharmony_ci } 372362306a36Sopenharmony_ci } 372462306a36Sopenharmony_ci 372562306a36Sopenharmony_ci return ret; 372662306a36Sopenharmony_ci} 372762306a36Sopenharmony_ci 372862306a36Sopenharmony_ci/* 372962306a36Sopenharmony_ci * Try to free some space for qgroup. 373062306a36Sopenharmony_ci * 373162306a36Sopenharmony_ci * For qgroup, there are only 3 ways to free qgroup space: 373262306a36Sopenharmony_ci * - Flush nodatacow write 373362306a36Sopenharmony_ci * Any nodatacow write will free its reserved data space at run_delalloc_range(). 373462306a36Sopenharmony_ci * In theory, we should only flush nodatacow inodes, but it's not yet 373562306a36Sopenharmony_ci * possible, so we need to flush the whole root. 373662306a36Sopenharmony_ci * 373762306a36Sopenharmony_ci * - Wait for ordered extents 373862306a36Sopenharmony_ci * When ordered extents are finished, their reserved metadata is finally 373962306a36Sopenharmony_ci * converted to per_trans status, which can be freed by later commit 374062306a36Sopenharmony_ci * transaction. 374162306a36Sopenharmony_ci * 374262306a36Sopenharmony_ci * - Commit transaction 374362306a36Sopenharmony_ci * This would free the meta_per_trans space. 374462306a36Sopenharmony_ci * In theory this shouldn't provide much space, but any more qgroup space 374562306a36Sopenharmony_ci * is needed. 374662306a36Sopenharmony_ci */ 374762306a36Sopenharmony_cistatic int try_flush_qgroup(struct btrfs_root *root) 374862306a36Sopenharmony_ci{ 374962306a36Sopenharmony_ci struct btrfs_trans_handle *trans; 375062306a36Sopenharmony_ci int ret; 375162306a36Sopenharmony_ci 375262306a36Sopenharmony_ci /* Can't hold an open transaction or we run the risk of deadlocking. */ 375362306a36Sopenharmony_ci ASSERT(current->journal_info == NULL); 375462306a36Sopenharmony_ci if (WARN_ON(current->journal_info)) 375562306a36Sopenharmony_ci return 0; 375662306a36Sopenharmony_ci 375762306a36Sopenharmony_ci /* 375862306a36Sopenharmony_ci * We don't want to run flush again and again, so if there is a running 375962306a36Sopenharmony_ci * one, we won't try to start a new flush, but exit directly. 376062306a36Sopenharmony_ci */ 376162306a36Sopenharmony_ci if (test_and_set_bit(BTRFS_ROOT_QGROUP_FLUSHING, &root->state)) { 376262306a36Sopenharmony_ci wait_event(root->qgroup_flush_wait, 376362306a36Sopenharmony_ci !test_bit(BTRFS_ROOT_QGROUP_FLUSHING, &root->state)); 376462306a36Sopenharmony_ci return 0; 376562306a36Sopenharmony_ci } 376662306a36Sopenharmony_ci 376762306a36Sopenharmony_ci ret = btrfs_start_delalloc_snapshot(root, true); 376862306a36Sopenharmony_ci if (ret < 0) 376962306a36Sopenharmony_ci goto out; 377062306a36Sopenharmony_ci btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1); 377162306a36Sopenharmony_ci 377262306a36Sopenharmony_ci trans = btrfs_attach_transaction_barrier(root); 377362306a36Sopenharmony_ci if (IS_ERR(trans)) { 377462306a36Sopenharmony_ci ret = PTR_ERR(trans); 377562306a36Sopenharmony_ci if (ret == -ENOENT) 377662306a36Sopenharmony_ci ret = 0; 377762306a36Sopenharmony_ci goto out; 377862306a36Sopenharmony_ci } 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci ret = btrfs_commit_transaction(trans); 378162306a36Sopenharmony_ciout: 378262306a36Sopenharmony_ci clear_bit(BTRFS_ROOT_QGROUP_FLUSHING, &root->state); 378362306a36Sopenharmony_ci wake_up(&root->qgroup_flush_wait); 378462306a36Sopenharmony_ci return ret; 378562306a36Sopenharmony_ci} 378662306a36Sopenharmony_ci 378762306a36Sopenharmony_cistatic int qgroup_reserve_data(struct btrfs_inode *inode, 378862306a36Sopenharmony_ci struct extent_changeset **reserved_ret, u64 start, 378962306a36Sopenharmony_ci u64 len) 379062306a36Sopenharmony_ci{ 379162306a36Sopenharmony_ci struct btrfs_root *root = inode->root; 379262306a36Sopenharmony_ci struct extent_changeset *reserved; 379362306a36Sopenharmony_ci bool new_reserved = false; 379462306a36Sopenharmony_ci u64 orig_reserved; 379562306a36Sopenharmony_ci u64 to_reserve; 379662306a36Sopenharmony_ci int ret; 379762306a36Sopenharmony_ci 379862306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags) || 379962306a36Sopenharmony_ci !is_fstree(root->root_key.objectid) || len == 0) 380062306a36Sopenharmony_ci return 0; 380162306a36Sopenharmony_ci 380262306a36Sopenharmony_ci /* @reserved parameter is mandatory for qgroup */ 380362306a36Sopenharmony_ci if (WARN_ON(!reserved_ret)) 380462306a36Sopenharmony_ci return -EINVAL; 380562306a36Sopenharmony_ci if (!*reserved_ret) { 380662306a36Sopenharmony_ci new_reserved = true; 380762306a36Sopenharmony_ci *reserved_ret = extent_changeset_alloc(); 380862306a36Sopenharmony_ci if (!*reserved_ret) 380962306a36Sopenharmony_ci return -ENOMEM; 381062306a36Sopenharmony_ci } 381162306a36Sopenharmony_ci reserved = *reserved_ret; 381262306a36Sopenharmony_ci /* Record already reserved space */ 381362306a36Sopenharmony_ci orig_reserved = reserved->bytes_changed; 381462306a36Sopenharmony_ci ret = set_record_extent_bits(&inode->io_tree, start, 381562306a36Sopenharmony_ci start + len -1, EXTENT_QGROUP_RESERVED, reserved); 381662306a36Sopenharmony_ci 381762306a36Sopenharmony_ci /* Newly reserved space */ 381862306a36Sopenharmony_ci to_reserve = reserved->bytes_changed - orig_reserved; 381962306a36Sopenharmony_ci trace_btrfs_qgroup_reserve_data(&inode->vfs_inode, start, len, 382062306a36Sopenharmony_ci to_reserve, QGROUP_RESERVE); 382162306a36Sopenharmony_ci if (ret < 0) 382262306a36Sopenharmony_ci goto out; 382362306a36Sopenharmony_ci ret = qgroup_reserve(root, to_reserve, true, BTRFS_QGROUP_RSV_DATA); 382462306a36Sopenharmony_ci if (ret < 0) 382562306a36Sopenharmony_ci goto cleanup; 382662306a36Sopenharmony_ci 382762306a36Sopenharmony_ci return ret; 382862306a36Sopenharmony_ci 382962306a36Sopenharmony_cicleanup: 383062306a36Sopenharmony_ci qgroup_unreserve_range(inode, reserved, start, len); 383162306a36Sopenharmony_ciout: 383262306a36Sopenharmony_ci if (new_reserved) { 383362306a36Sopenharmony_ci extent_changeset_free(reserved); 383462306a36Sopenharmony_ci *reserved_ret = NULL; 383562306a36Sopenharmony_ci } 383662306a36Sopenharmony_ci return ret; 383762306a36Sopenharmony_ci} 383862306a36Sopenharmony_ci 383962306a36Sopenharmony_ci/* 384062306a36Sopenharmony_ci * Reserve qgroup space for range [start, start + len). 384162306a36Sopenharmony_ci * 384262306a36Sopenharmony_ci * This function will either reserve space from related qgroups or do nothing 384362306a36Sopenharmony_ci * if the range is already reserved. 384462306a36Sopenharmony_ci * 384562306a36Sopenharmony_ci * Return 0 for successful reservation 384662306a36Sopenharmony_ci * Return <0 for error (including -EQUOT) 384762306a36Sopenharmony_ci * 384862306a36Sopenharmony_ci * NOTE: This function may sleep for memory allocation, dirty page flushing and 384962306a36Sopenharmony_ci * commit transaction. So caller should not hold any dirty page locked. 385062306a36Sopenharmony_ci */ 385162306a36Sopenharmony_ciint btrfs_qgroup_reserve_data(struct btrfs_inode *inode, 385262306a36Sopenharmony_ci struct extent_changeset **reserved_ret, u64 start, 385362306a36Sopenharmony_ci u64 len) 385462306a36Sopenharmony_ci{ 385562306a36Sopenharmony_ci int ret; 385662306a36Sopenharmony_ci 385762306a36Sopenharmony_ci ret = qgroup_reserve_data(inode, reserved_ret, start, len); 385862306a36Sopenharmony_ci if (ret <= 0 && ret != -EDQUOT) 385962306a36Sopenharmony_ci return ret; 386062306a36Sopenharmony_ci 386162306a36Sopenharmony_ci ret = try_flush_qgroup(inode->root); 386262306a36Sopenharmony_ci if (ret < 0) 386362306a36Sopenharmony_ci return ret; 386462306a36Sopenharmony_ci return qgroup_reserve_data(inode, reserved_ret, start, len); 386562306a36Sopenharmony_ci} 386662306a36Sopenharmony_ci 386762306a36Sopenharmony_ci/* Free ranges specified by @reserved, normally in error path */ 386862306a36Sopenharmony_cistatic int qgroup_free_reserved_data(struct btrfs_inode *inode, 386962306a36Sopenharmony_ci struct extent_changeset *reserved, 387062306a36Sopenharmony_ci u64 start, u64 len, u64 *freed_ret) 387162306a36Sopenharmony_ci{ 387262306a36Sopenharmony_ci struct btrfs_root *root = inode->root; 387362306a36Sopenharmony_ci struct ulist_node *unode; 387462306a36Sopenharmony_ci struct ulist_iterator uiter; 387562306a36Sopenharmony_ci struct extent_changeset changeset; 387662306a36Sopenharmony_ci u64 freed = 0; 387762306a36Sopenharmony_ci int ret; 387862306a36Sopenharmony_ci 387962306a36Sopenharmony_ci extent_changeset_init(&changeset); 388062306a36Sopenharmony_ci len = round_up(start + len, root->fs_info->sectorsize); 388162306a36Sopenharmony_ci start = round_down(start, root->fs_info->sectorsize); 388262306a36Sopenharmony_ci 388362306a36Sopenharmony_ci ULIST_ITER_INIT(&uiter); 388462306a36Sopenharmony_ci while ((unode = ulist_next(&reserved->range_changed, &uiter))) { 388562306a36Sopenharmony_ci u64 range_start = unode->val; 388662306a36Sopenharmony_ci /* unode->aux is the inclusive end */ 388762306a36Sopenharmony_ci u64 range_len = unode->aux - range_start + 1; 388862306a36Sopenharmony_ci u64 free_start; 388962306a36Sopenharmony_ci u64 free_len; 389062306a36Sopenharmony_ci 389162306a36Sopenharmony_ci extent_changeset_release(&changeset); 389262306a36Sopenharmony_ci 389362306a36Sopenharmony_ci /* Only free range in range [start, start + len) */ 389462306a36Sopenharmony_ci if (range_start >= start + len || 389562306a36Sopenharmony_ci range_start + range_len <= start) 389662306a36Sopenharmony_ci continue; 389762306a36Sopenharmony_ci free_start = max(range_start, start); 389862306a36Sopenharmony_ci free_len = min(start + len, range_start + range_len) - 389962306a36Sopenharmony_ci free_start; 390062306a36Sopenharmony_ci /* 390162306a36Sopenharmony_ci * TODO: To also modify reserved->ranges_reserved to reflect 390262306a36Sopenharmony_ci * the modification. 390362306a36Sopenharmony_ci * 390462306a36Sopenharmony_ci * However as long as we free qgroup reserved according to 390562306a36Sopenharmony_ci * EXTENT_QGROUP_RESERVED, we won't double free. 390662306a36Sopenharmony_ci * So not need to rush. 390762306a36Sopenharmony_ci */ 390862306a36Sopenharmony_ci ret = clear_record_extent_bits(&inode->io_tree, free_start, 390962306a36Sopenharmony_ci free_start + free_len - 1, 391062306a36Sopenharmony_ci EXTENT_QGROUP_RESERVED, &changeset); 391162306a36Sopenharmony_ci if (ret < 0) 391262306a36Sopenharmony_ci goto out; 391362306a36Sopenharmony_ci freed += changeset.bytes_changed; 391462306a36Sopenharmony_ci } 391562306a36Sopenharmony_ci btrfs_qgroup_free_refroot(root->fs_info, root->root_key.objectid, freed, 391662306a36Sopenharmony_ci BTRFS_QGROUP_RSV_DATA); 391762306a36Sopenharmony_ci if (freed_ret) 391862306a36Sopenharmony_ci *freed_ret = freed; 391962306a36Sopenharmony_ci ret = 0; 392062306a36Sopenharmony_ciout: 392162306a36Sopenharmony_ci extent_changeset_release(&changeset); 392262306a36Sopenharmony_ci return ret; 392362306a36Sopenharmony_ci} 392462306a36Sopenharmony_ci 392562306a36Sopenharmony_cistatic int __btrfs_qgroup_release_data(struct btrfs_inode *inode, 392662306a36Sopenharmony_ci struct extent_changeset *reserved, u64 start, u64 len, 392762306a36Sopenharmony_ci u64 *released, int free) 392862306a36Sopenharmony_ci{ 392962306a36Sopenharmony_ci struct extent_changeset changeset; 393062306a36Sopenharmony_ci int trace_op = QGROUP_RELEASE; 393162306a36Sopenharmony_ci int ret; 393262306a36Sopenharmony_ci 393362306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &inode->root->fs_info->flags)) 393462306a36Sopenharmony_ci return 0; 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci /* In release case, we shouldn't have @reserved */ 393762306a36Sopenharmony_ci WARN_ON(!free && reserved); 393862306a36Sopenharmony_ci if (free && reserved) 393962306a36Sopenharmony_ci return qgroup_free_reserved_data(inode, reserved, start, len, released); 394062306a36Sopenharmony_ci extent_changeset_init(&changeset); 394162306a36Sopenharmony_ci ret = clear_record_extent_bits(&inode->io_tree, start, start + len -1, 394262306a36Sopenharmony_ci EXTENT_QGROUP_RESERVED, &changeset); 394362306a36Sopenharmony_ci if (ret < 0) 394462306a36Sopenharmony_ci goto out; 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_ci if (free) 394762306a36Sopenharmony_ci trace_op = QGROUP_FREE; 394862306a36Sopenharmony_ci trace_btrfs_qgroup_release_data(&inode->vfs_inode, start, len, 394962306a36Sopenharmony_ci changeset.bytes_changed, trace_op); 395062306a36Sopenharmony_ci if (free) 395162306a36Sopenharmony_ci btrfs_qgroup_free_refroot(inode->root->fs_info, 395262306a36Sopenharmony_ci inode->root->root_key.objectid, 395362306a36Sopenharmony_ci changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA); 395462306a36Sopenharmony_ci if (released) 395562306a36Sopenharmony_ci *released = changeset.bytes_changed; 395662306a36Sopenharmony_ciout: 395762306a36Sopenharmony_ci extent_changeset_release(&changeset); 395862306a36Sopenharmony_ci return ret; 395962306a36Sopenharmony_ci} 396062306a36Sopenharmony_ci 396162306a36Sopenharmony_ci/* 396262306a36Sopenharmony_ci * Free a reserved space range from io_tree and related qgroups 396362306a36Sopenharmony_ci * 396462306a36Sopenharmony_ci * Should be called when a range of pages get invalidated before reaching disk. 396562306a36Sopenharmony_ci * Or for error cleanup case. 396662306a36Sopenharmony_ci * if @reserved is given, only reserved range in [@start, @start + @len) will 396762306a36Sopenharmony_ci * be freed. 396862306a36Sopenharmony_ci * 396962306a36Sopenharmony_ci * For data written to disk, use btrfs_qgroup_release_data(). 397062306a36Sopenharmony_ci * 397162306a36Sopenharmony_ci * NOTE: This function may sleep for memory allocation. 397262306a36Sopenharmony_ci */ 397362306a36Sopenharmony_ciint btrfs_qgroup_free_data(struct btrfs_inode *inode, 397462306a36Sopenharmony_ci struct extent_changeset *reserved, 397562306a36Sopenharmony_ci u64 start, u64 len, u64 *freed) 397662306a36Sopenharmony_ci{ 397762306a36Sopenharmony_ci return __btrfs_qgroup_release_data(inode, reserved, start, len, freed, 1); 397862306a36Sopenharmony_ci} 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci/* 398162306a36Sopenharmony_ci * Release a reserved space range from io_tree only. 398262306a36Sopenharmony_ci * 398362306a36Sopenharmony_ci * Should be called when a range of pages get written to disk and corresponding 398462306a36Sopenharmony_ci * FILE_EXTENT is inserted into corresponding root. 398562306a36Sopenharmony_ci * 398662306a36Sopenharmony_ci * Since new qgroup accounting framework will only update qgroup numbers at 398762306a36Sopenharmony_ci * commit_transaction() time, its reserved space shouldn't be freed from 398862306a36Sopenharmony_ci * related qgroups. 398962306a36Sopenharmony_ci * 399062306a36Sopenharmony_ci * But we should release the range from io_tree, to allow further write to be 399162306a36Sopenharmony_ci * COWed. 399262306a36Sopenharmony_ci * 399362306a36Sopenharmony_ci * NOTE: This function may sleep for memory allocation. 399462306a36Sopenharmony_ci */ 399562306a36Sopenharmony_ciint btrfs_qgroup_release_data(struct btrfs_inode *inode, u64 start, u64 len, u64 *released) 399662306a36Sopenharmony_ci{ 399762306a36Sopenharmony_ci return __btrfs_qgroup_release_data(inode, NULL, start, len, released, 0); 399862306a36Sopenharmony_ci} 399962306a36Sopenharmony_ci 400062306a36Sopenharmony_cistatic void add_root_meta_rsv(struct btrfs_root *root, int num_bytes, 400162306a36Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 400262306a36Sopenharmony_ci{ 400362306a36Sopenharmony_ci if (type != BTRFS_QGROUP_RSV_META_PREALLOC && 400462306a36Sopenharmony_ci type != BTRFS_QGROUP_RSV_META_PERTRANS) 400562306a36Sopenharmony_ci return; 400662306a36Sopenharmony_ci if (num_bytes == 0) 400762306a36Sopenharmony_ci return; 400862306a36Sopenharmony_ci 400962306a36Sopenharmony_ci spin_lock(&root->qgroup_meta_rsv_lock); 401062306a36Sopenharmony_ci if (type == BTRFS_QGROUP_RSV_META_PREALLOC) 401162306a36Sopenharmony_ci root->qgroup_meta_rsv_prealloc += num_bytes; 401262306a36Sopenharmony_ci else 401362306a36Sopenharmony_ci root->qgroup_meta_rsv_pertrans += num_bytes; 401462306a36Sopenharmony_ci spin_unlock(&root->qgroup_meta_rsv_lock); 401562306a36Sopenharmony_ci} 401662306a36Sopenharmony_ci 401762306a36Sopenharmony_cistatic int sub_root_meta_rsv(struct btrfs_root *root, int num_bytes, 401862306a36Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 401962306a36Sopenharmony_ci{ 402062306a36Sopenharmony_ci if (type != BTRFS_QGROUP_RSV_META_PREALLOC && 402162306a36Sopenharmony_ci type != BTRFS_QGROUP_RSV_META_PERTRANS) 402262306a36Sopenharmony_ci return 0; 402362306a36Sopenharmony_ci if (num_bytes == 0) 402462306a36Sopenharmony_ci return 0; 402562306a36Sopenharmony_ci 402662306a36Sopenharmony_ci spin_lock(&root->qgroup_meta_rsv_lock); 402762306a36Sopenharmony_ci if (type == BTRFS_QGROUP_RSV_META_PREALLOC) { 402862306a36Sopenharmony_ci num_bytes = min_t(u64, root->qgroup_meta_rsv_prealloc, 402962306a36Sopenharmony_ci num_bytes); 403062306a36Sopenharmony_ci root->qgroup_meta_rsv_prealloc -= num_bytes; 403162306a36Sopenharmony_ci } else { 403262306a36Sopenharmony_ci num_bytes = min_t(u64, root->qgroup_meta_rsv_pertrans, 403362306a36Sopenharmony_ci num_bytes); 403462306a36Sopenharmony_ci root->qgroup_meta_rsv_pertrans -= num_bytes; 403562306a36Sopenharmony_ci } 403662306a36Sopenharmony_ci spin_unlock(&root->qgroup_meta_rsv_lock); 403762306a36Sopenharmony_ci return num_bytes; 403862306a36Sopenharmony_ci} 403962306a36Sopenharmony_ci 404062306a36Sopenharmony_ciint btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, 404162306a36Sopenharmony_ci enum btrfs_qgroup_rsv_type type, bool enforce) 404262306a36Sopenharmony_ci{ 404362306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 404462306a36Sopenharmony_ci int ret; 404562306a36Sopenharmony_ci 404662306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || 404762306a36Sopenharmony_ci !is_fstree(root->root_key.objectid) || num_bytes == 0) 404862306a36Sopenharmony_ci return 0; 404962306a36Sopenharmony_ci 405062306a36Sopenharmony_ci BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize)); 405162306a36Sopenharmony_ci trace_qgroup_meta_reserve(root, (s64)num_bytes, type); 405262306a36Sopenharmony_ci ret = qgroup_reserve(root, num_bytes, enforce, type); 405362306a36Sopenharmony_ci if (ret < 0) 405462306a36Sopenharmony_ci return ret; 405562306a36Sopenharmony_ci /* 405662306a36Sopenharmony_ci * Record what we have reserved into root. 405762306a36Sopenharmony_ci * 405862306a36Sopenharmony_ci * To avoid quota disabled->enabled underflow. 405962306a36Sopenharmony_ci * In that case, we may try to free space we haven't reserved 406062306a36Sopenharmony_ci * (since quota was disabled), so record what we reserved into root. 406162306a36Sopenharmony_ci * And ensure later release won't underflow this number. 406262306a36Sopenharmony_ci */ 406362306a36Sopenharmony_ci add_root_meta_rsv(root, num_bytes, type); 406462306a36Sopenharmony_ci return ret; 406562306a36Sopenharmony_ci} 406662306a36Sopenharmony_ci 406762306a36Sopenharmony_ciint __btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes, 406862306a36Sopenharmony_ci enum btrfs_qgroup_rsv_type type, bool enforce, 406962306a36Sopenharmony_ci bool noflush) 407062306a36Sopenharmony_ci{ 407162306a36Sopenharmony_ci int ret; 407262306a36Sopenharmony_ci 407362306a36Sopenharmony_ci ret = btrfs_qgroup_reserve_meta(root, num_bytes, type, enforce); 407462306a36Sopenharmony_ci if ((ret <= 0 && ret != -EDQUOT) || noflush) 407562306a36Sopenharmony_ci return ret; 407662306a36Sopenharmony_ci 407762306a36Sopenharmony_ci ret = try_flush_qgroup(root); 407862306a36Sopenharmony_ci if (ret < 0) 407962306a36Sopenharmony_ci return ret; 408062306a36Sopenharmony_ci return btrfs_qgroup_reserve_meta(root, num_bytes, type, enforce); 408162306a36Sopenharmony_ci} 408262306a36Sopenharmony_ci 408362306a36Sopenharmony_civoid btrfs_qgroup_free_meta_all_pertrans(struct btrfs_root *root) 408462306a36Sopenharmony_ci{ 408562306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 408662306a36Sopenharmony_ci 408762306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || 408862306a36Sopenharmony_ci !is_fstree(root->root_key.objectid)) 408962306a36Sopenharmony_ci return; 409062306a36Sopenharmony_ci 409162306a36Sopenharmony_ci /* TODO: Update trace point to handle such free */ 409262306a36Sopenharmony_ci trace_qgroup_meta_free_all_pertrans(root); 409362306a36Sopenharmony_ci /* Special value -1 means to free all reserved space */ 409462306a36Sopenharmony_ci btrfs_qgroup_free_refroot(fs_info, root->root_key.objectid, (u64)-1, 409562306a36Sopenharmony_ci BTRFS_QGROUP_RSV_META_PERTRANS); 409662306a36Sopenharmony_ci} 409762306a36Sopenharmony_ci 409862306a36Sopenharmony_civoid __btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes, 409962306a36Sopenharmony_ci enum btrfs_qgroup_rsv_type type) 410062306a36Sopenharmony_ci{ 410162306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 410262306a36Sopenharmony_ci 410362306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || 410462306a36Sopenharmony_ci !is_fstree(root->root_key.objectid)) 410562306a36Sopenharmony_ci return; 410662306a36Sopenharmony_ci 410762306a36Sopenharmony_ci /* 410862306a36Sopenharmony_ci * reservation for META_PREALLOC can happen before quota is enabled, 410962306a36Sopenharmony_ci * which can lead to underflow. 411062306a36Sopenharmony_ci * Here ensure we will only free what we really have reserved. 411162306a36Sopenharmony_ci */ 411262306a36Sopenharmony_ci num_bytes = sub_root_meta_rsv(root, num_bytes, type); 411362306a36Sopenharmony_ci BUG_ON(num_bytes != round_down(num_bytes, fs_info->nodesize)); 411462306a36Sopenharmony_ci trace_qgroup_meta_reserve(root, -(s64)num_bytes, type); 411562306a36Sopenharmony_ci btrfs_qgroup_free_refroot(fs_info, root->root_key.objectid, 411662306a36Sopenharmony_ci num_bytes, type); 411762306a36Sopenharmony_ci} 411862306a36Sopenharmony_ci 411962306a36Sopenharmony_cistatic void qgroup_convert_meta(struct btrfs_fs_info *fs_info, u64 ref_root, 412062306a36Sopenharmony_ci int num_bytes) 412162306a36Sopenharmony_ci{ 412262306a36Sopenharmony_ci struct btrfs_qgroup *qgroup; 412362306a36Sopenharmony_ci LIST_HEAD(qgroup_list); 412462306a36Sopenharmony_ci 412562306a36Sopenharmony_ci if (num_bytes == 0) 412662306a36Sopenharmony_ci return; 412762306a36Sopenharmony_ci if (!fs_info->quota_root) 412862306a36Sopenharmony_ci return; 412962306a36Sopenharmony_ci 413062306a36Sopenharmony_ci spin_lock(&fs_info->qgroup_lock); 413162306a36Sopenharmony_ci qgroup = find_qgroup_rb(fs_info, ref_root); 413262306a36Sopenharmony_ci if (!qgroup) 413362306a36Sopenharmony_ci goto out; 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_ci qgroup_iterator_add(&qgroup_list, qgroup); 413662306a36Sopenharmony_ci list_for_each_entry(qgroup, &qgroup_list, iterator) { 413762306a36Sopenharmony_ci struct btrfs_qgroup_list *glist; 413862306a36Sopenharmony_ci 413962306a36Sopenharmony_ci qgroup_rsv_release(fs_info, qgroup, num_bytes, 414062306a36Sopenharmony_ci BTRFS_QGROUP_RSV_META_PREALLOC); 414162306a36Sopenharmony_ci if (!sb_rdonly(fs_info->sb)) 414262306a36Sopenharmony_ci qgroup_rsv_add(fs_info, qgroup, num_bytes, 414362306a36Sopenharmony_ci BTRFS_QGROUP_RSV_META_PERTRANS); 414462306a36Sopenharmony_ci 414562306a36Sopenharmony_ci list_for_each_entry(glist, &qgroup->groups, next_group) 414662306a36Sopenharmony_ci qgroup_iterator_add(&qgroup_list, glist->group); 414762306a36Sopenharmony_ci } 414862306a36Sopenharmony_ciout: 414962306a36Sopenharmony_ci qgroup_iterator_clean(&qgroup_list); 415062306a36Sopenharmony_ci spin_unlock(&fs_info->qgroup_lock); 415162306a36Sopenharmony_ci} 415262306a36Sopenharmony_ci 415362306a36Sopenharmony_civoid btrfs_qgroup_convert_reserved_meta(struct btrfs_root *root, int num_bytes) 415462306a36Sopenharmony_ci{ 415562306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 415662306a36Sopenharmony_ci 415762306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) || 415862306a36Sopenharmony_ci !is_fstree(root->root_key.objectid)) 415962306a36Sopenharmony_ci return; 416062306a36Sopenharmony_ci /* Same as btrfs_qgroup_free_meta_prealloc() */ 416162306a36Sopenharmony_ci num_bytes = sub_root_meta_rsv(root, num_bytes, 416262306a36Sopenharmony_ci BTRFS_QGROUP_RSV_META_PREALLOC); 416362306a36Sopenharmony_ci trace_qgroup_meta_convert(root, num_bytes); 416462306a36Sopenharmony_ci qgroup_convert_meta(fs_info, root->root_key.objectid, num_bytes); 416562306a36Sopenharmony_ci} 416662306a36Sopenharmony_ci 416762306a36Sopenharmony_ci/* 416862306a36Sopenharmony_ci * Check qgroup reserved space leaking, normally at destroy inode 416962306a36Sopenharmony_ci * time 417062306a36Sopenharmony_ci */ 417162306a36Sopenharmony_civoid btrfs_qgroup_check_reserved_leak(struct btrfs_inode *inode) 417262306a36Sopenharmony_ci{ 417362306a36Sopenharmony_ci struct extent_changeset changeset; 417462306a36Sopenharmony_ci struct ulist_node *unode; 417562306a36Sopenharmony_ci struct ulist_iterator iter; 417662306a36Sopenharmony_ci int ret; 417762306a36Sopenharmony_ci 417862306a36Sopenharmony_ci extent_changeset_init(&changeset); 417962306a36Sopenharmony_ci ret = clear_record_extent_bits(&inode->io_tree, 0, (u64)-1, 418062306a36Sopenharmony_ci EXTENT_QGROUP_RESERVED, &changeset); 418162306a36Sopenharmony_ci 418262306a36Sopenharmony_ci WARN_ON(ret < 0); 418362306a36Sopenharmony_ci if (WARN_ON(changeset.bytes_changed)) { 418462306a36Sopenharmony_ci ULIST_ITER_INIT(&iter); 418562306a36Sopenharmony_ci while ((unode = ulist_next(&changeset.range_changed, &iter))) { 418662306a36Sopenharmony_ci btrfs_warn(inode->root->fs_info, 418762306a36Sopenharmony_ci "leaking qgroup reserved space, ino: %llu, start: %llu, end: %llu", 418862306a36Sopenharmony_ci btrfs_ino(inode), unode->val, unode->aux); 418962306a36Sopenharmony_ci } 419062306a36Sopenharmony_ci btrfs_qgroup_free_refroot(inode->root->fs_info, 419162306a36Sopenharmony_ci inode->root->root_key.objectid, 419262306a36Sopenharmony_ci changeset.bytes_changed, BTRFS_QGROUP_RSV_DATA); 419362306a36Sopenharmony_ci 419462306a36Sopenharmony_ci } 419562306a36Sopenharmony_ci extent_changeset_release(&changeset); 419662306a36Sopenharmony_ci} 419762306a36Sopenharmony_ci 419862306a36Sopenharmony_civoid btrfs_qgroup_init_swapped_blocks( 419962306a36Sopenharmony_ci struct btrfs_qgroup_swapped_blocks *swapped_blocks) 420062306a36Sopenharmony_ci{ 420162306a36Sopenharmony_ci int i; 420262306a36Sopenharmony_ci 420362306a36Sopenharmony_ci spin_lock_init(&swapped_blocks->lock); 420462306a36Sopenharmony_ci for (i = 0; i < BTRFS_MAX_LEVEL; i++) 420562306a36Sopenharmony_ci swapped_blocks->blocks[i] = RB_ROOT; 420662306a36Sopenharmony_ci swapped_blocks->swapped = false; 420762306a36Sopenharmony_ci} 420862306a36Sopenharmony_ci 420962306a36Sopenharmony_ci/* 421062306a36Sopenharmony_ci * Delete all swapped blocks record of @root. 421162306a36Sopenharmony_ci * Every record here means we skipped a full subtree scan for qgroup. 421262306a36Sopenharmony_ci * 421362306a36Sopenharmony_ci * Gets called when committing one transaction. 421462306a36Sopenharmony_ci */ 421562306a36Sopenharmony_civoid btrfs_qgroup_clean_swapped_blocks(struct btrfs_root *root) 421662306a36Sopenharmony_ci{ 421762306a36Sopenharmony_ci struct btrfs_qgroup_swapped_blocks *swapped_blocks; 421862306a36Sopenharmony_ci int i; 421962306a36Sopenharmony_ci 422062306a36Sopenharmony_ci swapped_blocks = &root->swapped_blocks; 422162306a36Sopenharmony_ci 422262306a36Sopenharmony_ci spin_lock(&swapped_blocks->lock); 422362306a36Sopenharmony_ci if (!swapped_blocks->swapped) 422462306a36Sopenharmony_ci goto out; 422562306a36Sopenharmony_ci for (i = 0; i < BTRFS_MAX_LEVEL; i++) { 422662306a36Sopenharmony_ci struct rb_root *cur_root = &swapped_blocks->blocks[i]; 422762306a36Sopenharmony_ci struct btrfs_qgroup_swapped_block *entry; 422862306a36Sopenharmony_ci struct btrfs_qgroup_swapped_block *next; 422962306a36Sopenharmony_ci 423062306a36Sopenharmony_ci rbtree_postorder_for_each_entry_safe(entry, next, cur_root, 423162306a36Sopenharmony_ci node) 423262306a36Sopenharmony_ci kfree(entry); 423362306a36Sopenharmony_ci swapped_blocks->blocks[i] = RB_ROOT; 423462306a36Sopenharmony_ci } 423562306a36Sopenharmony_ci swapped_blocks->swapped = false; 423662306a36Sopenharmony_ciout: 423762306a36Sopenharmony_ci spin_unlock(&swapped_blocks->lock); 423862306a36Sopenharmony_ci} 423962306a36Sopenharmony_ci 424062306a36Sopenharmony_ci/* 424162306a36Sopenharmony_ci * Add subtree roots record into @subvol_root. 424262306a36Sopenharmony_ci * 424362306a36Sopenharmony_ci * @subvol_root: tree root of the subvolume tree get swapped 424462306a36Sopenharmony_ci * @bg: block group under balance 424562306a36Sopenharmony_ci * @subvol_parent/slot: pointer to the subtree root in subvolume tree 424662306a36Sopenharmony_ci * @reloc_parent/slot: pointer to the subtree root in reloc tree 424762306a36Sopenharmony_ci * BOTH POINTERS ARE BEFORE TREE SWAP 424862306a36Sopenharmony_ci * @last_snapshot: last snapshot generation of the subvolume tree 424962306a36Sopenharmony_ci */ 425062306a36Sopenharmony_ciint btrfs_qgroup_add_swapped_blocks(struct btrfs_trans_handle *trans, 425162306a36Sopenharmony_ci struct btrfs_root *subvol_root, 425262306a36Sopenharmony_ci struct btrfs_block_group *bg, 425362306a36Sopenharmony_ci struct extent_buffer *subvol_parent, int subvol_slot, 425462306a36Sopenharmony_ci struct extent_buffer *reloc_parent, int reloc_slot, 425562306a36Sopenharmony_ci u64 last_snapshot) 425662306a36Sopenharmony_ci{ 425762306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = subvol_root->fs_info; 425862306a36Sopenharmony_ci struct btrfs_qgroup_swapped_blocks *blocks = &subvol_root->swapped_blocks; 425962306a36Sopenharmony_ci struct btrfs_qgroup_swapped_block *block; 426062306a36Sopenharmony_ci struct rb_node **cur; 426162306a36Sopenharmony_ci struct rb_node *parent = NULL; 426262306a36Sopenharmony_ci int level = btrfs_header_level(subvol_parent) - 1; 426362306a36Sopenharmony_ci int ret = 0; 426462306a36Sopenharmony_ci 426562306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 426662306a36Sopenharmony_ci return 0; 426762306a36Sopenharmony_ci 426862306a36Sopenharmony_ci if (btrfs_node_ptr_generation(subvol_parent, subvol_slot) > 426962306a36Sopenharmony_ci btrfs_node_ptr_generation(reloc_parent, reloc_slot)) { 427062306a36Sopenharmony_ci btrfs_err_rl(fs_info, 427162306a36Sopenharmony_ci "%s: bad parameter order, subvol_gen=%llu reloc_gen=%llu", 427262306a36Sopenharmony_ci __func__, 427362306a36Sopenharmony_ci btrfs_node_ptr_generation(subvol_parent, subvol_slot), 427462306a36Sopenharmony_ci btrfs_node_ptr_generation(reloc_parent, reloc_slot)); 427562306a36Sopenharmony_ci return -EUCLEAN; 427662306a36Sopenharmony_ci } 427762306a36Sopenharmony_ci 427862306a36Sopenharmony_ci block = kmalloc(sizeof(*block), GFP_NOFS); 427962306a36Sopenharmony_ci if (!block) { 428062306a36Sopenharmony_ci ret = -ENOMEM; 428162306a36Sopenharmony_ci goto out; 428262306a36Sopenharmony_ci } 428362306a36Sopenharmony_ci 428462306a36Sopenharmony_ci /* 428562306a36Sopenharmony_ci * @reloc_parent/slot is still before swap, while @block is going to 428662306a36Sopenharmony_ci * record the bytenr after swap, so we do the swap here. 428762306a36Sopenharmony_ci */ 428862306a36Sopenharmony_ci block->subvol_bytenr = btrfs_node_blockptr(reloc_parent, reloc_slot); 428962306a36Sopenharmony_ci block->subvol_generation = btrfs_node_ptr_generation(reloc_parent, 429062306a36Sopenharmony_ci reloc_slot); 429162306a36Sopenharmony_ci block->reloc_bytenr = btrfs_node_blockptr(subvol_parent, subvol_slot); 429262306a36Sopenharmony_ci block->reloc_generation = btrfs_node_ptr_generation(subvol_parent, 429362306a36Sopenharmony_ci subvol_slot); 429462306a36Sopenharmony_ci block->last_snapshot = last_snapshot; 429562306a36Sopenharmony_ci block->level = level; 429662306a36Sopenharmony_ci 429762306a36Sopenharmony_ci /* 429862306a36Sopenharmony_ci * If we have bg == NULL, we're called from btrfs_recover_relocation(), 429962306a36Sopenharmony_ci * no one else can modify tree blocks thus we qgroup will not change 430062306a36Sopenharmony_ci * no matter the value of trace_leaf. 430162306a36Sopenharmony_ci */ 430262306a36Sopenharmony_ci if (bg && bg->flags & BTRFS_BLOCK_GROUP_DATA) 430362306a36Sopenharmony_ci block->trace_leaf = true; 430462306a36Sopenharmony_ci else 430562306a36Sopenharmony_ci block->trace_leaf = false; 430662306a36Sopenharmony_ci btrfs_node_key_to_cpu(reloc_parent, &block->first_key, reloc_slot); 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_ci /* Insert @block into @blocks */ 430962306a36Sopenharmony_ci spin_lock(&blocks->lock); 431062306a36Sopenharmony_ci cur = &blocks->blocks[level].rb_node; 431162306a36Sopenharmony_ci while (*cur) { 431262306a36Sopenharmony_ci struct btrfs_qgroup_swapped_block *entry; 431362306a36Sopenharmony_ci 431462306a36Sopenharmony_ci parent = *cur; 431562306a36Sopenharmony_ci entry = rb_entry(parent, struct btrfs_qgroup_swapped_block, 431662306a36Sopenharmony_ci node); 431762306a36Sopenharmony_ci 431862306a36Sopenharmony_ci if (entry->subvol_bytenr < block->subvol_bytenr) { 431962306a36Sopenharmony_ci cur = &(*cur)->rb_left; 432062306a36Sopenharmony_ci } else if (entry->subvol_bytenr > block->subvol_bytenr) { 432162306a36Sopenharmony_ci cur = &(*cur)->rb_right; 432262306a36Sopenharmony_ci } else { 432362306a36Sopenharmony_ci if (entry->subvol_generation != 432462306a36Sopenharmony_ci block->subvol_generation || 432562306a36Sopenharmony_ci entry->reloc_bytenr != block->reloc_bytenr || 432662306a36Sopenharmony_ci entry->reloc_generation != 432762306a36Sopenharmony_ci block->reloc_generation) { 432862306a36Sopenharmony_ci /* 432962306a36Sopenharmony_ci * Duplicated but mismatch entry found. 433062306a36Sopenharmony_ci * Shouldn't happen. 433162306a36Sopenharmony_ci * 433262306a36Sopenharmony_ci * Marking qgroup inconsistent should be enough 433362306a36Sopenharmony_ci * for end users. 433462306a36Sopenharmony_ci */ 433562306a36Sopenharmony_ci WARN_ON(IS_ENABLED(CONFIG_BTRFS_DEBUG)); 433662306a36Sopenharmony_ci ret = -EEXIST; 433762306a36Sopenharmony_ci } 433862306a36Sopenharmony_ci kfree(block); 433962306a36Sopenharmony_ci goto out_unlock; 434062306a36Sopenharmony_ci } 434162306a36Sopenharmony_ci } 434262306a36Sopenharmony_ci rb_link_node(&block->node, parent, cur); 434362306a36Sopenharmony_ci rb_insert_color(&block->node, &blocks->blocks[level]); 434462306a36Sopenharmony_ci blocks->swapped = true; 434562306a36Sopenharmony_ciout_unlock: 434662306a36Sopenharmony_ci spin_unlock(&blocks->lock); 434762306a36Sopenharmony_ciout: 434862306a36Sopenharmony_ci if (ret < 0) 434962306a36Sopenharmony_ci qgroup_mark_inconsistent(fs_info); 435062306a36Sopenharmony_ci return ret; 435162306a36Sopenharmony_ci} 435262306a36Sopenharmony_ci 435362306a36Sopenharmony_ci/* 435462306a36Sopenharmony_ci * Check if the tree block is a subtree root, and if so do the needed 435562306a36Sopenharmony_ci * delayed subtree trace for qgroup. 435662306a36Sopenharmony_ci * 435762306a36Sopenharmony_ci * This is called during btrfs_cow_block(). 435862306a36Sopenharmony_ci */ 435962306a36Sopenharmony_ciint btrfs_qgroup_trace_subtree_after_cow(struct btrfs_trans_handle *trans, 436062306a36Sopenharmony_ci struct btrfs_root *root, 436162306a36Sopenharmony_ci struct extent_buffer *subvol_eb) 436262306a36Sopenharmony_ci{ 436362306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = root->fs_info; 436462306a36Sopenharmony_ci struct btrfs_tree_parent_check check = { 0 }; 436562306a36Sopenharmony_ci struct btrfs_qgroup_swapped_blocks *blocks = &root->swapped_blocks; 436662306a36Sopenharmony_ci struct btrfs_qgroup_swapped_block *block; 436762306a36Sopenharmony_ci struct extent_buffer *reloc_eb = NULL; 436862306a36Sopenharmony_ci struct rb_node *node; 436962306a36Sopenharmony_ci bool found = false; 437062306a36Sopenharmony_ci bool swapped = false; 437162306a36Sopenharmony_ci int level = btrfs_header_level(subvol_eb); 437262306a36Sopenharmony_ci int ret = 0; 437362306a36Sopenharmony_ci int i; 437462306a36Sopenharmony_ci 437562306a36Sopenharmony_ci if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) 437662306a36Sopenharmony_ci return 0; 437762306a36Sopenharmony_ci if (!is_fstree(root->root_key.objectid) || !root->reloc_root) 437862306a36Sopenharmony_ci return 0; 437962306a36Sopenharmony_ci 438062306a36Sopenharmony_ci spin_lock(&blocks->lock); 438162306a36Sopenharmony_ci if (!blocks->swapped) { 438262306a36Sopenharmony_ci spin_unlock(&blocks->lock); 438362306a36Sopenharmony_ci return 0; 438462306a36Sopenharmony_ci } 438562306a36Sopenharmony_ci node = blocks->blocks[level].rb_node; 438662306a36Sopenharmony_ci 438762306a36Sopenharmony_ci while (node) { 438862306a36Sopenharmony_ci block = rb_entry(node, struct btrfs_qgroup_swapped_block, node); 438962306a36Sopenharmony_ci if (block->subvol_bytenr < subvol_eb->start) { 439062306a36Sopenharmony_ci node = node->rb_left; 439162306a36Sopenharmony_ci } else if (block->subvol_bytenr > subvol_eb->start) { 439262306a36Sopenharmony_ci node = node->rb_right; 439362306a36Sopenharmony_ci } else { 439462306a36Sopenharmony_ci found = true; 439562306a36Sopenharmony_ci break; 439662306a36Sopenharmony_ci } 439762306a36Sopenharmony_ci } 439862306a36Sopenharmony_ci if (!found) { 439962306a36Sopenharmony_ci spin_unlock(&blocks->lock); 440062306a36Sopenharmony_ci goto out; 440162306a36Sopenharmony_ci } 440262306a36Sopenharmony_ci /* Found one, remove it from @blocks first and update blocks->swapped */ 440362306a36Sopenharmony_ci rb_erase(&block->node, &blocks->blocks[level]); 440462306a36Sopenharmony_ci for (i = 0; i < BTRFS_MAX_LEVEL; i++) { 440562306a36Sopenharmony_ci if (RB_EMPTY_ROOT(&blocks->blocks[i])) { 440662306a36Sopenharmony_ci swapped = true; 440762306a36Sopenharmony_ci break; 440862306a36Sopenharmony_ci } 440962306a36Sopenharmony_ci } 441062306a36Sopenharmony_ci blocks->swapped = swapped; 441162306a36Sopenharmony_ci spin_unlock(&blocks->lock); 441262306a36Sopenharmony_ci 441362306a36Sopenharmony_ci check.level = block->level; 441462306a36Sopenharmony_ci check.transid = block->reloc_generation; 441562306a36Sopenharmony_ci check.has_first_key = true; 441662306a36Sopenharmony_ci memcpy(&check.first_key, &block->first_key, sizeof(check.first_key)); 441762306a36Sopenharmony_ci 441862306a36Sopenharmony_ci /* Read out reloc subtree root */ 441962306a36Sopenharmony_ci reloc_eb = read_tree_block(fs_info, block->reloc_bytenr, &check); 442062306a36Sopenharmony_ci if (IS_ERR(reloc_eb)) { 442162306a36Sopenharmony_ci ret = PTR_ERR(reloc_eb); 442262306a36Sopenharmony_ci reloc_eb = NULL; 442362306a36Sopenharmony_ci goto free_out; 442462306a36Sopenharmony_ci } 442562306a36Sopenharmony_ci if (!extent_buffer_uptodate(reloc_eb)) { 442662306a36Sopenharmony_ci ret = -EIO; 442762306a36Sopenharmony_ci goto free_out; 442862306a36Sopenharmony_ci } 442962306a36Sopenharmony_ci 443062306a36Sopenharmony_ci ret = qgroup_trace_subtree_swap(trans, reloc_eb, subvol_eb, 443162306a36Sopenharmony_ci block->last_snapshot, block->trace_leaf); 443262306a36Sopenharmony_cifree_out: 443362306a36Sopenharmony_ci kfree(block); 443462306a36Sopenharmony_ci free_extent_buffer(reloc_eb); 443562306a36Sopenharmony_ciout: 443662306a36Sopenharmony_ci if (ret < 0) { 443762306a36Sopenharmony_ci btrfs_err_rl(fs_info, 443862306a36Sopenharmony_ci "failed to account subtree at bytenr %llu: %d", 443962306a36Sopenharmony_ci subvol_eb->start, ret); 444062306a36Sopenharmony_ci qgroup_mark_inconsistent(fs_info); 444162306a36Sopenharmony_ci } 444262306a36Sopenharmony_ci return ret; 444362306a36Sopenharmony_ci} 444462306a36Sopenharmony_ci 444562306a36Sopenharmony_civoid btrfs_qgroup_destroy_extent_records(struct btrfs_transaction *trans) 444662306a36Sopenharmony_ci{ 444762306a36Sopenharmony_ci struct btrfs_qgroup_extent_record *entry; 444862306a36Sopenharmony_ci struct btrfs_qgroup_extent_record *next; 444962306a36Sopenharmony_ci struct rb_root *root; 445062306a36Sopenharmony_ci 445162306a36Sopenharmony_ci root = &trans->delayed_refs.dirty_extent_root; 445262306a36Sopenharmony_ci rbtree_postorder_for_each_entry_safe(entry, next, root, node) { 445362306a36Sopenharmony_ci ulist_free(entry->old_roots); 445462306a36Sopenharmony_ci kfree(entry); 445562306a36Sopenharmony_ci } 445662306a36Sopenharmony_ci *root = RB_ROOT; 445762306a36Sopenharmony_ci} 4458