| .. | .. |
|---|
| 4 | 4 | */ |
|---|
| 5 | 5 | |
|---|
| 6 | 6 | #include <linux/sched.h> |
|---|
| 7 | +#include <linux/sched/mm.h> |
|---|
| 7 | 8 | #include <linux/slab.h> |
|---|
| 8 | 9 | #include <linux/spinlock.h> |
|---|
| 9 | 10 | #include <linux/completion.h> |
|---|
| 10 | | -#include <linux/kobject.h> |
|---|
| 11 | 11 | #include <linux/bug.h> |
|---|
| 12 | | -#include <linux/debugfs.h> |
|---|
| 13 | | -#include <linux/sched/mm.h> |
|---|
| 12 | +#include <crypto/hash.h> |
|---|
| 14 | 13 | |
|---|
| 15 | 14 | #include "ctree.h" |
|---|
| 15 | +#include "discard.h" |
|---|
| 16 | 16 | #include "disk-io.h" |
|---|
| 17 | +#include "send.h" |
|---|
| 17 | 18 | #include "transaction.h" |
|---|
| 18 | 19 | #include "sysfs.h" |
|---|
| 19 | 20 | #include "volumes.h" |
|---|
| 21 | +#include "space-info.h" |
|---|
| 22 | +#include "block-group.h" |
|---|
| 23 | +#include "qgroup.h" |
|---|
| 24 | + |
|---|
| 25 | +struct btrfs_feature_attr { |
|---|
| 26 | + struct kobj_attribute kobj_attr; |
|---|
| 27 | + enum btrfs_feature_set feature_set; |
|---|
| 28 | + u64 feature_bit; |
|---|
| 29 | +}; |
|---|
| 30 | + |
|---|
| 31 | +/* For raid type sysfs entries */ |
|---|
| 32 | +struct raid_kobject { |
|---|
| 33 | + u64 flags; |
|---|
| 34 | + struct kobject kobj; |
|---|
| 35 | +}; |
|---|
| 36 | + |
|---|
| 37 | +#define __INIT_KOBJ_ATTR(_name, _mode, _show, _store) \ |
|---|
| 38 | +{ \ |
|---|
| 39 | + .attr = { .name = __stringify(_name), .mode = _mode }, \ |
|---|
| 40 | + .show = _show, \ |
|---|
| 41 | + .store = _store, \ |
|---|
| 42 | +} |
|---|
| 43 | + |
|---|
| 44 | +#define BTRFS_ATTR_RW(_prefix, _name, _show, _store) \ |
|---|
| 45 | + static struct kobj_attribute btrfs_attr_##_prefix##_##_name = \ |
|---|
| 46 | + __INIT_KOBJ_ATTR(_name, 0644, _show, _store) |
|---|
| 47 | + |
|---|
| 48 | +#define BTRFS_ATTR(_prefix, _name, _show) \ |
|---|
| 49 | + static struct kobj_attribute btrfs_attr_##_prefix##_##_name = \ |
|---|
| 50 | + __INIT_KOBJ_ATTR(_name, 0444, _show, NULL) |
|---|
| 51 | + |
|---|
| 52 | +#define BTRFS_ATTR_PTR(_prefix, _name) \ |
|---|
| 53 | + (&btrfs_attr_##_prefix##_##_name.attr) |
|---|
| 54 | + |
|---|
| 55 | +#define BTRFS_FEAT_ATTR(_name, _feature_set, _feature_prefix, _feature_bit) \ |
|---|
| 56 | +static struct btrfs_feature_attr btrfs_attr_features_##_name = { \ |
|---|
| 57 | + .kobj_attr = __INIT_KOBJ_ATTR(_name, S_IRUGO, \ |
|---|
| 58 | + btrfs_feature_attr_show, \ |
|---|
| 59 | + btrfs_feature_attr_store), \ |
|---|
| 60 | + .feature_set = _feature_set, \ |
|---|
| 61 | + .feature_bit = _feature_prefix ##_## _feature_bit, \ |
|---|
| 62 | +} |
|---|
| 63 | +#define BTRFS_FEAT_ATTR_PTR(_name) \ |
|---|
| 64 | + (&btrfs_attr_features_##_name.kobj_attr.attr) |
|---|
| 65 | + |
|---|
| 66 | +#define BTRFS_FEAT_ATTR_COMPAT(name, feature) \ |
|---|
| 67 | + BTRFS_FEAT_ATTR(name, FEAT_COMPAT, BTRFS_FEATURE_COMPAT, feature) |
|---|
| 68 | +#define BTRFS_FEAT_ATTR_COMPAT_RO(name, feature) \ |
|---|
| 69 | + BTRFS_FEAT_ATTR(name, FEAT_COMPAT_RO, BTRFS_FEATURE_COMPAT_RO, feature) |
|---|
| 70 | +#define BTRFS_FEAT_ATTR_INCOMPAT(name, feature) \ |
|---|
| 71 | + BTRFS_FEAT_ATTR(name, FEAT_INCOMPAT, BTRFS_FEATURE_INCOMPAT, feature) |
|---|
| 20 | 72 | |
|---|
| 21 | 73 | static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj); |
|---|
| 22 | 74 | static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj); |
|---|
| 75 | + |
|---|
| 76 | +static struct btrfs_feature_attr *to_btrfs_feature_attr(struct kobj_attribute *a) |
|---|
| 77 | +{ |
|---|
| 78 | + return container_of(a, struct btrfs_feature_attr, kobj_attr); |
|---|
| 79 | +} |
|---|
| 80 | + |
|---|
| 81 | +static struct kobj_attribute *attr_to_btrfs_attr(struct attribute *attr) |
|---|
| 82 | +{ |
|---|
| 83 | + return container_of(attr, struct kobj_attribute, attr); |
|---|
| 84 | +} |
|---|
| 85 | + |
|---|
| 86 | +static struct btrfs_feature_attr *attr_to_btrfs_feature_attr( |
|---|
| 87 | + struct attribute *attr) |
|---|
| 88 | +{ |
|---|
| 89 | + return to_btrfs_feature_attr(attr_to_btrfs_attr(attr)); |
|---|
| 90 | +} |
|---|
| 23 | 91 | |
|---|
| 24 | 92 | static u64 get_features(struct btrfs_fs_info *fs_info, |
|---|
| 25 | 93 | enum btrfs_feature_set set) |
|---|
| .. | .. |
|---|
| 89 | 157 | } else |
|---|
| 90 | 158 | val = can_modify_feature(fa); |
|---|
| 91 | 159 | |
|---|
| 92 | | - return snprintf(buf, PAGE_SIZE, "%d\n", val); |
|---|
| 160 | + return scnprintf(buf, PAGE_SIZE, "%d\n", val); |
|---|
| 93 | 161 | } |
|---|
| 94 | 162 | |
|---|
| 95 | 163 | static ssize_t btrfs_feature_attr_store(struct kobject *kobj, |
|---|
| .. | .. |
|---|
| 192 | 260 | BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56); |
|---|
| 193 | 261 | BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA); |
|---|
| 194 | 262 | BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES); |
|---|
| 263 | +BTRFS_FEAT_ATTR_INCOMPAT(metadata_uuid, METADATA_UUID); |
|---|
| 195 | 264 | BTRFS_FEAT_ATTR_COMPAT_RO(free_space_tree, FREE_SPACE_TREE); |
|---|
| 265 | +BTRFS_FEAT_ATTR_INCOMPAT(raid1c34, RAID1C34); |
|---|
| 196 | 266 | |
|---|
| 197 | 267 | static struct attribute *btrfs_supported_feature_attrs[] = { |
|---|
| 198 | 268 | BTRFS_FEAT_ATTR_PTR(mixed_backref), |
|---|
| .. | .. |
|---|
| 205 | 275 | BTRFS_FEAT_ATTR_PTR(raid56), |
|---|
| 206 | 276 | BTRFS_FEAT_ATTR_PTR(skinny_metadata), |
|---|
| 207 | 277 | BTRFS_FEAT_ATTR_PTR(no_holes), |
|---|
| 278 | + BTRFS_FEAT_ATTR_PTR(metadata_uuid), |
|---|
| 208 | 279 | BTRFS_FEAT_ATTR_PTR(free_space_tree), |
|---|
| 280 | + BTRFS_FEAT_ATTR_PTR(raid1c34), |
|---|
| 209 | 281 | NULL |
|---|
| 210 | 282 | }; |
|---|
| 211 | 283 | |
|---|
| .. | .. |
|---|
| 225 | 297 | static ssize_t rmdir_subvol_show(struct kobject *kobj, |
|---|
| 226 | 298 | struct kobj_attribute *ka, char *buf) |
|---|
| 227 | 299 | { |
|---|
| 228 | | - return snprintf(buf, PAGE_SIZE, "0\n"); |
|---|
| 300 | + return scnprintf(buf, PAGE_SIZE, "0\n"); |
|---|
| 229 | 301 | } |
|---|
| 230 | 302 | BTRFS_ATTR(static_feature, rmdir_subvol, rmdir_subvol_show); |
|---|
| 231 | 303 | |
|---|
| 304 | +static ssize_t supported_checksums_show(struct kobject *kobj, |
|---|
| 305 | + struct kobj_attribute *a, char *buf) |
|---|
| 306 | +{ |
|---|
| 307 | + ssize_t ret = 0; |
|---|
| 308 | + int i; |
|---|
| 309 | + |
|---|
| 310 | + for (i = 0; i < btrfs_get_num_csums(); i++) { |
|---|
| 311 | + /* |
|---|
| 312 | + * This "trick" only works as long as 'enum btrfs_csum_type' has |
|---|
| 313 | + * no holes in it |
|---|
| 314 | + */ |
|---|
| 315 | + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s%s", |
|---|
| 316 | + (i == 0 ? "" : " "), btrfs_super_csum_name(i)); |
|---|
| 317 | + |
|---|
| 318 | + } |
|---|
| 319 | + |
|---|
| 320 | + ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); |
|---|
| 321 | + return ret; |
|---|
| 322 | +} |
|---|
| 323 | +BTRFS_ATTR(static_feature, supported_checksums, supported_checksums_show); |
|---|
| 324 | + |
|---|
| 325 | +static ssize_t send_stream_version_show(struct kobject *kobj, |
|---|
| 326 | + struct kobj_attribute *ka, char *buf) |
|---|
| 327 | +{ |
|---|
| 328 | + return snprintf(buf, PAGE_SIZE, "%d\n", BTRFS_SEND_STREAM_VERSION); |
|---|
| 329 | +} |
|---|
| 330 | +BTRFS_ATTR(static_feature, send_stream_version, send_stream_version_show); |
|---|
| 331 | + |
|---|
| 232 | 332 | static struct attribute *btrfs_supported_static_feature_attrs[] = { |
|---|
| 233 | 333 | BTRFS_ATTR_PTR(static_feature, rmdir_subvol), |
|---|
| 334 | + BTRFS_ATTR_PTR(static_feature, supported_checksums), |
|---|
| 335 | + BTRFS_ATTR_PTR(static_feature, send_stream_version), |
|---|
| 234 | 336 | NULL |
|---|
| 235 | 337 | }; |
|---|
| 236 | 338 | |
|---|
| .. | .. |
|---|
| 245 | 347 | .attrs = btrfs_supported_static_feature_attrs, |
|---|
| 246 | 348 | }; |
|---|
| 247 | 349 | |
|---|
| 350 | +#ifdef CONFIG_BTRFS_DEBUG |
|---|
| 351 | + |
|---|
| 352 | +/* |
|---|
| 353 | + * Discard statistics and tunables |
|---|
| 354 | + */ |
|---|
| 355 | +#define discard_to_fs_info(_kobj) to_fs_info((_kobj)->parent->parent) |
|---|
| 356 | + |
|---|
| 357 | +static ssize_t btrfs_discardable_bytes_show(struct kobject *kobj, |
|---|
| 358 | + struct kobj_attribute *a, |
|---|
| 359 | + char *buf) |
|---|
| 360 | +{ |
|---|
| 361 | + struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
|---|
| 362 | + |
|---|
| 363 | + return scnprintf(buf, PAGE_SIZE, "%lld\n", |
|---|
| 364 | + atomic64_read(&fs_info->discard_ctl.discardable_bytes)); |
|---|
| 365 | +} |
|---|
| 366 | +BTRFS_ATTR(discard, discardable_bytes, btrfs_discardable_bytes_show); |
|---|
| 367 | + |
|---|
| 368 | +static ssize_t btrfs_discardable_extents_show(struct kobject *kobj, |
|---|
| 369 | + struct kobj_attribute *a, |
|---|
| 370 | + char *buf) |
|---|
| 371 | +{ |
|---|
| 372 | + struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
|---|
| 373 | + |
|---|
| 374 | + return scnprintf(buf, PAGE_SIZE, "%d\n", |
|---|
| 375 | + atomic_read(&fs_info->discard_ctl.discardable_extents)); |
|---|
| 376 | +} |
|---|
| 377 | +BTRFS_ATTR(discard, discardable_extents, btrfs_discardable_extents_show); |
|---|
| 378 | + |
|---|
| 379 | +static ssize_t btrfs_discard_bitmap_bytes_show(struct kobject *kobj, |
|---|
| 380 | + struct kobj_attribute *a, |
|---|
| 381 | + char *buf) |
|---|
| 382 | +{ |
|---|
| 383 | + struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
|---|
| 384 | + |
|---|
| 385 | + return scnprintf(buf, PAGE_SIZE, "%llu\n", |
|---|
| 386 | + fs_info->discard_ctl.discard_bitmap_bytes); |
|---|
| 387 | +} |
|---|
| 388 | +BTRFS_ATTR(discard, discard_bitmap_bytes, btrfs_discard_bitmap_bytes_show); |
|---|
| 389 | + |
|---|
| 390 | +static ssize_t btrfs_discard_bytes_saved_show(struct kobject *kobj, |
|---|
| 391 | + struct kobj_attribute *a, |
|---|
| 392 | + char *buf) |
|---|
| 393 | +{ |
|---|
| 394 | + struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
|---|
| 395 | + |
|---|
| 396 | + return scnprintf(buf, PAGE_SIZE, "%lld\n", |
|---|
| 397 | + atomic64_read(&fs_info->discard_ctl.discard_bytes_saved)); |
|---|
| 398 | +} |
|---|
| 399 | +BTRFS_ATTR(discard, discard_bytes_saved, btrfs_discard_bytes_saved_show); |
|---|
| 400 | + |
|---|
| 401 | +static ssize_t btrfs_discard_extent_bytes_show(struct kobject *kobj, |
|---|
| 402 | + struct kobj_attribute *a, |
|---|
| 403 | + char *buf) |
|---|
| 404 | +{ |
|---|
| 405 | + struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
|---|
| 406 | + |
|---|
| 407 | + return scnprintf(buf, PAGE_SIZE, "%llu\n", |
|---|
| 408 | + fs_info->discard_ctl.discard_extent_bytes); |
|---|
| 409 | +} |
|---|
| 410 | +BTRFS_ATTR(discard, discard_extent_bytes, btrfs_discard_extent_bytes_show); |
|---|
| 411 | + |
|---|
| 412 | +static ssize_t btrfs_discard_iops_limit_show(struct kobject *kobj, |
|---|
| 413 | + struct kobj_attribute *a, |
|---|
| 414 | + char *buf) |
|---|
| 415 | +{ |
|---|
| 416 | + struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
|---|
| 417 | + |
|---|
| 418 | + return scnprintf(buf, PAGE_SIZE, "%u\n", |
|---|
| 419 | + READ_ONCE(fs_info->discard_ctl.iops_limit)); |
|---|
| 420 | +} |
|---|
| 421 | + |
|---|
| 422 | +static ssize_t btrfs_discard_iops_limit_store(struct kobject *kobj, |
|---|
| 423 | + struct kobj_attribute *a, |
|---|
| 424 | + const char *buf, size_t len) |
|---|
| 425 | +{ |
|---|
| 426 | + struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
|---|
| 427 | + struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl; |
|---|
| 428 | + u32 iops_limit; |
|---|
| 429 | + int ret; |
|---|
| 430 | + |
|---|
| 431 | + ret = kstrtou32(buf, 10, &iops_limit); |
|---|
| 432 | + if (ret) |
|---|
| 433 | + return -EINVAL; |
|---|
| 434 | + |
|---|
| 435 | + WRITE_ONCE(discard_ctl->iops_limit, iops_limit); |
|---|
| 436 | + |
|---|
| 437 | + return len; |
|---|
| 438 | +} |
|---|
| 439 | +BTRFS_ATTR_RW(discard, iops_limit, btrfs_discard_iops_limit_show, |
|---|
| 440 | + btrfs_discard_iops_limit_store); |
|---|
| 441 | + |
|---|
| 442 | +static ssize_t btrfs_discard_kbps_limit_show(struct kobject *kobj, |
|---|
| 443 | + struct kobj_attribute *a, |
|---|
| 444 | + char *buf) |
|---|
| 445 | +{ |
|---|
| 446 | + struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
|---|
| 447 | + |
|---|
| 448 | + return scnprintf(buf, PAGE_SIZE, "%u\n", |
|---|
| 449 | + READ_ONCE(fs_info->discard_ctl.kbps_limit)); |
|---|
| 450 | +} |
|---|
| 451 | + |
|---|
| 452 | +static ssize_t btrfs_discard_kbps_limit_store(struct kobject *kobj, |
|---|
| 453 | + struct kobj_attribute *a, |
|---|
| 454 | + const char *buf, size_t len) |
|---|
| 455 | +{ |
|---|
| 456 | + struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
|---|
| 457 | + struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl; |
|---|
| 458 | + u32 kbps_limit; |
|---|
| 459 | + int ret; |
|---|
| 460 | + |
|---|
| 461 | + ret = kstrtou32(buf, 10, &kbps_limit); |
|---|
| 462 | + if (ret) |
|---|
| 463 | + return -EINVAL; |
|---|
| 464 | + |
|---|
| 465 | + WRITE_ONCE(discard_ctl->kbps_limit, kbps_limit); |
|---|
| 466 | + |
|---|
| 467 | + return len; |
|---|
| 468 | +} |
|---|
| 469 | +BTRFS_ATTR_RW(discard, kbps_limit, btrfs_discard_kbps_limit_show, |
|---|
| 470 | + btrfs_discard_kbps_limit_store); |
|---|
| 471 | + |
|---|
| 472 | +static ssize_t btrfs_discard_max_discard_size_show(struct kobject *kobj, |
|---|
| 473 | + struct kobj_attribute *a, |
|---|
| 474 | + char *buf) |
|---|
| 475 | +{ |
|---|
| 476 | + struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
|---|
| 477 | + |
|---|
| 478 | + return scnprintf(buf, PAGE_SIZE, "%llu\n", |
|---|
| 479 | + READ_ONCE(fs_info->discard_ctl.max_discard_size)); |
|---|
| 480 | +} |
|---|
| 481 | + |
|---|
| 482 | +static ssize_t btrfs_discard_max_discard_size_store(struct kobject *kobj, |
|---|
| 483 | + struct kobj_attribute *a, |
|---|
| 484 | + const char *buf, size_t len) |
|---|
| 485 | +{ |
|---|
| 486 | + struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); |
|---|
| 487 | + struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl; |
|---|
| 488 | + u64 max_discard_size; |
|---|
| 489 | + int ret; |
|---|
| 490 | + |
|---|
| 491 | + ret = kstrtou64(buf, 10, &max_discard_size); |
|---|
| 492 | + if (ret) |
|---|
| 493 | + return -EINVAL; |
|---|
| 494 | + |
|---|
| 495 | + WRITE_ONCE(discard_ctl->max_discard_size, max_discard_size); |
|---|
| 496 | + |
|---|
| 497 | + return len; |
|---|
| 498 | +} |
|---|
| 499 | +BTRFS_ATTR_RW(discard, max_discard_size, btrfs_discard_max_discard_size_show, |
|---|
| 500 | + btrfs_discard_max_discard_size_store); |
|---|
| 501 | + |
|---|
| 502 | +static const struct attribute *discard_debug_attrs[] = { |
|---|
| 503 | + BTRFS_ATTR_PTR(discard, discardable_bytes), |
|---|
| 504 | + BTRFS_ATTR_PTR(discard, discardable_extents), |
|---|
| 505 | + BTRFS_ATTR_PTR(discard, discard_bitmap_bytes), |
|---|
| 506 | + BTRFS_ATTR_PTR(discard, discard_bytes_saved), |
|---|
| 507 | + BTRFS_ATTR_PTR(discard, discard_extent_bytes), |
|---|
| 508 | + BTRFS_ATTR_PTR(discard, iops_limit), |
|---|
| 509 | + BTRFS_ATTR_PTR(discard, kbps_limit), |
|---|
| 510 | + BTRFS_ATTR_PTR(discard, max_discard_size), |
|---|
| 511 | + NULL, |
|---|
| 512 | +}; |
|---|
| 513 | + |
|---|
| 514 | +/* |
|---|
| 515 | + * Runtime debugging exported via sysfs |
|---|
| 516 | + * |
|---|
| 517 | + * /sys/fs/btrfs/debug - applies to module or all filesystems |
|---|
| 518 | + * /sys/fs/btrfs/UUID - applies only to the given filesystem |
|---|
| 519 | + */ |
|---|
| 520 | +static const struct attribute *btrfs_debug_mount_attrs[] = { |
|---|
| 521 | + NULL, |
|---|
| 522 | +}; |
|---|
| 523 | + |
|---|
| 524 | +static struct attribute *btrfs_debug_feature_attrs[] = { |
|---|
| 525 | + NULL |
|---|
| 526 | +}; |
|---|
| 527 | + |
|---|
| 528 | +static const struct attribute_group btrfs_debug_feature_attr_group = { |
|---|
| 529 | + .name = "debug", |
|---|
| 530 | + .attrs = btrfs_debug_feature_attrs, |
|---|
| 531 | +}; |
|---|
| 532 | + |
|---|
| 533 | +#endif |
|---|
| 534 | + |
|---|
| 248 | 535 | static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf) |
|---|
| 249 | 536 | { |
|---|
| 250 | 537 | u64 val; |
|---|
| .. | .. |
|---|
| 253 | 540 | val = *value_ptr; |
|---|
| 254 | 541 | if (lock) |
|---|
| 255 | 542 | spin_unlock(lock); |
|---|
| 256 | | - return snprintf(buf, PAGE_SIZE, "%llu\n", val); |
|---|
| 543 | + return scnprintf(buf, PAGE_SIZE, "%llu\n", val); |
|---|
| 257 | 544 | } |
|---|
| 258 | 545 | |
|---|
| 259 | 546 | static ssize_t global_rsv_size_show(struct kobject *kobj, |
|---|
| .. | .. |
|---|
| 287 | 574 | |
|---|
| 288 | 575 | { |
|---|
| 289 | 576 | struct btrfs_space_info *sinfo = to_space_info(kobj->parent); |
|---|
| 290 | | - struct btrfs_block_group_cache *block_group; |
|---|
| 577 | + struct btrfs_block_group *block_group; |
|---|
| 291 | 578 | int index = btrfs_bg_flags_to_raid_index(to_raid_kobj(kobj)->flags); |
|---|
| 292 | 579 | u64 val = 0; |
|---|
| 293 | 580 | |
|---|
| 294 | 581 | down_read(&sinfo->groups_sem); |
|---|
| 295 | 582 | list_for_each_entry(block_group, &sinfo->block_groups[index], list) { |
|---|
| 296 | 583 | if (&attr->attr == BTRFS_ATTR_PTR(raid, total_bytes)) |
|---|
| 297 | | - val += block_group->key.offset; |
|---|
| 584 | + val += block_group->length; |
|---|
| 298 | 585 | else |
|---|
| 299 | | - val += btrfs_block_group_used(&block_group->item); |
|---|
| 586 | + val += block_group->used; |
|---|
| 300 | 587 | } |
|---|
| 301 | 588 | up_read(&sinfo->groups_sem); |
|---|
| 302 | | - return snprintf(buf, PAGE_SIZE, "%llu\n", val); |
|---|
| 589 | + return scnprintf(buf, PAGE_SIZE, "%llu\n", val); |
|---|
| 303 | 590 | } |
|---|
| 304 | 591 | |
|---|
| 305 | | -static struct attribute *raid_attributes[] = { |
|---|
| 592 | +static struct attribute *raid_attrs[] = { |
|---|
| 306 | 593 | BTRFS_ATTR_PTR(raid, total_bytes), |
|---|
| 307 | 594 | BTRFS_ATTR_PTR(raid, used_bytes), |
|---|
| 308 | 595 | NULL |
|---|
| 309 | 596 | }; |
|---|
| 597 | +ATTRIBUTE_GROUPS(raid); |
|---|
| 310 | 598 | |
|---|
| 311 | 599 | static void release_raid_kobj(struct kobject *kobj) |
|---|
| 312 | 600 | { |
|---|
| 313 | 601 | kfree(to_raid_kobj(kobj)); |
|---|
| 314 | 602 | } |
|---|
| 315 | 603 | |
|---|
| 316 | | -struct kobj_type btrfs_raid_ktype = { |
|---|
| 604 | +static struct kobj_type btrfs_raid_ktype = { |
|---|
| 317 | 605 | .sysfs_ops = &kobj_sysfs_ops, |
|---|
| 318 | 606 | .release = release_raid_kobj, |
|---|
| 319 | | - .default_attrs = raid_attributes, |
|---|
| 607 | + .default_groups = raid_groups, |
|---|
| 320 | 608 | }; |
|---|
| 321 | 609 | |
|---|
| 322 | 610 | #define SPACE_INFO_ATTR(field) \ |
|---|
| .. | .. |
|---|
| 335 | 623 | { |
|---|
| 336 | 624 | struct btrfs_space_info *sinfo = to_space_info(kobj); |
|---|
| 337 | 625 | s64 val = percpu_counter_sum(&sinfo->total_bytes_pinned); |
|---|
| 338 | | - return snprintf(buf, PAGE_SIZE, "%lld\n", val); |
|---|
| 626 | + return scnprintf(buf, PAGE_SIZE, "%lld\n", val); |
|---|
| 339 | 627 | } |
|---|
| 340 | 628 | |
|---|
| 341 | 629 | SPACE_INFO_ATTR(flags); |
|---|
| .. | .. |
|---|
| 363 | 651 | BTRFS_ATTR_PTR(space_info, total_bytes_pinned), |
|---|
| 364 | 652 | NULL, |
|---|
| 365 | 653 | }; |
|---|
| 654 | +ATTRIBUTE_GROUPS(space_info); |
|---|
| 366 | 655 | |
|---|
| 367 | 656 | static void space_info_release(struct kobject *kobj) |
|---|
| 368 | 657 | { |
|---|
| .. | .. |
|---|
| 371 | 660 | kfree(sinfo); |
|---|
| 372 | 661 | } |
|---|
| 373 | 662 | |
|---|
| 374 | | -struct kobj_type space_info_ktype = { |
|---|
| 663 | +static struct kobj_type space_info_ktype = { |
|---|
| 375 | 664 | .sysfs_ops = &kobj_sysfs_ops, |
|---|
| 376 | 665 | .release = space_info_release, |
|---|
| 377 | | - .default_attrs = space_info_attrs, |
|---|
| 666 | + .default_groups = space_info_groups, |
|---|
| 378 | 667 | }; |
|---|
| 379 | 668 | |
|---|
| 380 | 669 | static const struct attribute *allocation_attrs[] = { |
|---|
| .. | .. |
|---|
| 391 | 680 | ssize_t ret; |
|---|
| 392 | 681 | |
|---|
| 393 | 682 | spin_lock(&fs_info->super_lock); |
|---|
| 394 | | - ret = snprintf(buf, PAGE_SIZE, label[0] ? "%s\n" : "%s", label); |
|---|
| 683 | + ret = scnprintf(buf, PAGE_SIZE, label[0] ? "%s\n" : "%s", label); |
|---|
| 395 | 684 | spin_unlock(&fs_info->super_lock); |
|---|
| 396 | 685 | |
|---|
| 397 | 686 | return ret; |
|---|
| .. | .. |
|---|
| 439 | 728 | { |
|---|
| 440 | 729 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
|---|
| 441 | 730 | |
|---|
| 442 | | - return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->nodesize); |
|---|
| 731 | + return scnprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->nodesize); |
|---|
| 443 | 732 | } |
|---|
| 444 | 733 | |
|---|
| 445 | 734 | BTRFS_ATTR(, nodesize, btrfs_nodesize_show); |
|---|
| .. | .. |
|---|
| 449 | 738 | { |
|---|
| 450 | 739 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
|---|
| 451 | 740 | |
|---|
| 452 | | - return snprintf(buf, PAGE_SIZE, "%u\n", |
|---|
| 453 | | - fs_info->super_copy->sectorsize); |
|---|
| 741 | + return scnprintf(buf, PAGE_SIZE, "%u\n", |
|---|
| 742 | + fs_info->super_copy->sectorsize); |
|---|
| 454 | 743 | } |
|---|
| 455 | 744 | |
|---|
| 456 | 745 | BTRFS_ATTR(, sectorsize, btrfs_sectorsize_show); |
|---|
| .. | .. |
|---|
| 460 | 749 | { |
|---|
| 461 | 750 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
|---|
| 462 | 751 | |
|---|
| 463 | | - return snprintf(buf, PAGE_SIZE, "%u\n", |
|---|
| 464 | | - fs_info->super_copy->sectorsize); |
|---|
| 752 | + return scnprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->sectorsize); |
|---|
| 465 | 753 | } |
|---|
| 466 | 754 | |
|---|
| 467 | 755 | BTRFS_ATTR(, clone_alignment, btrfs_clone_alignment_show); |
|---|
| .. | .. |
|---|
| 473 | 761 | int quota_override; |
|---|
| 474 | 762 | |
|---|
| 475 | 763 | quota_override = test_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags); |
|---|
| 476 | | - return snprintf(buf, PAGE_SIZE, "%d\n", quota_override); |
|---|
| 764 | + return scnprintf(buf, PAGE_SIZE, "%d\n", quota_override); |
|---|
| 477 | 765 | } |
|---|
| 478 | 766 | |
|---|
| 479 | 767 | static ssize_t quota_override_store(struct kobject *kobj, |
|---|
| .. | .. |
|---|
| 506 | 794 | |
|---|
| 507 | 795 | BTRFS_ATTR_RW(, quota_override, quota_override_show, quota_override_store); |
|---|
| 508 | 796 | |
|---|
| 797 | +static ssize_t btrfs_metadata_uuid_show(struct kobject *kobj, |
|---|
| 798 | + struct kobj_attribute *a, char *buf) |
|---|
| 799 | +{ |
|---|
| 800 | + struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
|---|
| 801 | + |
|---|
| 802 | + return scnprintf(buf, PAGE_SIZE, "%pU\n", |
|---|
| 803 | + fs_info->fs_devices->metadata_uuid); |
|---|
| 804 | +} |
|---|
| 805 | + |
|---|
| 806 | +BTRFS_ATTR(, metadata_uuid, btrfs_metadata_uuid_show); |
|---|
| 807 | + |
|---|
| 808 | +static ssize_t btrfs_checksum_show(struct kobject *kobj, |
|---|
| 809 | + struct kobj_attribute *a, char *buf) |
|---|
| 810 | +{ |
|---|
| 811 | + struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
|---|
| 812 | + u16 csum_type = btrfs_super_csum_type(fs_info->super_copy); |
|---|
| 813 | + |
|---|
| 814 | + return scnprintf(buf, PAGE_SIZE, "%s (%s)\n", |
|---|
| 815 | + btrfs_super_csum_name(csum_type), |
|---|
| 816 | + crypto_shash_driver_name(fs_info->csum_shash)); |
|---|
| 817 | +} |
|---|
| 818 | + |
|---|
| 819 | +BTRFS_ATTR(, checksum, btrfs_checksum_show); |
|---|
| 820 | + |
|---|
| 821 | +static ssize_t btrfs_exclusive_operation_show(struct kobject *kobj, |
|---|
| 822 | + struct kobj_attribute *a, char *buf) |
|---|
| 823 | +{ |
|---|
| 824 | + struct btrfs_fs_info *fs_info = to_fs_info(kobj); |
|---|
| 825 | + const char *str; |
|---|
| 826 | + |
|---|
| 827 | + switch (READ_ONCE(fs_info->exclusive_operation)) { |
|---|
| 828 | + case BTRFS_EXCLOP_NONE: |
|---|
| 829 | + str = "none\n"; |
|---|
| 830 | + break; |
|---|
| 831 | + case BTRFS_EXCLOP_BALANCE: |
|---|
| 832 | + str = "balance\n"; |
|---|
| 833 | + break; |
|---|
| 834 | + case BTRFS_EXCLOP_DEV_ADD: |
|---|
| 835 | + str = "device add\n"; |
|---|
| 836 | + break; |
|---|
| 837 | + case BTRFS_EXCLOP_DEV_REMOVE: |
|---|
| 838 | + str = "device remove\n"; |
|---|
| 839 | + break; |
|---|
| 840 | + case BTRFS_EXCLOP_DEV_REPLACE: |
|---|
| 841 | + str = "device replace\n"; |
|---|
| 842 | + break; |
|---|
| 843 | + case BTRFS_EXCLOP_RESIZE: |
|---|
| 844 | + str = "resize\n"; |
|---|
| 845 | + break; |
|---|
| 846 | + case BTRFS_EXCLOP_SWAP_ACTIVATE: |
|---|
| 847 | + str = "swap activate\n"; |
|---|
| 848 | + break; |
|---|
| 849 | + default: |
|---|
| 850 | + str = "UNKNOWN\n"; |
|---|
| 851 | + break; |
|---|
| 852 | + } |
|---|
| 853 | + return scnprintf(buf, PAGE_SIZE, "%s", str); |
|---|
| 854 | +} |
|---|
| 855 | +BTRFS_ATTR(, exclusive_operation, btrfs_exclusive_operation_show); |
|---|
| 856 | + |
|---|
| 509 | 857 | static const struct attribute *btrfs_attrs[] = { |
|---|
| 510 | 858 | BTRFS_ATTR_PTR(, label), |
|---|
| 511 | 859 | BTRFS_ATTR_PTR(, nodesize), |
|---|
| 512 | 860 | BTRFS_ATTR_PTR(, sectorsize), |
|---|
| 513 | 861 | BTRFS_ATTR_PTR(, clone_alignment), |
|---|
| 514 | 862 | BTRFS_ATTR_PTR(, quota_override), |
|---|
| 863 | + BTRFS_ATTR_PTR(, metadata_uuid), |
|---|
| 864 | + BTRFS_ATTR_PTR(, checksum), |
|---|
| 865 | + BTRFS_ATTR_PTR(, exclusive_operation), |
|---|
| 515 | 866 | NULL, |
|---|
| 516 | 867 | }; |
|---|
| 517 | 868 | |
|---|
| .. | .. |
|---|
| 596 | 947 | |
|---|
| 597 | 948 | static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) |
|---|
| 598 | 949 | { |
|---|
| 599 | | - if (fs_devs->device_dir_kobj) { |
|---|
| 600 | | - kobject_del(fs_devs->device_dir_kobj); |
|---|
| 601 | | - kobject_put(fs_devs->device_dir_kobj); |
|---|
| 602 | | - fs_devs->device_dir_kobj = NULL; |
|---|
| 950 | + if (fs_devs->devinfo_kobj) { |
|---|
| 951 | + kobject_del(fs_devs->devinfo_kobj); |
|---|
| 952 | + kobject_put(fs_devs->devinfo_kobj); |
|---|
| 953 | + fs_devs->devinfo_kobj = NULL; |
|---|
| 954 | + } |
|---|
| 955 | + |
|---|
| 956 | + if (fs_devs->devices_kobj) { |
|---|
| 957 | + kobject_del(fs_devs->devices_kobj); |
|---|
| 958 | + kobject_put(fs_devs->devices_kobj); |
|---|
| 959 | + fs_devs->devices_kobj = NULL; |
|---|
| 603 | 960 | } |
|---|
| 604 | 961 | |
|---|
| 605 | 962 | if (fs_devs->fsid_kobj.state_initialized) { |
|---|
| .. | .. |
|---|
| 624 | 981 | } |
|---|
| 625 | 982 | } |
|---|
| 626 | 983 | |
|---|
| 984 | +static void btrfs_sysfs_remove_fs_devices(struct btrfs_fs_devices *fs_devices) |
|---|
| 985 | +{ |
|---|
| 986 | + struct btrfs_device *device; |
|---|
| 987 | + struct btrfs_fs_devices *seed; |
|---|
| 988 | + |
|---|
| 989 | + list_for_each_entry(device, &fs_devices->devices, dev_list) |
|---|
| 990 | + btrfs_sysfs_remove_device(device); |
|---|
| 991 | + |
|---|
| 992 | + list_for_each_entry(seed, &fs_devices->seed_list, seed_list) { |
|---|
| 993 | + list_for_each_entry(device, &seed->devices, dev_list) |
|---|
| 994 | + btrfs_sysfs_remove_device(device); |
|---|
| 995 | + } |
|---|
| 996 | +} |
|---|
| 997 | + |
|---|
| 627 | 998 | void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info) |
|---|
| 628 | 999 | { |
|---|
| 629 | | - btrfs_reset_fs_info_ptr(fs_info); |
|---|
| 1000 | + struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj; |
|---|
| 1001 | + |
|---|
| 1002 | + sysfs_remove_link(fsid_kobj, "bdi"); |
|---|
| 630 | 1003 | |
|---|
| 631 | 1004 | if (fs_info->space_info_kobj) { |
|---|
| 632 | 1005 | sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs); |
|---|
| 633 | 1006 | kobject_del(fs_info->space_info_kobj); |
|---|
| 634 | 1007 | kobject_put(fs_info->space_info_kobj); |
|---|
| 635 | 1008 | } |
|---|
| 1009 | +#ifdef CONFIG_BTRFS_DEBUG |
|---|
| 1010 | + if (fs_info->discard_debug_kobj) { |
|---|
| 1011 | + sysfs_remove_files(fs_info->discard_debug_kobj, |
|---|
| 1012 | + discard_debug_attrs); |
|---|
| 1013 | + kobject_del(fs_info->discard_debug_kobj); |
|---|
| 1014 | + kobject_put(fs_info->discard_debug_kobj); |
|---|
| 1015 | + } |
|---|
| 1016 | + if (fs_info->debug_kobj) { |
|---|
| 1017 | + sysfs_remove_files(fs_info->debug_kobj, btrfs_debug_mount_attrs); |
|---|
| 1018 | + kobject_del(fs_info->debug_kobj); |
|---|
| 1019 | + kobject_put(fs_info->debug_kobj); |
|---|
| 1020 | + } |
|---|
| 1021 | +#endif |
|---|
| 636 | 1022 | addrm_unknown_feature_attrs(fs_info, false); |
|---|
| 637 | | - sysfs_remove_group(&fs_info->fs_devices->fsid_kobj, &btrfs_feature_attr_group); |
|---|
| 638 | | - sysfs_remove_files(&fs_info->fs_devices->fsid_kobj, btrfs_attrs); |
|---|
| 639 | | - btrfs_sysfs_rm_device_link(fs_info->fs_devices, NULL); |
|---|
| 1023 | + sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group); |
|---|
| 1024 | + sysfs_remove_files(fsid_kobj, btrfs_attrs); |
|---|
| 1025 | + btrfs_sysfs_remove_fs_devices(fs_info->fs_devices); |
|---|
| 640 | 1026 | } |
|---|
| 641 | 1027 | |
|---|
| 642 | | -const char * const btrfs_feature_set_names[FEAT_MAX] = { |
|---|
| 1028 | +static const char * const btrfs_feature_set_names[FEAT_MAX] = { |
|---|
| 643 | 1029 | [FEAT_COMPAT] = "compat", |
|---|
| 644 | 1030 | [FEAT_COMPAT_RO] = "compat_ro", |
|---|
| 645 | 1031 | [FEAT_INCOMPAT] = "incompat", |
|---|
| 646 | 1032 | }; |
|---|
| 1033 | + |
|---|
| 1034 | +const char *btrfs_feature_set_name(enum btrfs_feature_set set) |
|---|
| 1035 | +{ |
|---|
| 1036 | + return btrfs_feature_set_names[set]; |
|---|
| 1037 | +} |
|---|
| 647 | 1038 | |
|---|
| 648 | 1039 | char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags) |
|---|
| 649 | 1040 | { |
|---|
| .. | .. |
|---|
| 663 | 1054 | continue; |
|---|
| 664 | 1055 | |
|---|
| 665 | 1056 | name = btrfs_feature_attrs[set][i].kobj_attr.attr.name; |
|---|
| 666 | | - len += snprintf(str + len, bufsize - len, "%s%s", |
|---|
| 1057 | + len += scnprintf(str + len, bufsize - len, "%s%s", |
|---|
| 667 | 1058 | len ? "," : "", name); |
|---|
| 668 | 1059 | } |
|---|
| 669 | 1060 | |
|---|
| .. | .. |
|---|
| 714 | 1105 | } |
|---|
| 715 | 1106 | } |
|---|
| 716 | 1107 | |
|---|
| 717 | | -/* when one_device is NULL, it removes all device links */ |
|---|
| 1108 | +/* |
|---|
| 1109 | + * Create a sysfs entry for a given block group type at path |
|---|
| 1110 | + * /sys/fs/btrfs/UUID/allocation/data/TYPE |
|---|
| 1111 | + */ |
|---|
| 1112 | +void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache) |
|---|
| 1113 | +{ |
|---|
| 1114 | + struct btrfs_fs_info *fs_info = cache->fs_info; |
|---|
| 1115 | + struct btrfs_space_info *space_info = cache->space_info; |
|---|
| 1116 | + struct raid_kobject *rkobj; |
|---|
| 1117 | + const int index = btrfs_bg_flags_to_raid_index(cache->flags); |
|---|
| 1118 | + unsigned int nofs_flag; |
|---|
| 1119 | + int ret; |
|---|
| 718 | 1120 | |
|---|
| 719 | | -int btrfs_sysfs_rm_device_link(struct btrfs_fs_devices *fs_devices, |
|---|
| 720 | | - struct btrfs_device *one_device) |
|---|
| 1121 | + /* |
|---|
| 1122 | + * Setup a NOFS context because kobject_add(), deep in its call chain, |
|---|
| 1123 | + * does GFP_KERNEL allocations, and we are often called in a context |
|---|
| 1124 | + * where if reclaim is triggered we can deadlock (we are either holding |
|---|
| 1125 | + * a transaction handle or some lock required for a transaction |
|---|
| 1126 | + * commit). |
|---|
| 1127 | + */ |
|---|
| 1128 | + nofs_flag = memalloc_nofs_save(); |
|---|
| 1129 | + |
|---|
| 1130 | + rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS); |
|---|
| 1131 | + if (!rkobj) { |
|---|
| 1132 | + memalloc_nofs_restore(nofs_flag); |
|---|
| 1133 | + btrfs_warn(cache->fs_info, |
|---|
| 1134 | + "couldn't alloc memory for raid level kobject"); |
|---|
| 1135 | + return; |
|---|
| 1136 | + } |
|---|
| 1137 | + |
|---|
| 1138 | + rkobj->flags = cache->flags; |
|---|
| 1139 | + kobject_init(&rkobj->kobj, &btrfs_raid_ktype); |
|---|
| 1140 | + |
|---|
| 1141 | + /* |
|---|
| 1142 | + * We call this either on mount, or if we've created a block group for a |
|---|
| 1143 | + * new index type while running (i.e. when restriping). The running |
|---|
| 1144 | + * case is tricky because we could race with other threads, so we need |
|---|
| 1145 | + * to have this check to make sure we didn't already init the kobject. |
|---|
| 1146 | + * |
|---|
| 1147 | + * We don't have to protect on the free side because it only happens on |
|---|
| 1148 | + * unmount. |
|---|
| 1149 | + */ |
|---|
| 1150 | + spin_lock(&space_info->lock); |
|---|
| 1151 | + if (space_info->block_group_kobjs[index]) { |
|---|
| 1152 | + spin_unlock(&space_info->lock); |
|---|
| 1153 | + kobject_put(&rkobj->kobj); |
|---|
| 1154 | + return; |
|---|
| 1155 | + } else { |
|---|
| 1156 | + space_info->block_group_kobjs[index] = &rkobj->kobj; |
|---|
| 1157 | + } |
|---|
| 1158 | + spin_unlock(&space_info->lock); |
|---|
| 1159 | + |
|---|
| 1160 | + ret = kobject_add(&rkobj->kobj, &space_info->kobj, "%s", |
|---|
| 1161 | + btrfs_bg_type_to_raid_name(rkobj->flags)); |
|---|
| 1162 | + memalloc_nofs_restore(nofs_flag); |
|---|
| 1163 | + if (ret) { |
|---|
| 1164 | + spin_lock(&space_info->lock); |
|---|
| 1165 | + space_info->block_group_kobjs[index] = NULL; |
|---|
| 1166 | + spin_unlock(&space_info->lock); |
|---|
| 1167 | + kobject_put(&rkobj->kobj); |
|---|
| 1168 | + btrfs_warn(fs_info, |
|---|
| 1169 | + "failed to add kobject for block cache, ignoring"); |
|---|
| 1170 | + return; |
|---|
| 1171 | + } |
|---|
| 1172 | +} |
|---|
| 1173 | + |
|---|
| 1174 | +/* |
|---|
| 1175 | + * Remove sysfs directories for all block group types of a given space info and |
|---|
| 1176 | + * the space info as well |
|---|
| 1177 | + */ |
|---|
| 1178 | +void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info) |
|---|
| 1179 | +{ |
|---|
| 1180 | + int i; |
|---|
| 1181 | + |
|---|
| 1182 | + for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) { |
|---|
| 1183 | + struct kobject *kobj; |
|---|
| 1184 | + |
|---|
| 1185 | + kobj = space_info->block_group_kobjs[i]; |
|---|
| 1186 | + space_info->block_group_kobjs[i] = NULL; |
|---|
| 1187 | + if (kobj) { |
|---|
| 1188 | + kobject_del(kobj); |
|---|
| 1189 | + kobject_put(kobj); |
|---|
| 1190 | + } |
|---|
| 1191 | + } |
|---|
| 1192 | + kobject_del(&space_info->kobj); |
|---|
| 1193 | + kobject_put(&space_info->kobj); |
|---|
| 1194 | +} |
|---|
| 1195 | + |
|---|
| 1196 | +static const char *alloc_name(u64 flags) |
|---|
| 1197 | +{ |
|---|
| 1198 | + switch (flags) { |
|---|
| 1199 | + case BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA: |
|---|
| 1200 | + return "mixed"; |
|---|
| 1201 | + case BTRFS_BLOCK_GROUP_METADATA: |
|---|
| 1202 | + return "metadata"; |
|---|
| 1203 | + case BTRFS_BLOCK_GROUP_DATA: |
|---|
| 1204 | + return "data"; |
|---|
| 1205 | + case BTRFS_BLOCK_GROUP_SYSTEM: |
|---|
| 1206 | + return "system"; |
|---|
| 1207 | + default: |
|---|
| 1208 | + WARN_ON(1); |
|---|
| 1209 | + return "invalid-combination"; |
|---|
| 1210 | + }; |
|---|
| 1211 | +} |
|---|
| 1212 | + |
|---|
| 1213 | +/* |
|---|
| 1214 | + * Create a sysfs entry for a space info type at path |
|---|
| 1215 | + * /sys/fs/btrfs/UUID/allocation/TYPE |
|---|
| 1216 | + */ |
|---|
| 1217 | +int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info, |
|---|
| 1218 | + struct btrfs_space_info *space_info) |
|---|
| 1219 | +{ |
|---|
| 1220 | + int ret; |
|---|
| 1221 | + |
|---|
| 1222 | + ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype, |
|---|
| 1223 | + fs_info->space_info_kobj, "%s", |
|---|
| 1224 | + alloc_name(space_info->flags)); |
|---|
| 1225 | + if (ret) { |
|---|
| 1226 | + kobject_put(&space_info->kobj); |
|---|
| 1227 | + return ret; |
|---|
| 1228 | + } |
|---|
| 1229 | + |
|---|
| 1230 | + return 0; |
|---|
| 1231 | +} |
|---|
| 1232 | + |
|---|
| 1233 | +void btrfs_sysfs_remove_device(struct btrfs_device *device) |
|---|
| 721 | 1234 | { |
|---|
| 722 | 1235 | struct hd_struct *disk; |
|---|
| 723 | 1236 | struct kobject *disk_kobj; |
|---|
| 1237 | + struct kobject *devices_kobj; |
|---|
| 724 | 1238 | |
|---|
| 725 | | - if (!fs_devices->device_dir_kobj) |
|---|
| 726 | | - return -EINVAL; |
|---|
| 1239 | + /* |
|---|
| 1240 | + * Seed fs_devices devices_kobj aren't used, fetch kobject from the |
|---|
| 1241 | + * fs_info::fs_devices. |
|---|
| 1242 | + */ |
|---|
| 1243 | + devices_kobj = device->fs_info->fs_devices->devices_kobj; |
|---|
| 1244 | + ASSERT(devices_kobj); |
|---|
| 727 | 1245 | |
|---|
| 728 | | - if (one_device && one_device->bdev) { |
|---|
| 729 | | - disk = one_device->bdev->bd_part; |
|---|
| 1246 | + if (device->bdev) { |
|---|
| 1247 | + disk = device->bdev->bd_part; |
|---|
| 730 | 1248 | disk_kobj = &part_to_dev(disk)->kobj; |
|---|
| 731 | | - |
|---|
| 732 | | - sysfs_remove_link(fs_devices->device_dir_kobj, |
|---|
| 733 | | - disk_kobj->name); |
|---|
| 1249 | + sysfs_remove_link(devices_kobj, disk_kobj->name); |
|---|
| 734 | 1250 | } |
|---|
| 735 | 1251 | |
|---|
| 736 | | - if (one_device) |
|---|
| 737 | | - return 0; |
|---|
| 738 | | - |
|---|
| 739 | | - list_for_each_entry(one_device, |
|---|
| 740 | | - &fs_devices->devices, dev_list) { |
|---|
| 741 | | - if (!one_device->bdev) |
|---|
| 742 | | - continue; |
|---|
| 743 | | - disk = one_device->bdev->bd_part; |
|---|
| 744 | | - disk_kobj = &part_to_dev(disk)->kobj; |
|---|
| 745 | | - |
|---|
| 746 | | - sysfs_remove_link(fs_devices->device_dir_kobj, |
|---|
| 747 | | - disk_kobj->name); |
|---|
| 1252 | + if (device->devid_kobj.state_initialized) { |
|---|
| 1253 | + kobject_del(&device->devid_kobj); |
|---|
| 1254 | + kobject_put(&device->devid_kobj); |
|---|
| 1255 | + wait_for_completion(&device->kobj_unregister); |
|---|
| 748 | 1256 | } |
|---|
| 749 | | - |
|---|
| 750 | | - return 0; |
|---|
| 751 | 1257 | } |
|---|
| 752 | 1258 | |
|---|
| 753 | | -int btrfs_sysfs_add_device(struct btrfs_fs_devices *fs_devs) |
|---|
| 1259 | +static ssize_t btrfs_devinfo_in_fs_metadata_show(struct kobject *kobj, |
|---|
| 1260 | + struct kobj_attribute *a, |
|---|
| 1261 | + char *buf) |
|---|
| 754 | 1262 | { |
|---|
| 755 | | - if (!fs_devs->device_dir_kobj) |
|---|
| 756 | | - fs_devs->device_dir_kobj = kobject_create_and_add("devices", |
|---|
| 757 | | - &fs_devs->fsid_kobj); |
|---|
| 1263 | + int val; |
|---|
| 1264 | + struct btrfs_device *device = container_of(kobj, struct btrfs_device, |
|---|
| 1265 | + devid_kobj); |
|---|
| 758 | 1266 | |
|---|
| 759 | | - if (!fs_devs->device_dir_kobj) |
|---|
| 760 | | - return -ENOMEM; |
|---|
| 1267 | + val = !!test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state); |
|---|
| 761 | 1268 | |
|---|
| 762 | | - return 0; |
|---|
| 1269 | + return scnprintf(buf, PAGE_SIZE, "%d\n", val); |
|---|
| 1270 | +} |
|---|
| 1271 | +BTRFS_ATTR(devid, in_fs_metadata, btrfs_devinfo_in_fs_metadata_show); |
|---|
| 1272 | + |
|---|
| 1273 | +static ssize_t btrfs_devinfo_missing_show(struct kobject *kobj, |
|---|
| 1274 | + struct kobj_attribute *a, char *buf) |
|---|
| 1275 | +{ |
|---|
| 1276 | + int val; |
|---|
| 1277 | + struct btrfs_device *device = container_of(kobj, struct btrfs_device, |
|---|
| 1278 | + devid_kobj); |
|---|
| 1279 | + |
|---|
| 1280 | + val = !!test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state); |
|---|
| 1281 | + |
|---|
| 1282 | + return scnprintf(buf, PAGE_SIZE, "%d\n", val); |
|---|
| 1283 | +} |
|---|
| 1284 | +BTRFS_ATTR(devid, missing, btrfs_devinfo_missing_show); |
|---|
| 1285 | + |
|---|
| 1286 | +static ssize_t btrfs_devinfo_replace_target_show(struct kobject *kobj, |
|---|
| 1287 | + struct kobj_attribute *a, |
|---|
| 1288 | + char *buf) |
|---|
| 1289 | +{ |
|---|
| 1290 | + int val; |
|---|
| 1291 | + struct btrfs_device *device = container_of(kobj, struct btrfs_device, |
|---|
| 1292 | + devid_kobj); |
|---|
| 1293 | + |
|---|
| 1294 | + val = !!test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state); |
|---|
| 1295 | + |
|---|
| 1296 | + return scnprintf(buf, PAGE_SIZE, "%d\n", val); |
|---|
| 1297 | +} |
|---|
| 1298 | +BTRFS_ATTR(devid, replace_target, btrfs_devinfo_replace_target_show); |
|---|
| 1299 | + |
|---|
| 1300 | +static ssize_t btrfs_devinfo_writeable_show(struct kobject *kobj, |
|---|
| 1301 | + struct kobj_attribute *a, char *buf) |
|---|
| 1302 | +{ |
|---|
| 1303 | + int val; |
|---|
| 1304 | + struct btrfs_device *device = container_of(kobj, struct btrfs_device, |
|---|
| 1305 | + devid_kobj); |
|---|
| 1306 | + |
|---|
| 1307 | + val = !!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state); |
|---|
| 1308 | + |
|---|
| 1309 | + return scnprintf(buf, PAGE_SIZE, "%d\n", val); |
|---|
| 1310 | +} |
|---|
| 1311 | +BTRFS_ATTR(devid, writeable, btrfs_devinfo_writeable_show); |
|---|
| 1312 | + |
|---|
| 1313 | +static struct attribute *devid_attrs[] = { |
|---|
| 1314 | + BTRFS_ATTR_PTR(devid, in_fs_metadata), |
|---|
| 1315 | + BTRFS_ATTR_PTR(devid, missing), |
|---|
| 1316 | + BTRFS_ATTR_PTR(devid, replace_target), |
|---|
| 1317 | + BTRFS_ATTR_PTR(devid, writeable), |
|---|
| 1318 | + NULL |
|---|
| 1319 | +}; |
|---|
| 1320 | +ATTRIBUTE_GROUPS(devid); |
|---|
| 1321 | + |
|---|
| 1322 | +static void btrfs_release_devid_kobj(struct kobject *kobj) |
|---|
| 1323 | +{ |
|---|
| 1324 | + struct btrfs_device *device = container_of(kobj, struct btrfs_device, |
|---|
| 1325 | + devid_kobj); |
|---|
| 1326 | + |
|---|
| 1327 | + memset(&device->devid_kobj, 0, sizeof(struct kobject)); |
|---|
| 1328 | + complete(&device->kobj_unregister); |
|---|
| 763 | 1329 | } |
|---|
| 764 | 1330 | |
|---|
| 765 | | -int btrfs_sysfs_add_device_link(struct btrfs_fs_devices *fs_devices, |
|---|
| 766 | | - struct btrfs_device *one_device) |
|---|
| 1331 | +static struct kobj_type devid_ktype = { |
|---|
| 1332 | + .sysfs_ops = &kobj_sysfs_ops, |
|---|
| 1333 | + .default_groups = devid_groups, |
|---|
| 1334 | + .release = btrfs_release_devid_kobj, |
|---|
| 1335 | +}; |
|---|
| 1336 | + |
|---|
| 1337 | +int btrfs_sysfs_add_device(struct btrfs_device *device) |
|---|
| 767 | 1338 | { |
|---|
| 768 | | - int error = 0; |
|---|
| 769 | | - struct btrfs_device *dev; |
|---|
| 1339 | + int ret; |
|---|
| 770 | 1340 | unsigned int nofs_flag; |
|---|
| 1341 | + struct kobject *devices_kobj; |
|---|
| 1342 | + struct kobject *devinfo_kobj; |
|---|
| 1343 | + |
|---|
| 1344 | + /* |
|---|
| 1345 | + * Make sure we use the fs_info::fs_devices to fetch the kobjects even |
|---|
| 1346 | + * for the seed fs_devices |
|---|
| 1347 | + */ |
|---|
| 1348 | + devices_kobj = device->fs_info->fs_devices->devices_kobj; |
|---|
| 1349 | + devinfo_kobj = device->fs_info->fs_devices->devinfo_kobj; |
|---|
| 1350 | + ASSERT(devices_kobj); |
|---|
| 1351 | + ASSERT(devinfo_kobj); |
|---|
| 771 | 1352 | |
|---|
| 772 | 1353 | nofs_flag = memalloc_nofs_save(); |
|---|
| 773 | | - list_for_each_entry(dev, &fs_devices->devices, dev_list) { |
|---|
| 1354 | + |
|---|
| 1355 | + if (device->bdev) { |
|---|
| 774 | 1356 | struct hd_struct *disk; |
|---|
| 775 | 1357 | struct kobject *disk_kobj; |
|---|
| 776 | 1358 | |
|---|
| 777 | | - if (!dev->bdev) |
|---|
| 778 | | - continue; |
|---|
| 779 | | - |
|---|
| 780 | | - if (one_device && one_device != dev) |
|---|
| 781 | | - continue; |
|---|
| 782 | | - |
|---|
| 783 | | - disk = dev->bdev->bd_part; |
|---|
| 1359 | + disk = device->bdev->bd_part; |
|---|
| 784 | 1360 | disk_kobj = &part_to_dev(disk)->kobj; |
|---|
| 785 | 1361 | |
|---|
| 786 | | - error = sysfs_create_link(fs_devices->device_dir_kobj, |
|---|
| 787 | | - disk_kobj, disk_kobj->name); |
|---|
| 788 | | - if (error) |
|---|
| 789 | | - break; |
|---|
| 1362 | + ret = sysfs_create_link(devices_kobj, disk_kobj, disk_kobj->name); |
|---|
| 1363 | + if (ret) { |
|---|
| 1364 | + btrfs_warn(device->fs_info, |
|---|
| 1365 | + "creating sysfs device link for devid %llu failed: %d", |
|---|
| 1366 | + device->devid, ret); |
|---|
| 1367 | + goto out; |
|---|
| 1368 | + } |
|---|
| 790 | 1369 | } |
|---|
| 791 | | - memalloc_nofs_restore(nofs_flag); |
|---|
| 792 | 1370 | |
|---|
| 793 | | - return error; |
|---|
| 1371 | + init_completion(&device->kobj_unregister); |
|---|
| 1372 | + ret = kobject_init_and_add(&device->devid_kobj, &devid_ktype, |
|---|
| 1373 | + devinfo_kobj, "%llu", device->devid); |
|---|
| 1374 | + if (ret) { |
|---|
| 1375 | + kobject_put(&device->devid_kobj); |
|---|
| 1376 | + btrfs_warn(device->fs_info, |
|---|
| 1377 | + "devinfo init for devid %llu failed: %d", |
|---|
| 1378 | + device->devid, ret); |
|---|
| 1379 | + } |
|---|
| 1380 | + |
|---|
| 1381 | +out: |
|---|
| 1382 | + memalloc_nofs_restore(nofs_flag); |
|---|
| 1383 | + return ret; |
|---|
| 1384 | +} |
|---|
| 1385 | + |
|---|
| 1386 | +static int btrfs_sysfs_add_fs_devices(struct btrfs_fs_devices *fs_devices) |
|---|
| 1387 | +{ |
|---|
| 1388 | + int ret; |
|---|
| 1389 | + struct btrfs_device *device; |
|---|
| 1390 | + struct btrfs_fs_devices *seed; |
|---|
| 1391 | + |
|---|
| 1392 | + list_for_each_entry(device, &fs_devices->devices, dev_list) { |
|---|
| 1393 | + ret = btrfs_sysfs_add_device(device); |
|---|
| 1394 | + if (ret) |
|---|
| 1395 | + goto fail; |
|---|
| 1396 | + } |
|---|
| 1397 | + |
|---|
| 1398 | + list_for_each_entry(seed, &fs_devices->seed_list, seed_list) { |
|---|
| 1399 | + list_for_each_entry(device, &seed->devices, dev_list) { |
|---|
| 1400 | + ret = btrfs_sysfs_add_device(device); |
|---|
| 1401 | + if (ret) |
|---|
| 1402 | + goto fail; |
|---|
| 1403 | + } |
|---|
| 1404 | + } |
|---|
| 1405 | + |
|---|
| 1406 | + return 0; |
|---|
| 1407 | + |
|---|
| 1408 | +fail: |
|---|
| 1409 | + btrfs_sysfs_remove_fs_devices(fs_devices); |
|---|
| 1410 | + return ret; |
|---|
| 1411 | +} |
|---|
| 1412 | + |
|---|
| 1413 | +void btrfs_kobject_uevent(struct block_device *bdev, enum kobject_action action) |
|---|
| 1414 | +{ |
|---|
| 1415 | + int ret; |
|---|
| 1416 | + |
|---|
| 1417 | + ret = kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, action); |
|---|
| 1418 | + if (ret) |
|---|
| 1419 | + pr_warn("BTRFS: Sending event '%d' to kobject: '%s' (%p): failed\n", |
|---|
| 1420 | + action, kobject_name(&disk_to_dev(bdev->bd_disk)->kobj), |
|---|
| 1421 | + &disk_to_dev(bdev->bd_disk)->kobj); |
|---|
| 1422 | +} |
|---|
| 1423 | + |
|---|
| 1424 | +void btrfs_sysfs_update_sprout_fsid(struct btrfs_fs_devices *fs_devices) |
|---|
| 1425 | + |
|---|
| 1426 | +{ |
|---|
| 1427 | + char fsid_buf[BTRFS_UUID_UNPARSED_SIZE]; |
|---|
| 1428 | + |
|---|
| 1429 | + /* |
|---|
| 1430 | + * Sprouting changes fsid of the mounted filesystem, rename the fsid |
|---|
| 1431 | + * directory |
|---|
| 1432 | + */ |
|---|
| 1433 | + snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU", fs_devices->fsid); |
|---|
| 1434 | + if (kobject_rename(&fs_devices->fsid_kobj, fsid_buf)) |
|---|
| 1435 | + btrfs_warn(fs_devices->fs_info, |
|---|
| 1436 | + "sysfs: failed to create fsid for sprout"); |
|---|
| 1437 | +} |
|---|
| 1438 | + |
|---|
| 1439 | +void btrfs_sysfs_update_devid(struct btrfs_device *device) |
|---|
| 1440 | +{ |
|---|
| 1441 | + char tmp[24]; |
|---|
| 1442 | + |
|---|
| 1443 | + snprintf(tmp, sizeof(tmp), "%llu", device->devid); |
|---|
| 1444 | + |
|---|
| 1445 | + if (kobject_rename(&device->devid_kobj, tmp)) |
|---|
| 1446 | + btrfs_warn(device->fs_devices->fs_info, |
|---|
| 1447 | + "sysfs: failed to update devid for %llu", |
|---|
| 1448 | + device->devid); |
|---|
| 794 | 1449 | } |
|---|
| 795 | 1450 | |
|---|
| 796 | 1451 | /* /sys/fs/btrfs/ entry */ |
|---|
| 797 | 1452 | static struct kset *btrfs_kset; |
|---|
| 798 | 1453 | |
|---|
| 799 | | -/* /sys/kernel/debug/btrfs */ |
|---|
| 800 | | -static struct dentry *btrfs_debugfs_root_dentry; |
|---|
| 801 | | - |
|---|
| 802 | | -/* Debugging tunables and exported data */ |
|---|
| 803 | | -u64 btrfs_debugfs_test; |
|---|
| 804 | | - |
|---|
| 805 | 1454 | /* |
|---|
| 1455 | + * Creates: |
|---|
| 1456 | + * /sys/fs/btrfs/UUID |
|---|
| 1457 | + * |
|---|
| 806 | 1458 | * Can be called by the device discovery thread. |
|---|
| 807 | | - * And parent can be specified for seed device |
|---|
| 808 | 1459 | */ |
|---|
| 809 | | -int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs, |
|---|
| 810 | | - struct kobject *parent) |
|---|
| 1460 | +int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs) |
|---|
| 811 | 1461 | { |
|---|
| 812 | 1462 | int error; |
|---|
| 813 | 1463 | |
|---|
| 814 | 1464 | init_completion(&fs_devs->kobj_unregister); |
|---|
| 815 | 1465 | fs_devs->fsid_kobj.kset = btrfs_kset; |
|---|
| 816 | | - error = kobject_init_and_add(&fs_devs->fsid_kobj, |
|---|
| 817 | | - &btrfs_ktype, parent, "%pU", fs_devs->fsid); |
|---|
| 1466 | + error = kobject_init_and_add(&fs_devs->fsid_kobj, &btrfs_ktype, NULL, |
|---|
| 1467 | + "%pU", fs_devs->fsid); |
|---|
| 818 | 1468 | if (error) { |
|---|
| 819 | 1469 | kobject_put(&fs_devs->fsid_kobj); |
|---|
| 820 | 1470 | return error; |
|---|
| 1471 | + } |
|---|
| 1472 | + |
|---|
| 1473 | + fs_devs->devices_kobj = kobject_create_and_add("devices", |
|---|
| 1474 | + &fs_devs->fsid_kobj); |
|---|
| 1475 | + if (!fs_devs->devices_kobj) { |
|---|
| 1476 | + btrfs_err(fs_devs->fs_info, |
|---|
| 1477 | + "failed to init sysfs device interface"); |
|---|
| 1478 | + btrfs_sysfs_remove_fsid(fs_devs); |
|---|
| 1479 | + return -ENOMEM; |
|---|
| 1480 | + } |
|---|
| 1481 | + |
|---|
| 1482 | + fs_devs->devinfo_kobj = kobject_create_and_add("devinfo", |
|---|
| 1483 | + &fs_devs->fsid_kobj); |
|---|
| 1484 | + if (!fs_devs->devinfo_kobj) { |
|---|
| 1485 | + btrfs_err(fs_devs->fs_info, |
|---|
| 1486 | + "failed to init sysfs devinfo kobject"); |
|---|
| 1487 | + btrfs_sysfs_remove_fsid(fs_devs); |
|---|
| 1488 | + return -ENOMEM; |
|---|
| 821 | 1489 | } |
|---|
| 822 | 1490 | |
|---|
| 823 | 1491 | return 0; |
|---|
| .. | .. |
|---|
| 829 | 1497 | struct btrfs_fs_devices *fs_devs = fs_info->fs_devices; |
|---|
| 830 | 1498 | struct kobject *fsid_kobj = &fs_devs->fsid_kobj; |
|---|
| 831 | 1499 | |
|---|
| 832 | | - btrfs_set_fs_info_ptr(fs_info); |
|---|
| 833 | | - |
|---|
| 834 | | - error = btrfs_sysfs_add_device_link(fs_devs, NULL); |
|---|
| 1500 | + error = btrfs_sysfs_add_fs_devices(fs_devs); |
|---|
| 835 | 1501 | if (error) |
|---|
| 836 | 1502 | return error; |
|---|
| 837 | 1503 | |
|---|
| 838 | 1504 | error = sysfs_create_files(fsid_kobj, btrfs_attrs); |
|---|
| 839 | 1505 | if (error) { |
|---|
| 840 | | - btrfs_sysfs_rm_device_link(fs_devs, NULL); |
|---|
| 1506 | + btrfs_sysfs_remove_fs_devices(fs_devs); |
|---|
| 841 | 1507 | return error; |
|---|
| 842 | 1508 | } |
|---|
| 843 | 1509 | |
|---|
| .. | .. |
|---|
| 846 | 1512 | if (error) |
|---|
| 847 | 1513 | goto failure; |
|---|
| 848 | 1514 | |
|---|
| 1515 | +#ifdef CONFIG_BTRFS_DEBUG |
|---|
| 1516 | + fs_info->debug_kobj = kobject_create_and_add("debug", fsid_kobj); |
|---|
| 1517 | + if (!fs_info->debug_kobj) { |
|---|
| 1518 | + error = -ENOMEM; |
|---|
| 1519 | + goto failure; |
|---|
| 1520 | + } |
|---|
| 1521 | + |
|---|
| 1522 | + error = sysfs_create_files(fs_info->debug_kobj, btrfs_debug_mount_attrs); |
|---|
| 1523 | + if (error) |
|---|
| 1524 | + goto failure; |
|---|
| 1525 | + |
|---|
| 1526 | + /* Discard directory */ |
|---|
| 1527 | + fs_info->discard_debug_kobj = kobject_create_and_add("discard", |
|---|
| 1528 | + fs_info->debug_kobj); |
|---|
| 1529 | + if (!fs_info->discard_debug_kobj) { |
|---|
| 1530 | + error = -ENOMEM; |
|---|
| 1531 | + goto failure; |
|---|
| 1532 | + } |
|---|
| 1533 | + |
|---|
| 1534 | + error = sysfs_create_files(fs_info->discard_debug_kobj, |
|---|
| 1535 | + discard_debug_attrs); |
|---|
| 1536 | + if (error) |
|---|
| 1537 | + goto failure; |
|---|
| 1538 | +#endif |
|---|
| 1539 | + |
|---|
| 849 | 1540 | error = addrm_unknown_feature_attrs(fs_info, true); |
|---|
| 1541 | + if (error) |
|---|
| 1542 | + goto failure; |
|---|
| 1543 | + |
|---|
| 1544 | + error = sysfs_create_link(fsid_kobj, &fs_info->sb->s_bdi->dev->kobj, "bdi"); |
|---|
| 850 | 1545 | if (error) |
|---|
| 851 | 1546 | goto failure; |
|---|
| 852 | 1547 | |
|---|
| .. | .. |
|---|
| 867 | 1562 | return error; |
|---|
| 868 | 1563 | } |
|---|
| 869 | 1564 | |
|---|
| 1565 | +static inline struct btrfs_fs_info *qgroup_kobj_to_fs_info(struct kobject *kobj) |
|---|
| 1566 | +{ |
|---|
| 1567 | + return to_fs_info(kobj->parent->parent); |
|---|
| 1568 | +} |
|---|
| 1569 | + |
|---|
| 1570 | +#define QGROUP_ATTR(_member, _show_name) \ |
|---|
| 1571 | +static ssize_t btrfs_qgroup_show_##_member(struct kobject *qgroup_kobj, \ |
|---|
| 1572 | + struct kobj_attribute *a, \ |
|---|
| 1573 | + char *buf) \ |
|---|
| 1574 | +{ \ |
|---|
| 1575 | + struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj); \ |
|---|
| 1576 | + struct btrfs_qgroup *qgroup = container_of(qgroup_kobj, \ |
|---|
| 1577 | + struct btrfs_qgroup, kobj); \ |
|---|
| 1578 | + return btrfs_show_u64(&qgroup->_member, &fs_info->qgroup_lock, buf); \ |
|---|
| 1579 | +} \ |
|---|
| 1580 | +BTRFS_ATTR(qgroup, _show_name, btrfs_qgroup_show_##_member) |
|---|
| 1581 | + |
|---|
| 1582 | +#define QGROUP_RSV_ATTR(_name, _type) \ |
|---|
| 1583 | +static ssize_t btrfs_qgroup_rsv_show_##_name(struct kobject *qgroup_kobj, \ |
|---|
| 1584 | + struct kobj_attribute *a, \ |
|---|
| 1585 | + char *buf) \ |
|---|
| 1586 | +{ \ |
|---|
| 1587 | + struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj); \ |
|---|
| 1588 | + struct btrfs_qgroup *qgroup = container_of(qgroup_kobj, \ |
|---|
| 1589 | + struct btrfs_qgroup, kobj); \ |
|---|
| 1590 | + return btrfs_show_u64(&qgroup->rsv.values[_type], \ |
|---|
| 1591 | + &fs_info->qgroup_lock, buf); \ |
|---|
| 1592 | +} \ |
|---|
| 1593 | +BTRFS_ATTR(qgroup, rsv_##_name, btrfs_qgroup_rsv_show_##_name) |
|---|
| 1594 | + |
|---|
| 1595 | +QGROUP_ATTR(rfer, referenced); |
|---|
| 1596 | +QGROUP_ATTR(excl, exclusive); |
|---|
| 1597 | +QGROUP_ATTR(max_rfer, max_referenced); |
|---|
| 1598 | +QGROUP_ATTR(max_excl, max_exclusive); |
|---|
| 1599 | +QGROUP_ATTR(lim_flags, limit_flags); |
|---|
| 1600 | +QGROUP_RSV_ATTR(data, BTRFS_QGROUP_RSV_DATA); |
|---|
| 1601 | +QGROUP_RSV_ATTR(meta_pertrans, BTRFS_QGROUP_RSV_META_PERTRANS); |
|---|
| 1602 | +QGROUP_RSV_ATTR(meta_prealloc, BTRFS_QGROUP_RSV_META_PREALLOC); |
|---|
| 1603 | + |
|---|
| 1604 | +static struct attribute *qgroup_attrs[] = { |
|---|
| 1605 | + BTRFS_ATTR_PTR(qgroup, referenced), |
|---|
| 1606 | + BTRFS_ATTR_PTR(qgroup, exclusive), |
|---|
| 1607 | + BTRFS_ATTR_PTR(qgroup, max_referenced), |
|---|
| 1608 | + BTRFS_ATTR_PTR(qgroup, max_exclusive), |
|---|
| 1609 | + BTRFS_ATTR_PTR(qgroup, limit_flags), |
|---|
| 1610 | + BTRFS_ATTR_PTR(qgroup, rsv_data), |
|---|
| 1611 | + BTRFS_ATTR_PTR(qgroup, rsv_meta_pertrans), |
|---|
| 1612 | + BTRFS_ATTR_PTR(qgroup, rsv_meta_prealloc), |
|---|
| 1613 | + NULL |
|---|
| 1614 | +}; |
|---|
| 1615 | +ATTRIBUTE_GROUPS(qgroup); |
|---|
| 1616 | + |
|---|
| 1617 | +static void qgroup_release(struct kobject *kobj) |
|---|
| 1618 | +{ |
|---|
| 1619 | + struct btrfs_qgroup *qgroup = container_of(kobj, struct btrfs_qgroup, kobj); |
|---|
| 1620 | + |
|---|
| 1621 | + memset(&qgroup->kobj, 0, sizeof(*kobj)); |
|---|
| 1622 | +} |
|---|
| 1623 | + |
|---|
| 1624 | +static struct kobj_type qgroup_ktype = { |
|---|
| 1625 | + .sysfs_ops = &kobj_sysfs_ops, |
|---|
| 1626 | + .release = qgroup_release, |
|---|
| 1627 | + .default_groups = qgroup_groups, |
|---|
| 1628 | +}; |
|---|
| 1629 | + |
|---|
| 1630 | +int btrfs_sysfs_add_one_qgroup(struct btrfs_fs_info *fs_info, |
|---|
| 1631 | + struct btrfs_qgroup *qgroup) |
|---|
| 1632 | +{ |
|---|
| 1633 | + struct kobject *qgroups_kobj = fs_info->qgroups_kobj; |
|---|
| 1634 | + int ret; |
|---|
| 1635 | + |
|---|
| 1636 | + if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) |
|---|
| 1637 | + return 0; |
|---|
| 1638 | + if (qgroup->kobj.state_initialized) |
|---|
| 1639 | + return 0; |
|---|
| 1640 | + if (!qgroups_kobj) |
|---|
| 1641 | + return -EINVAL; |
|---|
| 1642 | + |
|---|
| 1643 | + ret = kobject_init_and_add(&qgroup->kobj, &qgroup_ktype, qgroups_kobj, |
|---|
| 1644 | + "%hu_%llu", btrfs_qgroup_level(qgroup->qgroupid), |
|---|
| 1645 | + btrfs_qgroup_subvolid(qgroup->qgroupid)); |
|---|
| 1646 | + if (ret < 0) |
|---|
| 1647 | + kobject_put(&qgroup->kobj); |
|---|
| 1648 | + |
|---|
| 1649 | + return ret; |
|---|
| 1650 | +} |
|---|
| 1651 | + |
|---|
| 1652 | +void btrfs_sysfs_del_qgroups(struct btrfs_fs_info *fs_info) |
|---|
| 1653 | +{ |
|---|
| 1654 | + struct btrfs_qgroup *qgroup; |
|---|
| 1655 | + struct btrfs_qgroup *next; |
|---|
| 1656 | + |
|---|
| 1657 | + if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) |
|---|
| 1658 | + return; |
|---|
| 1659 | + |
|---|
| 1660 | + rbtree_postorder_for_each_entry_safe(qgroup, next, |
|---|
| 1661 | + &fs_info->qgroup_tree, node) |
|---|
| 1662 | + btrfs_sysfs_del_one_qgroup(fs_info, qgroup); |
|---|
| 1663 | + if (fs_info->qgroups_kobj) { |
|---|
| 1664 | + kobject_del(fs_info->qgroups_kobj); |
|---|
| 1665 | + kobject_put(fs_info->qgroups_kobj); |
|---|
| 1666 | + fs_info->qgroups_kobj = NULL; |
|---|
| 1667 | + } |
|---|
| 1668 | +} |
|---|
| 1669 | + |
|---|
| 1670 | +/* Called when qgroups get initialized, thus there is no need for locking */ |
|---|
| 1671 | +int btrfs_sysfs_add_qgroups(struct btrfs_fs_info *fs_info) |
|---|
| 1672 | +{ |
|---|
| 1673 | + struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj; |
|---|
| 1674 | + struct btrfs_qgroup *qgroup; |
|---|
| 1675 | + struct btrfs_qgroup *next; |
|---|
| 1676 | + int ret = 0; |
|---|
| 1677 | + |
|---|
| 1678 | + if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) |
|---|
| 1679 | + return 0; |
|---|
| 1680 | + |
|---|
| 1681 | + ASSERT(fsid_kobj); |
|---|
| 1682 | + if (fs_info->qgroups_kobj) |
|---|
| 1683 | + return 0; |
|---|
| 1684 | + |
|---|
| 1685 | + fs_info->qgroups_kobj = kobject_create_and_add("qgroups", fsid_kobj); |
|---|
| 1686 | + if (!fs_info->qgroups_kobj) { |
|---|
| 1687 | + ret = -ENOMEM; |
|---|
| 1688 | + goto out; |
|---|
| 1689 | + } |
|---|
| 1690 | + rbtree_postorder_for_each_entry_safe(qgroup, next, |
|---|
| 1691 | + &fs_info->qgroup_tree, node) { |
|---|
| 1692 | + ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup); |
|---|
| 1693 | + if (ret < 0) |
|---|
| 1694 | + goto out; |
|---|
| 1695 | + } |
|---|
| 1696 | + |
|---|
| 1697 | +out: |
|---|
| 1698 | + if (ret < 0) |
|---|
| 1699 | + btrfs_sysfs_del_qgroups(fs_info); |
|---|
| 1700 | + return ret; |
|---|
| 1701 | +} |
|---|
| 1702 | + |
|---|
| 1703 | +void btrfs_sysfs_del_one_qgroup(struct btrfs_fs_info *fs_info, |
|---|
| 1704 | + struct btrfs_qgroup *qgroup) |
|---|
| 1705 | +{ |
|---|
| 1706 | + if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) |
|---|
| 1707 | + return; |
|---|
| 1708 | + |
|---|
| 1709 | + if (qgroup->kobj.state_initialized) { |
|---|
| 1710 | + kobject_del(&qgroup->kobj); |
|---|
| 1711 | + kobject_put(&qgroup->kobj); |
|---|
| 1712 | + } |
|---|
| 1713 | +} |
|---|
| 870 | 1714 | |
|---|
| 871 | 1715 | /* |
|---|
| 872 | 1716 | * Change per-fs features in /sys/fs/btrfs/UUID/features to match current |
|---|
| .. | .. |
|---|
| 877 | 1721 | { |
|---|
| 878 | 1722 | struct btrfs_fs_devices *fs_devs; |
|---|
| 879 | 1723 | struct kobject *fsid_kobj; |
|---|
| 880 | | - u64 features; |
|---|
| 881 | | - int ret; |
|---|
| 1724 | + u64 __maybe_unused features; |
|---|
| 1725 | + int __maybe_unused ret; |
|---|
| 882 | 1726 | |
|---|
| 883 | 1727 | if (!fs_info) |
|---|
| 884 | 1728 | return; |
|---|
| 885 | 1729 | |
|---|
| 1730 | + /* |
|---|
| 1731 | + * See 14e46e04958df74 and e410e34fad913dd, feature bit updates are not |
|---|
| 1732 | + * safe when called from some contexts (eg. balance) |
|---|
| 1733 | + */ |
|---|
| 886 | 1734 | features = get_features(fs_info, set); |
|---|
| 887 | 1735 | ASSERT(bit & supported_feature_masks[set]); |
|---|
| 888 | 1736 | |
|---|
| .. | .. |
|---|
| 900 | 1748 | ret = sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group); |
|---|
| 901 | 1749 | } |
|---|
| 902 | 1750 | |
|---|
| 903 | | -static int btrfs_init_debugfs(void) |
|---|
| 904 | | -{ |
|---|
| 905 | | -#ifdef CONFIG_DEBUG_FS |
|---|
| 906 | | - btrfs_debugfs_root_dentry = debugfs_create_dir("btrfs", NULL); |
|---|
| 907 | | - if (!btrfs_debugfs_root_dentry) |
|---|
| 908 | | - return -ENOMEM; |
|---|
| 909 | | - |
|---|
| 910 | | - /* |
|---|
| 911 | | - * Example code, how to export data through debugfs. |
|---|
| 912 | | - * |
|---|
| 913 | | - * file: /sys/kernel/debug/btrfs/test |
|---|
| 914 | | - * contents of: btrfs_debugfs_test |
|---|
| 915 | | - */ |
|---|
| 916 | | -#ifdef CONFIG_BTRFS_DEBUG |
|---|
| 917 | | - debugfs_create_u64("test", S_IRUGO | S_IWUSR, btrfs_debugfs_root_dentry, |
|---|
| 918 | | - &btrfs_debugfs_test); |
|---|
| 919 | | -#endif |
|---|
| 920 | | - |
|---|
| 921 | | -#endif |
|---|
| 922 | | - return 0; |
|---|
| 923 | | -} |
|---|
| 924 | | - |
|---|
| 925 | 1751 | int __init btrfs_init_sysfs(void) |
|---|
| 926 | 1752 | { |
|---|
| 927 | 1753 | int ret; |
|---|
| .. | .. |
|---|
| 929 | 1755 | btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); |
|---|
| 930 | 1756 | if (!btrfs_kset) |
|---|
| 931 | 1757 | return -ENOMEM; |
|---|
| 932 | | - |
|---|
| 933 | | - ret = btrfs_init_debugfs(); |
|---|
| 934 | | - if (ret) |
|---|
| 935 | | - goto out1; |
|---|
| 936 | 1758 | |
|---|
| 937 | 1759 | init_feature_attrs(); |
|---|
| 938 | 1760 | ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); |
|---|
| .. | .. |
|---|
| 943 | 1765 | if (ret) |
|---|
| 944 | 1766 | goto out_remove_group; |
|---|
| 945 | 1767 | |
|---|
| 1768 | +#ifdef CONFIG_BTRFS_DEBUG |
|---|
| 1769 | + ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group); |
|---|
| 1770 | + if (ret) { |
|---|
| 1771 | + sysfs_unmerge_group(&btrfs_kset->kobj, |
|---|
| 1772 | + &btrfs_static_feature_attr_group); |
|---|
| 1773 | + goto out_remove_group; |
|---|
| 1774 | + } |
|---|
| 1775 | +#endif |
|---|
| 1776 | + |
|---|
| 946 | 1777 | return 0; |
|---|
| 947 | 1778 | |
|---|
| 948 | 1779 | out_remove_group: |
|---|
| 949 | 1780 | sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); |
|---|
| 950 | 1781 | out2: |
|---|
| 951 | | - debugfs_remove_recursive(btrfs_debugfs_root_dentry); |
|---|
| 952 | | -out1: |
|---|
| 953 | 1782 | kset_unregister(btrfs_kset); |
|---|
| 954 | 1783 | |
|---|
| 955 | 1784 | return ret; |
|---|
| .. | .. |
|---|
| 960 | 1789 | sysfs_unmerge_group(&btrfs_kset->kobj, |
|---|
| 961 | 1790 | &btrfs_static_feature_attr_group); |
|---|
| 962 | 1791 | sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); |
|---|
| 1792 | +#ifdef CONFIG_BTRFS_DEBUG |
|---|
| 1793 | + sysfs_remove_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group); |
|---|
| 1794 | +#endif |
|---|
| 963 | 1795 | kset_unregister(btrfs_kset); |
|---|
| 964 | | - debugfs_remove_recursive(btrfs_debugfs_root_dentry); |
|---|
| 965 | 1796 | } |
|---|
| 966 | 1797 | |
|---|