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