xref: /linux/fs/btrfs/fs.c (revision 1cbfb828e05171ca2dd77b5988d068e6872480fe)
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. */
22 u16 btrfs_csum_type_size(u16 type)
23 {
24 	return btrfs_csums[type].size;
25 }
26 
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 
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  */
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 
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  */
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  */
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 
100 void btrfs_exclop_start_unlock(struct btrfs_fs_info *fs_info)
101 {
102 	spin_unlock(&fs_info->super_lock);
103 }
104 
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 
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 
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 
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 
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 
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