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