Blame view
fs/btrfs/sysfs.c
47.7 KB
c1d7c514f
|
1 |
// SPDX-License-Identifier: GPL-2.0 |
6cbd55707
|
2 3 |
/* * Copyright (C) 2007 Oracle. All rights reserved. |
6cbd55707
|
4 |
*/ |
58176a960
|
5 |
#include <linux/sched.h> |
32a9991f1
|
6 |
#include <linux/sched/mm.h> |
58176a960
|
7 8 9 |
#include <linux/slab.h> #include <linux/spinlock.h> #include <linux/completion.h> |
79da4fa4d
|
10 |
#include <linux/bug.h> |
41e6d2a80
|
11 |
#include <crypto/hash.h> |
58176a960
|
12 |
|
bae45de03
|
13 |
#include "ctree.h" |
dfb79ddb1
|
14 |
#include "discard.h" |
bae45de03
|
15 |
#include "disk-io.h" |
7573df554
|
16 |
#include "send.h" |
bae45de03
|
17 |
#include "transaction.h" |
079b72bca
|
18 |
#include "sysfs.h" |
29e5be240
|
19 |
#include "volumes.h" |
8719aaae8
|
20 |
#include "space-info.h" |
aac0023c2
|
21 |
#include "block-group.h" |
49e5fb462
|
22 |
#include "qgroup.h" |
079b72bca
|
23 |
|
9188db611
|
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
struct btrfs_feature_attr { struct kobj_attribute kobj_attr; enum btrfs_feature_set feature_set; u64 feature_bit; }; /* For raid type sysfs entries */ struct raid_kobject { u64 flags; struct kobject kobj; }; #define __INIT_KOBJ_ATTR(_name, _mode, _show, _store) \ { \ .attr = { .name = __stringify(_name), .mode = _mode }, \ .show = _show, \ .store = _store, \ } #define BTRFS_ATTR_RW(_prefix, _name, _show, _store) \ static struct kobj_attribute btrfs_attr_##_prefix##_##_name = \ __INIT_KOBJ_ATTR(_name, 0644, _show, _store) #define BTRFS_ATTR(_prefix, _name, _show) \ static struct kobj_attribute btrfs_attr_##_prefix##_##_name = \ __INIT_KOBJ_ATTR(_name, 0444, _show, NULL) #define BTRFS_ATTR_PTR(_prefix, _name) \ (&btrfs_attr_##_prefix##_##_name.attr) #define BTRFS_FEAT_ATTR(_name, _feature_set, _feature_prefix, _feature_bit) \ static struct btrfs_feature_attr btrfs_attr_features_##_name = { \ .kobj_attr = __INIT_KOBJ_ATTR(_name, S_IRUGO, \ btrfs_feature_attr_show, \ btrfs_feature_attr_store), \ .feature_set = _feature_set, \ .feature_bit = _feature_prefix ##_## _feature_bit, \ } #define BTRFS_FEAT_ATTR_PTR(_name) \ (&btrfs_attr_features_##_name.kobj_attr.attr) #define BTRFS_FEAT_ATTR_COMPAT(name, feature) \ BTRFS_FEAT_ATTR(name, FEAT_COMPAT, BTRFS_FEATURE_COMPAT, feature) #define BTRFS_FEAT_ATTR_COMPAT_RO(name, feature) \ BTRFS_FEAT_ATTR(name, FEAT_COMPAT_RO, BTRFS_FEATURE_COMPAT_RO, feature) #define BTRFS_FEAT_ATTR_INCOMPAT(name, feature) \ BTRFS_FEAT_ATTR(name, FEAT_INCOMPAT, BTRFS_FEATURE_INCOMPAT, feature) |
510d73600
|
71 |
static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj); |
2e7910d6c
|
72 |
static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj); |
5ac1d209f
|
73 |
|
8f52316c2
|
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
static struct btrfs_feature_attr *to_btrfs_feature_attr(struct kobj_attribute *a) { return container_of(a, struct btrfs_feature_attr, kobj_attr); } static struct kobj_attribute *attr_to_btrfs_attr(struct attribute *attr) { return container_of(attr, struct kobj_attribute, attr); } static struct btrfs_feature_attr *attr_to_btrfs_feature_attr( struct attribute *attr) { return to_btrfs_feature_attr(attr_to_btrfs_attr(attr)); } |
510d73600
|
89 90 |
static u64 get_features(struct btrfs_fs_info *fs_info, enum btrfs_feature_set set) |
5ac1d209f
|
91 |
{ |
510d73600
|
92 93 94 95 96 97 98 |
struct btrfs_super_block *disk_super = fs_info->super_copy; if (set == FEAT_COMPAT) return btrfs_super_compat_flags(disk_super); else if (set == FEAT_COMPAT_RO) return btrfs_super_compat_ro_flags(disk_super); else return btrfs_super_incompat_flags(disk_super); |
5ac1d209f
|
99 |
} |
ba631941e
|
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
static void set_features(struct btrfs_fs_info *fs_info, enum btrfs_feature_set set, u64 features) { struct btrfs_super_block *disk_super = fs_info->super_copy; if (set == FEAT_COMPAT) btrfs_set_super_compat_flags(disk_super, features); else if (set == FEAT_COMPAT_RO) btrfs_set_super_compat_ro_flags(disk_super, features); else btrfs_set_super_incompat_flags(disk_super, features); } static int can_modify_feature(struct btrfs_feature_attr *fa) { int val = 0; u64 set, clear; switch (fa->feature_set) { case FEAT_COMPAT: set = BTRFS_FEATURE_COMPAT_SAFE_SET; clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; break; case FEAT_COMPAT_RO: set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; break; case FEAT_INCOMPAT: set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; break; default: |
62e855771
|
130 131 |
pr_warn("btrfs: sysfs: unknown feature set %d ", |
cc37bb042
|
132 133 |
fa->feature_set); return 0; |
ba631941e
|
134 135 136 137 138 139 140 141 142 |
} if (set & fa->feature_bit) val |= 1; if (clear & fa->feature_bit) val |= 2; return val; } |
510d73600
|
143 144 |
static ssize_t btrfs_feature_attr_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) |
5ac1d209f
|
145 |
{ |
510d73600
|
146 |
int val = 0; |
5ac1d209f
|
147 |
struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
ba631941e
|
148 |
struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); |
510d73600
|
149 |
if (fs_info) { |
510d73600
|
150 151 152 |
u64 features = get_features(fs_info, fa->feature_set); if (features & fa->feature_bit) val = 1; |
ba631941e
|
153 154 |
} else val = can_modify_feature(fa); |
510d73600
|
155 |
|
abdd9feb4
|
156 157 |
return scnprintf(buf, PAGE_SIZE, "%d ", val); |
5ac1d209f
|
158 |
} |
ba631941e
|
159 160 161 162 163 164 |
static ssize_t btrfs_feature_attr_store(struct kobject *kobj, struct kobj_attribute *a, const char *buf, size_t count) { struct btrfs_fs_info *fs_info; struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); |
ba631941e
|
165 166 167 168 169 170 171 |
u64 features, set, clear; unsigned long val; int ret; fs_info = to_fs_info(kobj); if (!fs_info) return -EPERM; |
bc98a42c1
|
172 |
if (sb_rdonly(fs_info->sb)) |
ee6111386
|
173 |
return -EROFS; |
ba631941e
|
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
ret = kstrtoul(skip_spaces(buf), 0, &val); if (ret) return ret; if (fa->feature_set == FEAT_COMPAT) { set = BTRFS_FEATURE_COMPAT_SAFE_SET; clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; } else if (fa->feature_set == FEAT_COMPAT_RO) { set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; } else { set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; } features = get_features(fs_info, fa->feature_set); /* Nothing to do */ if ((val && (features & fa->feature_bit)) || (!val && !(features & fa->feature_bit))) return count; if ((val && !(set & fa->feature_bit)) || (!val && !(clear & fa->feature_bit))) { btrfs_info(fs_info, "%sabling feature %s on mounted fs is not supported.", val ? "En" : "Dis", fa->kobj_attr.attr.name); return -EPERM; } btrfs_info(fs_info, "%s %s feature flag", val ? "Setting" : "Clearing", fa->kobj_attr.attr.name); |
ba631941e
|
206 207 208 209 210 211 212 213 |
spin_lock(&fs_info->super_lock); features = get_features(fs_info, fa->feature_set); if (val) features |= fa->feature_bit; else features &= ~fa->feature_bit; set_features(fs_info, fa->feature_set, features); spin_unlock(&fs_info->super_lock); |
0eae2747e
|
214 215 216 217 218 |
/* * We don't want to do full transaction commit from inside sysfs */ btrfs_set_pending(fs_info, COMMIT); wake_up_process(fs_info->transaction_kthread); |
ba631941e
|
219 220 221 |
return count; } |
510d73600
|
222 223 |
static umode_t btrfs_feature_visible(struct kobject *kobj, struct attribute *attr, int unused) |
079b72bca
|
224 |
{ |
510d73600
|
225 226 227 228 229 230 231 232 233 |
struct btrfs_fs_info *fs_info = to_fs_info(kobj); umode_t mode = attr->mode; if (fs_info) { struct btrfs_feature_attr *fa; u64 features; fa = attr_to_btrfs_feature_attr(attr); features = get_features(fs_info, fa->feature_set); |
ba631941e
|
234 235 236 |
if (can_modify_feature(fa)) mode |= S_IWUSR; else if (!(features & fa->feature_bit)) |
510d73600
|
237 238 239 240 |
mode = 0; } return mode; |
079b72bca
|
241 242 243 244 245 246 |
} BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF); BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL); BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS); BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO); |
5c1aab1dd
|
247 |
BTRFS_FEAT_ATTR_INCOMPAT(compress_zstd, COMPRESS_ZSTD); |
079b72bca
|
248 249 250 251 |
BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA); BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF); BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56); BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA); |
c736c095d
|
252 |
BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES); |
56f20f400
|
253 |
BTRFS_FEAT_ATTR_INCOMPAT(metadata_uuid, METADATA_UUID); |
3b5bb73bd
|
254 |
BTRFS_FEAT_ATTR_COMPAT_RO(free_space_tree, FREE_SPACE_TREE); |
cfbb825c7
|
255 |
BTRFS_FEAT_ATTR_INCOMPAT(raid1c34, RAID1C34); |
079b72bca
|
256 257 258 259 260 261 |
static struct attribute *btrfs_supported_feature_attrs[] = { BTRFS_FEAT_ATTR_PTR(mixed_backref), BTRFS_FEAT_ATTR_PTR(default_subvol), BTRFS_FEAT_ATTR_PTR(mixed_groups), BTRFS_FEAT_ATTR_PTR(compress_lzo), |
5c1aab1dd
|
262 |
BTRFS_FEAT_ATTR_PTR(compress_zstd), |
079b72bca
|
263 264 265 266 |
BTRFS_FEAT_ATTR_PTR(big_metadata), BTRFS_FEAT_ATTR_PTR(extended_iref), BTRFS_FEAT_ATTR_PTR(raid56), BTRFS_FEAT_ATTR_PTR(skinny_metadata), |
c736c095d
|
267 |
BTRFS_FEAT_ATTR_PTR(no_holes), |
56f20f400
|
268 |
BTRFS_FEAT_ATTR_PTR(metadata_uuid), |
3b5bb73bd
|
269 |
BTRFS_FEAT_ATTR_PTR(free_space_tree), |
cfbb825c7
|
270 |
BTRFS_FEAT_ATTR_PTR(raid1c34), |
079b72bca
|
271 272 |
NULL }; |
f902bd3a5
|
273 274 275 276 277 278 279 |
/* * Features which depend on feature bits and may differ between each fs. * * /sys/fs/btrfs/features lists all available features of this kernel while * /sys/fs/btrfs/UUID/features shows features of the fs which are enabled or * can be changed online. */ |
079b72bca
|
280 281 |
static const struct attribute_group btrfs_feature_attr_group = { .name = "features", |
510d73600
|
282 |
.is_visible = btrfs_feature_visible, |
079b72bca
|
283 284 |
.attrs = btrfs_supported_feature_attrs, }; |
58176a960
|
285 |
|
f902bd3a5
|
286 287 288 |
static ssize_t rmdir_subvol_show(struct kobject *kobj, struct kobj_attribute *ka, char *buf) { |
abdd9feb4
|
289 290 |
return scnprintf(buf, PAGE_SIZE, "0 "); |
f902bd3a5
|
291 292 |
} BTRFS_ATTR(static_feature, rmdir_subvol, rmdir_subvol_show); |
f7cea56c0
|
293 294 295 296 297 298 299 300 301 302 303 |
static ssize_t supported_checksums_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { ssize_t ret = 0; int i; for (i = 0; i < btrfs_get_num_csums(); i++) { /* * This "trick" only works as long as 'enum btrfs_csum_type' has * no holes in it */ |
abdd9feb4
|
304 |
ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s%s", |
f7cea56c0
|
305 306 307 |
(i == 0 ? "" : " "), btrfs_super_csum_name(i)); } |
abdd9feb4
|
308 309 |
ret += scnprintf(buf + ret, PAGE_SIZE - ret, " "); |
f7cea56c0
|
310 311 312 |
return ret; } BTRFS_ATTR(static_feature, supported_checksums, supported_checksums_show); |
7573df554
|
313 314 315 316 317 318 319 |
static ssize_t send_stream_version_show(struct kobject *kobj, struct kobj_attribute *ka, char *buf) { return snprintf(buf, PAGE_SIZE, "%d ", BTRFS_SEND_STREAM_VERSION); } BTRFS_ATTR(static_feature, send_stream_version, send_stream_version_show); |
f902bd3a5
|
320 321 |
static struct attribute *btrfs_supported_static_feature_attrs[] = { BTRFS_ATTR_PTR(static_feature, rmdir_subvol), |
f7cea56c0
|
322 |
BTRFS_ATTR_PTR(static_feature, supported_checksums), |
7573df554
|
323 |
BTRFS_ATTR_PTR(static_feature, send_stream_version), |
f902bd3a5
|
324 325 326 327 328 329 330 331 332 333 334 335 336 |
NULL }; /* * Features which only depend on kernel version. * * These are listed in /sys/fs/btrfs/features along with * btrfs_feature_attr_group */ static const struct attribute_group btrfs_static_feature_attr_group = { .name = "features", .attrs = btrfs_supported_static_feature_attrs, }; |
6e369febb
|
337 338 339 |
#ifdef CONFIG_BTRFS_DEBUG /* |
e4faab844
|
340 341 |
* Discard statistics and tunables */ |
dfb79ddb1
|
342 |
#define discard_to_fs_info(_kobj) to_fs_info((_kobj)->parent->parent) |
5dc7c10b8
|
343 344 345 346 347 |
static ssize_t btrfs_discardable_bytes_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
abdd9feb4
|
348 349 |
return scnprintf(buf, PAGE_SIZE, "%lld ", |
5dc7c10b8
|
350 351 352 |
atomic64_read(&fs_info->discard_ctl.discardable_bytes)); } BTRFS_ATTR(discard, discardable_bytes, btrfs_discardable_bytes_show); |
dfb79ddb1
|
353 354 355 356 357 |
static ssize_t btrfs_discardable_extents_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
abdd9feb4
|
358 359 |
return scnprintf(buf, PAGE_SIZE, "%d ", |
dfb79ddb1
|
360 361 362 |
atomic_read(&fs_info->discard_ctl.discardable_extents)); } BTRFS_ATTR(discard, discardable_extents, btrfs_discardable_extents_show); |
9ddf648f9
|
363 364 365 366 367 |
static ssize_t btrfs_discard_bitmap_bytes_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
abdd9feb4
|
368 369 |
return scnprintf(buf, PAGE_SIZE, "%lld ", |
9ddf648f9
|
370 371 372 373 374 375 376 377 378 |
fs_info->discard_ctl.discard_bitmap_bytes); } BTRFS_ATTR(discard, discard_bitmap_bytes, btrfs_discard_bitmap_bytes_show); static ssize_t btrfs_discard_bytes_saved_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
abdd9feb4
|
379 380 |
return scnprintf(buf, PAGE_SIZE, "%lld ", |
9ddf648f9
|
381 382 383 384 385 386 387 388 389 |
atomic64_read(&fs_info->discard_ctl.discard_bytes_saved)); } BTRFS_ATTR(discard, discard_bytes_saved, btrfs_discard_bytes_saved_show); static ssize_t btrfs_discard_extent_bytes_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
abdd9feb4
|
390 391 |
return scnprintf(buf, PAGE_SIZE, "%lld ", |
9ddf648f9
|
392 393 394 |
fs_info->discard_ctl.discard_extent_bytes); } BTRFS_ATTR(discard, discard_extent_bytes, btrfs_discard_extent_bytes_show); |
a23093008
|
395 396 397 398 399 |
static ssize_t btrfs_discard_iops_limit_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
abdd9feb4
|
400 401 |
return scnprintf(buf, PAGE_SIZE, "%u ", |
a23093008
|
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 |
READ_ONCE(fs_info->discard_ctl.iops_limit)); } static ssize_t btrfs_discard_iops_limit_store(struct kobject *kobj, struct kobj_attribute *a, const char *buf, size_t len) { struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl; u32 iops_limit; int ret; ret = kstrtou32(buf, 10, &iops_limit); if (ret) return -EINVAL; WRITE_ONCE(discard_ctl->iops_limit, iops_limit); return len; } BTRFS_ATTR_RW(discard, iops_limit, btrfs_discard_iops_limit_show, btrfs_discard_iops_limit_store); |
e93591bb6
|
424 425 426 427 428 |
static ssize_t btrfs_discard_kbps_limit_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
abdd9feb4
|
429 430 |
return scnprintf(buf, PAGE_SIZE, "%u ", |
e93591bb6
|
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
READ_ONCE(fs_info->discard_ctl.kbps_limit)); } static ssize_t btrfs_discard_kbps_limit_store(struct kobject *kobj, struct kobj_attribute *a, const char *buf, size_t len) { struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl; u32 kbps_limit; int ret; ret = kstrtou32(buf, 10, &kbps_limit); if (ret) return -EINVAL; WRITE_ONCE(discard_ctl->kbps_limit, kbps_limit); return len; } BTRFS_ATTR_RW(discard, kbps_limit, btrfs_discard_kbps_limit_show, btrfs_discard_kbps_limit_store); |
19b2a2c71
|
453 454 455 456 457 |
static ssize_t btrfs_discard_max_discard_size_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
abdd9feb4
|
458 459 |
return scnprintf(buf, PAGE_SIZE, "%llu ", |
19b2a2c71
|
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 |
READ_ONCE(fs_info->discard_ctl.max_discard_size)); } static ssize_t btrfs_discard_max_discard_size_store(struct kobject *kobj, struct kobj_attribute *a, const char *buf, size_t len) { struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl; u64 max_discard_size; int ret; ret = kstrtou64(buf, 10, &max_discard_size); if (ret) return -EINVAL; WRITE_ONCE(discard_ctl->max_discard_size, max_discard_size); return len; } BTRFS_ATTR_RW(discard, max_discard_size, btrfs_discard_max_discard_size_show, btrfs_discard_max_discard_size_store); |
e4faab844
|
482 |
static const struct attribute *discard_debug_attrs[] = { |
5dc7c10b8
|
483 |
BTRFS_ATTR_PTR(discard, discardable_bytes), |
dfb79ddb1
|
484 |
BTRFS_ATTR_PTR(discard, discardable_extents), |
9ddf648f9
|
485 486 487 |
BTRFS_ATTR_PTR(discard, discard_bitmap_bytes), BTRFS_ATTR_PTR(discard, discard_bytes_saved), BTRFS_ATTR_PTR(discard, discard_extent_bytes), |
a23093008
|
488 |
BTRFS_ATTR_PTR(discard, iops_limit), |
e93591bb6
|
489 |
BTRFS_ATTR_PTR(discard, kbps_limit), |
19b2a2c71
|
490 |
BTRFS_ATTR_PTR(discard, max_discard_size), |
e4faab844
|
491 492 493 494 |
NULL, }; /* |
6e369febb
|
495 496 497 498 499 |
* Runtime debugging exported via sysfs * * /sys/fs/btrfs/debug - applies to module or all filesystems * /sys/fs/btrfs/UUID - applies only to the given filesystem */ |
93945cb43
|
500 501 502 |
static const struct attribute *btrfs_debug_mount_attrs[] = { NULL, }; |
6e369febb
|
503 504 505 506 507 508 509 510 511 512 |
static struct attribute *btrfs_debug_feature_attrs[] = { NULL }; static const struct attribute_group btrfs_debug_feature_attr_group = { .name = "debug", .attrs = btrfs_debug_feature_attrs, }; #endif |
6ab0a2029
|
513 514 515 516 517 518 519 520 |
static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf) { u64 val; if (lock) spin_lock(lock); val = *value_ptr; if (lock) spin_unlock(lock); |
abdd9feb4
|
521 522 |
return scnprintf(buf, PAGE_SIZE, "%llu ", val); |
6ab0a2029
|
523 524 525 526 527 528 529 530 531 |
} static ssize_t global_rsv_size_show(struct kobject *kobj, struct kobj_attribute *ka, char *buf) { struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf); } |
a969f4cc1
|
532 |
BTRFS_ATTR(allocation, global_rsv_size, global_rsv_size_show); |
6ab0a2029
|
533 534 535 536 537 538 539 540 |
static ssize_t global_rsv_reserved_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf); } |
a969f4cc1
|
541 |
BTRFS_ATTR(allocation, global_rsv_reserved, global_rsv_reserved_show); |
6ab0a2029
|
542 543 |
#define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj) |
c1895442b
|
544 |
#define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj) |
6ab0a2029
|
545 546 547 |
static ssize_t raid_bytes_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); |
a969f4cc1
|
548 549 |
BTRFS_ATTR(raid, total_bytes, raid_bytes_show); BTRFS_ATTR(raid, used_bytes, raid_bytes_show); |
6ab0a2029
|
550 551 552 553 554 555 |
static ssize_t raid_bytes_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { struct btrfs_space_info *sinfo = to_space_info(kobj->parent); |
32da5386d
|
556 |
struct btrfs_block_group *block_group; |
75cb379d2
|
557 |
int index = btrfs_bg_flags_to_raid_index(to_raid_kobj(kobj)->flags); |
6ab0a2029
|
558 559 560 561 |
u64 val = 0; down_read(&sinfo->groups_sem); list_for_each_entry(block_group, &sinfo->block_groups[index], list) { |
a969f4cc1
|
562 |
if (&attr->attr == BTRFS_ATTR_PTR(raid, total_bytes)) |
b3470b5db
|
563 |
val += block_group->length; |
6ab0a2029
|
564 |
else |
bf38be65f
|
565 |
val += block_group->used; |
6ab0a2029
|
566 567 |
} up_read(&sinfo->groups_sem); |
abdd9feb4
|
568 569 |
return scnprintf(buf, PAGE_SIZE, "%llu ", val); |
6ab0a2029
|
570 |
} |
7c7e30140
|
571 |
static struct attribute *raid_attrs[] = { |
a969f4cc1
|
572 573 |
BTRFS_ATTR_PTR(raid, total_bytes), BTRFS_ATTR_PTR(raid, used_bytes), |
6ab0a2029
|
574 575 |
NULL }; |
7c7e30140
|
576 |
ATTRIBUTE_GROUPS(raid); |
6ab0a2029
|
577 578 579 |
static void release_raid_kobj(struct kobject *kobj) { |
c1895442b
|
580 |
kfree(to_raid_kobj(kobj)); |
6ab0a2029
|
581 |
} |
536ea45cb
|
582 |
static struct kobj_type btrfs_raid_ktype = { |
6ab0a2029
|
583 584 |
.sysfs_ops = &kobj_sysfs_ops, .release = release_raid_kobj, |
7c7e30140
|
585 |
.default_groups = raid_groups, |
6ab0a2029
|
586 587 588 589 590 591 592 593 594 595 |
}; #define SPACE_INFO_ATTR(field) \ static ssize_t btrfs_space_info_show_##field(struct kobject *kobj, \ struct kobj_attribute *a, \ char *buf) \ { \ struct btrfs_space_info *sinfo = to_space_info(kobj); \ return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf); \ } \ |
a969f4cc1
|
596 |
BTRFS_ATTR(space_info, field, btrfs_space_info_show_##field) |
6ab0a2029
|
597 598 599 600 601 602 603 |
static ssize_t btrfs_space_info_show_total_bytes_pinned(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_space_info *sinfo = to_space_info(kobj); s64 val = percpu_counter_sum(&sinfo->total_bytes_pinned); |
abdd9feb4
|
604 605 |
return scnprintf(buf, PAGE_SIZE, "%lld ", val); |
6ab0a2029
|
606 607 608 609 610 611 612 613 |
} SPACE_INFO_ATTR(flags); SPACE_INFO_ATTR(total_bytes); SPACE_INFO_ATTR(bytes_used); SPACE_INFO_ATTR(bytes_pinned); SPACE_INFO_ATTR(bytes_reserved); SPACE_INFO_ATTR(bytes_may_use); |
c1fd5c30d
|
614 |
SPACE_INFO_ATTR(bytes_readonly); |
6ab0a2029
|
615 616 |
SPACE_INFO_ATTR(disk_used); SPACE_INFO_ATTR(disk_total); |
a969f4cc1
|
617 618 |
BTRFS_ATTR(space_info, total_bytes_pinned, btrfs_space_info_show_total_bytes_pinned); |
6ab0a2029
|
619 620 |
static struct attribute *space_info_attrs[] = { |
a969f4cc1
|
621 622 623 624 625 626 627 628 629 630 |
BTRFS_ATTR_PTR(space_info, flags), BTRFS_ATTR_PTR(space_info, total_bytes), BTRFS_ATTR_PTR(space_info, bytes_used), BTRFS_ATTR_PTR(space_info, bytes_pinned), BTRFS_ATTR_PTR(space_info, bytes_reserved), BTRFS_ATTR_PTR(space_info, bytes_may_use), BTRFS_ATTR_PTR(space_info, bytes_readonly), BTRFS_ATTR_PTR(space_info, disk_used), BTRFS_ATTR_PTR(space_info, disk_total), BTRFS_ATTR_PTR(space_info, total_bytes_pinned), |
6ab0a2029
|
631 632 |
NULL, }; |
7c7e30140
|
633 |
ATTRIBUTE_GROUPS(space_info); |
6ab0a2029
|
634 635 636 637 638 639 640 |
static void space_info_release(struct kobject *kobj) { struct btrfs_space_info *sinfo = to_space_info(kobj); percpu_counter_destroy(&sinfo->total_bytes_pinned); kfree(sinfo); } |
27992d014
|
641 |
static struct kobj_type space_info_ktype = { |
6ab0a2029
|
642 643 |
.sysfs_ops = &kobj_sysfs_ops, .release = space_info_release, |
7c7e30140
|
644 |
.default_groups = space_info_groups, |
6ab0a2029
|
645 646 647 |
}; static const struct attribute *allocation_attrs[] = { |
a969f4cc1
|
648 649 |
BTRFS_ATTR_PTR(allocation, global_rsv_reserved), BTRFS_ATTR_PTR(allocation, global_rsv_size), |
6ab0a2029
|
650 651 |
NULL, }; |
f8ba9c11f
|
652 653 654 655 |
static ssize_t btrfs_label_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
48fcc3ff7
|
656 |
char *label = fs_info->super_copy->label; |
ee17fc800
|
657 658 659 |
ssize_t ret; spin_lock(&fs_info->super_lock); |
abdd9feb4
|
660 661 |
ret = scnprintf(buf, PAGE_SIZE, label[0] ? "%s " : "%s", label); |
ee17fc800
|
662 663 664 |
spin_unlock(&fs_info->super_lock); return ret; |
f8ba9c11f
|
665 666 667 668 669 670 671 |
} static ssize_t btrfs_label_store(struct kobject *kobj, struct kobj_attribute *a, const char *buf, size_t len) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
48fcc3ff7
|
672 |
size_t p_len; |
f8ba9c11f
|
673 |
|
66ac9fe7b
|
674 675 |
if (!fs_info) return -EPERM; |
bc98a42c1
|
676 |
if (sb_rdonly(fs_info->sb)) |
79aec2b80
|
677 |
return -EROFS; |
48fcc3ff7
|
678 679 680 681 682 683 684 685 686 |
/* * p_len is the len until the first occurrence of either * ' ' or '\0' */ p_len = strcspn(buf, " "); if (p_len >= BTRFS_LABEL_SIZE) |
f8ba9c11f
|
687 |
return -EINVAL; |
f8ba9c11f
|
688 |
|
a6f69dc80
|
689 |
spin_lock(&fs_info->super_lock); |
48fcc3ff7
|
690 691 |
memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE); memcpy(fs_info->super_copy->label, buf, p_len); |
a6f69dc80
|
692 |
spin_unlock(&fs_info->super_lock); |
f8ba9c11f
|
693 |
|
a6f69dc80
|
694 695 696 697 698 |
/* * We don't want to do full transaction commit from inside sysfs */ btrfs_set_pending(fs_info, COMMIT); wake_up_process(fs_info->transaction_kthread); |
f8ba9c11f
|
699 |
|
a6f69dc80
|
700 |
return len; |
f8ba9c11f
|
701 |
} |
a969f4cc1
|
702 |
BTRFS_ATTR_RW(, label, btrfs_label_show, btrfs_label_store); |
f8ba9c11f
|
703 |
|
df93589a1
|
704 705 706 707 |
static ssize_t btrfs_nodesize_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
abdd9feb4
|
708 709 |
return scnprintf(buf, PAGE_SIZE, "%u ", fs_info->super_copy->nodesize); |
df93589a1
|
710 |
} |
a969f4cc1
|
711 |
BTRFS_ATTR(, nodesize, btrfs_nodesize_show); |
df93589a1
|
712 713 714 715 716 |
static ssize_t btrfs_sectorsize_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
abdd9feb4
|
717 718 719 |
return scnprintf(buf, PAGE_SIZE, "%u ", fs_info->super_copy->sectorsize); |
df93589a1
|
720 |
} |
a969f4cc1
|
721 |
BTRFS_ATTR(, sectorsize, btrfs_sectorsize_show); |
df93589a1
|
722 723 724 725 726 |
static ssize_t btrfs_clone_alignment_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
abdd9feb4
|
727 728 |
return scnprintf(buf, PAGE_SIZE, "%u ", fs_info->super_copy->sectorsize); |
df93589a1
|
729 |
} |
a969f4cc1
|
730 |
BTRFS_ATTR(, clone_alignment, btrfs_clone_alignment_show); |
df93589a1
|
731 |
|
2723480a0
|
732 733 734 735 736 737 738 |
static ssize_t quota_override_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); int quota_override; quota_override = test_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags); |
abdd9feb4
|
739 740 |
return scnprintf(buf, PAGE_SIZE, "%d ", quota_override); |
2723480a0
|
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 |
} static ssize_t quota_override_store(struct kobject *kobj, struct kobj_attribute *a, const char *buf, size_t len) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); unsigned long knob; int err; if (!fs_info) return -EPERM; if (!capable(CAP_SYS_RESOURCE)) return -EPERM; err = kstrtoul(buf, 10, &knob); if (err) return err; if (knob > 1) return -EINVAL; if (knob) set_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags); else clear_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags); return len; } |
a969f4cc1
|
770 |
BTRFS_ATTR_RW(, quota_override, quota_override_show, quota_override_store); |
2723480a0
|
771 |
|
56f20f400
|
772 773 774 775 |
static ssize_t btrfs_metadata_uuid_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
abdd9feb4
|
776 777 |
return scnprintf(buf, PAGE_SIZE, "%pU ", |
56f20f400
|
778 779 780 781 |
fs_info->fs_devices->metadata_uuid); } BTRFS_ATTR(, metadata_uuid, btrfs_metadata_uuid_show); |
41e6d2a80
|
782 783 784 785 786 |
static ssize_t btrfs_checksum_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); u16 csum_type = btrfs_super_csum_type(fs_info->super_copy); |
abdd9feb4
|
787 788 |
return scnprintf(buf, PAGE_SIZE, "%s (%s) ", |
41e6d2a80
|
789 790 791 792 793 |
btrfs_super_csum_name(csum_type), crypto_shash_driver_name(fs_info->csum_shash)); } BTRFS_ATTR(, checksum, btrfs_checksum_show); |
66a2823c5
|
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 |
static ssize_t btrfs_exclusive_operation_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { struct btrfs_fs_info *fs_info = to_fs_info(kobj); const char *str; switch (READ_ONCE(fs_info->exclusive_operation)) { case BTRFS_EXCLOP_NONE: str = "none "; break; case BTRFS_EXCLOP_BALANCE: str = "balance "; break; case BTRFS_EXCLOP_DEV_ADD: str = "device add "; break; case BTRFS_EXCLOP_DEV_REMOVE: str = "device remove "; break; case BTRFS_EXCLOP_DEV_REPLACE: str = "device replace "; break; case BTRFS_EXCLOP_RESIZE: str = "resize "; break; case BTRFS_EXCLOP_SWAP_ACTIVATE: str = "swap activate "; break; default: str = "UNKNOWN "; break; } return scnprintf(buf, PAGE_SIZE, "%s", str); } BTRFS_ATTR(, exclusive_operation, btrfs_exclusive_operation_show); |
0dd2906f7
|
837 |
static const struct attribute *btrfs_attrs[] = { |
a969f4cc1
|
838 839 840 841 842 |
BTRFS_ATTR_PTR(, label), BTRFS_ATTR_PTR(, nodesize), BTRFS_ATTR_PTR(, sectorsize), BTRFS_ATTR_PTR(, clone_alignment), BTRFS_ATTR_PTR(, quota_override), |
56f20f400
|
843 |
BTRFS_ATTR_PTR(, metadata_uuid), |
41e6d2a80
|
844 |
BTRFS_ATTR_PTR(, checksum), |
66a2823c5
|
845 |
BTRFS_ATTR_PTR(, exclusive_operation), |
f8ba9c11f
|
846 847 |
NULL, }; |
c1b7e4745
|
848 |
static void btrfs_release_fsid_kobj(struct kobject *kobj) |
510d73600
|
849 |
{ |
2e7910d6c
|
850 |
struct btrfs_fs_devices *fs_devs = to_fs_devs(kobj); |
248d200df
|
851 |
|
c1b7e4745
|
852 |
memset(&fs_devs->fsid_kobj, 0, sizeof(struct kobject)); |
2e7910d6c
|
853 |
complete(&fs_devs->kobj_unregister); |
510d73600
|
854 855 856 857 |
} static struct kobj_type btrfs_ktype = { .sysfs_ops = &kobj_sysfs_ops, |
c1b7e4745
|
858 |
.release = btrfs_release_fsid_kobj, |
510d73600
|
859 |
}; |
2e7910d6c
|
860 861 862 863 |
static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj) { if (kobj->ktype != &btrfs_ktype) return NULL; |
c1b7e4745
|
864 |
return container_of(kobj, struct btrfs_fs_devices, fsid_kobj); |
2e7910d6c
|
865 |
} |
510d73600
|
866 867 868 869 |
static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj) { if (kobj->ktype != &btrfs_ktype) return NULL; |
2e7910d6c
|
870 |
return to_fs_devs(kobj)->fs_info; |
510d73600
|
871 |
} |
58176a960
|
872 |
|
e453d989e
|
873 |
#define NUM_FEATURE_BITS 64 |
6c52157fa
|
874 875 876 |
#define BTRFS_FEATURE_NAME_MAX 13 static char btrfs_unknown_feature_names[FEAT_MAX][NUM_FEATURE_BITS][BTRFS_FEATURE_NAME_MAX]; static struct btrfs_feature_attr btrfs_feature_attrs[FEAT_MAX][NUM_FEATURE_BITS]; |
e453d989e
|
877 |
|
6c52157fa
|
878 |
static const u64 supported_feature_masks[FEAT_MAX] = { |
e453d989e
|
879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 |
[FEAT_COMPAT] = BTRFS_FEATURE_COMPAT_SUPP, [FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP, [FEAT_INCOMPAT] = BTRFS_FEATURE_INCOMPAT_SUPP, }; static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add) { int set; for (set = 0; set < FEAT_MAX; set++) { int i; struct attribute *attrs[2]; struct attribute_group agroup = { .name = "features", .attrs = attrs, }; u64 features = get_features(fs_info, set); features &= ~supported_feature_masks[set]; if (!features) continue; attrs[1] = NULL; for (i = 0; i < NUM_FEATURE_BITS; i++) { struct btrfs_feature_attr *fa; if (!(features & (1ULL << i))) continue; fa = &btrfs_feature_attrs[set][i]; attrs[0] = &fa->kobj_attr.attr; if (add) { int ret; |
c1b7e4745
|
912 |
ret = sysfs_merge_group(&fs_info->fs_devices->fsid_kobj, |
e453d989e
|
913 914 915 916 |
&agroup); if (ret) return ret; } else |
c1b7e4745
|
917 |
sysfs_unmerge_group(&fs_info->fs_devices->fsid_kobj, |
e453d989e
|
918 919 920 921 922 923 |
&agroup); } } return 0; } |
2e3e12815
|
924 |
static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) |
5ac1d209f
|
925 |
{ |
a013d141e
|
926 927 928 929 930 |
if (fs_devs->devinfo_kobj) { kobject_del(fs_devs->devinfo_kobj); kobject_put(fs_devs->devinfo_kobj); fs_devs->devinfo_kobj = NULL; } |
b5501504c
|
931 932 933 934 |
if (fs_devs->devices_kobj) { kobject_del(fs_devs->devices_kobj); kobject_put(fs_devs->devices_kobj); fs_devs->devices_kobj = NULL; |
aaf133051
|
935 |
} |
c1b7e4745
|
936 937 938 |
if (fs_devs->fsid_kobj.state_initialized) { kobject_del(&fs_devs->fsid_kobj); kobject_put(&fs_devs->fsid_kobj); |
f90fc5472
|
939 940 |
wait_for_completion(&fs_devs->kobj_unregister); } |
5ac1d209f
|
941 |
} |
2e3e12815
|
942 |
/* when fs_devs is NULL it will remove all fsid kobject */ |
1d1c1be37
|
943 |
void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) |
2e3e12815
|
944 945 946 947 948 949 950 |
{ struct list_head *fs_uuids = btrfs_get_fs_uuids(); if (fs_devs) { __btrfs_sysfs_remove_fsid(fs_devs); return; } |
c4babc5e3
|
951 |
list_for_each_entry(fs_devs, fs_uuids, fs_list) { |
2e3e12815
|
952 953 954 |
__btrfs_sysfs_remove_fsid(fs_devs); } } |
53f8a74cb
|
955 956 957 |
static void btrfs_sysfs_remove_fs_devices(struct btrfs_fs_devices *fs_devices) { struct btrfs_device *device; |
30b0e4e0e
|
958 |
struct btrfs_fs_devices *seed; |
53f8a74cb
|
959 960 961 |
list_for_each_entry(device, &fs_devices->devices, dev_list) btrfs_sysfs_remove_device(device); |
30b0e4e0e
|
962 963 964 965 966 |
list_for_each_entry(seed, &fs_devices->seed_list, seed_list) { list_for_each_entry(device, &seed->devices, dev_list) btrfs_sysfs_remove_device(device); } |
53f8a74cb
|
967 |
} |
6618a59bf
|
968 |
void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info) |
e453d989e
|
969 |
{ |
3092c68fc
|
970 |
struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj; |
3092c68fc
|
971 |
sysfs_remove_link(fsid_kobj, "bdi"); |
e453d989e
|
972 973 974 975 976 |
if (fs_info->space_info_kobj) { sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs); kobject_del(fs_info->space_info_kobj); kobject_put(fs_info->space_info_kobj); } |
71e8978eb
|
977 |
#ifdef CONFIG_BTRFS_DEBUG |
e4faab844
|
978 979 980 981 982 983 |
if (fs_info->discard_debug_kobj) { sysfs_remove_files(fs_info->discard_debug_kobj, discard_debug_attrs); kobject_del(fs_info->discard_debug_kobj); kobject_put(fs_info->discard_debug_kobj); } |
93945cb43
|
984 985 986 987 988 |
if (fs_info->debug_kobj) { sysfs_remove_files(fs_info->debug_kobj, btrfs_debug_mount_attrs); kobject_del(fs_info->debug_kobj); kobject_put(fs_info->debug_kobj); } |
71e8978eb
|
989 |
#endif |
e453d989e
|
990 |
addrm_unknown_feature_attrs(fs_info, false); |
3092c68fc
|
991 992 |
sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group); sysfs_remove_files(fsid_kobj, btrfs_attrs); |
53f8a74cb
|
993 |
btrfs_sysfs_remove_fs_devices(fs_info->fs_devices); |
e453d989e
|
994 |
} |
f10152bcc
|
995 |
static const char * const btrfs_feature_set_names[FEAT_MAX] = { |
79da4fa4d
|
996 997 998 999 |
[FEAT_COMPAT] = "compat", [FEAT_COMPAT_RO] = "compat_ro", [FEAT_INCOMPAT] = "incompat", }; |
9e6df7ced
|
1000 |
const char *btrfs_feature_set_name(enum btrfs_feature_set set) |
f10152bcc
|
1001 1002 1003 |
{ return btrfs_feature_set_names[set]; } |
3b02a68a6
|
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 |
char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags) { size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */ int len = 0; int i; char *str; str = kmalloc(bufsize, GFP_KERNEL); if (!str) return str; for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { const char *name; if (!(flags & (1ULL << i))) continue; name = btrfs_feature_attrs[set][i].kobj_attr.attr.name; |
abdd9feb4
|
1022 |
len += scnprintf(str + len, bufsize - len, "%s%s", |
3b02a68a6
|
1023 1024 1025 1026 1027 |
len ? "," : "", name); } return str; } |
79da4fa4d
|
1028 1029 1030 1031 1032 1033 1034 1035 1036 |
static void init_feature_attrs(void) { struct btrfs_feature_attr *fa; int set, i; BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names) != ARRAY_SIZE(btrfs_feature_attrs)); BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) != ARRAY_SIZE(btrfs_feature_attrs[0])); |
3b02a68a6
|
1037 1038 1039 |
memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs)); memset(btrfs_unknown_feature_names, 0, sizeof(btrfs_unknown_feature_names)); |
79da4fa4d
|
1040 1041 1042 |
for (i = 0; btrfs_supported_feature_attrs[i]; i++) { struct btrfs_feature_attr *sfa; struct attribute *a = btrfs_supported_feature_attrs[i]; |
3b02a68a6
|
1043 |
int bit; |
79da4fa4d
|
1044 |
sfa = attr_to_btrfs_feature_attr(a); |
3b02a68a6
|
1045 1046 |
bit = ilog2(sfa->feature_bit); fa = &btrfs_feature_attrs[sfa->feature_set][bit]; |
79da4fa4d
|
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 |
fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name; } for (set = 0; set < FEAT_MAX; set++) { for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { char *name = btrfs_unknown_feature_names[set][i]; fa = &btrfs_feature_attrs[set][i]; if (fa->kobj_attr.attr.name) continue; |
6c52157fa
|
1058 |
snprintf(name, BTRFS_FEATURE_NAME_MAX, "%s:%u", |
79da4fa4d
|
1059 1060 1061 1062 1063 1064 1065 1066 1067 |
btrfs_feature_set_names[set], i); fa->kobj_attr.attr.name = name; fa->kobj_attr.attr.mode = S_IRUGO; fa->feature_set = set; fa->feature_bit = 1ULL << i; } } } |
32a9991f1
|
1068 1069 1070 1071 |
/* * Create a sysfs entry for a given block group type at path * /sys/fs/btrfs/UUID/allocation/data/TYPE */ |
32da5386d
|
1072 |
void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache) |
32a9991f1
|
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 |
{ struct btrfs_fs_info *fs_info = cache->fs_info; struct btrfs_space_info *space_info = cache->space_info; struct raid_kobject *rkobj; const int index = btrfs_bg_flags_to_raid_index(cache->flags); unsigned int nofs_flag; int ret; /* * Setup a NOFS context because kobject_add(), deep in its call chain, * does GFP_KERNEL allocations, and we are often called in a context * where if reclaim is triggered we can deadlock (we are either holding * a transaction handle or some lock required for a transaction * commit). */ nofs_flag = memalloc_nofs_save(); rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS); if (!rkobj) { memalloc_nofs_restore(nofs_flag); btrfs_warn(cache->fs_info, "couldn't alloc memory for raid level kobject"); return; } rkobj->flags = cache->flags; kobject_init(&rkobj->kobj, &btrfs_raid_ktype); |
49ea112da
|
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 |
/* * We call this either on mount, or if we've created a block group for a * new index type while running (i.e. when restriping). The running * case is tricky because we could race with other threads, so we need * to have this check to make sure we didn't already init the kobject. * * We don't have to protect on the free side because it only happens on * unmount. */ spin_lock(&space_info->lock); if (space_info->block_group_kobjs[index]) { spin_unlock(&space_info->lock); kobject_put(&rkobj->kobj); return; } else { space_info->block_group_kobjs[index] = &rkobj->kobj; } spin_unlock(&space_info->lock); |
32a9991f1
|
1119 1120 1121 1122 |
ret = kobject_add(&rkobj->kobj, &space_info->kobj, "%s", btrfs_bg_type_to_raid_name(rkobj->flags)); memalloc_nofs_restore(nofs_flag); if (ret) { |
49ea112da
|
1123 1124 1125 |
spin_lock(&space_info->lock); space_info->block_group_kobjs[index] = NULL; spin_unlock(&space_info->lock); |
32a9991f1
|
1126 1127 1128 1129 1130 |
kobject_put(&rkobj->kobj); btrfs_warn(fs_info, "failed to add kobject for block cache, ignoring"); return; } |
32a9991f1
|
1131 |
} |
b5865babb
|
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 |
/* * Remove sysfs directories for all block group types of a given space info and * the space info as well */ void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info) { int i; for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) { struct kobject *kobj; kobj = space_info->block_group_kobjs[i]; space_info->block_group_kobjs[i] = NULL; if (kobj) { kobject_del(kobj); kobject_put(kobj); } } kobject_del(&space_info->kobj); kobject_put(&space_info->kobj); } |
b882327a7
|
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 |
static const char *alloc_name(u64 flags) { switch (flags) { case BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA: return "mixed"; case BTRFS_BLOCK_GROUP_METADATA: return "metadata"; case BTRFS_BLOCK_GROUP_DATA: return "data"; case BTRFS_BLOCK_GROUP_SYSTEM: return "system"; default: WARN_ON(1); return "invalid-combination"; }; } /* * Create a sysfs entry for a space info type at path * /sys/fs/btrfs/UUID/allocation/TYPE */ int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info, struct btrfs_space_info *space_info) { int ret; ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype, fs_info->space_info_kobj, "%s", alloc_name(space_info->flags)); if (ret) { kobject_put(&space_info->kobj); return ret; } return 0; } |
53f8a74cb
|
1189 |
void btrfs_sysfs_remove_device(struct btrfs_device *device) |
99994cde9
|
1190 1191 1192 |
{ struct hd_struct *disk; struct kobject *disk_kobj; |
985e233e9
|
1193 |
struct kobject *devices_kobj; |
99994cde9
|
1194 |
|
985e233e9
|
1195 1196 1197 1198 1199 1200 |
/* * Seed fs_devices devices_kobj aren't used, fetch kobject from the * fs_info::fs_devices. */ devices_kobj = device->fs_info->fs_devices->devices_kobj; ASSERT(devices_kobj); |
99994cde9
|
1201 |
|
985e233e9
|
1202 1203 1204 1205 1206 |
if (device->bdev) { disk = device->bdev->bd_part; disk_kobj = &part_to_dev(disk)->kobj; sysfs_remove_link(devices_kobj, disk_kobj->name); } |
668e48af7
|
1207 |
|
985e233e9
|
1208 1209 1210 1211 1212 1213 |
if (device->devid_kobj.state_initialized) { kobject_del(&device->devid_kobj); kobject_put(&device->devid_kobj); wait_for_completion(&device->kobj_unregister); } } |
99994cde9
|
1214 |
|
668e48af7
|
1215 1216 1217 1218 1219 1220 1221 1222 1223 |
static ssize_t btrfs_devinfo_in_fs_metadata_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { int val; struct btrfs_device *device = container_of(kobj, struct btrfs_device, devid_kobj); val = !!test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state); |
abdd9feb4
|
1224 1225 |
return scnprintf(buf, PAGE_SIZE, "%d ", val); |
668e48af7
|
1226 1227 |
} BTRFS_ATTR(devid, in_fs_metadata, btrfs_devinfo_in_fs_metadata_show); |
25864778b
|
1228 |
static ssize_t btrfs_devinfo_missing_show(struct kobject *kobj, |
668e48af7
|
1229 1230 1231 1232 1233 1234 1235 |
struct kobj_attribute *a, char *buf) { int val; struct btrfs_device *device = container_of(kobj, struct btrfs_device, devid_kobj); val = !!test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state); |
abdd9feb4
|
1236 1237 |
return scnprintf(buf, PAGE_SIZE, "%d ", val); |
668e48af7
|
1238 |
} |
25864778b
|
1239 |
BTRFS_ATTR(devid, missing, btrfs_devinfo_missing_show); |
668e48af7
|
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 |
static ssize_t btrfs_devinfo_replace_target_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { int val; struct btrfs_device *device = container_of(kobj, struct btrfs_device, devid_kobj); val = !!test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state); |
abdd9feb4
|
1250 1251 |
return scnprintf(buf, PAGE_SIZE, "%d ", val); |
668e48af7
|
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 |
} BTRFS_ATTR(devid, replace_target, btrfs_devinfo_replace_target_show); static ssize_t btrfs_devinfo_writeable_show(struct kobject *kobj, struct kobj_attribute *a, char *buf) { int val; struct btrfs_device *device = container_of(kobj, struct btrfs_device, devid_kobj); val = !!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state); |
abdd9feb4
|
1263 1264 |
return scnprintf(buf, PAGE_SIZE, "%d ", val); |
668e48af7
|
1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 |
} BTRFS_ATTR(devid, writeable, btrfs_devinfo_writeable_show); static struct attribute *devid_attrs[] = { BTRFS_ATTR_PTR(devid, in_fs_metadata), BTRFS_ATTR_PTR(devid, missing), BTRFS_ATTR_PTR(devid, replace_target), BTRFS_ATTR_PTR(devid, writeable), NULL }; ATTRIBUTE_GROUPS(devid); static void btrfs_release_devid_kobj(struct kobject *kobj) { struct btrfs_device *device = container_of(kobj, struct btrfs_device, devid_kobj); memset(&device->devid_kobj, 0, sizeof(struct kobject)); complete(&device->kobj_unregister); } static struct kobj_type devid_ktype = { .sysfs_ops = &kobj_sysfs_ops, .default_groups = devid_groups, .release = btrfs_release_devid_kobj, }; |
cd36da2e7
|
1291 |
int btrfs_sysfs_add_device(struct btrfs_device *device) |
00c921c23
|
1292 |
{ |
178a16c94
|
1293 |
int ret; |
a47bd78d0
|
1294 |
unsigned int nofs_flag; |
178a16c94
|
1295 1296 |
struct kobject *devices_kobj; struct kobject *devinfo_kobj; |
00c921c23
|
1297 |
|
178a16c94
|
1298 1299 1300 1301 1302 1303 1304 1305 |
/* * Make sure we use the fs_info::fs_devices to fetch the kobjects even * for the seed fs_devices */ devices_kobj = device->fs_info->fs_devices->devices_kobj; devinfo_kobj = device->fs_info->fs_devices->devinfo_kobj; ASSERT(devices_kobj); ASSERT(devinfo_kobj); |
f085381e6
|
1306 |
|
178a16c94
|
1307 |
nofs_flag = memalloc_nofs_save(); |
0d39376aa
|
1308 |
|
178a16c94
|
1309 1310 1311 |
if (device->bdev) { struct hd_struct *disk; struct kobject *disk_kobj; |
668e48af7
|
1312 |
|
178a16c94
|
1313 1314 |
disk = device->bdev->bd_part; disk_kobj = &part_to_dev(disk)->kobj; |
668e48af7
|
1315 |
|
178a16c94
|
1316 1317 1318 1319 1320 1321 |
ret = sysfs_create_link(devices_kobj, disk_kobj, disk_kobj->name); if (ret) { btrfs_warn(device->fs_info, "creating sysfs device link for devid %llu failed: %d", device->devid, ret); goto out; |
668e48af7
|
1322 |
} |
178a16c94
|
1323 |
} |
29e5be240
|
1324 |
|
178a16c94
|
1325 1326 1327 1328 1329 1330 1331 1332 |
init_completion(&device->kobj_unregister); ret = kobject_init_and_add(&device->devid_kobj, &devid_ktype, devinfo_kobj, "%llu", device->devid); if (ret) { kobject_put(&device->devid_kobj); btrfs_warn(device->fs_info, "devinfo init for devid %llu failed: %d", device->devid, ret); |
29e5be240
|
1333 |
} |
178a16c94
|
1334 1335 |
out: |
a47bd78d0
|
1336 |
memalloc_nofs_restore(nofs_flag); |
178a16c94
|
1337 1338 |
return ret; } |
29e5be240
|
1339 |
|
cd36da2e7
|
1340 |
static int btrfs_sysfs_add_fs_devices(struct btrfs_fs_devices *fs_devices) |
178a16c94
|
1341 1342 |
{ int ret; |
cd36da2e7
|
1343 |
struct btrfs_device *device; |
30b0e4e0e
|
1344 |
struct btrfs_fs_devices *seed; |
178a16c94
|
1345 1346 1347 1348 |
list_for_each_entry(device, &fs_devices->devices, dev_list) { ret = btrfs_sysfs_add_device(device); if (ret) |
7ad3912a7
|
1349 |
goto fail; |
178a16c94
|
1350 |
} |
30b0e4e0e
|
1351 1352 1353 1354 |
list_for_each_entry(seed, &fs_devices->seed_list, seed_list) { list_for_each_entry(device, &seed->devices, dev_list) { ret = btrfs_sysfs_add_device(device); if (ret) |
7ad3912a7
|
1355 |
goto fail; |
30b0e4e0e
|
1356 1357 |
} } |
178a16c94
|
1358 |
return 0; |
7ad3912a7
|
1359 1360 1361 1362 |
fail: btrfs_sysfs_remove_fs_devices(fs_devices); return ret; |
29e5be240
|
1363 |
} |
5b28692e0
|
1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 |
void btrfs_kobject_uevent(struct block_device *bdev, enum kobject_action action) { int ret; ret = kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, action); if (ret) pr_warn("BTRFS: Sending event '%d' to kobject: '%s' (%p): failed ", action, kobject_name(&disk_to_dev(bdev->bd_disk)->kobj), &disk_to_dev(bdev->bd_disk)->kobj); } |
8e5600818
|
1375 |
void btrfs_sysfs_update_sprout_fsid(struct btrfs_fs_devices *fs_devices) |
f93c39970
|
1376 1377 1378 1379 1380 1381 1382 |
{ char fsid_buf[BTRFS_UUID_UNPARSED_SIZE]; /* * Sprouting changes fsid of the mounted filesystem, rename the fsid * directory */ |
8e5600818
|
1383 |
snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU", fs_devices->fsid); |
f93c39970
|
1384 1385 1386 1387 |
if (kobject_rename(&fs_devices->fsid_kobj, fsid_buf)) btrfs_warn(fs_devices->fs_info, "sysfs: failed to create fsid for sprout"); } |
668e48af7
|
1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 |
void btrfs_sysfs_update_devid(struct btrfs_device *device) { char tmp[24]; snprintf(tmp, sizeof(tmp), "%llu", device->devid); if (kobject_rename(&device->devid_kobj, tmp)) btrfs_warn(device->fs_devices->fs_info, "sysfs: failed to update devid for %llu", device->devid); } |
510d73600
|
1399 1400 |
/* /sys/fs/btrfs/ entry */ static struct kset *btrfs_kset; |
720592157
|
1401 |
/* |
c6761a9ed
|
1402 1403 1404 |
* Creates: * /sys/fs/btrfs/UUID * |
720592157
|
1405 |
* Can be called by the device discovery thread. |
720592157
|
1406 |
*/ |
c6761a9ed
|
1407 |
int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs) |
5ac1d209f
|
1408 1409 |
{ int error; |
2e7910d6c
|
1410 |
init_completion(&fs_devs->kobj_unregister); |
c1b7e4745
|
1411 |
fs_devs->fsid_kobj.kset = btrfs_kset; |
c6761a9ed
|
1412 1413 |
error = kobject_init_and_add(&fs_devs->fsid_kobj, &btrfs_ktype, NULL, "%pU", fs_devs->fsid); |
e32773357
|
1414 1415 1416 1417 |
if (error) { kobject_put(&fs_devs->fsid_kobj); return error; } |
bc036bb33
|
1418 1419 1420 1421 1422 |
fs_devs->devices_kobj = kobject_create_and_add("devices", &fs_devs->fsid_kobj); if (!fs_devs->devices_kobj) { btrfs_err(fs_devs->fs_info, "failed to init sysfs device interface"); |
1f6087e69
|
1423 |
btrfs_sysfs_remove_fsid(fs_devs); |
bc036bb33
|
1424 1425 |
return -ENOMEM; } |
a013d141e
|
1426 1427 1428 1429 1430 1431 1432 1433 |
fs_devs->devinfo_kobj = kobject_create_and_add("devinfo", &fs_devs->fsid_kobj); if (!fs_devs->devinfo_kobj) { btrfs_err(fs_devs->fs_info, "failed to init sysfs devinfo kobject"); btrfs_sysfs_remove_fsid(fs_devs); return -ENOMEM; } |
e32773357
|
1434 |
return 0; |
720592157
|
1435 |
} |
96f3136e5
|
1436 |
int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info) |
720592157
|
1437 1438 |
{ int error; |
2e7910d6c
|
1439 |
struct btrfs_fs_devices *fs_devs = fs_info->fs_devices; |
c1b7e4745
|
1440 |
struct kobject *fsid_kobj = &fs_devs->fsid_kobj; |
720592157
|
1441 |
|
cd36da2e7
|
1442 |
error = btrfs_sysfs_add_fs_devices(fs_devs); |
b7c35e81a
|
1443 |
if (error) |
aaf133051
|
1444 |
return error; |
aaf133051
|
1445 |
|
c1b7e4745
|
1446 |
error = sysfs_create_files(fsid_kobj, btrfs_attrs); |
e453d989e
|
1447 |
if (error) { |
53f8a74cb
|
1448 |
btrfs_sysfs_remove_fs_devices(fs_devs); |
e453d989e
|
1449 1450 |
return error; } |
79da4fa4d
|
1451 |
|
c1b7e4745
|
1452 |
error = sysfs_create_group(fsid_kobj, |
0dd2906f7
|
1453 1454 1455 |
&btrfs_feature_attr_group); if (error) goto failure; |
6e369febb
|
1456 |
#ifdef CONFIG_BTRFS_DEBUG |
93945cb43
|
1457 1458 1459 1460 1461 1462 1463 |
fs_info->debug_kobj = kobject_create_and_add("debug", fsid_kobj); if (!fs_info->debug_kobj) { error = -ENOMEM; goto failure; } error = sysfs_create_files(fs_info->debug_kobj, btrfs_debug_mount_attrs); |
6e369febb
|
1464 1465 |
if (error) goto failure; |
e4faab844
|
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 |
/* Discard directory */ fs_info->discard_debug_kobj = kobject_create_and_add("discard", fs_info->debug_kobj); if (!fs_info->discard_debug_kobj) { error = -ENOMEM; goto failure; } error = sysfs_create_files(fs_info->discard_debug_kobj, discard_debug_attrs); if (error) goto failure; |
6e369febb
|
1479 |
#endif |
e453d989e
|
1480 |
error = addrm_unknown_feature_attrs(fs_info, true); |
79da4fa4d
|
1481 1482 |
if (error) goto failure; |
3092c68fc
|
1483 1484 1485 |
error = sysfs_create_link(fsid_kobj, &fs_info->sb->s_bdi->dev->kobj, "bdi"); if (error) goto failure; |
6ab0a2029
|
1486 |
fs_info->space_info_kobj = kobject_create_and_add("allocation", |
c1b7e4745
|
1487 |
fsid_kobj); |
6ab0a2029
|
1488 1489 1490 1491 1492 1493 1494 1495 |
if (!fs_info->space_info_kobj) { error = -ENOMEM; goto failure; } error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs); if (error) goto failure; |
79da4fa4d
|
1496 1497 |
return 0; failure: |
6618a59bf
|
1498 |
btrfs_sysfs_remove_mounted(fs_info); |
5ac1d209f
|
1499 1500 |
return error; } |
49e5fb462
|
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 |
static inline struct btrfs_fs_info *qgroup_kobj_to_fs_info(struct kobject *kobj) { return to_fs_info(kobj->parent->parent); } #define QGROUP_ATTR(_member, _show_name) \ static ssize_t btrfs_qgroup_show_##_member(struct kobject *qgroup_kobj, \ struct kobj_attribute *a, \ char *buf) \ { \ struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj); \ struct btrfs_qgroup *qgroup = container_of(qgroup_kobj, \ struct btrfs_qgroup, kobj); \ return btrfs_show_u64(&qgroup->_member, &fs_info->qgroup_lock, buf); \ } \ BTRFS_ATTR(qgroup, _show_name, btrfs_qgroup_show_##_member) #define QGROUP_RSV_ATTR(_name, _type) \ static ssize_t btrfs_qgroup_rsv_show_##_name(struct kobject *qgroup_kobj, \ struct kobj_attribute *a, \ char *buf) \ { \ struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj); \ struct btrfs_qgroup *qgroup = container_of(qgroup_kobj, \ struct btrfs_qgroup, kobj); \ return btrfs_show_u64(&qgroup->rsv.values[_type], \ &fs_info->qgroup_lock, buf); \ } \ BTRFS_ATTR(qgroup, rsv_##_name, btrfs_qgroup_rsv_show_##_name) QGROUP_ATTR(rfer, referenced); QGROUP_ATTR(excl, exclusive); QGROUP_ATTR(max_rfer, max_referenced); QGROUP_ATTR(max_excl, max_exclusive); QGROUP_ATTR(lim_flags, limit_flags); QGROUP_RSV_ATTR(data, BTRFS_QGROUP_RSV_DATA); QGROUP_RSV_ATTR(meta_pertrans, BTRFS_QGROUP_RSV_META_PERTRANS); QGROUP_RSV_ATTR(meta_prealloc, BTRFS_QGROUP_RSV_META_PREALLOC); static struct attribute *qgroup_attrs[] = { BTRFS_ATTR_PTR(qgroup, referenced), BTRFS_ATTR_PTR(qgroup, exclusive), BTRFS_ATTR_PTR(qgroup, max_referenced), BTRFS_ATTR_PTR(qgroup, max_exclusive), BTRFS_ATTR_PTR(qgroup, limit_flags), BTRFS_ATTR_PTR(qgroup, rsv_data), BTRFS_ATTR_PTR(qgroup, rsv_meta_pertrans), BTRFS_ATTR_PTR(qgroup, rsv_meta_prealloc), NULL }; ATTRIBUTE_GROUPS(qgroup); static void qgroup_release(struct kobject *kobj) { struct btrfs_qgroup *qgroup = container_of(kobj, struct btrfs_qgroup, kobj); memset(&qgroup->kobj, 0, sizeof(*kobj)); } static struct kobj_type qgroup_ktype = { .sysfs_ops = &kobj_sysfs_ops, .release = qgroup_release, .default_groups = qgroup_groups, }; int btrfs_sysfs_add_one_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup) { struct kobject *qgroups_kobj = fs_info->qgroups_kobj; int ret; if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) return 0; if (qgroup->kobj.state_initialized) return 0; if (!qgroups_kobj) return -EINVAL; ret = kobject_init_and_add(&qgroup->kobj, &qgroup_ktype, qgroups_kobj, "%hu_%llu", btrfs_qgroup_level(qgroup->qgroupid), btrfs_qgroup_subvolid(qgroup->qgroupid)); if (ret < 0) kobject_put(&qgroup->kobj); return ret; } void btrfs_sysfs_del_qgroups(struct btrfs_fs_info *fs_info) { struct btrfs_qgroup *qgroup; struct btrfs_qgroup *next; if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) return; rbtree_postorder_for_each_entry_safe(qgroup, next, &fs_info->qgroup_tree, node) btrfs_sysfs_del_one_qgroup(fs_info, qgroup); |
62ab2cc04
|
1599 1600 1601 1602 1603 |
if (fs_info->qgroups_kobj) { kobject_del(fs_info->qgroups_kobj); kobject_put(fs_info->qgroups_kobj); fs_info->qgroups_kobj = NULL; } |
49e5fb462
|
1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 |
} /* Called when qgroups get initialized, thus there is no need for locking */ int btrfs_sysfs_add_qgroups(struct btrfs_fs_info *fs_info) { struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj; struct btrfs_qgroup *qgroup; struct btrfs_qgroup *next; int ret = 0; if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) return 0; ASSERT(fsid_kobj); if (fs_info->qgroups_kobj) return 0; fs_info->qgroups_kobj = kobject_create_and_add("qgroups", fsid_kobj); if (!fs_info->qgroups_kobj) { ret = -ENOMEM; goto out; } rbtree_postorder_for_each_entry_safe(qgroup, next, &fs_info->qgroup_tree, node) { ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup); if (ret < 0) goto out; } out: if (ret < 0) btrfs_sysfs_del_qgroups(fs_info); return ret; } void btrfs_sysfs_del_one_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup) { if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) return; if (qgroup->kobj.state_initialized) { kobject_del(&qgroup->kobj); kobject_put(&qgroup->kobj); } } |
444e75169
|
1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 |
/* * Change per-fs features in /sys/fs/btrfs/UUID/features to match current * values in superblock. Call after any changes to incompat/compat_ro flags */ void btrfs_sysfs_feature_update(struct btrfs_fs_info *fs_info, u64 bit, enum btrfs_feature_set set) { struct btrfs_fs_devices *fs_devs; struct kobject *fsid_kobj; |
24646481f
|
1660 1661 |
u64 __maybe_unused features; int __maybe_unused ret; |
444e75169
|
1662 1663 1664 |
if (!fs_info) return; |
24646481f
|
1665 1666 1667 1668 |
/* * See 14e46e04958df74 and e410e34fad913dd, feature bit updates are not * safe when called from some contexts (eg. balance) */ |
444e75169
|
1669 1670 1671 1672 1673 |
features = get_features(fs_info, set); ASSERT(bit & supported_feature_masks[set]); fs_devs = fs_info->fs_devices; fsid_kobj = &fs_devs->fsid_kobj; |
bf6092066
|
1674 1675 |
if (!fsid_kobj->state_initialized) return; |
444e75169
|
1676 1677 1678 1679 1680 1681 1682 |
/* * FIXME: this is too heavy to update just one value, ideally we'd like * to use sysfs_update_group but some refactoring is needed first. */ sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group); ret = sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group); } |
f5c29bd9d
|
1683 |
int __init btrfs_init_sysfs(void) |
58176a960
|
1684 |
{ |
079b72bca
|
1685 |
int ret; |
1bae30982
|
1686 |
|
e3fe4e712
|
1687 1688 1689 |
btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); if (!btrfs_kset) return -ENOMEM; |
079b72bca
|
1690 |
|
1bae30982
|
1691 |
init_feature_attrs(); |
079b72bca
|
1692 |
ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); |
001a648df
|
1693 1694 |
if (ret) goto out2; |
f902bd3a5
|
1695 1696 1697 1698 |
ret = sysfs_merge_group(&btrfs_kset->kobj, &btrfs_static_feature_attr_group); if (ret) goto out_remove_group; |
001a648df
|
1699 |
|
6e369febb
|
1700 1701 1702 1703 1704 |
#ifdef CONFIG_BTRFS_DEBUG ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group); if (ret) goto out2; #endif |
001a648df
|
1705 |
return 0; |
f902bd3a5
|
1706 1707 1708 |
out_remove_group: sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); |
001a648df
|
1709 |
out2: |
001a648df
|
1710 |
kset_unregister(btrfs_kset); |
079b72bca
|
1711 |
|
1bae30982
|
1712 |
return ret; |
58176a960
|
1713 |
} |
e67c718b5
|
1714 |
void __cold btrfs_exit_sysfs(void) |
58176a960
|
1715 |
{ |
f902bd3a5
|
1716 1717 |
sysfs_unmerge_group(&btrfs_kset->kobj, &btrfs_static_feature_attr_group); |
079b72bca
|
1718 |
sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); |
71e8978eb
|
1719 1720 1721 |
#ifdef CONFIG_BTRFS_DEBUG sysfs_remove_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group); #endif |
e3fe4e712
|
1722 |
kset_unregister(btrfs_kset); |
58176a960
|
1723 |
} |
55d474148
|
1724 |