]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - fs/btrfs/space-info.c
btrfs: move the space_info handling code to space-info.c
[mirror_ubuntu-jammy-kernel.git] / fs / btrfs / space-info.c
CommitLineData
280c2908
JB
1// SPDX-License-Identifier: GPL-2.0
2
3#include "ctree.h"
4#include "space-info.h"
5#include "sysfs.h"
6#include "volumes.h"
7
8u64 btrfs_space_info_used(struct btrfs_space_info *s_info,
9 bool may_use_included)
10{
11 ASSERT(s_info);
12 return s_info->bytes_used + s_info->bytes_reserved +
13 s_info->bytes_pinned + s_info->bytes_readonly +
14 (may_use_included ? s_info->bytes_may_use : 0);
15}
16
17/*
18 * after adding space to the filesystem, we need to clear the full flags
19 * on all the space infos.
20 */
21void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
22{
23 struct list_head *head = &info->space_info;
24 struct btrfs_space_info *found;
25
26 rcu_read_lock();
27 list_for_each_entry_rcu(found, head, list)
28 found->full = 0;
29 rcu_read_unlock();
30}
31
32static const char *alloc_name(u64 flags)
33{
34 switch (flags) {
35 case BTRFS_BLOCK_GROUP_METADATA|BTRFS_BLOCK_GROUP_DATA:
36 return "mixed";
37 case BTRFS_BLOCK_GROUP_METADATA:
38 return "metadata";
39 case BTRFS_BLOCK_GROUP_DATA:
40 return "data";
41 case BTRFS_BLOCK_GROUP_SYSTEM:
42 return "system";
43 default:
44 WARN_ON(1);
45 return "invalid-combination";
46 };
47}
48
49static int create_space_info(struct btrfs_fs_info *info, u64 flags)
50{
51
52 struct btrfs_space_info *space_info;
53 int i;
54 int ret;
55
56 space_info = kzalloc(sizeof(*space_info), GFP_NOFS);
57 if (!space_info)
58 return -ENOMEM;
59
60 ret = percpu_counter_init(&space_info->total_bytes_pinned, 0,
61 GFP_KERNEL);
62 if (ret) {
63 kfree(space_info);
64 return ret;
65 }
66
67 for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
68 INIT_LIST_HEAD(&space_info->block_groups[i]);
69 init_rwsem(&space_info->groups_sem);
70 spin_lock_init(&space_info->lock);
71 space_info->flags = flags & BTRFS_BLOCK_GROUP_TYPE_MASK;
72 space_info->force_alloc = CHUNK_ALLOC_NO_FORCE;
73 init_waitqueue_head(&space_info->wait);
74 INIT_LIST_HEAD(&space_info->ro_bgs);
75 INIT_LIST_HEAD(&space_info->tickets);
76 INIT_LIST_HEAD(&space_info->priority_tickets);
77
78 ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype,
79 info->space_info_kobj, "%s",
80 alloc_name(space_info->flags));
81 if (ret) {
82 kobject_put(&space_info->kobj);
83 return ret;
84 }
85
86 list_add_rcu(&space_info->list, &info->space_info);
87 if (flags & BTRFS_BLOCK_GROUP_DATA)
88 info->data_sinfo = space_info;
89
90 return ret;
91}
92
93int btrfs_init_space_info(struct btrfs_fs_info *fs_info)
94{
95 struct btrfs_super_block *disk_super;
96 u64 features;
97 u64 flags;
98 int mixed = 0;
99 int ret;
100
101 disk_super = fs_info->super_copy;
102 if (!btrfs_super_root(disk_super))
103 return -EINVAL;
104
105 features = btrfs_super_incompat_flags(disk_super);
106 if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS)
107 mixed = 1;
108
109 flags = BTRFS_BLOCK_GROUP_SYSTEM;
110 ret = create_space_info(fs_info, flags);
111 if (ret)
112 goto out;
113
114 if (mixed) {
115 flags = BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA;
116 ret = create_space_info(fs_info, flags);
117 } else {
118 flags = BTRFS_BLOCK_GROUP_METADATA;
119 ret = create_space_info(fs_info, flags);
120 if (ret)
121 goto out;
122
123 flags = BTRFS_BLOCK_GROUP_DATA;
124 ret = create_space_info(fs_info, flags);
125 }
126out:
127 return ret;
128}
129
130void btrfs_update_space_info(struct btrfs_fs_info *info, u64 flags,
131 u64 total_bytes, u64 bytes_used,
132 u64 bytes_readonly,
133 struct btrfs_space_info **space_info)
134{
135 struct btrfs_space_info *found;
136 int factor;
137
138 factor = btrfs_bg_type_to_factor(flags);
139
140 found = btrfs_find_space_info(info, flags);
141 ASSERT(found);
142 spin_lock(&found->lock);
143 found->total_bytes += total_bytes;
144 found->disk_total += total_bytes * factor;
145 found->bytes_used += bytes_used;
146 found->disk_used += bytes_used * factor;
147 found->bytes_readonly += bytes_readonly;
148 if (total_bytes > 0)
149 found->full = 0;
150 btrfs_space_info_add_new_bytes(info, found,
151 total_bytes - bytes_used -
152 bytes_readonly);
153 spin_unlock(&found->lock);
154 *space_info = found;
155}
156
157struct btrfs_space_info *btrfs_find_space_info(struct btrfs_fs_info *info,
158 u64 flags)
159{
160 struct list_head *head = &info->space_info;
161 struct btrfs_space_info *found;
162
163 flags &= BTRFS_BLOCK_GROUP_TYPE_MASK;
164
165 rcu_read_lock();
166 list_for_each_entry_rcu(found, head, list) {
167 if (found->flags & flags) {
168 rcu_read_unlock();
169 return found;
170 }
171 }
172 rcu_read_unlock();
173 return NULL;
174}