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