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