18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2007 Oracle. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/sched.h> 78c2ecf20Sopenharmony_ci#include <linux/sched/mm.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 108c2ecf20Sopenharmony_ci#include <linux/completion.h> 118c2ecf20Sopenharmony_ci#include <linux/bug.h> 128c2ecf20Sopenharmony_ci#include <crypto/hash.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "ctree.h" 158c2ecf20Sopenharmony_ci#include "discard.h" 168c2ecf20Sopenharmony_ci#include "disk-io.h" 178c2ecf20Sopenharmony_ci#include "send.h" 188c2ecf20Sopenharmony_ci#include "transaction.h" 198c2ecf20Sopenharmony_ci#include "sysfs.h" 208c2ecf20Sopenharmony_ci#include "volumes.h" 218c2ecf20Sopenharmony_ci#include "space-info.h" 228c2ecf20Sopenharmony_ci#include "block-group.h" 238c2ecf20Sopenharmony_ci#include "qgroup.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct btrfs_feature_attr { 268c2ecf20Sopenharmony_ci struct kobj_attribute kobj_attr; 278c2ecf20Sopenharmony_ci enum btrfs_feature_set feature_set; 288c2ecf20Sopenharmony_ci u64 feature_bit; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* For raid type sysfs entries */ 328c2ecf20Sopenharmony_cistruct raid_kobject { 338c2ecf20Sopenharmony_ci u64 flags; 348c2ecf20Sopenharmony_ci struct kobject kobj; 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define __INIT_KOBJ_ATTR(_name, _mode, _show, _store) \ 388c2ecf20Sopenharmony_ci{ \ 398c2ecf20Sopenharmony_ci .attr = { .name = __stringify(_name), .mode = _mode }, \ 408c2ecf20Sopenharmony_ci .show = _show, \ 418c2ecf20Sopenharmony_ci .store = _store, \ 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define BTRFS_ATTR_RW(_prefix, _name, _show, _store) \ 458c2ecf20Sopenharmony_ci static struct kobj_attribute btrfs_attr_##_prefix##_##_name = \ 468c2ecf20Sopenharmony_ci __INIT_KOBJ_ATTR(_name, 0644, _show, _store) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define BTRFS_ATTR(_prefix, _name, _show) \ 498c2ecf20Sopenharmony_ci static struct kobj_attribute btrfs_attr_##_prefix##_##_name = \ 508c2ecf20Sopenharmony_ci __INIT_KOBJ_ATTR(_name, 0444, _show, NULL) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define BTRFS_ATTR_PTR(_prefix, _name) \ 538c2ecf20Sopenharmony_ci (&btrfs_attr_##_prefix##_##_name.attr) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define BTRFS_FEAT_ATTR(_name, _feature_set, _feature_prefix, _feature_bit) \ 568c2ecf20Sopenharmony_cistatic struct btrfs_feature_attr btrfs_attr_features_##_name = { \ 578c2ecf20Sopenharmony_ci .kobj_attr = __INIT_KOBJ_ATTR(_name, S_IRUGO, \ 588c2ecf20Sopenharmony_ci btrfs_feature_attr_show, \ 598c2ecf20Sopenharmony_ci btrfs_feature_attr_store), \ 608c2ecf20Sopenharmony_ci .feature_set = _feature_set, \ 618c2ecf20Sopenharmony_ci .feature_bit = _feature_prefix ##_## _feature_bit, \ 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci#define BTRFS_FEAT_ATTR_PTR(_name) \ 648c2ecf20Sopenharmony_ci (&btrfs_attr_features_##_name.kobj_attr.attr) 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define BTRFS_FEAT_ATTR_COMPAT(name, feature) \ 678c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR(name, FEAT_COMPAT, BTRFS_FEATURE_COMPAT, feature) 688c2ecf20Sopenharmony_ci#define BTRFS_FEAT_ATTR_COMPAT_RO(name, feature) \ 698c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR(name, FEAT_COMPAT_RO, BTRFS_FEATURE_COMPAT_RO, feature) 708c2ecf20Sopenharmony_ci#define BTRFS_FEAT_ATTR_INCOMPAT(name, feature) \ 718c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR(name, FEAT_INCOMPAT, BTRFS_FEATURE_INCOMPAT, feature) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj); 748c2ecf20Sopenharmony_cistatic inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic struct btrfs_feature_attr *to_btrfs_feature_attr(struct kobj_attribute *a) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci return container_of(a, struct btrfs_feature_attr, kobj_attr); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic struct kobj_attribute *attr_to_btrfs_attr(struct attribute *attr) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci return container_of(attr, struct kobj_attribute, attr); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic struct btrfs_feature_attr *attr_to_btrfs_feature_attr( 878c2ecf20Sopenharmony_ci struct attribute *attr) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci return to_btrfs_feature_attr(attr_to_btrfs_attr(attr)); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic u64 get_features(struct btrfs_fs_info *fs_info, 938c2ecf20Sopenharmony_ci enum btrfs_feature_set set) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct btrfs_super_block *disk_super = fs_info->super_copy; 968c2ecf20Sopenharmony_ci if (set == FEAT_COMPAT) 978c2ecf20Sopenharmony_ci return btrfs_super_compat_flags(disk_super); 988c2ecf20Sopenharmony_ci else if (set == FEAT_COMPAT_RO) 998c2ecf20Sopenharmony_ci return btrfs_super_compat_ro_flags(disk_super); 1008c2ecf20Sopenharmony_ci else 1018c2ecf20Sopenharmony_ci return btrfs_super_incompat_flags(disk_super); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void set_features(struct btrfs_fs_info *fs_info, 1058c2ecf20Sopenharmony_ci enum btrfs_feature_set set, u64 features) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct btrfs_super_block *disk_super = fs_info->super_copy; 1088c2ecf20Sopenharmony_ci if (set == FEAT_COMPAT) 1098c2ecf20Sopenharmony_ci btrfs_set_super_compat_flags(disk_super, features); 1108c2ecf20Sopenharmony_ci else if (set == FEAT_COMPAT_RO) 1118c2ecf20Sopenharmony_ci btrfs_set_super_compat_ro_flags(disk_super, features); 1128c2ecf20Sopenharmony_ci else 1138c2ecf20Sopenharmony_ci btrfs_set_super_incompat_flags(disk_super, features); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int can_modify_feature(struct btrfs_feature_attr *fa) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int val = 0; 1198c2ecf20Sopenharmony_ci u64 set, clear; 1208c2ecf20Sopenharmony_ci switch (fa->feature_set) { 1218c2ecf20Sopenharmony_ci case FEAT_COMPAT: 1228c2ecf20Sopenharmony_ci set = BTRFS_FEATURE_COMPAT_SAFE_SET; 1238c2ecf20Sopenharmony_ci clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci case FEAT_COMPAT_RO: 1268c2ecf20Sopenharmony_ci set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; 1278c2ecf20Sopenharmony_ci clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci case FEAT_INCOMPAT: 1308c2ecf20Sopenharmony_ci set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; 1318c2ecf20Sopenharmony_ci clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; 1328c2ecf20Sopenharmony_ci break; 1338c2ecf20Sopenharmony_ci default: 1348c2ecf20Sopenharmony_ci pr_warn("btrfs: sysfs: unknown feature set %d\n", 1358c2ecf20Sopenharmony_ci fa->feature_set); 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (set & fa->feature_bit) 1408c2ecf20Sopenharmony_ci val |= 1; 1418c2ecf20Sopenharmony_ci if (clear & fa->feature_bit) 1428c2ecf20Sopenharmony_ci val |= 2; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return val; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic ssize_t btrfs_feature_attr_show(struct kobject *kobj, 1488c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci int val = 0; 1518c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 1528c2ecf20Sopenharmony_ci struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); 1538c2ecf20Sopenharmony_ci if (fs_info) { 1548c2ecf20Sopenharmony_ci u64 features = get_features(fs_info, fa->feature_set); 1558c2ecf20Sopenharmony_ci if (features & fa->feature_bit) 1568c2ecf20Sopenharmony_ci val = 1; 1578c2ecf20Sopenharmony_ci } else 1588c2ecf20Sopenharmony_ci val = can_modify_feature(fa); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", val); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic ssize_t btrfs_feature_attr_store(struct kobject *kobj, 1648c2ecf20Sopenharmony_ci struct kobj_attribute *a, 1658c2ecf20Sopenharmony_ci const char *buf, size_t count) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info; 1688c2ecf20Sopenharmony_ci struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); 1698c2ecf20Sopenharmony_ci u64 features, set, clear; 1708c2ecf20Sopenharmony_ci unsigned long val; 1718c2ecf20Sopenharmony_ci int ret; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci fs_info = to_fs_info(kobj); 1748c2ecf20Sopenharmony_ci if (!fs_info) 1758c2ecf20Sopenharmony_ci return -EPERM; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (sb_rdonly(fs_info->sb)) 1788c2ecf20Sopenharmony_ci return -EROFS; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ret = kstrtoul(skip_spaces(buf), 0, &val); 1818c2ecf20Sopenharmony_ci if (ret) 1828c2ecf20Sopenharmony_ci return ret; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (fa->feature_set == FEAT_COMPAT) { 1858c2ecf20Sopenharmony_ci set = BTRFS_FEATURE_COMPAT_SAFE_SET; 1868c2ecf20Sopenharmony_ci clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; 1878c2ecf20Sopenharmony_ci } else if (fa->feature_set == FEAT_COMPAT_RO) { 1888c2ecf20Sopenharmony_ci set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; 1898c2ecf20Sopenharmony_ci clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; 1908c2ecf20Sopenharmony_ci } else { 1918c2ecf20Sopenharmony_ci set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; 1928c2ecf20Sopenharmony_ci clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci features = get_features(fs_info, fa->feature_set); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* Nothing to do */ 1988c2ecf20Sopenharmony_ci if ((val && (features & fa->feature_bit)) || 1998c2ecf20Sopenharmony_ci (!val && !(features & fa->feature_bit))) 2008c2ecf20Sopenharmony_ci return count; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci if ((val && !(set & fa->feature_bit)) || 2038c2ecf20Sopenharmony_ci (!val && !(clear & fa->feature_bit))) { 2048c2ecf20Sopenharmony_ci btrfs_info(fs_info, 2058c2ecf20Sopenharmony_ci "%sabling feature %s on mounted fs is not supported.", 2068c2ecf20Sopenharmony_ci val ? "En" : "Dis", fa->kobj_attr.attr.name); 2078c2ecf20Sopenharmony_ci return -EPERM; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci btrfs_info(fs_info, "%s %s feature flag", 2118c2ecf20Sopenharmony_ci val ? "Setting" : "Clearing", fa->kobj_attr.attr.name); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci spin_lock(&fs_info->super_lock); 2148c2ecf20Sopenharmony_ci features = get_features(fs_info, fa->feature_set); 2158c2ecf20Sopenharmony_ci if (val) 2168c2ecf20Sopenharmony_ci features |= fa->feature_bit; 2178c2ecf20Sopenharmony_ci else 2188c2ecf20Sopenharmony_ci features &= ~fa->feature_bit; 2198c2ecf20Sopenharmony_ci set_features(fs_info, fa->feature_set, features); 2208c2ecf20Sopenharmony_ci spin_unlock(&fs_info->super_lock); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* 2238c2ecf20Sopenharmony_ci * We don't want to do full transaction commit from inside sysfs 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci btrfs_set_pending(fs_info, COMMIT); 2268c2ecf20Sopenharmony_ci wake_up_process(fs_info->transaction_kthread); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci return count; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic umode_t btrfs_feature_visible(struct kobject *kobj, 2328c2ecf20Sopenharmony_ci struct attribute *attr, int unused) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 2358c2ecf20Sopenharmony_ci umode_t mode = attr->mode; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (fs_info) { 2388c2ecf20Sopenharmony_ci struct btrfs_feature_attr *fa; 2398c2ecf20Sopenharmony_ci u64 features; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci fa = attr_to_btrfs_feature_attr(attr); 2428c2ecf20Sopenharmony_ci features = get_features(fs_info, fa->feature_set); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (can_modify_feature(fa)) 2458c2ecf20Sopenharmony_ci mode |= S_IWUSR; 2468c2ecf20Sopenharmony_ci else if (!(features & fa->feature_bit)) 2478c2ecf20Sopenharmony_ci mode = 0; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return mode; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF); 2548c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL); 2558c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS); 2568c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO); 2578c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(compress_zstd, COMPRESS_ZSTD); 2588c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA); 2598c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF); 2608c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56); 2618c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA); 2628c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES); 2638c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(metadata_uuid, METADATA_UUID); 2648c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_COMPAT_RO(free_space_tree, FREE_SPACE_TREE); 2658c2ecf20Sopenharmony_ciBTRFS_FEAT_ATTR_INCOMPAT(raid1c34, RAID1C34); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic struct attribute *btrfs_supported_feature_attrs[] = { 2688c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(mixed_backref), 2698c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(default_subvol), 2708c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(mixed_groups), 2718c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(compress_lzo), 2728c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(compress_zstd), 2738c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(big_metadata), 2748c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(extended_iref), 2758c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(raid56), 2768c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(skinny_metadata), 2778c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(no_holes), 2788c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(metadata_uuid), 2798c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(free_space_tree), 2808c2ecf20Sopenharmony_ci BTRFS_FEAT_ATTR_PTR(raid1c34), 2818c2ecf20Sopenharmony_ci NULL 2828c2ecf20Sopenharmony_ci}; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/* 2858c2ecf20Sopenharmony_ci * Features which depend on feature bits and may differ between each fs. 2868c2ecf20Sopenharmony_ci * 2878c2ecf20Sopenharmony_ci * /sys/fs/btrfs/features lists all available features of this kernel while 2888c2ecf20Sopenharmony_ci * /sys/fs/btrfs/UUID/features shows features of the fs which are enabled or 2898c2ecf20Sopenharmony_ci * can be changed online. 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_cistatic const struct attribute_group btrfs_feature_attr_group = { 2928c2ecf20Sopenharmony_ci .name = "features", 2938c2ecf20Sopenharmony_ci .is_visible = btrfs_feature_visible, 2948c2ecf20Sopenharmony_ci .attrs = btrfs_supported_feature_attrs, 2958c2ecf20Sopenharmony_ci}; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic ssize_t rmdir_subvol_show(struct kobject *kobj, 2988c2ecf20Sopenharmony_ci struct kobj_attribute *ka, char *buf) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "0\n"); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ciBTRFS_ATTR(static_feature, rmdir_subvol, rmdir_subvol_show); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic ssize_t supported_checksums_show(struct kobject *kobj, 3058c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci ssize_t ret = 0; 3088c2ecf20Sopenharmony_ci int i; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci for (i = 0; i < btrfs_get_num_csums(); i++) { 3118c2ecf20Sopenharmony_ci /* 3128c2ecf20Sopenharmony_ci * This "trick" only works as long as 'enum btrfs_csum_type' has 3138c2ecf20Sopenharmony_ci * no holes in it 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s%s", 3168c2ecf20Sopenharmony_ci (i == 0 ? "" : " "), btrfs_super_csum_name(i)); 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); 3218c2ecf20Sopenharmony_ci return ret; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ciBTRFS_ATTR(static_feature, supported_checksums, supported_checksums_show); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic ssize_t send_stream_version_show(struct kobject *kobj, 3268c2ecf20Sopenharmony_ci struct kobj_attribute *ka, char *buf) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", BTRFS_SEND_STREAM_VERSION); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ciBTRFS_ATTR(static_feature, send_stream_version, send_stream_version_show); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic struct attribute *btrfs_supported_static_feature_attrs[] = { 3338c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(static_feature, rmdir_subvol), 3348c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(static_feature, supported_checksums), 3358c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(static_feature, send_stream_version), 3368c2ecf20Sopenharmony_ci NULL 3378c2ecf20Sopenharmony_ci}; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci/* 3408c2ecf20Sopenharmony_ci * Features which only depend on kernel version. 3418c2ecf20Sopenharmony_ci * 3428c2ecf20Sopenharmony_ci * These are listed in /sys/fs/btrfs/features along with 3438c2ecf20Sopenharmony_ci * btrfs_feature_attr_group 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_cistatic const struct attribute_group btrfs_static_feature_attr_group = { 3468c2ecf20Sopenharmony_ci .name = "features", 3478c2ecf20Sopenharmony_ci .attrs = btrfs_supported_static_feature_attrs, 3488c2ecf20Sopenharmony_ci}; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci#ifdef CONFIG_BTRFS_DEBUG 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci/* 3538c2ecf20Sopenharmony_ci * Discard statistics and tunables 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_ci#define discard_to_fs_info(_kobj) to_fs_info((_kobj)->parent->parent) 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic ssize_t btrfs_discardable_bytes_show(struct kobject *kobj, 3588c2ecf20Sopenharmony_ci struct kobj_attribute *a, 3598c2ecf20Sopenharmony_ci char *buf) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%lld\n", 3648c2ecf20Sopenharmony_ci atomic64_read(&fs_info->discard_ctl.discardable_bytes)); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ciBTRFS_ATTR(discard, discardable_bytes, btrfs_discardable_bytes_show); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic ssize_t btrfs_discardable_extents_show(struct kobject *kobj, 3698c2ecf20Sopenharmony_ci struct kobj_attribute *a, 3708c2ecf20Sopenharmony_ci char *buf) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", 3758c2ecf20Sopenharmony_ci atomic_read(&fs_info->discard_ctl.discardable_extents)); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ciBTRFS_ATTR(discard, discardable_extents, btrfs_discardable_extents_show); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic ssize_t btrfs_discard_bitmap_bytes_show(struct kobject *kobj, 3808c2ecf20Sopenharmony_ci struct kobj_attribute *a, 3818c2ecf20Sopenharmony_ci char *buf) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%llu\n", 3868c2ecf20Sopenharmony_ci fs_info->discard_ctl.discard_bitmap_bytes); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ciBTRFS_ATTR(discard, discard_bitmap_bytes, btrfs_discard_bitmap_bytes_show); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic ssize_t btrfs_discard_bytes_saved_show(struct kobject *kobj, 3918c2ecf20Sopenharmony_ci struct kobj_attribute *a, 3928c2ecf20Sopenharmony_ci char *buf) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%lld\n", 3978c2ecf20Sopenharmony_ci atomic64_read(&fs_info->discard_ctl.discard_bytes_saved)); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ciBTRFS_ATTR(discard, discard_bytes_saved, btrfs_discard_bytes_saved_show); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic ssize_t btrfs_discard_extent_bytes_show(struct kobject *kobj, 4028c2ecf20Sopenharmony_ci struct kobj_attribute *a, 4038c2ecf20Sopenharmony_ci char *buf) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%llu\n", 4088c2ecf20Sopenharmony_ci fs_info->discard_ctl.discard_extent_bytes); 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ciBTRFS_ATTR(discard, discard_extent_bytes, btrfs_discard_extent_bytes_show); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic ssize_t btrfs_discard_iops_limit_show(struct kobject *kobj, 4138c2ecf20Sopenharmony_ci struct kobj_attribute *a, 4148c2ecf20Sopenharmony_ci char *buf) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", 4198c2ecf20Sopenharmony_ci READ_ONCE(fs_info->discard_ctl.iops_limit)); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic ssize_t btrfs_discard_iops_limit_store(struct kobject *kobj, 4238c2ecf20Sopenharmony_ci struct kobj_attribute *a, 4248c2ecf20Sopenharmony_ci const char *buf, size_t len) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); 4278c2ecf20Sopenharmony_ci struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl; 4288c2ecf20Sopenharmony_ci u32 iops_limit; 4298c2ecf20Sopenharmony_ci int ret; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci ret = kstrtou32(buf, 10, &iops_limit); 4328c2ecf20Sopenharmony_ci if (ret) 4338c2ecf20Sopenharmony_ci return -EINVAL; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci WRITE_ONCE(discard_ctl->iops_limit, iops_limit); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return len; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ciBTRFS_ATTR_RW(discard, iops_limit, btrfs_discard_iops_limit_show, 4408c2ecf20Sopenharmony_ci btrfs_discard_iops_limit_store); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic ssize_t btrfs_discard_kbps_limit_show(struct kobject *kobj, 4438c2ecf20Sopenharmony_ci struct kobj_attribute *a, 4448c2ecf20Sopenharmony_ci char *buf) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", 4498c2ecf20Sopenharmony_ci READ_ONCE(fs_info->discard_ctl.kbps_limit)); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic ssize_t btrfs_discard_kbps_limit_store(struct kobject *kobj, 4538c2ecf20Sopenharmony_ci struct kobj_attribute *a, 4548c2ecf20Sopenharmony_ci const char *buf, size_t len) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); 4578c2ecf20Sopenharmony_ci struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl; 4588c2ecf20Sopenharmony_ci u32 kbps_limit; 4598c2ecf20Sopenharmony_ci int ret; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci ret = kstrtou32(buf, 10, &kbps_limit); 4628c2ecf20Sopenharmony_ci if (ret) 4638c2ecf20Sopenharmony_ci return -EINVAL; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci WRITE_ONCE(discard_ctl->kbps_limit, kbps_limit); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return len; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ciBTRFS_ATTR_RW(discard, kbps_limit, btrfs_discard_kbps_limit_show, 4708c2ecf20Sopenharmony_ci btrfs_discard_kbps_limit_store); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic ssize_t btrfs_discard_max_discard_size_show(struct kobject *kobj, 4738c2ecf20Sopenharmony_ci struct kobj_attribute *a, 4748c2ecf20Sopenharmony_ci char *buf) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%llu\n", 4798c2ecf20Sopenharmony_ci READ_ONCE(fs_info->discard_ctl.max_discard_size)); 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic ssize_t btrfs_discard_max_discard_size_store(struct kobject *kobj, 4838c2ecf20Sopenharmony_ci struct kobj_attribute *a, 4848c2ecf20Sopenharmony_ci const char *buf, size_t len) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj); 4878c2ecf20Sopenharmony_ci struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl; 4888c2ecf20Sopenharmony_ci u64 max_discard_size; 4898c2ecf20Sopenharmony_ci int ret; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci ret = kstrtou64(buf, 10, &max_discard_size); 4928c2ecf20Sopenharmony_ci if (ret) 4938c2ecf20Sopenharmony_ci return -EINVAL; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci WRITE_ONCE(discard_ctl->max_discard_size, max_discard_size); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return len; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ciBTRFS_ATTR_RW(discard, max_discard_size, btrfs_discard_max_discard_size_show, 5008c2ecf20Sopenharmony_ci btrfs_discard_max_discard_size_store); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic const struct attribute *discard_debug_attrs[] = { 5038c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(discard, discardable_bytes), 5048c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(discard, discardable_extents), 5058c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(discard, discard_bitmap_bytes), 5068c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(discard, discard_bytes_saved), 5078c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(discard, discard_extent_bytes), 5088c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(discard, iops_limit), 5098c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(discard, kbps_limit), 5108c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(discard, max_discard_size), 5118c2ecf20Sopenharmony_ci NULL, 5128c2ecf20Sopenharmony_ci}; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci/* 5158c2ecf20Sopenharmony_ci * Runtime debugging exported via sysfs 5168c2ecf20Sopenharmony_ci * 5178c2ecf20Sopenharmony_ci * /sys/fs/btrfs/debug - applies to module or all filesystems 5188c2ecf20Sopenharmony_ci * /sys/fs/btrfs/UUID - applies only to the given filesystem 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_cistatic const struct attribute *btrfs_debug_mount_attrs[] = { 5218c2ecf20Sopenharmony_ci NULL, 5228c2ecf20Sopenharmony_ci}; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic struct attribute *btrfs_debug_feature_attrs[] = { 5258c2ecf20Sopenharmony_ci NULL 5268c2ecf20Sopenharmony_ci}; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic const struct attribute_group btrfs_debug_feature_attr_group = { 5298c2ecf20Sopenharmony_ci .name = "debug", 5308c2ecf20Sopenharmony_ci .attrs = btrfs_debug_feature_attrs, 5318c2ecf20Sopenharmony_ci}; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci#endif 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci u64 val; 5388c2ecf20Sopenharmony_ci if (lock) 5398c2ecf20Sopenharmony_ci spin_lock(lock); 5408c2ecf20Sopenharmony_ci val = *value_ptr; 5418c2ecf20Sopenharmony_ci if (lock) 5428c2ecf20Sopenharmony_ci spin_unlock(lock); 5438c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%llu\n", val); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic ssize_t global_rsv_size_show(struct kobject *kobj, 5478c2ecf20Sopenharmony_ci struct kobj_attribute *ka, char *buf) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); 5508c2ecf20Sopenharmony_ci struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; 5518c2ecf20Sopenharmony_ci return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ciBTRFS_ATTR(allocation, global_rsv_size, global_rsv_size_show); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic ssize_t global_rsv_reserved_show(struct kobject *kobj, 5568c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); 5598c2ecf20Sopenharmony_ci struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; 5608c2ecf20Sopenharmony_ci return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf); 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ciBTRFS_ATTR(allocation, global_rsv_reserved, global_rsv_reserved_show); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci#define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj) 5658c2ecf20Sopenharmony_ci#define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj) 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic ssize_t raid_bytes_show(struct kobject *kobj, 5688c2ecf20Sopenharmony_ci struct kobj_attribute *attr, char *buf); 5698c2ecf20Sopenharmony_ciBTRFS_ATTR(raid, total_bytes, raid_bytes_show); 5708c2ecf20Sopenharmony_ciBTRFS_ATTR(raid, used_bytes, raid_bytes_show); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic ssize_t raid_bytes_show(struct kobject *kobj, 5738c2ecf20Sopenharmony_ci struct kobj_attribute *attr, char *buf) 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct btrfs_space_info *sinfo = to_space_info(kobj->parent); 5778c2ecf20Sopenharmony_ci struct btrfs_block_group *block_group; 5788c2ecf20Sopenharmony_ci int index = btrfs_bg_flags_to_raid_index(to_raid_kobj(kobj)->flags); 5798c2ecf20Sopenharmony_ci u64 val = 0; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci down_read(&sinfo->groups_sem); 5828c2ecf20Sopenharmony_ci list_for_each_entry(block_group, &sinfo->block_groups[index], list) { 5838c2ecf20Sopenharmony_ci if (&attr->attr == BTRFS_ATTR_PTR(raid, total_bytes)) 5848c2ecf20Sopenharmony_ci val += block_group->length; 5858c2ecf20Sopenharmony_ci else 5868c2ecf20Sopenharmony_ci val += block_group->used; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci up_read(&sinfo->groups_sem); 5898c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%llu\n", val); 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic struct attribute *raid_attrs[] = { 5938c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(raid, total_bytes), 5948c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(raid, used_bytes), 5958c2ecf20Sopenharmony_ci NULL 5968c2ecf20Sopenharmony_ci}; 5978c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(raid); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic void release_raid_kobj(struct kobject *kobj) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci kfree(to_raid_kobj(kobj)); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic struct kobj_type btrfs_raid_ktype = { 6058c2ecf20Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 6068c2ecf20Sopenharmony_ci .release = release_raid_kobj, 6078c2ecf20Sopenharmony_ci .default_groups = raid_groups, 6088c2ecf20Sopenharmony_ci}; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci#define SPACE_INFO_ATTR(field) \ 6118c2ecf20Sopenharmony_cistatic ssize_t btrfs_space_info_show_##field(struct kobject *kobj, \ 6128c2ecf20Sopenharmony_ci struct kobj_attribute *a, \ 6138c2ecf20Sopenharmony_ci char *buf) \ 6148c2ecf20Sopenharmony_ci{ \ 6158c2ecf20Sopenharmony_ci struct btrfs_space_info *sinfo = to_space_info(kobj); \ 6168c2ecf20Sopenharmony_ci return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf); \ 6178c2ecf20Sopenharmony_ci} \ 6188c2ecf20Sopenharmony_ciBTRFS_ATTR(space_info, field, btrfs_space_info_show_##field) 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic ssize_t btrfs_space_info_show_total_bytes_pinned(struct kobject *kobj, 6218c2ecf20Sopenharmony_ci struct kobj_attribute *a, 6228c2ecf20Sopenharmony_ci char *buf) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct btrfs_space_info *sinfo = to_space_info(kobj); 6258c2ecf20Sopenharmony_ci s64 val = percpu_counter_sum(&sinfo->total_bytes_pinned); 6268c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%lld\n", val); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ciSPACE_INFO_ATTR(flags); 6308c2ecf20Sopenharmony_ciSPACE_INFO_ATTR(total_bytes); 6318c2ecf20Sopenharmony_ciSPACE_INFO_ATTR(bytes_used); 6328c2ecf20Sopenharmony_ciSPACE_INFO_ATTR(bytes_pinned); 6338c2ecf20Sopenharmony_ciSPACE_INFO_ATTR(bytes_reserved); 6348c2ecf20Sopenharmony_ciSPACE_INFO_ATTR(bytes_may_use); 6358c2ecf20Sopenharmony_ciSPACE_INFO_ATTR(bytes_readonly); 6368c2ecf20Sopenharmony_ciSPACE_INFO_ATTR(disk_used); 6378c2ecf20Sopenharmony_ciSPACE_INFO_ATTR(disk_total); 6388c2ecf20Sopenharmony_ciBTRFS_ATTR(space_info, total_bytes_pinned, 6398c2ecf20Sopenharmony_ci btrfs_space_info_show_total_bytes_pinned); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic struct attribute *space_info_attrs[] = { 6428c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(space_info, flags), 6438c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(space_info, total_bytes), 6448c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(space_info, bytes_used), 6458c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(space_info, bytes_pinned), 6468c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(space_info, bytes_reserved), 6478c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(space_info, bytes_may_use), 6488c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(space_info, bytes_readonly), 6498c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(space_info, disk_used), 6508c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(space_info, disk_total), 6518c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(space_info, total_bytes_pinned), 6528c2ecf20Sopenharmony_ci NULL, 6538c2ecf20Sopenharmony_ci}; 6548c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(space_info); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic void space_info_release(struct kobject *kobj) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci struct btrfs_space_info *sinfo = to_space_info(kobj); 6598c2ecf20Sopenharmony_ci percpu_counter_destroy(&sinfo->total_bytes_pinned); 6608c2ecf20Sopenharmony_ci kfree(sinfo); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic struct kobj_type space_info_ktype = { 6648c2ecf20Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 6658c2ecf20Sopenharmony_ci .release = space_info_release, 6668c2ecf20Sopenharmony_ci .default_groups = space_info_groups, 6678c2ecf20Sopenharmony_ci}; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic const struct attribute *allocation_attrs[] = { 6708c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(allocation, global_rsv_reserved), 6718c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(allocation, global_rsv_size), 6728c2ecf20Sopenharmony_ci NULL, 6738c2ecf20Sopenharmony_ci}; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic ssize_t btrfs_label_show(struct kobject *kobj, 6768c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 6798c2ecf20Sopenharmony_ci char *label = fs_info->super_copy->label; 6808c2ecf20Sopenharmony_ci ssize_t ret; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci spin_lock(&fs_info->super_lock); 6838c2ecf20Sopenharmony_ci ret = scnprintf(buf, PAGE_SIZE, label[0] ? "%s\n" : "%s", label); 6848c2ecf20Sopenharmony_ci spin_unlock(&fs_info->super_lock); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci return ret; 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cistatic ssize_t btrfs_label_store(struct kobject *kobj, 6908c2ecf20Sopenharmony_ci struct kobj_attribute *a, 6918c2ecf20Sopenharmony_ci const char *buf, size_t len) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 6948c2ecf20Sopenharmony_ci size_t p_len; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (!fs_info) 6978c2ecf20Sopenharmony_ci return -EPERM; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (sb_rdonly(fs_info->sb)) 7008c2ecf20Sopenharmony_ci return -EROFS; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* 7038c2ecf20Sopenharmony_ci * p_len is the len until the first occurrence of either 7048c2ecf20Sopenharmony_ci * '\n' or '\0' 7058c2ecf20Sopenharmony_ci */ 7068c2ecf20Sopenharmony_ci p_len = strcspn(buf, "\n"); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (p_len >= BTRFS_LABEL_SIZE) 7098c2ecf20Sopenharmony_ci return -EINVAL; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci spin_lock(&fs_info->super_lock); 7128c2ecf20Sopenharmony_ci memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE); 7138c2ecf20Sopenharmony_ci memcpy(fs_info->super_copy->label, buf, p_len); 7148c2ecf20Sopenharmony_ci spin_unlock(&fs_info->super_lock); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci /* 7178c2ecf20Sopenharmony_ci * We don't want to do full transaction commit from inside sysfs 7188c2ecf20Sopenharmony_ci */ 7198c2ecf20Sopenharmony_ci btrfs_set_pending(fs_info, COMMIT); 7208c2ecf20Sopenharmony_ci wake_up_process(fs_info->transaction_kthread); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci return len; 7238c2ecf20Sopenharmony_ci} 7248c2ecf20Sopenharmony_ciBTRFS_ATTR_RW(, label, btrfs_label_show, btrfs_label_store); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic ssize_t btrfs_nodesize_show(struct kobject *kobj, 7278c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->nodesize); 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ciBTRFS_ATTR(, nodesize, btrfs_nodesize_show); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic ssize_t btrfs_sectorsize_show(struct kobject *kobj, 7378c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", 7428c2ecf20Sopenharmony_ci fs_info->super_copy->sectorsize); 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ciBTRFS_ATTR(, sectorsize, btrfs_sectorsize_show); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic ssize_t btrfs_clone_alignment_show(struct kobject *kobj, 7488c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->sectorsize); 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ciBTRFS_ATTR(, clone_alignment, btrfs_clone_alignment_show); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic ssize_t quota_override_show(struct kobject *kobj, 7588c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 7618c2ecf20Sopenharmony_ci int quota_override; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci quota_override = test_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags); 7648c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", quota_override); 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic ssize_t quota_override_store(struct kobject *kobj, 7688c2ecf20Sopenharmony_ci struct kobj_attribute *a, 7698c2ecf20Sopenharmony_ci const char *buf, size_t len) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 7728c2ecf20Sopenharmony_ci unsigned long knob; 7738c2ecf20Sopenharmony_ci int err; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (!fs_info) 7768c2ecf20Sopenharmony_ci return -EPERM; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_RESOURCE)) 7798c2ecf20Sopenharmony_ci return -EPERM; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci err = kstrtoul(buf, 10, &knob); 7828c2ecf20Sopenharmony_ci if (err) 7838c2ecf20Sopenharmony_ci return err; 7848c2ecf20Sopenharmony_ci if (knob > 1) 7858c2ecf20Sopenharmony_ci return -EINVAL; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (knob) 7888c2ecf20Sopenharmony_ci set_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags); 7898c2ecf20Sopenharmony_ci else 7908c2ecf20Sopenharmony_ci clear_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci return len; 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ciBTRFS_ATTR_RW(, quota_override, quota_override_show, quota_override_store); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic ssize_t btrfs_metadata_uuid_show(struct kobject *kobj, 7988c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%pU\n", 8038c2ecf20Sopenharmony_ci fs_info->fs_devices->metadata_uuid); 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ciBTRFS_ATTR(, metadata_uuid, btrfs_metadata_uuid_show); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic ssize_t btrfs_checksum_show(struct kobject *kobj, 8098c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 8128c2ecf20Sopenharmony_ci u16 csum_type = btrfs_super_csum_type(fs_info->super_copy); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%s (%s)\n", 8158c2ecf20Sopenharmony_ci btrfs_super_csum_name(csum_type), 8168c2ecf20Sopenharmony_ci crypto_shash_driver_name(fs_info->csum_shash)); 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ciBTRFS_ATTR(, checksum, btrfs_checksum_show); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic ssize_t btrfs_exclusive_operation_show(struct kobject *kobj, 8228c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = to_fs_info(kobj); 8258c2ecf20Sopenharmony_ci const char *str; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci switch (READ_ONCE(fs_info->exclusive_operation)) { 8288c2ecf20Sopenharmony_ci case BTRFS_EXCLOP_NONE: 8298c2ecf20Sopenharmony_ci str = "none\n"; 8308c2ecf20Sopenharmony_ci break; 8318c2ecf20Sopenharmony_ci case BTRFS_EXCLOP_BALANCE: 8328c2ecf20Sopenharmony_ci str = "balance\n"; 8338c2ecf20Sopenharmony_ci break; 8348c2ecf20Sopenharmony_ci case BTRFS_EXCLOP_DEV_ADD: 8358c2ecf20Sopenharmony_ci str = "device add\n"; 8368c2ecf20Sopenharmony_ci break; 8378c2ecf20Sopenharmony_ci case BTRFS_EXCLOP_DEV_REMOVE: 8388c2ecf20Sopenharmony_ci str = "device remove\n"; 8398c2ecf20Sopenharmony_ci break; 8408c2ecf20Sopenharmony_ci case BTRFS_EXCLOP_DEV_REPLACE: 8418c2ecf20Sopenharmony_ci str = "device replace\n"; 8428c2ecf20Sopenharmony_ci break; 8438c2ecf20Sopenharmony_ci case BTRFS_EXCLOP_RESIZE: 8448c2ecf20Sopenharmony_ci str = "resize\n"; 8458c2ecf20Sopenharmony_ci break; 8468c2ecf20Sopenharmony_ci case BTRFS_EXCLOP_SWAP_ACTIVATE: 8478c2ecf20Sopenharmony_ci str = "swap activate\n"; 8488c2ecf20Sopenharmony_ci break; 8498c2ecf20Sopenharmony_ci default: 8508c2ecf20Sopenharmony_ci str = "UNKNOWN\n"; 8518c2ecf20Sopenharmony_ci break; 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%s", str); 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ciBTRFS_ATTR(, exclusive_operation, btrfs_exclusive_operation_show); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic const struct attribute *btrfs_attrs[] = { 8588c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(, label), 8598c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(, nodesize), 8608c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(, sectorsize), 8618c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(, clone_alignment), 8628c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(, quota_override), 8638c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(, metadata_uuid), 8648c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(, checksum), 8658c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(, exclusive_operation), 8668c2ecf20Sopenharmony_ci NULL, 8678c2ecf20Sopenharmony_ci}; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_cistatic void btrfs_release_fsid_kobj(struct kobject *kobj) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci struct btrfs_fs_devices *fs_devs = to_fs_devs(kobj); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci memset(&fs_devs->fsid_kobj, 0, sizeof(struct kobject)); 8748c2ecf20Sopenharmony_ci complete(&fs_devs->kobj_unregister); 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic struct kobj_type btrfs_ktype = { 8788c2ecf20Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 8798c2ecf20Sopenharmony_ci .release = btrfs_release_fsid_kobj, 8808c2ecf20Sopenharmony_ci}; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci if (kobj->ktype != &btrfs_ktype) 8858c2ecf20Sopenharmony_ci return NULL; 8868c2ecf20Sopenharmony_ci return container_of(kobj, struct btrfs_fs_devices, fsid_kobj); 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_cistatic inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci if (kobj->ktype != &btrfs_ktype) 8928c2ecf20Sopenharmony_ci return NULL; 8938c2ecf20Sopenharmony_ci return to_fs_devs(kobj)->fs_info; 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci#define NUM_FEATURE_BITS 64 8978c2ecf20Sopenharmony_ci#define BTRFS_FEATURE_NAME_MAX 13 8988c2ecf20Sopenharmony_cistatic char btrfs_unknown_feature_names[FEAT_MAX][NUM_FEATURE_BITS][BTRFS_FEATURE_NAME_MAX]; 8998c2ecf20Sopenharmony_cistatic struct btrfs_feature_attr btrfs_feature_attrs[FEAT_MAX][NUM_FEATURE_BITS]; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic const u64 supported_feature_masks[FEAT_MAX] = { 9028c2ecf20Sopenharmony_ci [FEAT_COMPAT] = BTRFS_FEATURE_COMPAT_SUPP, 9038c2ecf20Sopenharmony_ci [FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP, 9048c2ecf20Sopenharmony_ci [FEAT_INCOMPAT] = BTRFS_FEATURE_INCOMPAT_SUPP, 9058c2ecf20Sopenharmony_ci}; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci int set; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci for (set = 0; set < FEAT_MAX; set++) { 9128c2ecf20Sopenharmony_ci int i; 9138c2ecf20Sopenharmony_ci struct attribute *attrs[2]; 9148c2ecf20Sopenharmony_ci struct attribute_group agroup = { 9158c2ecf20Sopenharmony_ci .name = "features", 9168c2ecf20Sopenharmony_ci .attrs = attrs, 9178c2ecf20Sopenharmony_ci }; 9188c2ecf20Sopenharmony_ci u64 features = get_features(fs_info, set); 9198c2ecf20Sopenharmony_ci features &= ~supported_feature_masks[set]; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if (!features) 9228c2ecf20Sopenharmony_ci continue; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci attrs[1] = NULL; 9258c2ecf20Sopenharmony_ci for (i = 0; i < NUM_FEATURE_BITS; i++) { 9268c2ecf20Sopenharmony_ci struct btrfs_feature_attr *fa; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (!(features & (1ULL << i))) 9298c2ecf20Sopenharmony_ci continue; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci fa = &btrfs_feature_attrs[set][i]; 9328c2ecf20Sopenharmony_ci attrs[0] = &fa->kobj_attr.attr; 9338c2ecf20Sopenharmony_ci if (add) { 9348c2ecf20Sopenharmony_ci int ret; 9358c2ecf20Sopenharmony_ci ret = sysfs_merge_group(&fs_info->fs_devices->fsid_kobj, 9368c2ecf20Sopenharmony_ci &agroup); 9378c2ecf20Sopenharmony_ci if (ret) 9388c2ecf20Sopenharmony_ci return ret; 9398c2ecf20Sopenharmony_ci } else 9408c2ecf20Sopenharmony_ci sysfs_unmerge_group(&fs_info->fs_devices->fsid_kobj, 9418c2ecf20Sopenharmony_ci &agroup); 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci return 0; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci if (fs_devs->devinfo_kobj) { 9518c2ecf20Sopenharmony_ci kobject_del(fs_devs->devinfo_kobj); 9528c2ecf20Sopenharmony_ci kobject_put(fs_devs->devinfo_kobj); 9538c2ecf20Sopenharmony_ci fs_devs->devinfo_kobj = NULL; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (fs_devs->devices_kobj) { 9578c2ecf20Sopenharmony_ci kobject_del(fs_devs->devices_kobj); 9588c2ecf20Sopenharmony_ci kobject_put(fs_devs->devices_kobj); 9598c2ecf20Sopenharmony_ci fs_devs->devices_kobj = NULL; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (fs_devs->fsid_kobj.state_initialized) { 9638c2ecf20Sopenharmony_ci kobject_del(&fs_devs->fsid_kobj); 9648c2ecf20Sopenharmony_ci kobject_put(&fs_devs->fsid_kobj); 9658c2ecf20Sopenharmony_ci wait_for_completion(&fs_devs->kobj_unregister); 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci/* when fs_devs is NULL it will remove all fsid kobject */ 9708c2ecf20Sopenharmony_civoid btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci struct list_head *fs_uuids = btrfs_get_fs_uuids(); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (fs_devs) { 9758c2ecf20Sopenharmony_ci __btrfs_sysfs_remove_fsid(fs_devs); 9768c2ecf20Sopenharmony_ci return; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci list_for_each_entry(fs_devs, fs_uuids, fs_list) { 9808c2ecf20Sopenharmony_ci __btrfs_sysfs_remove_fsid(fs_devs); 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic void btrfs_sysfs_remove_fs_devices(struct btrfs_fs_devices *fs_devices) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci struct btrfs_device *device; 9878c2ecf20Sopenharmony_ci struct btrfs_fs_devices *seed; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci list_for_each_entry(device, &fs_devices->devices, dev_list) 9908c2ecf20Sopenharmony_ci btrfs_sysfs_remove_device(device); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci list_for_each_entry(seed, &fs_devices->seed_list, seed_list) { 9938c2ecf20Sopenharmony_ci list_for_each_entry(device, &seed->devices, dev_list) 9948c2ecf20Sopenharmony_ci btrfs_sysfs_remove_device(device); 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_civoid btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci sysfs_remove_link(fsid_kobj, "bdi"); 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (fs_info->space_info_kobj) { 10058c2ecf20Sopenharmony_ci sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs); 10068c2ecf20Sopenharmony_ci kobject_del(fs_info->space_info_kobj); 10078c2ecf20Sopenharmony_ci kobject_put(fs_info->space_info_kobj); 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci#ifdef CONFIG_BTRFS_DEBUG 10108c2ecf20Sopenharmony_ci if (fs_info->discard_debug_kobj) { 10118c2ecf20Sopenharmony_ci sysfs_remove_files(fs_info->discard_debug_kobj, 10128c2ecf20Sopenharmony_ci discard_debug_attrs); 10138c2ecf20Sopenharmony_ci kobject_del(fs_info->discard_debug_kobj); 10148c2ecf20Sopenharmony_ci kobject_put(fs_info->discard_debug_kobj); 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci if (fs_info->debug_kobj) { 10178c2ecf20Sopenharmony_ci sysfs_remove_files(fs_info->debug_kobj, btrfs_debug_mount_attrs); 10188c2ecf20Sopenharmony_ci kobject_del(fs_info->debug_kobj); 10198c2ecf20Sopenharmony_ci kobject_put(fs_info->debug_kobj); 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci#endif 10228c2ecf20Sopenharmony_ci addrm_unknown_feature_attrs(fs_info, false); 10238c2ecf20Sopenharmony_ci sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group); 10248c2ecf20Sopenharmony_ci sysfs_remove_files(fsid_kobj, btrfs_attrs); 10258c2ecf20Sopenharmony_ci btrfs_sysfs_remove_fs_devices(fs_info->fs_devices); 10268c2ecf20Sopenharmony_ci} 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_cistatic const char * const btrfs_feature_set_names[FEAT_MAX] = { 10298c2ecf20Sopenharmony_ci [FEAT_COMPAT] = "compat", 10308c2ecf20Sopenharmony_ci [FEAT_COMPAT_RO] = "compat_ro", 10318c2ecf20Sopenharmony_ci [FEAT_INCOMPAT] = "incompat", 10328c2ecf20Sopenharmony_ci}; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ciconst char *btrfs_feature_set_name(enum btrfs_feature_set set) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci return btrfs_feature_set_names[set]; 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cichar *btrfs_printable_features(enum btrfs_feature_set set, u64 flags) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */ 10428c2ecf20Sopenharmony_ci int len = 0; 10438c2ecf20Sopenharmony_ci int i; 10448c2ecf20Sopenharmony_ci char *str; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci str = kmalloc(bufsize, GFP_KERNEL); 10478c2ecf20Sopenharmony_ci if (!str) 10488c2ecf20Sopenharmony_ci return str; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { 10518c2ecf20Sopenharmony_ci const char *name; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci if (!(flags & (1ULL << i))) 10548c2ecf20Sopenharmony_ci continue; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci name = btrfs_feature_attrs[set][i].kobj_attr.attr.name; 10578c2ecf20Sopenharmony_ci len += scnprintf(str + len, bufsize - len, "%s%s", 10588c2ecf20Sopenharmony_ci len ? "," : "", name); 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci return str; 10628c2ecf20Sopenharmony_ci} 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_cistatic void init_feature_attrs(void) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci struct btrfs_feature_attr *fa; 10678c2ecf20Sopenharmony_ci int set, i; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names) != 10708c2ecf20Sopenharmony_ci ARRAY_SIZE(btrfs_feature_attrs)); 10718c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) != 10728c2ecf20Sopenharmony_ci ARRAY_SIZE(btrfs_feature_attrs[0])); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs)); 10758c2ecf20Sopenharmony_ci memset(btrfs_unknown_feature_names, 0, 10768c2ecf20Sopenharmony_ci sizeof(btrfs_unknown_feature_names)); 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci for (i = 0; btrfs_supported_feature_attrs[i]; i++) { 10798c2ecf20Sopenharmony_ci struct btrfs_feature_attr *sfa; 10808c2ecf20Sopenharmony_ci struct attribute *a = btrfs_supported_feature_attrs[i]; 10818c2ecf20Sopenharmony_ci int bit; 10828c2ecf20Sopenharmony_ci sfa = attr_to_btrfs_feature_attr(a); 10838c2ecf20Sopenharmony_ci bit = ilog2(sfa->feature_bit); 10848c2ecf20Sopenharmony_ci fa = &btrfs_feature_attrs[sfa->feature_set][bit]; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name; 10878c2ecf20Sopenharmony_ci } 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci for (set = 0; set < FEAT_MAX; set++) { 10908c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { 10918c2ecf20Sopenharmony_ci char *name = btrfs_unknown_feature_names[set][i]; 10928c2ecf20Sopenharmony_ci fa = &btrfs_feature_attrs[set][i]; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (fa->kobj_attr.attr.name) 10958c2ecf20Sopenharmony_ci continue; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci snprintf(name, BTRFS_FEATURE_NAME_MAX, "%s:%u", 10988c2ecf20Sopenharmony_ci btrfs_feature_set_names[set], i); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci fa->kobj_attr.attr.name = name; 11018c2ecf20Sopenharmony_ci fa->kobj_attr.attr.mode = S_IRUGO; 11028c2ecf20Sopenharmony_ci fa->feature_set = set; 11038c2ecf20Sopenharmony_ci fa->feature_bit = 1ULL << i; 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci/* 11098c2ecf20Sopenharmony_ci * Create a sysfs entry for a given block group type at path 11108c2ecf20Sopenharmony_ci * /sys/fs/btrfs/UUID/allocation/data/TYPE 11118c2ecf20Sopenharmony_ci */ 11128c2ecf20Sopenharmony_civoid btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = cache->fs_info; 11158c2ecf20Sopenharmony_ci struct btrfs_space_info *space_info = cache->space_info; 11168c2ecf20Sopenharmony_ci struct raid_kobject *rkobj; 11178c2ecf20Sopenharmony_ci const int index = btrfs_bg_flags_to_raid_index(cache->flags); 11188c2ecf20Sopenharmony_ci unsigned int nofs_flag; 11198c2ecf20Sopenharmony_ci int ret; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* 11228c2ecf20Sopenharmony_ci * Setup a NOFS context because kobject_add(), deep in its call chain, 11238c2ecf20Sopenharmony_ci * does GFP_KERNEL allocations, and we are often called in a context 11248c2ecf20Sopenharmony_ci * where if reclaim is triggered we can deadlock (we are either holding 11258c2ecf20Sopenharmony_ci * a transaction handle or some lock required for a transaction 11268c2ecf20Sopenharmony_ci * commit). 11278c2ecf20Sopenharmony_ci */ 11288c2ecf20Sopenharmony_ci nofs_flag = memalloc_nofs_save(); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS); 11318c2ecf20Sopenharmony_ci if (!rkobj) { 11328c2ecf20Sopenharmony_ci memalloc_nofs_restore(nofs_flag); 11338c2ecf20Sopenharmony_ci btrfs_warn(cache->fs_info, 11348c2ecf20Sopenharmony_ci "couldn't alloc memory for raid level kobject"); 11358c2ecf20Sopenharmony_ci return; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci rkobj->flags = cache->flags; 11398c2ecf20Sopenharmony_ci kobject_init(&rkobj->kobj, &btrfs_raid_ktype); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci /* 11428c2ecf20Sopenharmony_ci * We call this either on mount, or if we've created a block group for a 11438c2ecf20Sopenharmony_ci * new index type while running (i.e. when restriping). The running 11448c2ecf20Sopenharmony_ci * case is tricky because we could race with other threads, so we need 11458c2ecf20Sopenharmony_ci * to have this check to make sure we didn't already init the kobject. 11468c2ecf20Sopenharmony_ci * 11478c2ecf20Sopenharmony_ci * We don't have to protect on the free side because it only happens on 11488c2ecf20Sopenharmony_ci * unmount. 11498c2ecf20Sopenharmony_ci */ 11508c2ecf20Sopenharmony_ci spin_lock(&space_info->lock); 11518c2ecf20Sopenharmony_ci if (space_info->block_group_kobjs[index]) { 11528c2ecf20Sopenharmony_ci spin_unlock(&space_info->lock); 11538c2ecf20Sopenharmony_ci kobject_put(&rkobj->kobj); 11548c2ecf20Sopenharmony_ci return; 11558c2ecf20Sopenharmony_ci } else { 11568c2ecf20Sopenharmony_ci space_info->block_group_kobjs[index] = &rkobj->kobj; 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci spin_unlock(&space_info->lock); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci ret = kobject_add(&rkobj->kobj, &space_info->kobj, "%s", 11618c2ecf20Sopenharmony_ci btrfs_bg_type_to_raid_name(rkobj->flags)); 11628c2ecf20Sopenharmony_ci memalloc_nofs_restore(nofs_flag); 11638c2ecf20Sopenharmony_ci if (ret) { 11648c2ecf20Sopenharmony_ci spin_lock(&space_info->lock); 11658c2ecf20Sopenharmony_ci space_info->block_group_kobjs[index] = NULL; 11668c2ecf20Sopenharmony_ci spin_unlock(&space_info->lock); 11678c2ecf20Sopenharmony_ci kobject_put(&rkobj->kobj); 11688c2ecf20Sopenharmony_ci btrfs_warn(fs_info, 11698c2ecf20Sopenharmony_ci "failed to add kobject for block cache, ignoring"); 11708c2ecf20Sopenharmony_ci return; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci/* 11758c2ecf20Sopenharmony_ci * Remove sysfs directories for all block group types of a given space info and 11768c2ecf20Sopenharmony_ci * the space info as well 11778c2ecf20Sopenharmony_ci */ 11788c2ecf20Sopenharmony_civoid btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info) 11798c2ecf20Sopenharmony_ci{ 11808c2ecf20Sopenharmony_ci int i; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) { 11838c2ecf20Sopenharmony_ci struct kobject *kobj; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci kobj = space_info->block_group_kobjs[i]; 11868c2ecf20Sopenharmony_ci space_info->block_group_kobjs[i] = NULL; 11878c2ecf20Sopenharmony_ci if (kobj) { 11888c2ecf20Sopenharmony_ci kobject_del(kobj); 11898c2ecf20Sopenharmony_ci kobject_put(kobj); 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci kobject_del(&space_info->kobj); 11938c2ecf20Sopenharmony_ci kobject_put(&space_info->kobj); 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistatic const char *alloc_name(u64 flags) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci switch (flags) { 11998c2ecf20Sopenharmony_ci case BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA: 12008c2ecf20Sopenharmony_ci return "mixed"; 12018c2ecf20Sopenharmony_ci case BTRFS_BLOCK_GROUP_METADATA: 12028c2ecf20Sopenharmony_ci return "metadata"; 12038c2ecf20Sopenharmony_ci case BTRFS_BLOCK_GROUP_DATA: 12048c2ecf20Sopenharmony_ci return "data"; 12058c2ecf20Sopenharmony_ci case BTRFS_BLOCK_GROUP_SYSTEM: 12068c2ecf20Sopenharmony_ci return "system"; 12078c2ecf20Sopenharmony_ci default: 12088c2ecf20Sopenharmony_ci WARN_ON(1); 12098c2ecf20Sopenharmony_ci return "invalid-combination"; 12108c2ecf20Sopenharmony_ci }; 12118c2ecf20Sopenharmony_ci} 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci/* 12148c2ecf20Sopenharmony_ci * Create a sysfs entry for a space info type at path 12158c2ecf20Sopenharmony_ci * /sys/fs/btrfs/UUID/allocation/TYPE 12168c2ecf20Sopenharmony_ci */ 12178c2ecf20Sopenharmony_ciint btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info, 12188c2ecf20Sopenharmony_ci struct btrfs_space_info *space_info) 12198c2ecf20Sopenharmony_ci{ 12208c2ecf20Sopenharmony_ci int ret; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype, 12238c2ecf20Sopenharmony_ci fs_info->space_info_kobj, "%s", 12248c2ecf20Sopenharmony_ci alloc_name(space_info->flags)); 12258c2ecf20Sopenharmony_ci if (ret) { 12268c2ecf20Sopenharmony_ci kobject_put(&space_info->kobj); 12278c2ecf20Sopenharmony_ci return ret; 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci return 0; 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_civoid btrfs_sysfs_remove_device(struct btrfs_device *device) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci struct hd_struct *disk; 12368c2ecf20Sopenharmony_ci struct kobject *disk_kobj; 12378c2ecf20Sopenharmony_ci struct kobject *devices_kobj; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* 12408c2ecf20Sopenharmony_ci * Seed fs_devices devices_kobj aren't used, fetch kobject from the 12418c2ecf20Sopenharmony_ci * fs_info::fs_devices. 12428c2ecf20Sopenharmony_ci */ 12438c2ecf20Sopenharmony_ci devices_kobj = device->fs_info->fs_devices->devices_kobj; 12448c2ecf20Sopenharmony_ci ASSERT(devices_kobj); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if (device->bdev) { 12478c2ecf20Sopenharmony_ci disk = device->bdev->bd_part; 12488c2ecf20Sopenharmony_ci disk_kobj = &part_to_dev(disk)->kobj; 12498c2ecf20Sopenharmony_ci sysfs_remove_link(devices_kobj, disk_kobj->name); 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if (device->devid_kobj.state_initialized) { 12538c2ecf20Sopenharmony_ci kobject_del(&device->devid_kobj); 12548c2ecf20Sopenharmony_ci kobject_put(&device->devid_kobj); 12558c2ecf20Sopenharmony_ci wait_for_completion(&device->kobj_unregister); 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci} 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_cistatic ssize_t btrfs_devinfo_in_fs_metadata_show(struct kobject *kobj, 12608c2ecf20Sopenharmony_ci struct kobj_attribute *a, 12618c2ecf20Sopenharmony_ci char *buf) 12628c2ecf20Sopenharmony_ci{ 12638c2ecf20Sopenharmony_ci int val; 12648c2ecf20Sopenharmony_ci struct btrfs_device *device = container_of(kobj, struct btrfs_device, 12658c2ecf20Sopenharmony_ci devid_kobj); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci val = !!test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", val); 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ciBTRFS_ATTR(devid, in_fs_metadata, btrfs_devinfo_in_fs_metadata_show); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic ssize_t btrfs_devinfo_missing_show(struct kobject *kobj, 12748c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 12758c2ecf20Sopenharmony_ci{ 12768c2ecf20Sopenharmony_ci int val; 12778c2ecf20Sopenharmony_ci struct btrfs_device *device = container_of(kobj, struct btrfs_device, 12788c2ecf20Sopenharmony_ci devid_kobj); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci val = !!test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", val); 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ciBTRFS_ATTR(devid, missing, btrfs_devinfo_missing_show); 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_cistatic ssize_t btrfs_devinfo_replace_target_show(struct kobject *kobj, 12878c2ecf20Sopenharmony_ci struct kobj_attribute *a, 12888c2ecf20Sopenharmony_ci char *buf) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci int val; 12918c2ecf20Sopenharmony_ci struct btrfs_device *device = container_of(kobj, struct btrfs_device, 12928c2ecf20Sopenharmony_ci devid_kobj); 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci val = !!test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", val); 12978c2ecf20Sopenharmony_ci} 12988c2ecf20Sopenharmony_ciBTRFS_ATTR(devid, replace_target, btrfs_devinfo_replace_target_show); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_cistatic ssize_t btrfs_devinfo_writeable_show(struct kobject *kobj, 13018c2ecf20Sopenharmony_ci struct kobj_attribute *a, char *buf) 13028c2ecf20Sopenharmony_ci{ 13038c2ecf20Sopenharmony_ci int val; 13048c2ecf20Sopenharmony_ci struct btrfs_device *device = container_of(kobj, struct btrfs_device, 13058c2ecf20Sopenharmony_ci devid_kobj); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci val = !!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state); 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci return scnprintf(buf, PAGE_SIZE, "%d\n", val); 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ciBTRFS_ATTR(devid, writeable, btrfs_devinfo_writeable_show); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_cistatic struct attribute *devid_attrs[] = { 13148c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(devid, in_fs_metadata), 13158c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(devid, missing), 13168c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(devid, replace_target), 13178c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(devid, writeable), 13188c2ecf20Sopenharmony_ci NULL 13198c2ecf20Sopenharmony_ci}; 13208c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(devid); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_cistatic void btrfs_release_devid_kobj(struct kobject *kobj) 13238c2ecf20Sopenharmony_ci{ 13248c2ecf20Sopenharmony_ci struct btrfs_device *device = container_of(kobj, struct btrfs_device, 13258c2ecf20Sopenharmony_ci devid_kobj); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci memset(&device->devid_kobj, 0, sizeof(struct kobject)); 13288c2ecf20Sopenharmony_ci complete(&device->kobj_unregister); 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic struct kobj_type devid_ktype = { 13328c2ecf20Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 13338c2ecf20Sopenharmony_ci .default_groups = devid_groups, 13348c2ecf20Sopenharmony_ci .release = btrfs_release_devid_kobj, 13358c2ecf20Sopenharmony_ci}; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ciint btrfs_sysfs_add_device(struct btrfs_device *device) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci int ret; 13408c2ecf20Sopenharmony_ci unsigned int nofs_flag; 13418c2ecf20Sopenharmony_ci struct kobject *devices_kobj; 13428c2ecf20Sopenharmony_ci struct kobject *devinfo_kobj; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci /* 13458c2ecf20Sopenharmony_ci * Make sure we use the fs_info::fs_devices to fetch the kobjects even 13468c2ecf20Sopenharmony_ci * for the seed fs_devices 13478c2ecf20Sopenharmony_ci */ 13488c2ecf20Sopenharmony_ci devices_kobj = device->fs_info->fs_devices->devices_kobj; 13498c2ecf20Sopenharmony_ci devinfo_kobj = device->fs_info->fs_devices->devinfo_kobj; 13508c2ecf20Sopenharmony_ci ASSERT(devices_kobj); 13518c2ecf20Sopenharmony_ci ASSERT(devinfo_kobj); 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci nofs_flag = memalloc_nofs_save(); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci if (device->bdev) { 13568c2ecf20Sopenharmony_ci struct hd_struct *disk; 13578c2ecf20Sopenharmony_ci struct kobject *disk_kobj; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci disk = device->bdev->bd_part; 13608c2ecf20Sopenharmony_ci disk_kobj = &part_to_dev(disk)->kobj; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci ret = sysfs_create_link(devices_kobj, disk_kobj, disk_kobj->name); 13638c2ecf20Sopenharmony_ci if (ret) { 13648c2ecf20Sopenharmony_ci btrfs_warn(device->fs_info, 13658c2ecf20Sopenharmony_ci "creating sysfs device link for devid %llu failed: %d", 13668c2ecf20Sopenharmony_ci device->devid, ret); 13678c2ecf20Sopenharmony_ci goto out; 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci init_completion(&device->kobj_unregister); 13728c2ecf20Sopenharmony_ci ret = kobject_init_and_add(&device->devid_kobj, &devid_ktype, 13738c2ecf20Sopenharmony_ci devinfo_kobj, "%llu", device->devid); 13748c2ecf20Sopenharmony_ci if (ret) { 13758c2ecf20Sopenharmony_ci kobject_put(&device->devid_kobj); 13768c2ecf20Sopenharmony_ci btrfs_warn(device->fs_info, 13778c2ecf20Sopenharmony_ci "devinfo init for devid %llu failed: %d", 13788c2ecf20Sopenharmony_ci device->devid, ret); 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ciout: 13828c2ecf20Sopenharmony_ci memalloc_nofs_restore(nofs_flag); 13838c2ecf20Sopenharmony_ci return ret; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic int btrfs_sysfs_add_fs_devices(struct btrfs_fs_devices *fs_devices) 13878c2ecf20Sopenharmony_ci{ 13888c2ecf20Sopenharmony_ci int ret; 13898c2ecf20Sopenharmony_ci struct btrfs_device *device; 13908c2ecf20Sopenharmony_ci struct btrfs_fs_devices *seed; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci list_for_each_entry(device, &fs_devices->devices, dev_list) { 13938c2ecf20Sopenharmony_ci ret = btrfs_sysfs_add_device(device); 13948c2ecf20Sopenharmony_ci if (ret) 13958c2ecf20Sopenharmony_ci goto fail; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci list_for_each_entry(seed, &fs_devices->seed_list, seed_list) { 13998c2ecf20Sopenharmony_ci list_for_each_entry(device, &seed->devices, dev_list) { 14008c2ecf20Sopenharmony_ci ret = btrfs_sysfs_add_device(device); 14018c2ecf20Sopenharmony_ci if (ret) 14028c2ecf20Sopenharmony_ci goto fail; 14038c2ecf20Sopenharmony_ci } 14048c2ecf20Sopenharmony_ci } 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci return 0; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_cifail: 14098c2ecf20Sopenharmony_ci btrfs_sysfs_remove_fs_devices(fs_devices); 14108c2ecf20Sopenharmony_ci return ret; 14118c2ecf20Sopenharmony_ci} 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_civoid btrfs_kobject_uevent(struct block_device *bdev, enum kobject_action action) 14148c2ecf20Sopenharmony_ci{ 14158c2ecf20Sopenharmony_ci int ret; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci ret = kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, action); 14188c2ecf20Sopenharmony_ci if (ret) 14198c2ecf20Sopenharmony_ci pr_warn("BTRFS: Sending event '%d' to kobject: '%s' (%p): failed\n", 14208c2ecf20Sopenharmony_ci action, kobject_name(&disk_to_dev(bdev->bd_disk)->kobj), 14218c2ecf20Sopenharmony_ci &disk_to_dev(bdev->bd_disk)->kobj); 14228c2ecf20Sopenharmony_ci} 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_civoid btrfs_sysfs_update_sprout_fsid(struct btrfs_fs_devices *fs_devices) 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci char fsid_buf[BTRFS_UUID_UNPARSED_SIZE]; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci /* 14308c2ecf20Sopenharmony_ci * Sprouting changes fsid of the mounted filesystem, rename the fsid 14318c2ecf20Sopenharmony_ci * directory 14328c2ecf20Sopenharmony_ci */ 14338c2ecf20Sopenharmony_ci snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU", fs_devices->fsid); 14348c2ecf20Sopenharmony_ci if (kobject_rename(&fs_devices->fsid_kobj, fsid_buf)) 14358c2ecf20Sopenharmony_ci btrfs_warn(fs_devices->fs_info, 14368c2ecf20Sopenharmony_ci "sysfs: failed to create fsid for sprout"); 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_civoid btrfs_sysfs_update_devid(struct btrfs_device *device) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci char tmp[24]; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci snprintf(tmp, sizeof(tmp), "%llu", device->devid); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci if (kobject_rename(&device->devid_kobj, tmp)) 14468c2ecf20Sopenharmony_ci btrfs_warn(device->fs_devices->fs_info, 14478c2ecf20Sopenharmony_ci "sysfs: failed to update devid for %llu", 14488c2ecf20Sopenharmony_ci device->devid); 14498c2ecf20Sopenharmony_ci} 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci/* /sys/fs/btrfs/ entry */ 14528c2ecf20Sopenharmony_cistatic struct kset *btrfs_kset; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci/* 14558c2ecf20Sopenharmony_ci * Creates: 14568c2ecf20Sopenharmony_ci * /sys/fs/btrfs/UUID 14578c2ecf20Sopenharmony_ci * 14588c2ecf20Sopenharmony_ci * Can be called by the device discovery thread. 14598c2ecf20Sopenharmony_ci */ 14608c2ecf20Sopenharmony_ciint btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs) 14618c2ecf20Sopenharmony_ci{ 14628c2ecf20Sopenharmony_ci int error; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci init_completion(&fs_devs->kobj_unregister); 14658c2ecf20Sopenharmony_ci fs_devs->fsid_kobj.kset = btrfs_kset; 14668c2ecf20Sopenharmony_ci error = kobject_init_and_add(&fs_devs->fsid_kobj, &btrfs_ktype, NULL, 14678c2ecf20Sopenharmony_ci "%pU", fs_devs->fsid); 14688c2ecf20Sopenharmony_ci if (error) { 14698c2ecf20Sopenharmony_ci kobject_put(&fs_devs->fsid_kobj); 14708c2ecf20Sopenharmony_ci return error; 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci fs_devs->devices_kobj = kobject_create_and_add("devices", 14748c2ecf20Sopenharmony_ci &fs_devs->fsid_kobj); 14758c2ecf20Sopenharmony_ci if (!fs_devs->devices_kobj) { 14768c2ecf20Sopenharmony_ci btrfs_err(fs_devs->fs_info, 14778c2ecf20Sopenharmony_ci "failed to init sysfs device interface"); 14788c2ecf20Sopenharmony_ci btrfs_sysfs_remove_fsid(fs_devs); 14798c2ecf20Sopenharmony_ci return -ENOMEM; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci fs_devs->devinfo_kobj = kobject_create_and_add("devinfo", 14838c2ecf20Sopenharmony_ci &fs_devs->fsid_kobj); 14848c2ecf20Sopenharmony_ci if (!fs_devs->devinfo_kobj) { 14858c2ecf20Sopenharmony_ci btrfs_err(fs_devs->fs_info, 14868c2ecf20Sopenharmony_ci "failed to init sysfs devinfo kobject"); 14878c2ecf20Sopenharmony_ci btrfs_sysfs_remove_fsid(fs_devs); 14888c2ecf20Sopenharmony_ci return -ENOMEM; 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci return 0; 14928c2ecf20Sopenharmony_ci} 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ciint btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info) 14958c2ecf20Sopenharmony_ci{ 14968c2ecf20Sopenharmony_ci int error; 14978c2ecf20Sopenharmony_ci struct btrfs_fs_devices *fs_devs = fs_info->fs_devices; 14988c2ecf20Sopenharmony_ci struct kobject *fsid_kobj = &fs_devs->fsid_kobj; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci error = btrfs_sysfs_add_fs_devices(fs_devs); 15018c2ecf20Sopenharmony_ci if (error) 15028c2ecf20Sopenharmony_ci return error; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci error = sysfs_create_files(fsid_kobj, btrfs_attrs); 15058c2ecf20Sopenharmony_ci if (error) { 15068c2ecf20Sopenharmony_ci btrfs_sysfs_remove_fs_devices(fs_devs); 15078c2ecf20Sopenharmony_ci return error; 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci error = sysfs_create_group(fsid_kobj, 15118c2ecf20Sopenharmony_ci &btrfs_feature_attr_group); 15128c2ecf20Sopenharmony_ci if (error) 15138c2ecf20Sopenharmony_ci goto failure; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci#ifdef CONFIG_BTRFS_DEBUG 15168c2ecf20Sopenharmony_ci fs_info->debug_kobj = kobject_create_and_add("debug", fsid_kobj); 15178c2ecf20Sopenharmony_ci if (!fs_info->debug_kobj) { 15188c2ecf20Sopenharmony_ci error = -ENOMEM; 15198c2ecf20Sopenharmony_ci goto failure; 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci error = sysfs_create_files(fs_info->debug_kobj, btrfs_debug_mount_attrs); 15238c2ecf20Sopenharmony_ci if (error) 15248c2ecf20Sopenharmony_ci goto failure; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* Discard directory */ 15278c2ecf20Sopenharmony_ci fs_info->discard_debug_kobj = kobject_create_and_add("discard", 15288c2ecf20Sopenharmony_ci fs_info->debug_kobj); 15298c2ecf20Sopenharmony_ci if (!fs_info->discard_debug_kobj) { 15308c2ecf20Sopenharmony_ci error = -ENOMEM; 15318c2ecf20Sopenharmony_ci goto failure; 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci error = sysfs_create_files(fs_info->discard_debug_kobj, 15358c2ecf20Sopenharmony_ci discard_debug_attrs); 15368c2ecf20Sopenharmony_ci if (error) 15378c2ecf20Sopenharmony_ci goto failure; 15388c2ecf20Sopenharmony_ci#endif 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci error = addrm_unknown_feature_attrs(fs_info, true); 15418c2ecf20Sopenharmony_ci if (error) 15428c2ecf20Sopenharmony_ci goto failure; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_ci error = sysfs_create_link(fsid_kobj, &fs_info->sb->s_bdi->dev->kobj, "bdi"); 15458c2ecf20Sopenharmony_ci if (error) 15468c2ecf20Sopenharmony_ci goto failure; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci fs_info->space_info_kobj = kobject_create_and_add("allocation", 15498c2ecf20Sopenharmony_ci fsid_kobj); 15508c2ecf20Sopenharmony_ci if (!fs_info->space_info_kobj) { 15518c2ecf20Sopenharmony_ci error = -ENOMEM; 15528c2ecf20Sopenharmony_ci goto failure; 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs); 15568c2ecf20Sopenharmony_ci if (error) 15578c2ecf20Sopenharmony_ci goto failure; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci return 0; 15608c2ecf20Sopenharmony_cifailure: 15618c2ecf20Sopenharmony_ci btrfs_sysfs_remove_mounted(fs_info); 15628c2ecf20Sopenharmony_ci return error; 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_cistatic inline struct btrfs_fs_info *qgroup_kobj_to_fs_info(struct kobject *kobj) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci return to_fs_info(kobj->parent->parent); 15688c2ecf20Sopenharmony_ci} 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci#define QGROUP_ATTR(_member, _show_name) \ 15718c2ecf20Sopenharmony_cistatic ssize_t btrfs_qgroup_show_##_member(struct kobject *qgroup_kobj, \ 15728c2ecf20Sopenharmony_ci struct kobj_attribute *a, \ 15738c2ecf20Sopenharmony_ci char *buf) \ 15748c2ecf20Sopenharmony_ci{ \ 15758c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj); \ 15768c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup = container_of(qgroup_kobj, \ 15778c2ecf20Sopenharmony_ci struct btrfs_qgroup, kobj); \ 15788c2ecf20Sopenharmony_ci return btrfs_show_u64(&qgroup->_member, &fs_info->qgroup_lock, buf); \ 15798c2ecf20Sopenharmony_ci} \ 15808c2ecf20Sopenharmony_ciBTRFS_ATTR(qgroup, _show_name, btrfs_qgroup_show_##_member) 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci#define QGROUP_RSV_ATTR(_name, _type) \ 15838c2ecf20Sopenharmony_cistatic ssize_t btrfs_qgroup_rsv_show_##_name(struct kobject *qgroup_kobj, \ 15848c2ecf20Sopenharmony_ci struct kobj_attribute *a, \ 15858c2ecf20Sopenharmony_ci char *buf) \ 15868c2ecf20Sopenharmony_ci{ \ 15878c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj); \ 15888c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup = container_of(qgroup_kobj, \ 15898c2ecf20Sopenharmony_ci struct btrfs_qgroup, kobj); \ 15908c2ecf20Sopenharmony_ci return btrfs_show_u64(&qgroup->rsv.values[_type], \ 15918c2ecf20Sopenharmony_ci &fs_info->qgroup_lock, buf); \ 15928c2ecf20Sopenharmony_ci} \ 15938c2ecf20Sopenharmony_ciBTRFS_ATTR(qgroup, rsv_##_name, btrfs_qgroup_rsv_show_##_name) 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ciQGROUP_ATTR(rfer, referenced); 15968c2ecf20Sopenharmony_ciQGROUP_ATTR(excl, exclusive); 15978c2ecf20Sopenharmony_ciQGROUP_ATTR(max_rfer, max_referenced); 15988c2ecf20Sopenharmony_ciQGROUP_ATTR(max_excl, max_exclusive); 15998c2ecf20Sopenharmony_ciQGROUP_ATTR(lim_flags, limit_flags); 16008c2ecf20Sopenharmony_ciQGROUP_RSV_ATTR(data, BTRFS_QGROUP_RSV_DATA); 16018c2ecf20Sopenharmony_ciQGROUP_RSV_ATTR(meta_pertrans, BTRFS_QGROUP_RSV_META_PERTRANS); 16028c2ecf20Sopenharmony_ciQGROUP_RSV_ATTR(meta_prealloc, BTRFS_QGROUP_RSV_META_PREALLOC); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_cistatic struct attribute *qgroup_attrs[] = { 16058c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(qgroup, referenced), 16068c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(qgroup, exclusive), 16078c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(qgroup, max_referenced), 16088c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(qgroup, max_exclusive), 16098c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(qgroup, limit_flags), 16108c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(qgroup, rsv_data), 16118c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(qgroup, rsv_meta_pertrans), 16128c2ecf20Sopenharmony_ci BTRFS_ATTR_PTR(qgroup, rsv_meta_prealloc), 16138c2ecf20Sopenharmony_ci NULL 16148c2ecf20Sopenharmony_ci}; 16158c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(qgroup); 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_cistatic void qgroup_release(struct kobject *kobj) 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup = container_of(kobj, struct btrfs_qgroup, kobj); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci memset(&qgroup->kobj, 0, sizeof(*kobj)); 16228c2ecf20Sopenharmony_ci} 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_cistatic struct kobj_type qgroup_ktype = { 16258c2ecf20Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 16268c2ecf20Sopenharmony_ci .release = qgroup_release, 16278c2ecf20Sopenharmony_ci .default_groups = qgroup_groups, 16288c2ecf20Sopenharmony_ci}; 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ciint btrfs_sysfs_add_one_qgroup(struct btrfs_fs_info *fs_info, 16318c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup) 16328c2ecf20Sopenharmony_ci{ 16338c2ecf20Sopenharmony_ci struct kobject *qgroups_kobj = fs_info->qgroups_kobj; 16348c2ecf20Sopenharmony_ci int ret; 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_ci if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) 16378c2ecf20Sopenharmony_ci return 0; 16388c2ecf20Sopenharmony_ci if (qgroup->kobj.state_initialized) 16398c2ecf20Sopenharmony_ci return 0; 16408c2ecf20Sopenharmony_ci if (!qgroups_kobj) 16418c2ecf20Sopenharmony_ci return -EINVAL; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci ret = kobject_init_and_add(&qgroup->kobj, &qgroup_ktype, qgroups_kobj, 16448c2ecf20Sopenharmony_ci "%hu_%llu", btrfs_qgroup_level(qgroup->qgroupid), 16458c2ecf20Sopenharmony_ci btrfs_qgroup_subvolid(qgroup->qgroupid)); 16468c2ecf20Sopenharmony_ci if (ret < 0) 16478c2ecf20Sopenharmony_ci kobject_put(&qgroup->kobj); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci return ret; 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_civoid btrfs_sysfs_del_qgroups(struct btrfs_fs_info *fs_info) 16538c2ecf20Sopenharmony_ci{ 16548c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 16558c2ecf20Sopenharmony_ci struct btrfs_qgroup *next; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) 16588c2ecf20Sopenharmony_ci return; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci rbtree_postorder_for_each_entry_safe(qgroup, next, 16618c2ecf20Sopenharmony_ci &fs_info->qgroup_tree, node) 16628c2ecf20Sopenharmony_ci btrfs_sysfs_del_one_qgroup(fs_info, qgroup); 16638c2ecf20Sopenharmony_ci if (fs_info->qgroups_kobj) { 16648c2ecf20Sopenharmony_ci kobject_del(fs_info->qgroups_kobj); 16658c2ecf20Sopenharmony_ci kobject_put(fs_info->qgroups_kobj); 16668c2ecf20Sopenharmony_ci fs_info->qgroups_kobj = NULL; 16678c2ecf20Sopenharmony_ci } 16688c2ecf20Sopenharmony_ci} 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci/* Called when qgroups get initialized, thus there is no need for locking */ 16718c2ecf20Sopenharmony_ciint btrfs_sysfs_add_qgroups(struct btrfs_fs_info *fs_info) 16728c2ecf20Sopenharmony_ci{ 16738c2ecf20Sopenharmony_ci struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj; 16748c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup; 16758c2ecf20Sopenharmony_ci struct btrfs_qgroup *next; 16768c2ecf20Sopenharmony_ci int ret = 0; 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) 16798c2ecf20Sopenharmony_ci return 0; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci ASSERT(fsid_kobj); 16828c2ecf20Sopenharmony_ci if (fs_info->qgroups_kobj) 16838c2ecf20Sopenharmony_ci return 0; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci fs_info->qgroups_kobj = kobject_create_and_add("qgroups", fsid_kobj); 16868c2ecf20Sopenharmony_ci if (!fs_info->qgroups_kobj) { 16878c2ecf20Sopenharmony_ci ret = -ENOMEM; 16888c2ecf20Sopenharmony_ci goto out; 16898c2ecf20Sopenharmony_ci } 16908c2ecf20Sopenharmony_ci rbtree_postorder_for_each_entry_safe(qgroup, next, 16918c2ecf20Sopenharmony_ci &fs_info->qgroup_tree, node) { 16928c2ecf20Sopenharmony_ci ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup); 16938c2ecf20Sopenharmony_ci if (ret < 0) 16948c2ecf20Sopenharmony_ci goto out; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ciout: 16988c2ecf20Sopenharmony_ci if (ret < 0) 16998c2ecf20Sopenharmony_ci btrfs_sysfs_del_qgroups(fs_info); 17008c2ecf20Sopenharmony_ci return ret; 17018c2ecf20Sopenharmony_ci} 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_civoid btrfs_sysfs_del_one_qgroup(struct btrfs_fs_info *fs_info, 17048c2ecf20Sopenharmony_ci struct btrfs_qgroup *qgroup) 17058c2ecf20Sopenharmony_ci{ 17068c2ecf20Sopenharmony_ci if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state)) 17078c2ecf20Sopenharmony_ci return; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci if (qgroup->kobj.state_initialized) { 17108c2ecf20Sopenharmony_ci kobject_del(&qgroup->kobj); 17118c2ecf20Sopenharmony_ci kobject_put(&qgroup->kobj); 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci} 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ci/* 17168c2ecf20Sopenharmony_ci * Change per-fs features in /sys/fs/btrfs/UUID/features to match current 17178c2ecf20Sopenharmony_ci * values in superblock. Call after any changes to incompat/compat_ro flags 17188c2ecf20Sopenharmony_ci */ 17198c2ecf20Sopenharmony_civoid btrfs_sysfs_feature_update(struct btrfs_fs_info *fs_info, 17208c2ecf20Sopenharmony_ci u64 bit, enum btrfs_feature_set set) 17218c2ecf20Sopenharmony_ci{ 17228c2ecf20Sopenharmony_ci struct btrfs_fs_devices *fs_devs; 17238c2ecf20Sopenharmony_ci struct kobject *fsid_kobj; 17248c2ecf20Sopenharmony_ci u64 __maybe_unused features; 17258c2ecf20Sopenharmony_ci int __maybe_unused ret; 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci if (!fs_info) 17288c2ecf20Sopenharmony_ci return; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci /* 17318c2ecf20Sopenharmony_ci * See 14e46e04958df74 and e410e34fad913dd, feature bit updates are not 17328c2ecf20Sopenharmony_ci * safe when called from some contexts (eg. balance) 17338c2ecf20Sopenharmony_ci */ 17348c2ecf20Sopenharmony_ci features = get_features(fs_info, set); 17358c2ecf20Sopenharmony_ci ASSERT(bit & supported_feature_masks[set]); 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci fs_devs = fs_info->fs_devices; 17388c2ecf20Sopenharmony_ci fsid_kobj = &fs_devs->fsid_kobj; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci if (!fsid_kobj->state_initialized) 17418c2ecf20Sopenharmony_ci return; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci /* 17448c2ecf20Sopenharmony_ci * FIXME: this is too heavy to update just one value, ideally we'd like 17458c2ecf20Sopenharmony_ci * to use sysfs_update_group but some refactoring is needed first. 17468c2ecf20Sopenharmony_ci */ 17478c2ecf20Sopenharmony_ci sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group); 17488c2ecf20Sopenharmony_ci ret = sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group); 17498c2ecf20Sopenharmony_ci} 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ciint __init btrfs_init_sysfs(void) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci int ret; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); 17568c2ecf20Sopenharmony_ci if (!btrfs_kset) 17578c2ecf20Sopenharmony_ci return -ENOMEM; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci init_feature_attrs(); 17608c2ecf20Sopenharmony_ci ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); 17618c2ecf20Sopenharmony_ci if (ret) 17628c2ecf20Sopenharmony_ci goto out2; 17638c2ecf20Sopenharmony_ci ret = sysfs_merge_group(&btrfs_kset->kobj, 17648c2ecf20Sopenharmony_ci &btrfs_static_feature_attr_group); 17658c2ecf20Sopenharmony_ci if (ret) 17668c2ecf20Sopenharmony_ci goto out_remove_group; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci#ifdef CONFIG_BTRFS_DEBUG 17698c2ecf20Sopenharmony_ci ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group); 17708c2ecf20Sopenharmony_ci if (ret) { 17718c2ecf20Sopenharmony_ci sysfs_unmerge_group(&btrfs_kset->kobj, 17728c2ecf20Sopenharmony_ci &btrfs_static_feature_attr_group); 17738c2ecf20Sopenharmony_ci goto out_remove_group; 17748c2ecf20Sopenharmony_ci } 17758c2ecf20Sopenharmony_ci#endif 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci return 0; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ciout_remove_group: 17808c2ecf20Sopenharmony_ci sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); 17818c2ecf20Sopenharmony_ciout2: 17828c2ecf20Sopenharmony_ci kset_unregister(btrfs_kset); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci return ret; 17858c2ecf20Sopenharmony_ci} 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_civoid __cold btrfs_exit_sysfs(void) 17888c2ecf20Sopenharmony_ci{ 17898c2ecf20Sopenharmony_ci sysfs_unmerge_group(&btrfs_kset->kobj, 17908c2ecf20Sopenharmony_ci &btrfs_static_feature_attr_group); 17918c2ecf20Sopenharmony_ci sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); 17928c2ecf20Sopenharmony_ci#ifdef CONFIG_BTRFS_DEBUG 17938c2ecf20Sopenharmony_ci sysfs_remove_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group); 17948c2ecf20Sopenharmony_ci#endif 17958c2ecf20Sopenharmony_ci kset_unregister(btrfs_kset); 17968c2ecf20Sopenharmony_ci} 17978c2ecf20Sopenharmony_ci 1798