Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2
3#include "messages.h"
4#include "fs.h"
5#include "accessors.h"
6#include "volumes.h"
7
8static const struct btrfs_csums {
9 u16 size;
10 const char name[10];
11 const char driver[12];
12} btrfs_csums[] = {
13 [BTRFS_CSUM_TYPE_CRC32] = { .size = 4, .name = "crc32c" },
14 [BTRFS_CSUM_TYPE_XXHASH] = { .size = 8, .name = "xxhash64" },
15 [BTRFS_CSUM_TYPE_SHA256] = { .size = 32, .name = "sha256" },
16 [BTRFS_CSUM_TYPE_BLAKE2] = { .size = 32, .name = "blake2b",
17 .driver = "blake2b-256" },
18};
19
20/* This exists for btrfs-progs usages. */
21u16 btrfs_csum_type_size(u16 type)
22{
23 return btrfs_csums[type].size;
24}
25
26int btrfs_super_csum_size(const struct btrfs_super_block *s)
27{
28 u16 t = btrfs_super_csum_type(s);
29
30 /* csum type is validated at mount time. */
31 return btrfs_csum_type_size(t);
32}
33
34const char *btrfs_super_csum_name(u16 csum_type)
35{
36 /* csum type is validated at mount time. */
37 return btrfs_csums[csum_type].name;
38}
39
40/*
41 * Return driver name if defined, otherwise the name that's also a valid driver
42 * name.
43 */
44const char *btrfs_super_csum_driver(u16 csum_type)
45{
46 /* csum type is validated at mount time */
47 return btrfs_csums[csum_type].driver[0] ?
48 btrfs_csums[csum_type].driver :
49 btrfs_csums[csum_type].name;
50}
51
52size_t __attribute_const__ btrfs_get_num_csums(void)
53{
54 return ARRAY_SIZE(btrfs_csums);
55}
56
57/*
58 * Start exclusive operation @type, return true on success.
59 */
60bool btrfs_exclop_start(struct btrfs_fs_info *fs_info,
61 enum btrfs_exclusive_operation type)
62{
63 bool ret = false;
64
65 spin_lock(&fs_info->super_lock);
66 if (fs_info->exclusive_operation == BTRFS_EXCLOP_NONE) {
67 fs_info->exclusive_operation = type;
68 ret = true;
69 }
70 spin_unlock(&fs_info->super_lock);
71
72 return ret;
73}
74
75/*
76 * Conditionally allow to enter the exclusive operation in case it's compatible
77 * with the running one. This must be paired with btrfs_exclop_start_unlock()
78 * and btrfs_exclop_finish().
79 *
80 * Compatibility:
81 * - the same type is already running
82 * - when trying to add a device and balance has been paused
83 * - not BTRFS_EXCLOP_NONE - this is intentionally incompatible and the caller
84 * must check the condition first that would allow none -> @type
85 */
86bool btrfs_exclop_start_try_lock(struct btrfs_fs_info *fs_info,
87 enum btrfs_exclusive_operation type)
88{
89 spin_lock(&fs_info->super_lock);
90 if (fs_info->exclusive_operation == type ||
91 (fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE_PAUSED &&
92 type == BTRFS_EXCLOP_DEV_ADD))
93 return true;
94
95 spin_unlock(&fs_info->super_lock);
96 return false;
97}
98
99void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info)
100{
101 spin_unlock(&fs_info->super_lock);
102}
103
104void btrfs_exclop_finish(struct btrfs_fs_info *fs_info)
105{
106 spin_lock(&fs_info->super_lock);
107 WRITE_ONCE(fs_info->exclusive_operation, BTRFS_EXCLOP_NONE);
108 spin_unlock(&fs_info->super_lock);
109 sysfs_notify(&fs_info->fs_devices->fsid_kobj, NULL, "exclusive_operation");
110}
111
112void btrfs_exclop_balance(struct btrfs_fs_info *fs_info,
113 enum btrfs_exclusive_operation op)
114{
115 switch (op) {
116 case BTRFS_EXCLOP_BALANCE_PAUSED:
117 spin_lock(&fs_info->super_lock);
118 ASSERT(fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE ||
119 fs_info->exclusive_operation == BTRFS_EXCLOP_DEV_ADD ||
120 fs_info->exclusive_operation == BTRFS_EXCLOP_NONE ||
121 fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE_PAUSED);
122 fs_info->exclusive_operation = BTRFS_EXCLOP_BALANCE_PAUSED;
123 spin_unlock(&fs_info->super_lock);
124 break;
125 case BTRFS_EXCLOP_BALANCE:
126 spin_lock(&fs_info->super_lock);
127 ASSERT(fs_info->exclusive_operation == BTRFS_EXCLOP_BALANCE_PAUSED);
128 fs_info->exclusive_operation = BTRFS_EXCLOP_BALANCE;
129 spin_unlock(&fs_info->super_lock);
130 break;
131 default:
132 btrfs_warn(fs_info,
133 "invalid exclop balance operation %d requested", op);
134 }
135}
136
137void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag,
138 const char *name)
139{
140 struct btrfs_super_block *disk_super;
141 u64 features;
142
143 disk_super = fs_info->super_copy;
144 features = btrfs_super_incompat_flags(disk_super);
145 if (!(features & flag)) {
146 spin_lock(&fs_info->super_lock);
147 features = btrfs_super_incompat_flags(disk_super);
148 if (!(features & flag)) {
149 features |= flag;
150 btrfs_set_super_incompat_flags(disk_super, features);
151 btrfs_info(fs_info,
152 "setting incompat feature flag for %s (0x%llx)",
153 name, flag);
154 }
155 spin_unlock(&fs_info->super_lock);
156 set_bit(BTRFS_FS_FEATURE_CHANGED, &fs_info->flags);
157 }
158}
159
160void __btrfs_clear_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag,
161 const char *name)
162{
163 struct btrfs_super_block *disk_super;
164 u64 features;
165
166 disk_super = fs_info->super_copy;
167 features = btrfs_super_incompat_flags(disk_super);
168 if (features & flag) {
169 spin_lock(&fs_info->super_lock);
170 features = btrfs_super_incompat_flags(disk_super);
171 if (features & flag) {
172 features &= ~flag;
173 btrfs_set_super_incompat_flags(disk_super, features);
174 btrfs_info(fs_info,
175 "clearing incompat feature flag for %s (0x%llx)",
176 name, flag);
177 }
178 spin_unlock(&fs_info->super_lock);
179 set_bit(BTRFS_FS_FEATURE_CHANGED, &fs_info->flags);
180 }
181}
182
183void __btrfs_set_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag,
184 const char *name)
185{
186 struct btrfs_super_block *disk_super;
187 u64 features;
188
189 disk_super = fs_info->super_copy;
190 features = btrfs_super_compat_ro_flags(disk_super);
191 if (!(features & flag)) {
192 spin_lock(&fs_info->super_lock);
193 features = btrfs_super_compat_ro_flags(disk_super);
194 if (!(features & flag)) {
195 features |= flag;
196 btrfs_set_super_compat_ro_flags(disk_super, features);
197 btrfs_info(fs_info,
198 "setting compat-ro feature flag for %s (0x%llx)",
199 name, flag);
200 }
201 spin_unlock(&fs_info->super_lock);
202 set_bit(BTRFS_FS_FEATURE_CHANGED, &fs_info->flags);
203 }
204}
205
206void __btrfs_clear_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag,
207 const char *name)
208{
209 struct btrfs_super_block *disk_super;
210 u64 features;
211
212 disk_super = fs_info->super_copy;
213 features = btrfs_super_compat_ro_flags(disk_super);
214 if (features & flag) {
215 spin_lock(&fs_info->super_lock);
216 features = btrfs_super_compat_ro_flags(disk_super);
217 if (features & flag) {
218 features &= ~flag;
219 btrfs_set_super_compat_ro_flags(disk_super, features);
220 btrfs_info(fs_info,
221 "clearing compat-ro feature flag for %s (0x%llx)",
222 name, flag);
223 }
224 spin_unlock(&fs_info->super_lock);
225 set_bit(BTRFS_FS_FEATURE_CHANGED, &fs_info->flags);
226 }
227}