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 
8 static 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. */
21 u16 btrfs_csum_type_size(u16 type)
22 {
23 	return btrfs_csums[type].size;
24 }
25 
26 int 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 
34 const 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  */
44 const 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 
52 size_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  */
60 bool 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  */
86 bool 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 
99 void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info)
100 {
101 	spin_unlock(&fs_info->super_lock);
102 }
103 
104 void 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 
112 void 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 
137 void __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 
160 void __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 
183 void __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 
206 void __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 }
228