xref: /openbmc/linux/fs/btrfs/sysfs.c (revision 3e1ad196)
1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0
26cbd5570SChris Mason /*
36cbd5570SChris Mason  * Copyright (C) 2007 Oracle.  All rights reserved.
46cbd5570SChris Mason  */
56cbd5570SChris Mason 
658176a96SJosef Bacik #include <linux/sched.h>
732a9991fSDavid Sterba #include <linux/sched/mm.h>
858176a96SJosef Bacik #include <linux/slab.h>
958176a96SJosef Bacik #include <linux/spinlock.h>
1058176a96SJosef Bacik #include <linux/completion.h>
1179da4fa4SJeff Mahoney #include <linux/bug.h>
1241e6d2a8SJohannes Thumshirn #include <crypto/hash.h>
1358176a96SJosef Bacik 
14bae45de0SChris Mason #include "ctree.h"
15dfb79ddbSDennis Zhou #include "discard.h"
16bae45de0SChris Mason #include "disk-io.h"
177573df55SOmar Sandoval #include "send.h"
18bae45de0SChris Mason #include "transaction.h"
19079b72bcSJeff Mahoney #include "sysfs.h"
2029e5be24SJeff Mahoney #include "volumes.h"
218719aaaeSJosef Bacik #include "space-info.h"
22aac0023cSJosef Bacik #include "block-group.h"
2349e5fb46SQu Wenruo #include "qgroup.h"
24079b72bcSJeff Mahoney 
25e7849e33SAnand Jain /*
26e7849e33SAnand Jain  * Structure name                       Path
27e7849e33SAnand Jain  * --------------------------------------------------------------------------
28e7849e33SAnand Jain  * btrfs_supported_static_feature_attrs /sys/fs/btrfs/features
29e7849e33SAnand Jain  * btrfs_supported_feature_attrs	/sys/fs/btrfs/features and
30e7849e33SAnand Jain  *					/sys/fs/btrfs/<uuid>/features
31e7849e33SAnand Jain  * btrfs_attrs				/sys/fs/btrfs/<uuid>
32e7849e33SAnand Jain  * devid_attrs				/sys/fs/btrfs/<uuid>/devinfo/<devid>
33e7849e33SAnand Jain  * allocation_attrs			/sys/fs/btrfs/<uuid>/allocation
34e7849e33SAnand Jain  * qgroup_attrs				/sys/fs/btrfs/<uuid>/qgroups/<level>_<qgroupid>
35e7849e33SAnand Jain  * space_info_attrs			/sys/fs/btrfs/<uuid>/allocation/<bg-type>
36e7849e33SAnand Jain  * raid_attrs				/sys/fs/btrfs/<uuid>/allocation/<bg-type>/<bg-profile>
37e7849e33SAnand Jain  *
38e7849e33SAnand Jain  * When built with BTRFS_CONFIG_DEBUG:
39e7849e33SAnand Jain  *
40e7849e33SAnand Jain  * btrfs_debug_feature_attrs		/sys/fs/btrfs/debug
41e7849e33SAnand Jain  * btrfs_debug_mount_attrs		/sys/fs/btrfs/<uuid>/debug
42e7849e33SAnand Jain  * discard_debug_attrs			/sys/fs/btrfs/<uuid>/debug/discard
43e7849e33SAnand Jain  */
44e7849e33SAnand Jain 
459188db61SDavid Sterba struct btrfs_feature_attr {
469188db61SDavid Sterba 	struct kobj_attribute kobj_attr;
479188db61SDavid Sterba 	enum btrfs_feature_set feature_set;
489188db61SDavid Sterba 	u64 feature_bit;
499188db61SDavid Sterba };
509188db61SDavid Sterba 
519188db61SDavid Sterba /* For raid type sysfs entries */
529188db61SDavid Sterba struct raid_kobject {
539188db61SDavid Sterba 	u64 flags;
549188db61SDavid Sterba 	struct kobject kobj;
559188db61SDavid Sterba };
569188db61SDavid Sterba 
579188db61SDavid Sterba #define __INIT_KOBJ_ATTR(_name, _mode, _show, _store)			\
589188db61SDavid Sterba {									\
599188db61SDavid Sterba 	.attr	= { .name = __stringify(_name), .mode = _mode },	\
609188db61SDavid Sterba 	.show	= _show,						\
619188db61SDavid Sterba 	.store	= _store,						\
629188db61SDavid Sterba }
639188db61SDavid Sterba 
649188db61SDavid Sterba #define BTRFS_ATTR_RW(_prefix, _name, _show, _store)			\
659188db61SDavid Sterba 	static struct kobj_attribute btrfs_attr_##_prefix##_##_name =	\
669188db61SDavid Sterba 			__INIT_KOBJ_ATTR(_name, 0644, _show, _store)
679188db61SDavid Sterba 
689188db61SDavid Sterba #define BTRFS_ATTR(_prefix, _name, _show)				\
699188db61SDavid Sterba 	static struct kobj_attribute btrfs_attr_##_prefix##_##_name =	\
709188db61SDavid Sterba 			__INIT_KOBJ_ATTR(_name, 0444, _show, NULL)
719188db61SDavid Sterba 
729188db61SDavid Sterba #define BTRFS_ATTR_PTR(_prefix, _name)					\
739188db61SDavid Sterba 	(&btrfs_attr_##_prefix##_##_name.attr)
749188db61SDavid Sterba 
759188db61SDavid Sterba #define BTRFS_FEAT_ATTR(_name, _feature_set, _feature_prefix, _feature_bit)  \
769188db61SDavid Sterba static struct btrfs_feature_attr btrfs_attr_features_##_name = {	     \
779188db61SDavid Sterba 	.kobj_attr = __INIT_KOBJ_ATTR(_name, S_IRUGO,			     \
789188db61SDavid Sterba 				      btrfs_feature_attr_show,		     \
799188db61SDavid Sterba 				      btrfs_feature_attr_store),	     \
809188db61SDavid Sterba 	.feature_set	= _feature_set,					     \
819188db61SDavid Sterba 	.feature_bit	= _feature_prefix ##_## _feature_bit,		     \
829188db61SDavid Sterba }
839188db61SDavid Sterba #define BTRFS_FEAT_ATTR_PTR(_name)					     \
849188db61SDavid Sterba 	(&btrfs_attr_features_##_name.kobj_attr.attr)
859188db61SDavid Sterba 
869188db61SDavid Sterba #define BTRFS_FEAT_ATTR_COMPAT(name, feature) \
879188db61SDavid Sterba 	BTRFS_FEAT_ATTR(name, FEAT_COMPAT, BTRFS_FEATURE_COMPAT, feature)
889188db61SDavid Sterba #define BTRFS_FEAT_ATTR_COMPAT_RO(name, feature) \
899188db61SDavid Sterba 	BTRFS_FEAT_ATTR(name, FEAT_COMPAT_RO, BTRFS_FEATURE_COMPAT_RO, feature)
909188db61SDavid Sterba #define BTRFS_FEAT_ATTR_INCOMPAT(name, feature) \
919188db61SDavid Sterba 	BTRFS_FEAT_ATTR(name, FEAT_INCOMPAT, BTRFS_FEATURE_INCOMPAT, feature)
929188db61SDavid Sterba 
93510d7360SJeff Mahoney static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj);
942e7910d6SAnand Jain static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj);
955ac1d209SJeff Mahoney 
968f52316cSDavid Sterba static struct btrfs_feature_attr *to_btrfs_feature_attr(struct kobj_attribute *a)
978f52316cSDavid Sterba {
988f52316cSDavid Sterba 	return container_of(a, struct btrfs_feature_attr, kobj_attr);
998f52316cSDavid Sterba }
1008f52316cSDavid Sterba 
1018f52316cSDavid Sterba static struct kobj_attribute *attr_to_btrfs_attr(struct attribute *attr)
1028f52316cSDavid Sterba {
1038f52316cSDavid Sterba 	return container_of(attr, struct kobj_attribute, attr);
1048f52316cSDavid Sterba }
1058f52316cSDavid Sterba 
1068f52316cSDavid Sterba static struct btrfs_feature_attr *attr_to_btrfs_feature_attr(
1078f52316cSDavid Sterba 		struct attribute *attr)
1088f52316cSDavid Sterba {
1098f52316cSDavid Sterba 	return to_btrfs_feature_attr(attr_to_btrfs_attr(attr));
1108f52316cSDavid Sterba }
1118f52316cSDavid Sterba 
112510d7360SJeff Mahoney static u64 get_features(struct btrfs_fs_info *fs_info,
113510d7360SJeff Mahoney 			enum btrfs_feature_set set)
1145ac1d209SJeff Mahoney {
115510d7360SJeff Mahoney 	struct btrfs_super_block *disk_super = fs_info->super_copy;
116510d7360SJeff Mahoney 	if (set == FEAT_COMPAT)
117510d7360SJeff Mahoney 		return btrfs_super_compat_flags(disk_super);
118510d7360SJeff Mahoney 	else if (set == FEAT_COMPAT_RO)
119510d7360SJeff Mahoney 		return btrfs_super_compat_ro_flags(disk_super);
120510d7360SJeff Mahoney 	else
121510d7360SJeff Mahoney 		return btrfs_super_incompat_flags(disk_super);
1225ac1d209SJeff Mahoney }
1235ac1d209SJeff Mahoney 
124ba631941SJeff Mahoney static void set_features(struct btrfs_fs_info *fs_info,
125ba631941SJeff Mahoney 			 enum btrfs_feature_set set, u64 features)
126ba631941SJeff Mahoney {
127ba631941SJeff Mahoney 	struct btrfs_super_block *disk_super = fs_info->super_copy;
128ba631941SJeff Mahoney 	if (set == FEAT_COMPAT)
129ba631941SJeff Mahoney 		btrfs_set_super_compat_flags(disk_super, features);
130ba631941SJeff Mahoney 	else if (set == FEAT_COMPAT_RO)
131ba631941SJeff Mahoney 		btrfs_set_super_compat_ro_flags(disk_super, features);
132ba631941SJeff Mahoney 	else
133ba631941SJeff Mahoney 		btrfs_set_super_incompat_flags(disk_super, features);
134ba631941SJeff Mahoney }
135ba631941SJeff Mahoney 
136ba631941SJeff Mahoney static int can_modify_feature(struct btrfs_feature_attr *fa)
137ba631941SJeff Mahoney {
138ba631941SJeff Mahoney 	int val = 0;
139ba631941SJeff Mahoney 	u64 set, clear;
140ba631941SJeff Mahoney 	switch (fa->feature_set) {
141ba631941SJeff Mahoney 	case FEAT_COMPAT:
142ba631941SJeff Mahoney 		set = BTRFS_FEATURE_COMPAT_SAFE_SET;
143ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR;
144ba631941SJeff Mahoney 		break;
145ba631941SJeff Mahoney 	case FEAT_COMPAT_RO:
146ba631941SJeff Mahoney 		set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET;
147ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR;
148ba631941SJeff Mahoney 		break;
149ba631941SJeff Mahoney 	case FEAT_INCOMPAT:
150ba631941SJeff Mahoney 		set = BTRFS_FEATURE_INCOMPAT_SAFE_SET;
151ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR;
152ba631941SJeff Mahoney 		break;
153ba631941SJeff Mahoney 	default:
15462e85577SJeff Mahoney 		pr_warn("btrfs: sysfs: unknown feature set %d\n",
155cc37bb04SDavid Sterba 				fa->feature_set);
156cc37bb04SDavid Sterba 		return 0;
157ba631941SJeff Mahoney 	}
158ba631941SJeff Mahoney 
159ba631941SJeff Mahoney 	if (set & fa->feature_bit)
160ba631941SJeff Mahoney 		val |= 1;
161ba631941SJeff Mahoney 	if (clear & fa->feature_bit)
162ba631941SJeff Mahoney 		val |= 2;
163ba631941SJeff Mahoney 
164ba631941SJeff Mahoney 	return val;
165ba631941SJeff Mahoney }
166ba631941SJeff Mahoney 
167079b72bcSJeff Mahoney static ssize_t btrfs_feature_attr_show(struct kobject *kobj,
168079b72bcSJeff Mahoney 				       struct kobj_attribute *a, char *buf)
169079b72bcSJeff Mahoney {
170510d7360SJeff Mahoney 	int val = 0;
171510d7360SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
172510d7360SJeff Mahoney 	struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a);
173ba631941SJeff Mahoney 	if (fs_info) {
174510d7360SJeff Mahoney 		u64 features = get_features(fs_info, fa->feature_set);
175510d7360SJeff Mahoney 		if (features & fa->feature_bit)
176510d7360SJeff Mahoney 			val = 1;
177ba631941SJeff Mahoney 	} else
178ba631941SJeff Mahoney 		val = can_modify_feature(fa);
179510d7360SJeff Mahoney 
180020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
181510d7360SJeff Mahoney }
182510d7360SJeff Mahoney 
183ba631941SJeff Mahoney static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
184ba631941SJeff Mahoney 					struct kobj_attribute *a,
185ba631941SJeff Mahoney 					const char *buf, size_t count)
186ba631941SJeff Mahoney {
187ba631941SJeff Mahoney 	struct btrfs_fs_info *fs_info;
188ba631941SJeff Mahoney 	struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a);
189ba631941SJeff Mahoney 	u64 features, set, clear;
190ba631941SJeff Mahoney 	unsigned long val;
191ba631941SJeff Mahoney 	int ret;
192ba631941SJeff Mahoney 
193ba631941SJeff Mahoney 	fs_info = to_fs_info(kobj);
194ba631941SJeff Mahoney 	if (!fs_info)
195ba631941SJeff Mahoney 		return -EPERM;
196ba631941SJeff Mahoney 
197bc98a42cSDavid Howells 	if (sb_rdonly(fs_info->sb))
198ee611138SDavid Sterba 		return -EROFS;
199ee611138SDavid Sterba 
200ba631941SJeff Mahoney 	ret = kstrtoul(skip_spaces(buf), 0, &val);
201ba631941SJeff Mahoney 	if (ret)
202ba631941SJeff Mahoney 		return ret;
203ba631941SJeff Mahoney 
204ba631941SJeff Mahoney 	if (fa->feature_set == FEAT_COMPAT) {
205ba631941SJeff Mahoney 		set = BTRFS_FEATURE_COMPAT_SAFE_SET;
206ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR;
207ba631941SJeff Mahoney 	} else if (fa->feature_set == FEAT_COMPAT_RO) {
208ba631941SJeff Mahoney 		set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET;
209ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR;
210ba631941SJeff Mahoney 	} else {
211ba631941SJeff Mahoney 		set = BTRFS_FEATURE_INCOMPAT_SAFE_SET;
212ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR;
213ba631941SJeff Mahoney 	}
214ba631941SJeff Mahoney 
215ba631941SJeff Mahoney 	features = get_features(fs_info, fa->feature_set);
216ba631941SJeff Mahoney 
217ba631941SJeff Mahoney 	/* Nothing to do */
218ba631941SJeff Mahoney 	if ((val && (features & fa->feature_bit)) ||
219ba631941SJeff Mahoney 	    (!val && !(features & fa->feature_bit)))
220ba631941SJeff Mahoney 		return count;
221ba631941SJeff Mahoney 
222ba631941SJeff Mahoney 	if ((val && !(set & fa->feature_bit)) ||
223ba631941SJeff Mahoney 	    (!val && !(clear & fa->feature_bit))) {
224ba631941SJeff Mahoney 		btrfs_info(fs_info,
225ba631941SJeff Mahoney 			"%sabling feature %s on mounted fs is not supported.",
226ba631941SJeff Mahoney 			val ? "En" : "Dis", fa->kobj_attr.attr.name);
227ba631941SJeff Mahoney 		return -EPERM;
228ba631941SJeff Mahoney 	}
229ba631941SJeff Mahoney 
230ba631941SJeff Mahoney 	btrfs_info(fs_info, "%s %s feature flag",
231ba631941SJeff Mahoney 		   val ? "Setting" : "Clearing", fa->kobj_attr.attr.name);
232ba631941SJeff Mahoney 
233ba631941SJeff Mahoney 	spin_lock(&fs_info->super_lock);
234ba631941SJeff Mahoney 	features = get_features(fs_info, fa->feature_set);
235ba631941SJeff Mahoney 	if (val)
236ba631941SJeff Mahoney 		features |= fa->feature_bit;
237ba631941SJeff Mahoney 	else
238ba631941SJeff Mahoney 		features &= ~fa->feature_bit;
239ba631941SJeff Mahoney 	set_features(fs_info, fa->feature_set, features);
240ba631941SJeff Mahoney 	spin_unlock(&fs_info->super_lock);
241ba631941SJeff Mahoney 
2420eae2747SDavid Sterba 	/*
2430eae2747SDavid Sterba 	 * We don't want to do full transaction commit from inside sysfs
2440eae2747SDavid Sterba 	 */
2450eae2747SDavid Sterba 	btrfs_set_pending(fs_info, COMMIT);
2460eae2747SDavid Sterba 	wake_up_process(fs_info->transaction_kthread);
247ba631941SJeff Mahoney 
248ba631941SJeff Mahoney 	return count;
249ba631941SJeff Mahoney }
250ba631941SJeff Mahoney 
251510d7360SJeff Mahoney static umode_t btrfs_feature_visible(struct kobject *kobj,
252510d7360SJeff Mahoney 				     struct attribute *attr, int unused)
253510d7360SJeff Mahoney {
254510d7360SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
255510d7360SJeff Mahoney 	umode_t mode = attr->mode;
256510d7360SJeff Mahoney 
257510d7360SJeff Mahoney 	if (fs_info) {
258510d7360SJeff Mahoney 		struct btrfs_feature_attr *fa;
259510d7360SJeff Mahoney 		u64 features;
260510d7360SJeff Mahoney 
261510d7360SJeff Mahoney 		fa = attr_to_btrfs_feature_attr(attr);
262510d7360SJeff Mahoney 		features = get_features(fs_info, fa->feature_set);
263510d7360SJeff Mahoney 
264ba631941SJeff Mahoney 		if (can_modify_feature(fa))
265ba631941SJeff Mahoney 			mode |= S_IWUSR;
266ba631941SJeff Mahoney 		else if (!(features & fa->feature_bit))
267510d7360SJeff Mahoney 			mode = 0;
268510d7360SJeff Mahoney 	}
269510d7360SJeff Mahoney 
270510d7360SJeff Mahoney 	return mode;
271079b72bcSJeff Mahoney }
272079b72bcSJeff Mahoney 
273079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF);
274079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL);
275079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS);
276079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO);
2775c1aab1dSNick Terrell BTRFS_FEAT_ATTR_INCOMPAT(compress_zstd, COMPRESS_ZSTD);
278079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA);
279079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF);
280079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56);
281079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA);
282c736c095SDavid Sterba BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES);
28356f20f40SNikolay Borisov BTRFS_FEAT_ATTR_INCOMPAT(metadata_uuid, METADATA_UUID);
2843b5bb73bSDavid Sterba BTRFS_FEAT_ATTR_COMPAT_RO(free_space_tree, FREE_SPACE_TREE);
285cfbb825cSDavid Sterba BTRFS_FEAT_ATTR_INCOMPAT(raid1c34, RAID1C34);
2867b3d5a90SNaohiro Aota #ifdef CONFIG_BTRFS_DEBUG
2872c7d2a23SJosef Bacik /* Remove once support for zoned allocation is feature complete */
2887b3d5a90SNaohiro Aota BTRFS_FEAT_ATTR_INCOMPAT(zoned, ZONED);
2892c7d2a23SJosef Bacik /* Remove once support for extent tree v2 is feature complete */
2902c7d2a23SJosef Bacik BTRFS_FEAT_ATTR_INCOMPAT(extent_tree_v2, EXTENT_TREE_V2);
2917b3d5a90SNaohiro Aota #endif
29214605409SBoris Burkov #ifdef CONFIG_FS_VERITY
29314605409SBoris Burkov BTRFS_FEAT_ATTR_COMPAT_RO(verity, VERITY);
29414605409SBoris Burkov #endif
295079b72bcSJeff Mahoney 
296e7849e33SAnand Jain /*
297e7849e33SAnand Jain  * Features which depend on feature bits and may differ between each fs.
298e7849e33SAnand Jain  *
299e7849e33SAnand Jain  * /sys/fs/btrfs/features      - all available features implemeted by this version
300e7849e33SAnand Jain  * /sys/fs/btrfs/UUID/features - features of the fs which are enabled or
301e7849e33SAnand Jain  *                               can be changed on a mounted filesystem.
302e7849e33SAnand Jain  */
303079b72bcSJeff Mahoney static struct attribute *btrfs_supported_feature_attrs[] = {
304079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(mixed_backref),
305079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(default_subvol),
306079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(mixed_groups),
307079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(compress_lzo),
3085c1aab1dSNick Terrell 	BTRFS_FEAT_ATTR_PTR(compress_zstd),
309079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(big_metadata),
310079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(extended_iref),
311079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(raid56),
312079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(skinny_metadata),
313c736c095SDavid Sterba 	BTRFS_FEAT_ATTR_PTR(no_holes),
31456f20f40SNikolay Borisov 	BTRFS_FEAT_ATTR_PTR(metadata_uuid),
3153b5bb73bSDavid Sterba 	BTRFS_FEAT_ATTR_PTR(free_space_tree),
316cfbb825cSDavid Sterba 	BTRFS_FEAT_ATTR_PTR(raid1c34),
3177b3d5a90SNaohiro Aota #ifdef CONFIG_BTRFS_DEBUG
3187b3d5a90SNaohiro Aota 	BTRFS_FEAT_ATTR_PTR(zoned),
3192c7d2a23SJosef Bacik 	BTRFS_FEAT_ATTR_PTR(extent_tree_v2),
3207b3d5a90SNaohiro Aota #endif
32114605409SBoris Burkov #ifdef CONFIG_FS_VERITY
32214605409SBoris Burkov 	BTRFS_FEAT_ATTR_PTR(verity),
32314605409SBoris Burkov #endif
324079b72bcSJeff Mahoney 	NULL
325079b72bcSJeff Mahoney };
326079b72bcSJeff Mahoney 
327079b72bcSJeff Mahoney static const struct attribute_group btrfs_feature_attr_group = {
328079b72bcSJeff Mahoney 	.name = "features",
329510d7360SJeff Mahoney 	.is_visible = btrfs_feature_visible,
330079b72bcSJeff Mahoney 	.attrs = btrfs_supported_feature_attrs,
331079b72bcSJeff Mahoney };
33258176a96SJosef Bacik 
333f902bd3aSMisono Tomohiro static ssize_t rmdir_subvol_show(struct kobject *kobj,
334f902bd3aSMisono Tomohiro 				 struct kobj_attribute *ka, char *buf)
335f902bd3aSMisono Tomohiro {
336020e5277SAnand Jain 	return sysfs_emit(buf, "0\n");
337f902bd3aSMisono Tomohiro }
338f902bd3aSMisono Tomohiro BTRFS_ATTR(static_feature, rmdir_subvol, rmdir_subvol_show);
339f902bd3aSMisono Tomohiro 
340f7cea56cSDavid Sterba static ssize_t supported_checksums_show(struct kobject *kobj,
341f7cea56cSDavid Sterba 					struct kobj_attribute *a, char *buf)
342f7cea56cSDavid Sterba {
343f7cea56cSDavid Sterba 	ssize_t ret = 0;
344f7cea56cSDavid Sterba 	int i;
345f7cea56cSDavid Sterba 
346f7cea56cSDavid Sterba 	for (i = 0; i < btrfs_get_num_csums(); i++) {
347f7cea56cSDavid Sterba 		/*
348f7cea56cSDavid Sterba 		 * This "trick" only works as long as 'enum btrfs_csum_type' has
349f7cea56cSDavid Sterba 		 * no holes in it
350f7cea56cSDavid Sterba 		 */
351020e5277SAnand Jain 		ret += sysfs_emit_at(buf, ret, "%s%s", (i == 0 ? "" : " "),
352020e5277SAnand Jain 				     btrfs_super_csum_name(i));
353f7cea56cSDavid Sterba 
354f7cea56cSDavid Sterba 	}
355f7cea56cSDavid Sterba 
356020e5277SAnand Jain 	ret += sysfs_emit_at(buf, ret, "\n");
357f7cea56cSDavid Sterba 	return ret;
358f7cea56cSDavid Sterba }
359f7cea56cSDavid Sterba BTRFS_ATTR(static_feature, supported_checksums, supported_checksums_show);
360f7cea56cSDavid Sterba 
3617573df55SOmar Sandoval static ssize_t send_stream_version_show(struct kobject *kobj,
3627573df55SOmar Sandoval 					struct kobj_attribute *ka, char *buf)
3637573df55SOmar Sandoval {
364020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", BTRFS_SEND_STREAM_VERSION);
3657573df55SOmar Sandoval }
3667573df55SOmar Sandoval BTRFS_ATTR(static_feature, send_stream_version, send_stream_version_show);
3677573df55SOmar Sandoval 
368ceafe3ccSJosef Bacik static const char *rescue_opts[] = {
369ceafe3ccSJosef Bacik 	"usebackuproot",
370ceafe3ccSJosef Bacik 	"nologreplay",
37142437a63SJosef Bacik 	"ignorebadroots",
372882dbe0cSJosef Bacik 	"ignoredatacsums",
3739037d3cbSJosef Bacik 	"all",
374ceafe3ccSJosef Bacik };
375ceafe3ccSJosef Bacik 
376ceafe3ccSJosef Bacik static ssize_t supported_rescue_options_show(struct kobject *kobj,
377ceafe3ccSJosef Bacik 					     struct kobj_attribute *a,
378ceafe3ccSJosef Bacik 					     char *buf)
379ceafe3ccSJosef Bacik {
380ceafe3ccSJosef Bacik 	ssize_t ret = 0;
381ceafe3ccSJosef Bacik 	int i;
382ceafe3ccSJosef Bacik 
383ceafe3ccSJosef Bacik 	for (i = 0; i < ARRAY_SIZE(rescue_opts); i++)
384020e5277SAnand Jain 		ret += sysfs_emit_at(buf, ret, "%s%s", (i ? " " : ""), rescue_opts[i]);
385020e5277SAnand Jain 	ret += sysfs_emit_at(buf, ret, "\n");
386ceafe3ccSJosef Bacik 	return ret;
387ceafe3ccSJosef Bacik }
388ceafe3ccSJosef Bacik BTRFS_ATTR(static_feature, supported_rescue_options,
389ceafe3ccSJosef Bacik 	   supported_rescue_options_show);
390ceafe3ccSJosef Bacik 
391fc57ad8dSQu Wenruo static ssize_t supported_sectorsizes_show(struct kobject *kobj,
392fc57ad8dSQu Wenruo 					  struct kobj_attribute *a,
393fc57ad8dSQu Wenruo 					  char *buf)
394fc57ad8dSQu Wenruo {
395fc57ad8dSQu Wenruo 	ssize_t ret = 0;
396fc57ad8dSQu Wenruo 
39795ea0486SQu Wenruo 	/* 4K sector size is also supported with 64K page size */
39895ea0486SQu Wenruo 	if (PAGE_SIZE == SZ_64K)
399020e5277SAnand Jain 		ret += sysfs_emit_at(buf, ret, "%u ", SZ_4K);
40095ea0486SQu Wenruo 
401fc57ad8dSQu Wenruo 	/* Only sectorsize == PAGE_SIZE is now supported */
402020e5277SAnand Jain 	ret += sysfs_emit_at(buf, ret, "%lu\n", PAGE_SIZE);
403fc57ad8dSQu Wenruo 
404fc57ad8dSQu Wenruo 	return ret;
405fc57ad8dSQu Wenruo }
406fc57ad8dSQu Wenruo BTRFS_ATTR(static_feature, supported_sectorsizes,
407fc57ad8dSQu Wenruo 	   supported_sectorsizes_show);
408fc57ad8dSQu Wenruo 
409e7849e33SAnand Jain /*
410e7849e33SAnand Jain  * Features which only depend on kernel version.
411e7849e33SAnand Jain  *
412e7849e33SAnand Jain  * These are listed in /sys/fs/btrfs/features along with
413e7849e33SAnand Jain  * btrfs_supported_feature_attrs.
414e7849e33SAnand Jain  */
415f902bd3aSMisono Tomohiro static struct attribute *btrfs_supported_static_feature_attrs[] = {
416f902bd3aSMisono Tomohiro 	BTRFS_ATTR_PTR(static_feature, rmdir_subvol),
417f7cea56cSDavid Sterba 	BTRFS_ATTR_PTR(static_feature, supported_checksums),
4187573df55SOmar Sandoval 	BTRFS_ATTR_PTR(static_feature, send_stream_version),
419ceafe3ccSJosef Bacik 	BTRFS_ATTR_PTR(static_feature, supported_rescue_options),
420fc57ad8dSQu Wenruo 	BTRFS_ATTR_PTR(static_feature, supported_sectorsizes),
421f902bd3aSMisono Tomohiro 	NULL
422f902bd3aSMisono Tomohiro };
423f902bd3aSMisono Tomohiro 
424f902bd3aSMisono Tomohiro static const struct attribute_group btrfs_static_feature_attr_group = {
425f902bd3aSMisono Tomohiro 	.name = "features",
426f902bd3aSMisono Tomohiro 	.attrs = btrfs_supported_static_feature_attrs,
427f902bd3aSMisono Tomohiro };
428f902bd3aSMisono Tomohiro 
4296e369febSDavid Sterba #ifdef CONFIG_BTRFS_DEBUG
4306e369febSDavid Sterba 
4316e369febSDavid Sterba /*
432e4faab84SDennis Zhou  * Discard statistics and tunables
433e4faab84SDennis Zhou  */
434dfb79ddbSDennis Zhou #define discard_to_fs_info(_kobj)	to_fs_info((_kobj)->parent->parent)
435dfb79ddbSDennis Zhou 
4365dc7c10bSDennis Zhou static ssize_t btrfs_discardable_bytes_show(struct kobject *kobj,
4375dc7c10bSDennis Zhou 					    struct kobj_attribute *a,
4385dc7c10bSDennis Zhou 					    char *buf)
4395dc7c10bSDennis Zhou {
4405dc7c10bSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4415dc7c10bSDennis Zhou 
442020e5277SAnand Jain 	return sysfs_emit(buf, "%lld\n",
4435dc7c10bSDennis Zhou 			atomic64_read(&fs_info->discard_ctl.discardable_bytes));
4445dc7c10bSDennis Zhou }
4455dc7c10bSDennis Zhou BTRFS_ATTR(discard, discardable_bytes, btrfs_discardable_bytes_show);
4465dc7c10bSDennis Zhou 
447dfb79ddbSDennis Zhou static ssize_t btrfs_discardable_extents_show(struct kobject *kobj,
448dfb79ddbSDennis Zhou 					      struct kobj_attribute *a,
449dfb79ddbSDennis Zhou 					      char *buf)
450dfb79ddbSDennis Zhou {
451dfb79ddbSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
452dfb79ddbSDennis Zhou 
453020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n",
454dfb79ddbSDennis Zhou 			atomic_read(&fs_info->discard_ctl.discardable_extents));
455dfb79ddbSDennis Zhou }
456dfb79ddbSDennis Zhou BTRFS_ATTR(discard, discardable_extents, btrfs_discardable_extents_show);
457dfb79ddbSDennis Zhou 
4589ddf648fSDennis Zhou static ssize_t btrfs_discard_bitmap_bytes_show(struct kobject *kobj,
4599ddf648fSDennis Zhou 					       struct kobj_attribute *a,
4609ddf648fSDennis Zhou 					       char *buf)
4619ddf648fSDennis Zhou {
4629ddf648fSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4639ddf648fSDennis Zhou 
464020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n",
4659ddf648fSDennis Zhou 			  fs_info->discard_ctl.discard_bitmap_bytes);
4669ddf648fSDennis Zhou }
4679ddf648fSDennis Zhou BTRFS_ATTR(discard, discard_bitmap_bytes, btrfs_discard_bitmap_bytes_show);
4689ddf648fSDennis Zhou 
4699ddf648fSDennis Zhou static ssize_t btrfs_discard_bytes_saved_show(struct kobject *kobj,
4709ddf648fSDennis Zhou 					      struct kobj_attribute *a,
4719ddf648fSDennis Zhou 					      char *buf)
4729ddf648fSDennis Zhou {
4739ddf648fSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4749ddf648fSDennis Zhou 
475020e5277SAnand Jain 	return sysfs_emit(buf, "%lld\n",
4769ddf648fSDennis Zhou 		atomic64_read(&fs_info->discard_ctl.discard_bytes_saved));
4779ddf648fSDennis Zhou }
4789ddf648fSDennis Zhou BTRFS_ATTR(discard, discard_bytes_saved, btrfs_discard_bytes_saved_show);
4799ddf648fSDennis Zhou 
4809ddf648fSDennis Zhou static ssize_t btrfs_discard_extent_bytes_show(struct kobject *kobj,
4819ddf648fSDennis Zhou 					       struct kobj_attribute *a,
4829ddf648fSDennis Zhou 					       char *buf)
4839ddf648fSDennis Zhou {
4849ddf648fSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4859ddf648fSDennis Zhou 
486020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n",
4879ddf648fSDennis Zhou 			  fs_info->discard_ctl.discard_extent_bytes);
4889ddf648fSDennis Zhou }
4899ddf648fSDennis Zhou BTRFS_ATTR(discard, discard_extent_bytes, btrfs_discard_extent_bytes_show);
4909ddf648fSDennis Zhou 
491a2309300SDennis Zhou static ssize_t btrfs_discard_iops_limit_show(struct kobject *kobj,
492a2309300SDennis Zhou 					     struct kobj_attribute *a,
493a2309300SDennis Zhou 					     char *buf)
494a2309300SDennis Zhou {
495a2309300SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
496a2309300SDennis Zhou 
497020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n",
498a2309300SDennis Zhou 			  READ_ONCE(fs_info->discard_ctl.iops_limit));
499a2309300SDennis Zhou }
500a2309300SDennis Zhou 
501a2309300SDennis Zhou static ssize_t btrfs_discard_iops_limit_store(struct kobject *kobj,
502a2309300SDennis Zhou 					      struct kobj_attribute *a,
503a2309300SDennis Zhou 					      const char *buf, size_t len)
504a2309300SDennis Zhou {
505a2309300SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
506a2309300SDennis Zhou 	struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl;
507a2309300SDennis Zhou 	u32 iops_limit;
508a2309300SDennis Zhou 	int ret;
509a2309300SDennis Zhou 
510a2309300SDennis Zhou 	ret = kstrtou32(buf, 10, &iops_limit);
511a2309300SDennis Zhou 	if (ret)
512a2309300SDennis Zhou 		return -EINVAL;
513a2309300SDennis Zhou 
514a2309300SDennis Zhou 	WRITE_ONCE(discard_ctl->iops_limit, iops_limit);
5153e48d8d2SPavel Begunkov 	btrfs_discard_calc_delay(discard_ctl);
5163e48d8d2SPavel Begunkov 	btrfs_discard_schedule_work(discard_ctl, true);
517a2309300SDennis Zhou 	return len;
518a2309300SDennis Zhou }
519a2309300SDennis Zhou BTRFS_ATTR_RW(discard, iops_limit, btrfs_discard_iops_limit_show,
520a2309300SDennis Zhou 	      btrfs_discard_iops_limit_store);
521a2309300SDennis Zhou 
522e93591bbSDennis Zhou static ssize_t btrfs_discard_kbps_limit_show(struct kobject *kobj,
523e93591bbSDennis Zhou 					     struct kobj_attribute *a,
524e93591bbSDennis Zhou 					     char *buf)
525e93591bbSDennis Zhou {
526e93591bbSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
527e93591bbSDennis Zhou 
528020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n",
529e93591bbSDennis Zhou 			  READ_ONCE(fs_info->discard_ctl.kbps_limit));
530e93591bbSDennis Zhou }
531e93591bbSDennis Zhou 
532e93591bbSDennis Zhou static ssize_t btrfs_discard_kbps_limit_store(struct kobject *kobj,
533e93591bbSDennis Zhou 					      struct kobj_attribute *a,
534e93591bbSDennis Zhou 					      const char *buf, size_t len)
535e93591bbSDennis Zhou {
536e93591bbSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
537e93591bbSDennis Zhou 	struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl;
538e93591bbSDennis Zhou 	u32 kbps_limit;
539e93591bbSDennis Zhou 	int ret;
540e93591bbSDennis Zhou 
541e93591bbSDennis Zhou 	ret = kstrtou32(buf, 10, &kbps_limit);
542e93591bbSDennis Zhou 	if (ret)
543e93591bbSDennis Zhou 		return -EINVAL;
544e93591bbSDennis Zhou 
545e93591bbSDennis Zhou 	WRITE_ONCE(discard_ctl->kbps_limit, kbps_limit);
5463e48d8d2SPavel Begunkov 	btrfs_discard_schedule_work(discard_ctl, true);
547e93591bbSDennis Zhou 	return len;
548e93591bbSDennis Zhou }
549e93591bbSDennis Zhou BTRFS_ATTR_RW(discard, kbps_limit, btrfs_discard_kbps_limit_show,
550e93591bbSDennis Zhou 	      btrfs_discard_kbps_limit_store);
551e93591bbSDennis Zhou 
55219b2a2c7SDennis Zhou static ssize_t btrfs_discard_max_discard_size_show(struct kobject *kobj,
55319b2a2c7SDennis Zhou 						   struct kobj_attribute *a,
55419b2a2c7SDennis Zhou 						   char *buf)
55519b2a2c7SDennis Zhou {
55619b2a2c7SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
55719b2a2c7SDennis Zhou 
558020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n",
55919b2a2c7SDennis Zhou 			  READ_ONCE(fs_info->discard_ctl.max_discard_size));
56019b2a2c7SDennis Zhou }
56119b2a2c7SDennis Zhou 
56219b2a2c7SDennis Zhou static ssize_t btrfs_discard_max_discard_size_store(struct kobject *kobj,
56319b2a2c7SDennis Zhou 						    struct kobj_attribute *a,
56419b2a2c7SDennis Zhou 						    const char *buf, size_t len)
56519b2a2c7SDennis Zhou {
56619b2a2c7SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
56719b2a2c7SDennis Zhou 	struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl;
56819b2a2c7SDennis Zhou 	u64 max_discard_size;
56919b2a2c7SDennis Zhou 	int ret;
57019b2a2c7SDennis Zhou 
57119b2a2c7SDennis Zhou 	ret = kstrtou64(buf, 10, &max_discard_size);
57219b2a2c7SDennis Zhou 	if (ret)
57319b2a2c7SDennis Zhou 		return -EINVAL;
57419b2a2c7SDennis Zhou 
57519b2a2c7SDennis Zhou 	WRITE_ONCE(discard_ctl->max_discard_size, max_discard_size);
57619b2a2c7SDennis Zhou 
57719b2a2c7SDennis Zhou 	return len;
57819b2a2c7SDennis Zhou }
57919b2a2c7SDennis Zhou BTRFS_ATTR_RW(discard, max_discard_size, btrfs_discard_max_discard_size_show,
58019b2a2c7SDennis Zhou 	      btrfs_discard_max_discard_size_store);
58119b2a2c7SDennis Zhou 
582e7849e33SAnand Jain /*
583e7849e33SAnand Jain  * Per-filesystem debugging of discard (when mounted with discard=async).
584e7849e33SAnand Jain  *
585e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/debug/discard/
586e7849e33SAnand Jain  */
587e4faab84SDennis Zhou static const struct attribute *discard_debug_attrs[] = {
5885dc7c10bSDennis Zhou 	BTRFS_ATTR_PTR(discard, discardable_bytes),
589dfb79ddbSDennis Zhou 	BTRFS_ATTR_PTR(discard, discardable_extents),
5909ddf648fSDennis Zhou 	BTRFS_ATTR_PTR(discard, discard_bitmap_bytes),
5919ddf648fSDennis Zhou 	BTRFS_ATTR_PTR(discard, discard_bytes_saved),
5929ddf648fSDennis Zhou 	BTRFS_ATTR_PTR(discard, discard_extent_bytes),
593a2309300SDennis Zhou 	BTRFS_ATTR_PTR(discard, iops_limit),
594e93591bbSDennis Zhou 	BTRFS_ATTR_PTR(discard, kbps_limit),
59519b2a2c7SDennis Zhou 	BTRFS_ATTR_PTR(discard, max_discard_size),
596e4faab84SDennis Zhou 	NULL,
597e4faab84SDennis Zhou };
598e4faab84SDennis Zhou 
599e4faab84SDennis Zhou /*
600e7849e33SAnand Jain  * Per-filesystem runtime debugging exported via sysfs.
6016e369febSDavid Sterba  *
602e7849e33SAnand Jain  * Path: /sys/fs/btrfs/UUID/debug/
6036e369febSDavid Sterba  */
60493945cb4SDennis Zhou static const struct attribute *btrfs_debug_mount_attrs[] = {
60593945cb4SDennis Zhou 	NULL,
60693945cb4SDennis Zhou };
60793945cb4SDennis Zhou 
608e7849e33SAnand Jain /*
609e7849e33SAnand Jain  * Runtime debugging exported via sysfs, applies to all mounted filesystems.
610e7849e33SAnand Jain  *
611e7849e33SAnand Jain  * Path: /sys/fs/btrfs/debug
612e7849e33SAnand Jain  */
6136e369febSDavid Sterba static struct attribute *btrfs_debug_feature_attrs[] = {
6146e369febSDavid Sterba 	NULL
6156e369febSDavid Sterba };
6166e369febSDavid Sterba 
6176e369febSDavid Sterba static const struct attribute_group btrfs_debug_feature_attr_group = {
6186e369febSDavid Sterba 	.name = "debug",
6196e369febSDavid Sterba 	.attrs = btrfs_debug_feature_attrs,
6206e369febSDavid Sterba };
6216e369febSDavid Sterba 
6226e369febSDavid Sterba #endif
6236e369febSDavid Sterba 
6246ab0a202SJeff Mahoney static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf)
6256ab0a202SJeff Mahoney {
6266ab0a202SJeff Mahoney 	u64 val;
6276ab0a202SJeff Mahoney 	if (lock)
6286ab0a202SJeff Mahoney 		spin_lock(lock);
6296ab0a202SJeff Mahoney 	val = *value_ptr;
6306ab0a202SJeff Mahoney 	if (lock)
6316ab0a202SJeff Mahoney 		spin_unlock(lock);
632020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", val);
6336ab0a202SJeff Mahoney }
6346ab0a202SJeff Mahoney 
6356ab0a202SJeff Mahoney static ssize_t global_rsv_size_show(struct kobject *kobj,
6366ab0a202SJeff Mahoney 				    struct kobj_attribute *ka, char *buf)
6376ab0a202SJeff Mahoney {
6386ab0a202SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
6396ab0a202SJeff Mahoney 	struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
6406ab0a202SJeff Mahoney 	return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf);
6416ab0a202SJeff Mahoney }
642a969f4ccSHans van Kranenburg BTRFS_ATTR(allocation, global_rsv_size, global_rsv_size_show);
6436ab0a202SJeff Mahoney 
6446ab0a202SJeff Mahoney static ssize_t global_rsv_reserved_show(struct kobject *kobj,
6456ab0a202SJeff Mahoney 					struct kobj_attribute *a, char *buf)
6466ab0a202SJeff Mahoney {
6476ab0a202SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
6486ab0a202SJeff Mahoney 	struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
6496ab0a202SJeff Mahoney 	return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf);
6506ab0a202SJeff Mahoney }
651a969f4ccSHans van Kranenburg BTRFS_ATTR(allocation, global_rsv_reserved, global_rsv_reserved_show);
6526ab0a202SJeff Mahoney 
6536ab0a202SJeff Mahoney #define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj)
654c1895442SJeff Mahoney #define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj)
6556ab0a202SJeff Mahoney 
6566ab0a202SJeff Mahoney static ssize_t raid_bytes_show(struct kobject *kobj,
6576ab0a202SJeff Mahoney 			       struct kobj_attribute *attr, char *buf);
658a969f4ccSHans van Kranenburg BTRFS_ATTR(raid, total_bytes, raid_bytes_show);
659a969f4ccSHans van Kranenburg BTRFS_ATTR(raid, used_bytes, raid_bytes_show);
6606ab0a202SJeff Mahoney 
6616ab0a202SJeff Mahoney static ssize_t raid_bytes_show(struct kobject *kobj,
6626ab0a202SJeff Mahoney 			       struct kobj_attribute *attr, char *buf)
6636ab0a202SJeff Mahoney 
6646ab0a202SJeff Mahoney {
6656ab0a202SJeff Mahoney 	struct btrfs_space_info *sinfo = to_space_info(kobj->parent);
66632da5386SDavid Sterba 	struct btrfs_block_group *block_group;
66775cb379dSJeff Mahoney 	int index = btrfs_bg_flags_to_raid_index(to_raid_kobj(kobj)->flags);
6686ab0a202SJeff Mahoney 	u64 val = 0;
6696ab0a202SJeff Mahoney 
6706ab0a202SJeff Mahoney 	down_read(&sinfo->groups_sem);
6716ab0a202SJeff Mahoney 	list_for_each_entry(block_group, &sinfo->block_groups[index], list) {
672a969f4ccSHans van Kranenburg 		if (&attr->attr == BTRFS_ATTR_PTR(raid, total_bytes))
673b3470b5dSDavid Sterba 			val += block_group->length;
6746ab0a202SJeff Mahoney 		else
675bf38be65SDavid Sterba 			val += block_group->used;
6766ab0a202SJeff Mahoney 	}
6776ab0a202SJeff Mahoney 	up_read(&sinfo->groups_sem);
678020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", val);
6796ab0a202SJeff Mahoney }
6806ab0a202SJeff Mahoney 
681e7849e33SAnand Jain /*
682e7849e33SAnand Jain  * Allocation information about block group profiles.
683e7849e33SAnand Jain  *
684e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/allocation/<bg-type>/<bg-profile>/
685e7849e33SAnand Jain  */
6867c7e3014SKimberly Brown static struct attribute *raid_attrs[] = {
687a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(raid, total_bytes),
688a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(raid, used_bytes),
6896ab0a202SJeff Mahoney 	NULL
6906ab0a202SJeff Mahoney };
6917c7e3014SKimberly Brown ATTRIBUTE_GROUPS(raid);
6926ab0a202SJeff Mahoney 
6936ab0a202SJeff Mahoney static void release_raid_kobj(struct kobject *kobj)
6946ab0a202SJeff Mahoney {
695c1895442SJeff Mahoney 	kfree(to_raid_kobj(kobj));
6966ab0a202SJeff Mahoney }
6976ab0a202SJeff Mahoney 
698536ea45cSDavid Sterba static struct kobj_type btrfs_raid_ktype = {
6996ab0a202SJeff Mahoney 	.sysfs_ops = &kobj_sysfs_ops,
7006ab0a202SJeff Mahoney 	.release = release_raid_kobj,
7017c7e3014SKimberly Brown 	.default_groups = raid_groups,
7026ab0a202SJeff Mahoney };
7036ab0a202SJeff Mahoney 
7046ab0a202SJeff Mahoney #define SPACE_INFO_ATTR(field)						\
7056ab0a202SJeff Mahoney static ssize_t btrfs_space_info_show_##field(struct kobject *kobj,	\
7066ab0a202SJeff Mahoney 					     struct kobj_attribute *a,	\
7076ab0a202SJeff Mahoney 					     char *buf)			\
7086ab0a202SJeff Mahoney {									\
7096ab0a202SJeff Mahoney 	struct btrfs_space_info *sinfo = to_space_info(kobj);		\
7106ab0a202SJeff Mahoney 	return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf);	\
7116ab0a202SJeff Mahoney }									\
712a969f4ccSHans van Kranenburg BTRFS_ATTR(space_info, field, btrfs_space_info_show_##field)
7136ab0a202SJeff Mahoney 
7146ab0a202SJeff Mahoney SPACE_INFO_ATTR(flags);
7156ab0a202SJeff Mahoney SPACE_INFO_ATTR(total_bytes);
7166ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_used);
7176ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_pinned);
7186ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_reserved);
7196ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_may_use);
720c1fd5c30SWang Xiaoguang SPACE_INFO_ATTR(bytes_readonly);
721169e0da9SNaohiro Aota SPACE_INFO_ATTR(bytes_zone_unusable);
7226ab0a202SJeff Mahoney SPACE_INFO_ATTR(disk_used);
7236ab0a202SJeff Mahoney SPACE_INFO_ATTR(disk_total);
7246ab0a202SJeff Mahoney 
725e7849e33SAnand Jain /*
726e7849e33SAnand Jain  * Allocation information about block group types.
727e7849e33SAnand Jain  *
728e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/allocation/<bg-type>/
729e7849e33SAnand Jain  */
7306ab0a202SJeff Mahoney static struct attribute *space_info_attrs[] = {
731a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, flags),
732a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, total_bytes),
733a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_used),
734a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_pinned),
735a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_reserved),
736a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_may_use),
737a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_readonly),
738169e0da9SNaohiro Aota 	BTRFS_ATTR_PTR(space_info, bytes_zone_unusable),
739a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, disk_used),
740a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, disk_total),
7416ab0a202SJeff Mahoney 	NULL,
7426ab0a202SJeff Mahoney };
7437c7e3014SKimberly Brown ATTRIBUTE_GROUPS(space_info);
7446ab0a202SJeff Mahoney 
7456ab0a202SJeff Mahoney static void space_info_release(struct kobject *kobj)
7466ab0a202SJeff Mahoney {
7476ab0a202SJeff Mahoney 	struct btrfs_space_info *sinfo = to_space_info(kobj);
7486ab0a202SJeff Mahoney 	kfree(sinfo);
7496ab0a202SJeff Mahoney }
7506ab0a202SJeff Mahoney 
75127992d01SDavid Sterba static struct kobj_type space_info_ktype = {
7526ab0a202SJeff Mahoney 	.sysfs_ops = &kobj_sysfs_ops,
7536ab0a202SJeff Mahoney 	.release = space_info_release,
7547c7e3014SKimberly Brown 	.default_groups = space_info_groups,
7556ab0a202SJeff Mahoney };
7566ab0a202SJeff Mahoney 
757e7849e33SAnand Jain /*
758e7849e33SAnand Jain  * Allocation information about block groups.
759e7849e33SAnand Jain  *
760e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/allocation/
761e7849e33SAnand Jain  */
7626ab0a202SJeff Mahoney static const struct attribute *allocation_attrs[] = {
763a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(allocation, global_rsv_reserved),
764a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(allocation, global_rsv_size),
7656ab0a202SJeff Mahoney 	NULL,
7666ab0a202SJeff Mahoney };
7676ab0a202SJeff Mahoney 
768f8ba9c11SJeff Mahoney static ssize_t btrfs_label_show(struct kobject *kobj,
769f8ba9c11SJeff Mahoney 				struct kobj_attribute *a, char *buf)
770f8ba9c11SJeff Mahoney {
771f8ba9c11SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
77248fcc3ffSSatoru Takeuchi 	char *label = fs_info->super_copy->label;
773ee17fc80SDavid Sterba 	ssize_t ret;
774ee17fc80SDavid Sterba 
775ee17fc80SDavid Sterba 	spin_lock(&fs_info->super_lock);
776020e5277SAnand Jain 	ret = sysfs_emit(buf, label[0] ? "%s\n" : "%s", label);
777ee17fc80SDavid Sterba 	spin_unlock(&fs_info->super_lock);
778ee17fc80SDavid Sterba 
779ee17fc80SDavid Sterba 	return ret;
780f8ba9c11SJeff Mahoney }
781f8ba9c11SJeff Mahoney 
782f8ba9c11SJeff Mahoney static ssize_t btrfs_label_store(struct kobject *kobj,
783f8ba9c11SJeff Mahoney 				 struct kobj_attribute *a,
784f8ba9c11SJeff Mahoney 				 const char *buf, size_t len)
785f8ba9c11SJeff Mahoney {
786f8ba9c11SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
78748fcc3ffSSatoru Takeuchi 	size_t p_len;
788f8ba9c11SJeff Mahoney 
78966ac9fe7SDavid Sterba 	if (!fs_info)
79066ac9fe7SDavid Sterba 		return -EPERM;
79166ac9fe7SDavid Sterba 
792bc98a42cSDavid Howells 	if (sb_rdonly(fs_info->sb))
79379aec2b8SAnand Jain 		return -EROFS;
79479aec2b8SAnand Jain 
79548fcc3ffSSatoru Takeuchi 	/*
79648fcc3ffSSatoru Takeuchi 	 * p_len is the len until the first occurrence of either
79748fcc3ffSSatoru Takeuchi 	 * '\n' or '\0'
79848fcc3ffSSatoru Takeuchi 	 */
79948fcc3ffSSatoru Takeuchi 	p_len = strcspn(buf, "\n");
80048fcc3ffSSatoru Takeuchi 
80148fcc3ffSSatoru Takeuchi 	if (p_len >= BTRFS_LABEL_SIZE)
802f8ba9c11SJeff Mahoney 		return -EINVAL;
803f8ba9c11SJeff Mahoney 
804a6f69dc8SDavid Sterba 	spin_lock(&fs_info->super_lock);
80548fcc3ffSSatoru Takeuchi 	memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE);
80648fcc3ffSSatoru Takeuchi 	memcpy(fs_info->super_copy->label, buf, p_len);
807a6f69dc8SDavid Sterba 	spin_unlock(&fs_info->super_lock);
808f8ba9c11SJeff Mahoney 
809a6f69dc8SDavid Sterba 	/*
810a6f69dc8SDavid Sterba 	 * We don't want to do full transaction commit from inside sysfs
811a6f69dc8SDavid Sterba 	 */
812a6f69dc8SDavid Sterba 	btrfs_set_pending(fs_info, COMMIT);
813a6f69dc8SDavid Sterba 	wake_up_process(fs_info->transaction_kthread);
814a6f69dc8SDavid Sterba 
815f8ba9c11SJeff Mahoney 	return len;
816f8ba9c11SJeff Mahoney }
817a969f4ccSHans van Kranenburg BTRFS_ATTR_RW(, label, btrfs_label_show, btrfs_label_store);
818f8ba9c11SJeff Mahoney 
819df93589aSDavid Sterba static ssize_t btrfs_nodesize_show(struct kobject *kobj,
820df93589aSDavid Sterba 				struct kobj_attribute *a, char *buf)
821df93589aSDavid Sterba {
822df93589aSDavid Sterba 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
823df93589aSDavid Sterba 
824020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n", fs_info->super_copy->nodesize);
825df93589aSDavid Sterba }
826df93589aSDavid Sterba 
827a969f4ccSHans van Kranenburg BTRFS_ATTR(, nodesize, btrfs_nodesize_show);
828df93589aSDavid Sterba 
829df93589aSDavid Sterba static ssize_t btrfs_sectorsize_show(struct kobject *kobj,
830df93589aSDavid Sterba 				struct kobj_attribute *a, char *buf)
831df93589aSDavid Sterba {
832df93589aSDavid Sterba 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
833df93589aSDavid Sterba 
834020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n", fs_info->super_copy->sectorsize);
835df93589aSDavid Sterba }
836df93589aSDavid Sterba 
837a969f4ccSHans van Kranenburg BTRFS_ATTR(, sectorsize, btrfs_sectorsize_show);
838df93589aSDavid Sterba 
839df93589aSDavid Sterba static ssize_t btrfs_clone_alignment_show(struct kobject *kobj,
840df93589aSDavid Sterba 				struct kobj_attribute *a, char *buf)
841df93589aSDavid Sterba {
842df93589aSDavid Sterba 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
843df93589aSDavid Sterba 
844020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n", fs_info->super_copy->sectorsize);
845df93589aSDavid Sterba }
846df93589aSDavid Sterba 
847a969f4ccSHans van Kranenburg BTRFS_ATTR(, clone_alignment, btrfs_clone_alignment_show);
848df93589aSDavid Sterba 
8492723480aSSargun Dhillon static ssize_t quota_override_show(struct kobject *kobj,
8502723480aSSargun Dhillon 				   struct kobj_attribute *a, char *buf)
8512723480aSSargun Dhillon {
8522723480aSSargun Dhillon 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
8532723480aSSargun Dhillon 	int quota_override;
8542723480aSSargun Dhillon 
8552723480aSSargun Dhillon 	quota_override = test_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags);
856020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", quota_override);
8572723480aSSargun Dhillon }
8582723480aSSargun Dhillon 
8592723480aSSargun Dhillon static ssize_t quota_override_store(struct kobject *kobj,
8602723480aSSargun Dhillon 				    struct kobj_attribute *a,
8612723480aSSargun Dhillon 				    const char *buf, size_t len)
8622723480aSSargun Dhillon {
8632723480aSSargun Dhillon 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
8642723480aSSargun Dhillon 	unsigned long knob;
8652723480aSSargun Dhillon 	int err;
8662723480aSSargun Dhillon 
8672723480aSSargun Dhillon 	if (!fs_info)
8682723480aSSargun Dhillon 		return -EPERM;
8692723480aSSargun Dhillon 
8702723480aSSargun Dhillon 	if (!capable(CAP_SYS_RESOURCE))
8712723480aSSargun Dhillon 		return -EPERM;
8722723480aSSargun Dhillon 
8732723480aSSargun Dhillon 	err = kstrtoul(buf, 10, &knob);
8742723480aSSargun Dhillon 	if (err)
8752723480aSSargun Dhillon 		return err;
8762723480aSSargun Dhillon 	if (knob > 1)
8772723480aSSargun Dhillon 		return -EINVAL;
8782723480aSSargun Dhillon 
8792723480aSSargun Dhillon 	if (knob)
8802723480aSSargun Dhillon 		set_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags);
8812723480aSSargun Dhillon 	else
8822723480aSSargun Dhillon 		clear_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags);
8832723480aSSargun Dhillon 
8842723480aSSargun Dhillon 	return len;
8852723480aSSargun Dhillon }
8862723480aSSargun Dhillon 
887a969f4ccSHans van Kranenburg BTRFS_ATTR_RW(, quota_override, quota_override_show, quota_override_store);
8882723480aSSargun Dhillon 
88956f20f40SNikolay Borisov static ssize_t btrfs_metadata_uuid_show(struct kobject *kobj,
89056f20f40SNikolay Borisov 				struct kobj_attribute *a, char *buf)
89156f20f40SNikolay Borisov {
89256f20f40SNikolay Borisov 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
89356f20f40SNikolay Borisov 
894020e5277SAnand Jain 	return sysfs_emit(buf, "%pU\n", fs_info->fs_devices->metadata_uuid);
89556f20f40SNikolay Borisov }
89656f20f40SNikolay Borisov 
89756f20f40SNikolay Borisov BTRFS_ATTR(, metadata_uuid, btrfs_metadata_uuid_show);
89856f20f40SNikolay Borisov 
89941e6d2a8SJohannes Thumshirn static ssize_t btrfs_checksum_show(struct kobject *kobj,
90041e6d2a8SJohannes Thumshirn 				   struct kobj_attribute *a, char *buf)
90141e6d2a8SJohannes Thumshirn {
90241e6d2a8SJohannes Thumshirn 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
90341e6d2a8SJohannes Thumshirn 	u16 csum_type = btrfs_super_csum_type(fs_info->super_copy);
90441e6d2a8SJohannes Thumshirn 
905020e5277SAnand Jain 	return sysfs_emit(buf, "%s (%s)\n",
90641e6d2a8SJohannes Thumshirn 			  btrfs_super_csum_name(csum_type),
90741e6d2a8SJohannes Thumshirn 			  crypto_shash_driver_name(fs_info->csum_shash));
90841e6d2a8SJohannes Thumshirn }
90941e6d2a8SJohannes Thumshirn 
91041e6d2a8SJohannes Thumshirn BTRFS_ATTR(, checksum, btrfs_checksum_show);
91141e6d2a8SJohannes Thumshirn 
91266a2823cSGoldwyn Rodrigues static ssize_t btrfs_exclusive_operation_show(struct kobject *kobj,
91366a2823cSGoldwyn Rodrigues 		struct kobj_attribute *a, char *buf)
91466a2823cSGoldwyn Rodrigues {
91566a2823cSGoldwyn Rodrigues 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
91666a2823cSGoldwyn Rodrigues 	const char *str;
91766a2823cSGoldwyn Rodrigues 
91866a2823cSGoldwyn Rodrigues 	switch (READ_ONCE(fs_info->exclusive_operation)) {
91966a2823cSGoldwyn Rodrigues 		case  BTRFS_EXCLOP_NONE:
92066a2823cSGoldwyn Rodrigues 			str = "none\n";
92166a2823cSGoldwyn Rodrigues 			break;
92266a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_BALANCE:
92366a2823cSGoldwyn Rodrigues 			str = "balance\n";
92466a2823cSGoldwyn Rodrigues 			break;
925*3e1ad196SDavid Sterba 		case BTRFS_EXCLOP_BALANCE_PAUSED:
926*3e1ad196SDavid Sterba 			str = "balance paused\n";
927*3e1ad196SDavid Sterba 			break;
92866a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_ADD:
92966a2823cSGoldwyn Rodrigues 			str = "device add\n";
93066a2823cSGoldwyn Rodrigues 			break;
93166a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_REMOVE:
93266a2823cSGoldwyn Rodrigues 			str = "device remove\n";
93366a2823cSGoldwyn Rodrigues 			break;
93466a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_REPLACE:
93566a2823cSGoldwyn Rodrigues 			str = "device replace\n";
93666a2823cSGoldwyn Rodrigues 			break;
93766a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_RESIZE:
93866a2823cSGoldwyn Rodrigues 			str = "resize\n";
93966a2823cSGoldwyn Rodrigues 			break;
94066a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_SWAP_ACTIVATE:
94166a2823cSGoldwyn Rodrigues 			str = "swap activate\n";
94266a2823cSGoldwyn Rodrigues 			break;
94366a2823cSGoldwyn Rodrigues 		default:
94466a2823cSGoldwyn Rodrigues 			str = "UNKNOWN\n";
94566a2823cSGoldwyn Rodrigues 			break;
94666a2823cSGoldwyn Rodrigues 	}
947020e5277SAnand Jain 	return sysfs_emit(buf, "%s", str);
94866a2823cSGoldwyn Rodrigues }
94966a2823cSGoldwyn Rodrigues BTRFS_ATTR(, exclusive_operation, btrfs_exclusive_operation_show);
95066a2823cSGoldwyn Rodrigues 
951089c8b05SAnand Jain static ssize_t btrfs_generation_show(struct kobject *kobj,
952089c8b05SAnand Jain 				     struct kobj_attribute *a, char *buf)
953089c8b05SAnand Jain {
954089c8b05SAnand Jain 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
955089c8b05SAnand Jain 
956020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", fs_info->generation);
957089c8b05SAnand Jain }
958089c8b05SAnand Jain BTRFS_ATTR(, generation, btrfs_generation_show);
959089c8b05SAnand Jain 
960aaefed20SAnand Jain /*
961aaefed20SAnand Jain  * Look for an exact string @string in @buffer with possible leading or
962aaefed20SAnand Jain  * trailing whitespace
963aaefed20SAnand Jain  */
964aaefed20SAnand Jain static bool strmatch(const char *buffer, const char *string)
965aaefed20SAnand Jain {
966aaefed20SAnand Jain 	const size_t len = strlen(string);
967aaefed20SAnand Jain 
968aaefed20SAnand Jain 	/* Skip leading whitespace */
969aaefed20SAnand Jain 	buffer = skip_spaces(buffer);
970aaefed20SAnand Jain 
971aaefed20SAnand Jain 	/* Match entire string, check if the rest is whitespace or empty */
972aaefed20SAnand Jain 	if (strncmp(string, buffer, len) == 0 &&
973aaefed20SAnand Jain 	    strlen(skip_spaces(buffer + len)) == 0)
974aaefed20SAnand Jain 		return true;
975aaefed20SAnand Jain 
976aaefed20SAnand Jain 	return false;
977aaefed20SAnand Jain }
978aaefed20SAnand Jain 
9793d8cc17aSAnand Jain static const char * const btrfs_read_policy_name[] = { "pid" };
9803d8cc17aSAnand Jain 
9813d8cc17aSAnand Jain static ssize_t btrfs_read_policy_show(struct kobject *kobj,
9823d8cc17aSAnand Jain 				      struct kobj_attribute *a, char *buf)
9833d8cc17aSAnand Jain {
9843d8cc17aSAnand Jain 	struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
9853d8cc17aSAnand Jain 	ssize_t ret = 0;
9863d8cc17aSAnand Jain 	int i;
9873d8cc17aSAnand Jain 
9883d8cc17aSAnand Jain 	for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
9893d8cc17aSAnand Jain 		if (fs_devices->read_policy == i)
9903d8cc17aSAnand Jain 			ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s[%s]",
9913d8cc17aSAnand Jain 					 (ret == 0 ? "" : " "),
9923d8cc17aSAnand Jain 					 btrfs_read_policy_name[i]);
9933d8cc17aSAnand Jain 		else
9943d8cc17aSAnand Jain 			ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s%s",
9953d8cc17aSAnand Jain 					 (ret == 0 ? "" : " "),
9963d8cc17aSAnand Jain 					 btrfs_read_policy_name[i]);
9973d8cc17aSAnand Jain 	}
9983d8cc17aSAnand Jain 
9993d8cc17aSAnand Jain 	ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
10003d8cc17aSAnand Jain 
10013d8cc17aSAnand Jain 	return ret;
10023d8cc17aSAnand Jain }
10033d8cc17aSAnand Jain 
10043d8cc17aSAnand Jain static ssize_t btrfs_read_policy_store(struct kobject *kobj,
10053d8cc17aSAnand Jain 				       struct kobj_attribute *a,
10063d8cc17aSAnand Jain 				       const char *buf, size_t len)
10073d8cc17aSAnand Jain {
10083d8cc17aSAnand Jain 	struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
10093d8cc17aSAnand Jain 	int i;
10103d8cc17aSAnand Jain 
10113d8cc17aSAnand Jain 	for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
10123d8cc17aSAnand Jain 		if (strmatch(buf, btrfs_read_policy_name[i])) {
10133d8cc17aSAnand Jain 			if (i != fs_devices->read_policy) {
10143d8cc17aSAnand Jain 				fs_devices->read_policy = i;
10153d8cc17aSAnand Jain 				btrfs_info(fs_devices->fs_info,
10163d8cc17aSAnand Jain 					   "read policy set to '%s'",
10173d8cc17aSAnand Jain 					   btrfs_read_policy_name[i]);
10183d8cc17aSAnand Jain 			}
10193d8cc17aSAnand Jain 			return len;
10203d8cc17aSAnand Jain 		}
10213d8cc17aSAnand Jain 	}
10223d8cc17aSAnand Jain 
10233d8cc17aSAnand Jain 	return -EINVAL;
10243d8cc17aSAnand Jain }
10253d8cc17aSAnand Jain BTRFS_ATTR_RW(, read_policy, btrfs_read_policy_show, btrfs_read_policy_store);
10263d8cc17aSAnand Jain 
102718bb8bbfSJohannes Thumshirn static ssize_t btrfs_bg_reclaim_threshold_show(struct kobject *kobj,
102818bb8bbfSJohannes Thumshirn 					       struct kobj_attribute *a,
102918bb8bbfSJohannes Thumshirn 					       char *buf)
103018bb8bbfSJohannes Thumshirn {
103118bb8bbfSJohannes Thumshirn 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
103218bb8bbfSJohannes Thumshirn 	ssize_t ret;
103318bb8bbfSJohannes Thumshirn 
1034020e5277SAnand Jain 	ret = sysfs_emit(buf, "%d\n", READ_ONCE(fs_info->bg_reclaim_threshold));
103518bb8bbfSJohannes Thumshirn 
103618bb8bbfSJohannes Thumshirn 	return ret;
103718bb8bbfSJohannes Thumshirn }
103818bb8bbfSJohannes Thumshirn 
103918bb8bbfSJohannes Thumshirn static ssize_t btrfs_bg_reclaim_threshold_store(struct kobject *kobj,
104018bb8bbfSJohannes Thumshirn 						struct kobj_attribute *a,
104118bb8bbfSJohannes Thumshirn 						const char *buf, size_t len)
104218bb8bbfSJohannes Thumshirn {
104318bb8bbfSJohannes Thumshirn 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
104418bb8bbfSJohannes Thumshirn 	int thresh;
104518bb8bbfSJohannes Thumshirn 	int ret;
104618bb8bbfSJohannes Thumshirn 
104718bb8bbfSJohannes Thumshirn 	ret = kstrtoint(buf, 10, &thresh);
104818bb8bbfSJohannes Thumshirn 	if (ret)
104918bb8bbfSJohannes Thumshirn 		return ret;
105018bb8bbfSJohannes Thumshirn 
105177233c2dSJohannes Thumshirn 	if (thresh != 0 && (thresh <= 50 || thresh > 100))
105218bb8bbfSJohannes Thumshirn 		return -EINVAL;
105318bb8bbfSJohannes Thumshirn 
105477233c2dSJohannes Thumshirn 	WRITE_ONCE(fs_info->bg_reclaim_threshold, thresh);
105518bb8bbfSJohannes Thumshirn 
105618bb8bbfSJohannes Thumshirn 	return len;
105718bb8bbfSJohannes Thumshirn }
105818bb8bbfSJohannes Thumshirn BTRFS_ATTR_RW(, bg_reclaim_threshold, btrfs_bg_reclaim_threshold_show,
105918bb8bbfSJohannes Thumshirn 	      btrfs_bg_reclaim_threshold_store);
106018bb8bbfSJohannes Thumshirn 
1061e7849e33SAnand Jain /*
1062e7849e33SAnand Jain  * Per-filesystem information and stats.
1063e7849e33SAnand Jain  *
1064e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/
1065e7849e33SAnand Jain  */
10660dd2906fSAnand Jain static const struct attribute *btrfs_attrs[] = {
1067a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, label),
1068a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, nodesize),
1069a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, sectorsize),
1070a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, clone_alignment),
1071a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, quota_override),
107256f20f40SNikolay Borisov 	BTRFS_ATTR_PTR(, metadata_uuid),
107341e6d2a8SJohannes Thumshirn 	BTRFS_ATTR_PTR(, checksum),
107466a2823cSGoldwyn Rodrigues 	BTRFS_ATTR_PTR(, exclusive_operation),
1075089c8b05SAnand Jain 	BTRFS_ATTR_PTR(, generation),
10763d8cc17aSAnand Jain 	BTRFS_ATTR_PTR(, read_policy),
107718bb8bbfSJohannes Thumshirn 	BTRFS_ATTR_PTR(, bg_reclaim_threshold),
1078f8ba9c11SJeff Mahoney 	NULL,
1079f8ba9c11SJeff Mahoney };
1080f8ba9c11SJeff Mahoney 
1081c1b7e474SAnand Jain static void btrfs_release_fsid_kobj(struct kobject *kobj)
1082510d7360SJeff Mahoney {
10832e7910d6SAnand Jain 	struct btrfs_fs_devices *fs_devs = to_fs_devs(kobj);
1084248d200dSAnand Jain 
1085c1b7e474SAnand Jain 	memset(&fs_devs->fsid_kobj, 0, sizeof(struct kobject));
10862e7910d6SAnand Jain 	complete(&fs_devs->kobj_unregister);
1087510d7360SJeff Mahoney }
1088510d7360SJeff Mahoney 
1089510d7360SJeff Mahoney static struct kobj_type btrfs_ktype = {
1090510d7360SJeff Mahoney 	.sysfs_ops	= &kobj_sysfs_ops,
1091c1b7e474SAnand Jain 	.release	= btrfs_release_fsid_kobj,
1092510d7360SJeff Mahoney };
1093510d7360SJeff Mahoney 
10942e7910d6SAnand Jain static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj)
10952e7910d6SAnand Jain {
10962e7910d6SAnand Jain 	if (kobj->ktype != &btrfs_ktype)
10972e7910d6SAnand Jain 		return NULL;
1098c1b7e474SAnand Jain 	return container_of(kobj, struct btrfs_fs_devices, fsid_kobj);
10992e7910d6SAnand Jain }
11002e7910d6SAnand Jain 
1101510d7360SJeff Mahoney static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj)
1102510d7360SJeff Mahoney {
1103510d7360SJeff Mahoney 	if (kobj->ktype != &btrfs_ktype)
1104510d7360SJeff Mahoney 		return NULL;
11052e7910d6SAnand Jain 	return to_fs_devs(kobj)->fs_info;
1106510d7360SJeff Mahoney }
110758176a96SJosef Bacik 
1108e453d989SJeff Mahoney #define NUM_FEATURE_BITS 64
11096c52157fSTomohiro Misono #define BTRFS_FEATURE_NAME_MAX 13
11106c52157fSTomohiro Misono static char btrfs_unknown_feature_names[FEAT_MAX][NUM_FEATURE_BITS][BTRFS_FEATURE_NAME_MAX];
11116c52157fSTomohiro Misono static struct btrfs_feature_attr btrfs_feature_attrs[FEAT_MAX][NUM_FEATURE_BITS];
1112e453d989SJeff Mahoney 
1113a55e65b8SDavid Sterba static_assert(ARRAY_SIZE(btrfs_unknown_feature_names) ==
1114a55e65b8SDavid Sterba 	      ARRAY_SIZE(btrfs_feature_attrs));
1115a55e65b8SDavid Sterba static_assert(ARRAY_SIZE(btrfs_unknown_feature_names[0]) ==
1116a55e65b8SDavid Sterba 	      ARRAY_SIZE(btrfs_feature_attrs[0]));
1117a55e65b8SDavid Sterba 
11186c52157fSTomohiro Misono static const u64 supported_feature_masks[FEAT_MAX] = {
1119e453d989SJeff Mahoney 	[FEAT_COMPAT]    = BTRFS_FEATURE_COMPAT_SUPP,
1120e453d989SJeff Mahoney 	[FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP,
1121e453d989SJeff Mahoney 	[FEAT_INCOMPAT]  = BTRFS_FEATURE_INCOMPAT_SUPP,
1122e453d989SJeff Mahoney };
1123e453d989SJeff Mahoney 
1124e453d989SJeff Mahoney static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add)
11255ac1d209SJeff Mahoney {
1126e453d989SJeff Mahoney 	int set;
1127e453d989SJeff Mahoney 
1128e453d989SJeff Mahoney 	for (set = 0; set < FEAT_MAX; set++) {
1129e453d989SJeff Mahoney 		int i;
1130e453d989SJeff Mahoney 		struct attribute *attrs[2];
1131e453d989SJeff Mahoney 		struct attribute_group agroup = {
1132e453d989SJeff Mahoney 			.name = "features",
1133e453d989SJeff Mahoney 			.attrs = attrs,
1134e453d989SJeff Mahoney 		};
1135e453d989SJeff Mahoney 		u64 features = get_features(fs_info, set);
1136e453d989SJeff Mahoney 		features &= ~supported_feature_masks[set];
1137e453d989SJeff Mahoney 
1138e453d989SJeff Mahoney 		if (!features)
1139e453d989SJeff Mahoney 			continue;
1140e453d989SJeff Mahoney 
1141e453d989SJeff Mahoney 		attrs[1] = NULL;
1142e453d989SJeff Mahoney 		for (i = 0; i < NUM_FEATURE_BITS; i++) {
1143e453d989SJeff Mahoney 			struct btrfs_feature_attr *fa;
1144e453d989SJeff Mahoney 
1145e453d989SJeff Mahoney 			if (!(features & (1ULL << i)))
1146e453d989SJeff Mahoney 				continue;
1147e453d989SJeff Mahoney 
1148e453d989SJeff Mahoney 			fa = &btrfs_feature_attrs[set][i];
1149e453d989SJeff Mahoney 			attrs[0] = &fa->kobj_attr.attr;
1150e453d989SJeff Mahoney 			if (add) {
1151e453d989SJeff Mahoney 				int ret;
1152c1b7e474SAnand Jain 				ret = sysfs_merge_group(&fs_info->fs_devices->fsid_kobj,
1153e453d989SJeff Mahoney 							&agroup);
1154e453d989SJeff Mahoney 				if (ret)
1155e453d989SJeff Mahoney 					return ret;
1156e453d989SJeff Mahoney 			} else
1157c1b7e474SAnand Jain 				sysfs_unmerge_group(&fs_info->fs_devices->fsid_kobj,
1158e453d989SJeff Mahoney 						    &agroup);
1159e453d989SJeff Mahoney 		}
1160e453d989SJeff Mahoney 
1161e453d989SJeff Mahoney 	}
1162e453d989SJeff Mahoney 	return 0;
1163e453d989SJeff Mahoney }
1164e453d989SJeff Mahoney 
11652e3e1281SAnand Jain static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs)
1166e453d989SJeff Mahoney {
1167a013d141SAnand Jain 	if (fs_devs->devinfo_kobj) {
1168a013d141SAnand Jain 		kobject_del(fs_devs->devinfo_kobj);
1169a013d141SAnand Jain 		kobject_put(fs_devs->devinfo_kobj);
1170a013d141SAnand Jain 		fs_devs->devinfo_kobj = NULL;
1171a013d141SAnand Jain 	}
1172a013d141SAnand Jain 
1173b5501504SAnand Jain 	if (fs_devs->devices_kobj) {
1174b5501504SAnand Jain 		kobject_del(fs_devs->devices_kobj);
1175b5501504SAnand Jain 		kobject_put(fs_devs->devices_kobj);
1176b5501504SAnand Jain 		fs_devs->devices_kobj = NULL;
1177aaf13305SAnand Jain 	}
1178aaf13305SAnand Jain 
1179c1b7e474SAnand Jain 	if (fs_devs->fsid_kobj.state_initialized) {
1180c1b7e474SAnand Jain 		kobject_del(&fs_devs->fsid_kobj);
1181c1b7e474SAnand Jain 		kobject_put(&fs_devs->fsid_kobj);
11822e7910d6SAnand Jain 		wait_for_completion(&fs_devs->kobj_unregister);
11835ac1d209SJeff Mahoney 	}
1184f90fc547SAnand Jain }
11855ac1d209SJeff Mahoney 
11862e3e1281SAnand Jain /* when fs_devs is NULL it will remove all fsid kobject */
11871d1c1be3SAnand Jain void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs)
11882e3e1281SAnand Jain {
11892e3e1281SAnand Jain 	struct list_head *fs_uuids = btrfs_get_fs_uuids();
11902e3e1281SAnand Jain 
11912e3e1281SAnand Jain 	if (fs_devs) {
11922e3e1281SAnand Jain 		__btrfs_sysfs_remove_fsid(fs_devs);
11932e3e1281SAnand Jain 		return;
11942e3e1281SAnand Jain 	}
11952e3e1281SAnand Jain 
1196c4babc5eSAnand Jain 	list_for_each_entry(fs_devs, fs_uuids, fs_list) {
11972e3e1281SAnand Jain 		__btrfs_sysfs_remove_fsid(fs_devs);
11982e3e1281SAnand Jain 	}
11992e3e1281SAnand Jain }
12002e3e1281SAnand Jain 
120153f8a74cSAnand Jain static void btrfs_sysfs_remove_fs_devices(struct btrfs_fs_devices *fs_devices)
120253f8a74cSAnand Jain {
120353f8a74cSAnand Jain 	struct btrfs_device *device;
120430b0e4e0SAnand Jain 	struct btrfs_fs_devices *seed;
120553f8a74cSAnand Jain 
120653f8a74cSAnand Jain 	list_for_each_entry(device, &fs_devices->devices, dev_list)
120753f8a74cSAnand Jain 		btrfs_sysfs_remove_device(device);
120830b0e4e0SAnand Jain 
120930b0e4e0SAnand Jain 	list_for_each_entry(seed, &fs_devices->seed_list, seed_list) {
121030b0e4e0SAnand Jain 		list_for_each_entry(device, &seed->devices, dev_list)
121130b0e4e0SAnand Jain 			btrfs_sysfs_remove_device(device);
121230b0e4e0SAnand Jain 	}
121353f8a74cSAnand Jain }
121453f8a74cSAnand Jain 
12156618a59bSAnand Jain void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info)
1216e453d989SJeff Mahoney {
12173092c68fSNikolay Borisov 	struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj;
12183092c68fSNikolay Borisov 
12193092c68fSNikolay Borisov 	sysfs_remove_link(fsid_kobj, "bdi");
12203092c68fSNikolay Borisov 
1221e453d989SJeff Mahoney 	if (fs_info->space_info_kobj) {
1222e453d989SJeff Mahoney 		sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs);
1223e453d989SJeff Mahoney 		kobject_del(fs_info->space_info_kobj);
1224e453d989SJeff Mahoney 		kobject_put(fs_info->space_info_kobj);
1225e453d989SJeff Mahoney 	}
122671e8978eSDennis Zhou #ifdef CONFIG_BTRFS_DEBUG
1227e4faab84SDennis Zhou 	if (fs_info->discard_debug_kobj) {
1228e4faab84SDennis Zhou 		sysfs_remove_files(fs_info->discard_debug_kobj,
1229e4faab84SDennis Zhou 				   discard_debug_attrs);
1230e4faab84SDennis Zhou 		kobject_del(fs_info->discard_debug_kobj);
1231e4faab84SDennis Zhou 		kobject_put(fs_info->discard_debug_kobj);
1232e4faab84SDennis Zhou 	}
123393945cb4SDennis Zhou 	if (fs_info->debug_kobj) {
123493945cb4SDennis Zhou 		sysfs_remove_files(fs_info->debug_kobj, btrfs_debug_mount_attrs);
123593945cb4SDennis Zhou 		kobject_del(fs_info->debug_kobj);
123693945cb4SDennis Zhou 		kobject_put(fs_info->debug_kobj);
123793945cb4SDennis Zhou 	}
123871e8978eSDennis Zhou #endif
1239e453d989SJeff Mahoney 	addrm_unknown_feature_attrs(fs_info, false);
12403092c68fSNikolay Borisov 	sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group);
12413092c68fSNikolay Borisov 	sysfs_remove_files(fsid_kobj, btrfs_attrs);
124253f8a74cSAnand Jain 	btrfs_sysfs_remove_fs_devices(fs_info->fs_devices);
1243e453d989SJeff Mahoney }
1244e453d989SJeff Mahoney 
1245f10152bcSDavid Sterba static const char * const btrfs_feature_set_names[FEAT_MAX] = {
124679da4fa4SJeff Mahoney 	[FEAT_COMPAT]	 = "compat",
124779da4fa4SJeff Mahoney 	[FEAT_COMPAT_RO] = "compat_ro",
124879da4fa4SJeff Mahoney 	[FEAT_INCOMPAT]	 = "incompat",
124979da4fa4SJeff Mahoney };
125079da4fa4SJeff Mahoney 
12519e6df7ceSDavid Sterba const char *btrfs_feature_set_name(enum btrfs_feature_set set)
1252f10152bcSDavid Sterba {
1253f10152bcSDavid Sterba 	return btrfs_feature_set_names[set];
1254f10152bcSDavid Sterba }
1255f10152bcSDavid Sterba 
12563b02a68aSJeff Mahoney char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags)
12573b02a68aSJeff Mahoney {
12583b02a68aSJeff Mahoney 	size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */
12593b02a68aSJeff Mahoney 	int len = 0;
12603b02a68aSJeff Mahoney 	int i;
12613b02a68aSJeff Mahoney 	char *str;
12623b02a68aSJeff Mahoney 
12633b02a68aSJeff Mahoney 	str = kmalloc(bufsize, GFP_KERNEL);
12643b02a68aSJeff Mahoney 	if (!str)
12653b02a68aSJeff Mahoney 		return str;
12663b02a68aSJeff Mahoney 
12673b02a68aSJeff Mahoney 	for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
12683b02a68aSJeff Mahoney 		const char *name;
12693b02a68aSJeff Mahoney 
12703b02a68aSJeff Mahoney 		if (!(flags & (1ULL << i)))
12713b02a68aSJeff Mahoney 			continue;
12723b02a68aSJeff Mahoney 
12733b02a68aSJeff Mahoney 		name = btrfs_feature_attrs[set][i].kobj_attr.attr.name;
1274abdd9febSTakashi Iwai 		len += scnprintf(str + len, bufsize - len, "%s%s",
12753b02a68aSJeff Mahoney 				len ? "," : "", name);
12763b02a68aSJeff Mahoney 	}
12773b02a68aSJeff Mahoney 
12783b02a68aSJeff Mahoney 	return str;
12793b02a68aSJeff Mahoney }
12803b02a68aSJeff Mahoney 
128179da4fa4SJeff Mahoney static void init_feature_attrs(void)
128279da4fa4SJeff Mahoney {
128379da4fa4SJeff Mahoney 	struct btrfs_feature_attr *fa;
128479da4fa4SJeff Mahoney 	int set, i;
128579da4fa4SJeff Mahoney 
12863b02a68aSJeff Mahoney 	memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs));
12873b02a68aSJeff Mahoney 	memset(btrfs_unknown_feature_names, 0,
12883b02a68aSJeff Mahoney 	       sizeof(btrfs_unknown_feature_names));
12893b02a68aSJeff Mahoney 
129079da4fa4SJeff Mahoney 	for (i = 0; btrfs_supported_feature_attrs[i]; i++) {
129179da4fa4SJeff Mahoney 		struct btrfs_feature_attr *sfa;
129279da4fa4SJeff Mahoney 		struct attribute *a = btrfs_supported_feature_attrs[i];
12933b02a68aSJeff Mahoney 		int bit;
129479da4fa4SJeff Mahoney 		sfa = attr_to_btrfs_feature_attr(a);
12953b02a68aSJeff Mahoney 		bit = ilog2(sfa->feature_bit);
12963b02a68aSJeff Mahoney 		fa = &btrfs_feature_attrs[sfa->feature_set][bit];
129779da4fa4SJeff Mahoney 
129879da4fa4SJeff Mahoney 		fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name;
129979da4fa4SJeff Mahoney 	}
130079da4fa4SJeff Mahoney 
130179da4fa4SJeff Mahoney 	for (set = 0; set < FEAT_MAX; set++) {
130279da4fa4SJeff Mahoney 		for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
130379da4fa4SJeff Mahoney 			char *name = btrfs_unknown_feature_names[set][i];
130479da4fa4SJeff Mahoney 			fa = &btrfs_feature_attrs[set][i];
130579da4fa4SJeff Mahoney 
130679da4fa4SJeff Mahoney 			if (fa->kobj_attr.attr.name)
130779da4fa4SJeff Mahoney 				continue;
130879da4fa4SJeff Mahoney 
13096c52157fSTomohiro Misono 			snprintf(name, BTRFS_FEATURE_NAME_MAX, "%s:%u",
131079da4fa4SJeff Mahoney 				 btrfs_feature_set_names[set], i);
131179da4fa4SJeff Mahoney 
131279da4fa4SJeff Mahoney 			fa->kobj_attr.attr.name = name;
131379da4fa4SJeff Mahoney 			fa->kobj_attr.attr.mode = S_IRUGO;
131479da4fa4SJeff Mahoney 			fa->feature_set = set;
131579da4fa4SJeff Mahoney 			fa->feature_bit = 1ULL << i;
131679da4fa4SJeff Mahoney 		}
131779da4fa4SJeff Mahoney 	}
131879da4fa4SJeff Mahoney }
131979da4fa4SJeff Mahoney 
132032a9991fSDavid Sterba /*
132132a9991fSDavid Sterba  * Create a sysfs entry for a given block group type at path
132232a9991fSDavid Sterba  * /sys/fs/btrfs/UUID/allocation/data/TYPE
132332a9991fSDavid Sterba  */
132432da5386SDavid Sterba void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache)
132532a9991fSDavid Sterba {
132632a9991fSDavid Sterba 	struct btrfs_fs_info *fs_info = cache->fs_info;
132732a9991fSDavid Sterba 	struct btrfs_space_info *space_info = cache->space_info;
132832a9991fSDavid Sterba 	struct raid_kobject *rkobj;
132932a9991fSDavid Sterba 	const int index = btrfs_bg_flags_to_raid_index(cache->flags);
133032a9991fSDavid Sterba 	unsigned int nofs_flag;
133132a9991fSDavid Sterba 	int ret;
133232a9991fSDavid Sterba 
133332a9991fSDavid Sterba 	/*
133432a9991fSDavid Sterba 	 * Setup a NOFS context because kobject_add(), deep in its call chain,
133532a9991fSDavid Sterba 	 * does GFP_KERNEL allocations, and we are often called in a context
133632a9991fSDavid Sterba 	 * where if reclaim is triggered we can deadlock (we are either holding
133732a9991fSDavid Sterba 	 * a transaction handle or some lock required for a transaction
133832a9991fSDavid Sterba 	 * commit).
133932a9991fSDavid Sterba 	 */
134032a9991fSDavid Sterba 	nofs_flag = memalloc_nofs_save();
134132a9991fSDavid Sterba 
134232a9991fSDavid Sterba 	rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS);
134332a9991fSDavid Sterba 	if (!rkobj) {
134432a9991fSDavid Sterba 		memalloc_nofs_restore(nofs_flag);
134532a9991fSDavid Sterba 		btrfs_warn(cache->fs_info,
134632a9991fSDavid Sterba 				"couldn't alloc memory for raid level kobject");
134732a9991fSDavid Sterba 		return;
134832a9991fSDavid Sterba 	}
134932a9991fSDavid Sterba 
135032a9991fSDavid Sterba 	rkobj->flags = cache->flags;
135132a9991fSDavid Sterba 	kobject_init(&rkobj->kobj, &btrfs_raid_ktype);
135249ea112dSJosef Bacik 
135349ea112dSJosef Bacik 	/*
135449ea112dSJosef Bacik 	 * We call this either on mount, or if we've created a block group for a
135549ea112dSJosef Bacik 	 * new index type while running (i.e. when restriping).  The running
135649ea112dSJosef Bacik 	 * case is tricky because we could race with other threads, so we need
135749ea112dSJosef Bacik 	 * to have this check to make sure we didn't already init the kobject.
135849ea112dSJosef Bacik 	 *
135949ea112dSJosef Bacik 	 * We don't have to protect on the free side because it only happens on
136049ea112dSJosef Bacik 	 * unmount.
136149ea112dSJosef Bacik 	 */
136249ea112dSJosef Bacik 	spin_lock(&space_info->lock);
136349ea112dSJosef Bacik 	if (space_info->block_group_kobjs[index]) {
136449ea112dSJosef Bacik 		spin_unlock(&space_info->lock);
136549ea112dSJosef Bacik 		kobject_put(&rkobj->kobj);
136649ea112dSJosef Bacik 		return;
136749ea112dSJosef Bacik 	} else {
136849ea112dSJosef Bacik 		space_info->block_group_kobjs[index] = &rkobj->kobj;
136949ea112dSJosef Bacik 	}
137049ea112dSJosef Bacik 	spin_unlock(&space_info->lock);
137149ea112dSJosef Bacik 
137232a9991fSDavid Sterba 	ret = kobject_add(&rkobj->kobj, &space_info->kobj, "%s",
137332a9991fSDavid Sterba 			  btrfs_bg_type_to_raid_name(rkobj->flags));
137432a9991fSDavid Sterba 	memalloc_nofs_restore(nofs_flag);
137532a9991fSDavid Sterba 	if (ret) {
137649ea112dSJosef Bacik 		spin_lock(&space_info->lock);
137749ea112dSJosef Bacik 		space_info->block_group_kobjs[index] = NULL;
137849ea112dSJosef Bacik 		spin_unlock(&space_info->lock);
137932a9991fSDavid Sterba 		kobject_put(&rkobj->kobj);
138032a9991fSDavid Sterba 		btrfs_warn(fs_info,
138132a9991fSDavid Sterba 			"failed to add kobject for block cache, ignoring");
138232a9991fSDavid Sterba 		return;
138332a9991fSDavid Sterba 	}
138432a9991fSDavid Sterba }
138532a9991fSDavid Sterba 
1386b5865babSDavid Sterba /*
1387b5865babSDavid Sterba  * Remove sysfs directories for all block group types of a given space info and
1388b5865babSDavid Sterba  * the space info as well
1389b5865babSDavid Sterba  */
1390b5865babSDavid Sterba void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info)
1391b5865babSDavid Sterba {
1392b5865babSDavid Sterba 	int i;
1393b5865babSDavid Sterba 
1394b5865babSDavid Sterba 	for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
1395b5865babSDavid Sterba 		struct kobject *kobj;
1396b5865babSDavid Sterba 
1397b5865babSDavid Sterba 		kobj = space_info->block_group_kobjs[i];
1398b5865babSDavid Sterba 		space_info->block_group_kobjs[i] = NULL;
1399b5865babSDavid Sterba 		if (kobj) {
1400b5865babSDavid Sterba 			kobject_del(kobj);
1401b5865babSDavid Sterba 			kobject_put(kobj);
1402b5865babSDavid Sterba 		}
1403b5865babSDavid Sterba 	}
1404b5865babSDavid Sterba 	kobject_del(&space_info->kobj);
1405b5865babSDavid Sterba 	kobject_put(&space_info->kobj);
1406b5865babSDavid Sterba }
1407b5865babSDavid Sterba 
1408b882327aSDavid Sterba static const char *alloc_name(u64 flags)
1409b882327aSDavid Sterba {
1410b882327aSDavid Sterba 	switch (flags) {
1411b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA:
1412b882327aSDavid Sterba 		return "mixed";
1413b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_METADATA:
1414b882327aSDavid Sterba 		return "metadata";
1415b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_DATA:
1416b882327aSDavid Sterba 		return "data";
1417b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_SYSTEM:
1418b882327aSDavid Sterba 		return "system";
1419b882327aSDavid Sterba 	default:
1420b882327aSDavid Sterba 		WARN_ON(1);
1421b882327aSDavid Sterba 		return "invalid-combination";
1422445d8ab5STom Rix 	}
1423b882327aSDavid Sterba }
1424b882327aSDavid Sterba 
1425b882327aSDavid Sterba /*
1426b882327aSDavid Sterba  * Create a sysfs entry for a space info type at path
1427b882327aSDavid Sterba  * /sys/fs/btrfs/UUID/allocation/TYPE
1428b882327aSDavid Sterba  */
1429b882327aSDavid Sterba int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info,
1430b882327aSDavid Sterba 				    struct btrfs_space_info *space_info)
1431b882327aSDavid Sterba {
1432b882327aSDavid Sterba 	int ret;
1433b882327aSDavid Sterba 
1434b882327aSDavid Sterba 	ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype,
1435b882327aSDavid Sterba 				   fs_info->space_info_kobj, "%s",
1436b882327aSDavid Sterba 				   alloc_name(space_info->flags));
1437b882327aSDavid Sterba 	if (ret) {
1438b882327aSDavid Sterba 		kobject_put(&space_info->kobj);
1439b882327aSDavid Sterba 		return ret;
1440b882327aSDavid Sterba 	}
1441b882327aSDavid Sterba 
1442b882327aSDavid Sterba 	return 0;
1443b882327aSDavid Sterba }
1444b882327aSDavid Sterba 
144553f8a74cSAnand Jain void btrfs_sysfs_remove_device(struct btrfs_device *device)
144699994cdeSAnand Jain {
1447985e233eSAnand Jain 	struct kobject *devices_kobj;
144899994cdeSAnand Jain 
1449985e233eSAnand Jain 	/*
1450985e233eSAnand Jain 	 * Seed fs_devices devices_kobj aren't used, fetch kobject from the
1451985e233eSAnand Jain 	 * fs_info::fs_devices.
1452985e233eSAnand Jain 	 */
1453985e233eSAnand Jain 	devices_kobj = device->fs_info->fs_devices->devices_kobj;
1454985e233eSAnand Jain 	ASSERT(devices_kobj);
145599994cdeSAnand Jain 
14568d65269fSChristoph Hellwig 	if (device->bdev)
14578d65269fSChristoph Hellwig 		sysfs_remove_link(devices_kobj, bdev_kobj(device->bdev)->name);
145899994cdeSAnand Jain 
1459985e233eSAnand Jain 	if (device->devid_kobj.state_initialized) {
1460985e233eSAnand Jain 		kobject_del(&device->devid_kobj);
1461985e233eSAnand Jain 		kobject_put(&device->devid_kobj);
1462985e233eSAnand Jain 		wait_for_completion(&device->kobj_unregister);
1463985e233eSAnand Jain 	}
1464b5ddcffaSAnand Jain }
1465668e48afSAnand Jain 
1466668e48afSAnand Jain static ssize_t btrfs_devinfo_in_fs_metadata_show(struct kobject *kobj,
1467668e48afSAnand Jain 					         struct kobj_attribute *a,
1468668e48afSAnand Jain 					         char *buf)
1469668e48afSAnand Jain {
1470668e48afSAnand Jain 	int val;
1471668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1472668e48afSAnand Jain 						   devid_kobj);
1473668e48afSAnand Jain 
1474668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
1475668e48afSAnand Jain 
1476020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1477668e48afSAnand Jain }
1478668e48afSAnand Jain BTRFS_ATTR(devid, in_fs_metadata, btrfs_devinfo_in_fs_metadata_show);
1479668e48afSAnand Jain 
148025864778SAnand Jain static ssize_t btrfs_devinfo_missing_show(struct kobject *kobj,
1481668e48afSAnand Jain 					struct kobj_attribute *a, char *buf)
1482668e48afSAnand Jain {
1483668e48afSAnand Jain 	int val;
1484668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1485668e48afSAnand Jain 						   devid_kobj);
1486668e48afSAnand Jain 
1487668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state);
1488668e48afSAnand Jain 
1489020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1490668e48afSAnand Jain }
149125864778SAnand Jain BTRFS_ATTR(devid, missing, btrfs_devinfo_missing_show);
1492668e48afSAnand Jain 
1493668e48afSAnand Jain static ssize_t btrfs_devinfo_replace_target_show(struct kobject *kobj,
1494668e48afSAnand Jain 					         struct kobj_attribute *a,
1495668e48afSAnand Jain 					         char *buf)
1496668e48afSAnand Jain {
1497668e48afSAnand Jain 	int val;
1498668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1499668e48afSAnand Jain 						   devid_kobj);
1500668e48afSAnand Jain 
1501668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state);
1502668e48afSAnand Jain 
1503020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1504668e48afSAnand Jain }
1505668e48afSAnand Jain BTRFS_ATTR(devid, replace_target, btrfs_devinfo_replace_target_show);
1506668e48afSAnand Jain 
1507eb3b5053SDavid Sterba static ssize_t btrfs_devinfo_scrub_speed_max_show(struct kobject *kobj,
1508eb3b5053SDavid Sterba 					     struct kobj_attribute *a,
1509eb3b5053SDavid Sterba 					     char *buf)
1510eb3b5053SDavid Sterba {
1511eb3b5053SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1512eb3b5053SDavid Sterba 						   devid_kobj);
1513eb3b5053SDavid Sterba 
1514020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", READ_ONCE(device->scrub_speed_max));
1515eb3b5053SDavid Sterba }
1516eb3b5053SDavid Sterba 
1517eb3b5053SDavid Sterba static ssize_t btrfs_devinfo_scrub_speed_max_store(struct kobject *kobj,
1518eb3b5053SDavid Sterba 					      struct kobj_attribute *a,
1519eb3b5053SDavid Sterba 					      const char *buf, size_t len)
1520eb3b5053SDavid Sterba {
1521eb3b5053SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1522eb3b5053SDavid Sterba 						   devid_kobj);
1523eb3b5053SDavid Sterba 	char *endptr;
1524eb3b5053SDavid Sterba 	unsigned long long limit;
1525eb3b5053SDavid Sterba 
1526eb3b5053SDavid Sterba 	limit = memparse(buf, &endptr);
1527eb3b5053SDavid Sterba 	WRITE_ONCE(device->scrub_speed_max, limit);
1528eb3b5053SDavid Sterba 	return len;
1529eb3b5053SDavid Sterba }
1530eb3b5053SDavid Sterba BTRFS_ATTR_RW(devid, scrub_speed_max, btrfs_devinfo_scrub_speed_max_show,
1531eb3b5053SDavid Sterba 	      btrfs_devinfo_scrub_speed_max_store);
1532eb3b5053SDavid Sterba 
1533668e48afSAnand Jain static ssize_t btrfs_devinfo_writeable_show(struct kobject *kobj,
1534668e48afSAnand Jain 					    struct kobj_attribute *a, char *buf)
1535668e48afSAnand Jain {
1536668e48afSAnand Jain 	int val;
1537668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1538668e48afSAnand Jain 						   devid_kobj);
1539668e48afSAnand Jain 
1540668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
1541668e48afSAnand Jain 
1542020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1543668e48afSAnand Jain }
1544668e48afSAnand Jain BTRFS_ATTR(devid, writeable, btrfs_devinfo_writeable_show);
1545668e48afSAnand Jain 
1546a26d60deSAnand Jain static ssize_t btrfs_devinfo_fsid_show(struct kobject *kobj,
1547a26d60deSAnand Jain 				       struct kobj_attribute *a, char *buf)
1548a26d60deSAnand Jain {
1549a26d60deSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1550a26d60deSAnand Jain 						   devid_kobj);
1551a26d60deSAnand Jain 
1552a26d60deSAnand Jain 	return sysfs_emit(buf, "%pU\n", device->fs_devices->fsid);
1553a26d60deSAnand Jain }
1554a26d60deSAnand Jain BTRFS_ATTR(devid, fsid, btrfs_devinfo_fsid_show);
1555a26d60deSAnand Jain 
1556da658b57SDavid Sterba static ssize_t btrfs_devinfo_error_stats_show(struct kobject *kobj,
1557da658b57SDavid Sterba 		struct kobj_attribute *a, char *buf)
1558da658b57SDavid Sterba {
1559da658b57SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1560da658b57SDavid Sterba 						   devid_kobj);
1561da658b57SDavid Sterba 
1562da658b57SDavid Sterba 	if (!device->dev_stats_valid)
1563020e5277SAnand Jain 		return sysfs_emit(buf, "invalid\n");
1564da658b57SDavid Sterba 
1565da658b57SDavid Sterba 	/*
1566da658b57SDavid Sterba 	 * Print all at once so we get a snapshot of all values from the same
1567da658b57SDavid Sterba 	 * time. Keep them in sync and in order of definition of
1568da658b57SDavid Sterba 	 * btrfs_dev_stat_values.
1569da658b57SDavid Sterba 	 */
1570020e5277SAnand Jain 	return sysfs_emit(buf,
1571da658b57SDavid Sterba 		"write_errs %d\n"
1572da658b57SDavid Sterba 		"read_errs %d\n"
1573da658b57SDavid Sterba 		"flush_errs %d\n"
1574da658b57SDavid Sterba 		"corruption_errs %d\n"
1575da658b57SDavid Sterba 		"generation_errs %d\n",
1576da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_WRITE_ERRS),
1577da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_READ_ERRS),
1578da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_FLUSH_ERRS),
1579da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_CORRUPTION_ERRS),
1580da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_GENERATION_ERRS));
1581da658b57SDavid Sterba }
1582da658b57SDavid Sterba BTRFS_ATTR(devid, error_stats, btrfs_devinfo_error_stats_show);
1583da658b57SDavid Sterba 
1584e7849e33SAnand Jain /*
1585e7849e33SAnand Jain  * Information about one device.
1586e7849e33SAnand Jain  *
1587e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/devinfo/<devid>/
1588e7849e33SAnand Jain  */
1589668e48afSAnand Jain static struct attribute *devid_attrs[] = {
1590da658b57SDavid Sterba 	BTRFS_ATTR_PTR(devid, error_stats),
1591a26d60deSAnand Jain 	BTRFS_ATTR_PTR(devid, fsid),
1592668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, in_fs_metadata),
1593668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, missing),
1594668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, replace_target),
1595eb3b5053SDavid Sterba 	BTRFS_ATTR_PTR(devid, scrub_speed_max),
1596668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, writeable),
1597668e48afSAnand Jain 	NULL
1598668e48afSAnand Jain };
1599668e48afSAnand Jain ATTRIBUTE_GROUPS(devid);
1600668e48afSAnand Jain 
1601668e48afSAnand Jain static void btrfs_release_devid_kobj(struct kobject *kobj)
1602668e48afSAnand Jain {
1603668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1604668e48afSAnand Jain 						   devid_kobj);
1605668e48afSAnand Jain 
1606668e48afSAnand Jain 	memset(&device->devid_kobj, 0, sizeof(struct kobject));
1607668e48afSAnand Jain 	complete(&device->kobj_unregister);
1608668e48afSAnand Jain }
1609668e48afSAnand Jain 
1610668e48afSAnand Jain static struct kobj_type devid_ktype = {
1611668e48afSAnand Jain 	.sysfs_ops	= &kobj_sysfs_ops,
1612668e48afSAnand Jain 	.default_groups = devid_groups,
1613668e48afSAnand Jain 	.release	= btrfs_release_devid_kobj,
1614668e48afSAnand Jain };
1615668e48afSAnand Jain 
1616cd36da2eSAnand Jain int btrfs_sysfs_add_device(struct btrfs_device *device)
161729e5be24SJeff Mahoney {
1618178a16c9SAnand Jain 	int ret;
1619a47bd78dSJosef Bacik 	unsigned int nofs_flag;
1620178a16c9SAnand Jain 	struct kobject *devices_kobj;
1621178a16c9SAnand Jain 	struct kobject *devinfo_kobj;
1622178a16c9SAnand Jain 
1623178a16c9SAnand Jain 	/*
1624178a16c9SAnand Jain 	 * Make sure we use the fs_info::fs_devices to fetch the kobjects even
1625178a16c9SAnand Jain 	 * for the seed fs_devices
1626178a16c9SAnand Jain 	 */
1627178a16c9SAnand Jain 	devices_kobj = device->fs_info->fs_devices->devices_kobj;
1628178a16c9SAnand Jain 	devinfo_kobj = device->fs_info->fs_devices->devinfo_kobj;
1629178a16c9SAnand Jain 	ASSERT(devices_kobj);
1630178a16c9SAnand Jain 	ASSERT(devinfo_kobj);
163129e5be24SJeff Mahoney 
1632a47bd78dSJosef Bacik 	nofs_flag = memalloc_nofs_save();
1633f085381eSAnand Jain 
1634178a16c9SAnand Jain 	if (device->bdev) {
16358d65269fSChristoph Hellwig 		struct kobject *disk_kobj = bdev_kobj(device->bdev);
163629e5be24SJeff Mahoney 
1637178a16c9SAnand Jain 		ret = sysfs_create_link(devices_kobj, disk_kobj, disk_kobj->name);
1638178a16c9SAnand Jain 		if (ret) {
1639178a16c9SAnand Jain 			btrfs_warn(device->fs_info,
1640178a16c9SAnand Jain 				"creating sysfs device link for devid %llu failed: %d",
1641178a16c9SAnand Jain 				device->devid, ret);
1642178a16c9SAnand Jain 			goto out;
1643178a16c9SAnand Jain 		}
164429e5be24SJeff Mahoney 	}
164529e5be24SJeff Mahoney 
1646178a16c9SAnand Jain 	init_completion(&device->kobj_unregister);
1647178a16c9SAnand Jain 	ret = kobject_init_and_add(&device->devid_kobj, &devid_ktype,
1648178a16c9SAnand Jain 				   devinfo_kobj, "%llu", device->devid);
1649178a16c9SAnand Jain 	if (ret) {
1650178a16c9SAnand Jain 		kobject_put(&device->devid_kobj);
1651178a16c9SAnand Jain 		btrfs_warn(device->fs_info,
1652178a16c9SAnand Jain 			   "devinfo init for devid %llu failed: %d",
1653178a16c9SAnand Jain 			   device->devid, ret);
1654668e48afSAnand Jain 	}
1655178a16c9SAnand Jain 
1656178a16c9SAnand Jain out:
1657a47bd78dSJosef Bacik 	memalloc_nofs_restore(nofs_flag);
1658178a16c9SAnand Jain 	return ret;
1659178a16c9SAnand Jain }
1660668e48afSAnand Jain 
1661cd36da2eSAnand Jain static int btrfs_sysfs_add_fs_devices(struct btrfs_fs_devices *fs_devices)
1662178a16c9SAnand Jain {
1663178a16c9SAnand Jain 	int ret;
1664cd36da2eSAnand Jain 	struct btrfs_device *device;
166530b0e4e0SAnand Jain 	struct btrfs_fs_devices *seed;
1666178a16c9SAnand Jain 
1667178a16c9SAnand Jain 	list_for_each_entry(device, &fs_devices->devices, dev_list) {
1668178a16c9SAnand Jain 		ret = btrfs_sysfs_add_device(device);
1669178a16c9SAnand Jain 		if (ret)
16707ad3912aSAnand Jain 			goto fail;
1671178a16c9SAnand Jain 	}
1672178a16c9SAnand Jain 
167330b0e4e0SAnand Jain 	list_for_each_entry(seed, &fs_devices->seed_list, seed_list) {
167430b0e4e0SAnand Jain 		list_for_each_entry(device, &seed->devices, dev_list) {
167530b0e4e0SAnand Jain 			ret = btrfs_sysfs_add_device(device);
167630b0e4e0SAnand Jain 			if (ret)
16777ad3912aSAnand Jain 				goto fail;
167830b0e4e0SAnand Jain 		}
167930b0e4e0SAnand Jain 	}
168030b0e4e0SAnand Jain 
1681178a16c9SAnand Jain 	return 0;
16827ad3912aSAnand Jain 
16837ad3912aSAnand Jain fail:
16847ad3912aSAnand Jain 	btrfs_sysfs_remove_fs_devices(fs_devices);
16857ad3912aSAnand Jain 	return ret;
168629e5be24SJeff Mahoney }
168729e5be24SJeff Mahoney 
16885b28692eSDavid Sterba void btrfs_kobject_uevent(struct block_device *bdev, enum kobject_action action)
16895b28692eSDavid Sterba {
16905b28692eSDavid Sterba 	int ret;
16915b28692eSDavid Sterba 
16925b28692eSDavid Sterba 	ret = kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, action);
16935b28692eSDavid Sterba 	if (ret)
16945b28692eSDavid Sterba 		pr_warn("BTRFS: Sending event '%d' to kobject: '%s' (%p): failed\n",
16955b28692eSDavid Sterba 			action, kobject_name(&disk_to_dev(bdev->bd_disk)->kobj),
16965b28692eSDavid Sterba 			&disk_to_dev(bdev->bd_disk)->kobj);
16975b28692eSDavid Sterba }
16985b28692eSDavid Sterba 
16998e560081SNikolay Borisov void btrfs_sysfs_update_sprout_fsid(struct btrfs_fs_devices *fs_devices)
17008e560081SNikolay Borisov 
1701f93c3997SDavid Sterba {
1702f93c3997SDavid Sterba 	char fsid_buf[BTRFS_UUID_UNPARSED_SIZE];
1703f93c3997SDavid Sterba 
1704f93c3997SDavid Sterba 	/*
1705f93c3997SDavid Sterba 	 * Sprouting changes fsid of the mounted filesystem, rename the fsid
1706f93c3997SDavid Sterba 	 * directory
1707f93c3997SDavid Sterba 	 */
17088e560081SNikolay Borisov 	snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU", fs_devices->fsid);
1709f93c3997SDavid Sterba 	if (kobject_rename(&fs_devices->fsid_kobj, fsid_buf))
1710f93c3997SDavid Sterba 		btrfs_warn(fs_devices->fs_info,
1711f93c3997SDavid Sterba 				"sysfs: failed to create fsid for sprout");
1712f93c3997SDavid Sterba }
1713f93c3997SDavid Sterba 
1714668e48afSAnand Jain void btrfs_sysfs_update_devid(struct btrfs_device *device)
1715668e48afSAnand Jain {
1716668e48afSAnand Jain 	char tmp[24];
1717668e48afSAnand Jain 
1718668e48afSAnand Jain 	snprintf(tmp, sizeof(tmp), "%llu", device->devid);
1719668e48afSAnand Jain 
1720668e48afSAnand Jain 	if (kobject_rename(&device->devid_kobj, tmp))
1721668e48afSAnand Jain 		btrfs_warn(device->fs_devices->fs_info,
1722668e48afSAnand Jain 			   "sysfs: failed to update devid for %llu",
1723668e48afSAnand Jain 			   device->devid);
1724668e48afSAnand Jain }
1725668e48afSAnand Jain 
1726510d7360SJeff Mahoney /* /sys/fs/btrfs/ entry */
1727510d7360SJeff Mahoney static struct kset *btrfs_kset;
1728510d7360SJeff Mahoney 
172972059215SAnand Jain /*
1730c6761a9eSAnand Jain  * Creates:
1731c6761a9eSAnand Jain  *		/sys/fs/btrfs/UUID
1732c6761a9eSAnand Jain  *
173372059215SAnand Jain  * Can be called by the device discovery thread.
173472059215SAnand Jain  */
1735c6761a9eSAnand Jain int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs)
17365ac1d209SJeff Mahoney {
17375ac1d209SJeff Mahoney 	int error;
17385ac1d209SJeff Mahoney 
17392e7910d6SAnand Jain 	init_completion(&fs_devs->kobj_unregister);
1740c1b7e474SAnand Jain 	fs_devs->fsid_kobj.kset = btrfs_kset;
1741c6761a9eSAnand Jain 	error = kobject_init_and_add(&fs_devs->fsid_kobj, &btrfs_ktype, NULL,
1742c6761a9eSAnand Jain 				     "%pU", fs_devs->fsid);
1743e3277335STobin C. Harding 	if (error) {
1744e3277335STobin C. Harding 		kobject_put(&fs_devs->fsid_kobj);
174572059215SAnand Jain 		return error;
174672059215SAnand Jain 	}
174772059215SAnand Jain 
1748bc036bb3SAnand Jain 	fs_devs->devices_kobj = kobject_create_and_add("devices",
1749bc036bb3SAnand Jain 						       &fs_devs->fsid_kobj);
1750bc036bb3SAnand Jain 	if (!fs_devs->devices_kobj) {
1751bc036bb3SAnand Jain 		btrfs_err(fs_devs->fs_info,
1752bc036bb3SAnand Jain 			  "failed to init sysfs device interface");
17531f6087e6SAnand Jain 		btrfs_sysfs_remove_fsid(fs_devs);
1754bc036bb3SAnand Jain 		return -ENOMEM;
1755bc036bb3SAnand Jain 	}
1756bc036bb3SAnand Jain 
1757a013d141SAnand Jain 	fs_devs->devinfo_kobj = kobject_create_and_add("devinfo",
1758a013d141SAnand Jain 						       &fs_devs->fsid_kobj);
1759a013d141SAnand Jain 	if (!fs_devs->devinfo_kobj) {
1760a013d141SAnand Jain 		btrfs_err(fs_devs->fs_info,
1761a013d141SAnand Jain 			  "failed to init sysfs devinfo kobject");
1762a013d141SAnand Jain 		btrfs_sysfs_remove_fsid(fs_devs);
1763a013d141SAnand Jain 		return -ENOMEM;
1764a013d141SAnand Jain 	}
1765a013d141SAnand Jain 
1766e3277335STobin C. Harding 	return 0;
1767e3277335STobin C. Harding }
1768e3277335STobin C. Harding 
176996f3136eSAnand Jain int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info)
177072059215SAnand Jain {
177172059215SAnand Jain 	int error;
17722e7910d6SAnand Jain 	struct btrfs_fs_devices *fs_devs = fs_info->fs_devices;
1773c1b7e474SAnand Jain 	struct kobject *fsid_kobj = &fs_devs->fsid_kobj;
177472059215SAnand Jain 
1775cd36da2eSAnand Jain 	error = btrfs_sysfs_add_fs_devices(fs_devs);
1776e453d989SJeff Mahoney 	if (error)
1777e453d989SJeff Mahoney 		return error;
1778510d7360SJeff Mahoney 
1779c1b7e474SAnand Jain 	error = sysfs_create_files(fsid_kobj, btrfs_attrs);
1780e453d989SJeff Mahoney 	if (error) {
178153f8a74cSAnand Jain 		btrfs_sysfs_remove_fs_devices(fs_devs);
1782e453d989SJeff Mahoney 		return error;
1783e453d989SJeff Mahoney 	}
178479da4fa4SJeff Mahoney 
1785c1b7e474SAnand Jain 	error = sysfs_create_group(fsid_kobj,
17860dd2906fSAnand Jain 				   &btrfs_feature_attr_group);
17870dd2906fSAnand Jain 	if (error)
17880dd2906fSAnand Jain 		goto failure;
17890dd2906fSAnand Jain 
17906e369febSDavid Sterba #ifdef CONFIG_BTRFS_DEBUG
179193945cb4SDennis Zhou 	fs_info->debug_kobj = kobject_create_and_add("debug", fsid_kobj);
179293945cb4SDennis Zhou 	if (!fs_info->debug_kobj) {
179393945cb4SDennis Zhou 		error = -ENOMEM;
179493945cb4SDennis Zhou 		goto failure;
179593945cb4SDennis Zhou 	}
179693945cb4SDennis Zhou 
179793945cb4SDennis Zhou 	error = sysfs_create_files(fs_info->debug_kobj, btrfs_debug_mount_attrs);
17986e369febSDavid Sterba 	if (error)
17996e369febSDavid Sterba 		goto failure;
1800e4faab84SDennis Zhou 
1801e4faab84SDennis Zhou 	/* Discard directory */
1802e4faab84SDennis Zhou 	fs_info->discard_debug_kobj = kobject_create_and_add("discard",
1803e4faab84SDennis Zhou 						     fs_info->debug_kobj);
1804e4faab84SDennis Zhou 	if (!fs_info->discard_debug_kobj) {
1805e4faab84SDennis Zhou 		error = -ENOMEM;
1806e4faab84SDennis Zhou 		goto failure;
1807e4faab84SDennis Zhou 	}
1808e4faab84SDennis Zhou 
1809e4faab84SDennis Zhou 	error = sysfs_create_files(fs_info->discard_debug_kobj,
1810e4faab84SDennis Zhou 				   discard_debug_attrs);
1811e4faab84SDennis Zhou 	if (error)
1812e4faab84SDennis Zhou 		goto failure;
18136e369febSDavid Sterba #endif
18146e369febSDavid Sterba 
1815e453d989SJeff Mahoney 	error = addrm_unknown_feature_attrs(fs_info, true);
181679da4fa4SJeff Mahoney 	if (error)
181779da4fa4SJeff Mahoney 		goto failure;
181879da4fa4SJeff Mahoney 
18193092c68fSNikolay Borisov 	error = sysfs_create_link(fsid_kobj, &fs_info->sb->s_bdi->dev->kobj, "bdi");
18203092c68fSNikolay Borisov 	if (error)
18213092c68fSNikolay Borisov 		goto failure;
18223092c68fSNikolay Borisov 
18236ab0a202SJeff Mahoney 	fs_info->space_info_kobj = kobject_create_and_add("allocation",
1824c1b7e474SAnand Jain 						  fsid_kobj);
18256ab0a202SJeff Mahoney 	if (!fs_info->space_info_kobj) {
18266ab0a202SJeff Mahoney 		error = -ENOMEM;
18276ab0a202SJeff Mahoney 		goto failure;
18286ab0a202SJeff Mahoney 	}
18296ab0a202SJeff Mahoney 
18306ab0a202SJeff Mahoney 	error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs);
18316ab0a202SJeff Mahoney 	if (error)
18326ab0a202SJeff Mahoney 		goto failure;
18336ab0a202SJeff Mahoney 
183479da4fa4SJeff Mahoney 	return 0;
183579da4fa4SJeff Mahoney failure:
18366618a59bSAnand Jain 	btrfs_sysfs_remove_mounted(fs_info);
18375ac1d209SJeff Mahoney 	return error;
18385ac1d209SJeff Mahoney }
18395ac1d209SJeff Mahoney 
184049e5fb46SQu Wenruo static inline struct btrfs_fs_info *qgroup_kobj_to_fs_info(struct kobject *kobj)
184149e5fb46SQu Wenruo {
184249e5fb46SQu Wenruo 	return to_fs_info(kobj->parent->parent);
184349e5fb46SQu Wenruo }
184449e5fb46SQu Wenruo 
184549e5fb46SQu Wenruo #define QGROUP_ATTR(_member, _show_name)					\
184649e5fb46SQu Wenruo static ssize_t btrfs_qgroup_show_##_member(struct kobject *qgroup_kobj,		\
184749e5fb46SQu Wenruo 					   struct kobj_attribute *a,		\
184849e5fb46SQu Wenruo 					   char *buf)				\
184949e5fb46SQu Wenruo {										\
185049e5fb46SQu Wenruo 	struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj);	\
185149e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(qgroup_kobj,			\
185249e5fb46SQu Wenruo 			struct btrfs_qgroup, kobj);				\
185349e5fb46SQu Wenruo 	return btrfs_show_u64(&qgroup->_member, &fs_info->qgroup_lock, buf);	\
185449e5fb46SQu Wenruo }										\
185549e5fb46SQu Wenruo BTRFS_ATTR(qgroup, _show_name, btrfs_qgroup_show_##_member)
185649e5fb46SQu Wenruo 
185749e5fb46SQu Wenruo #define QGROUP_RSV_ATTR(_name, _type)						\
185849e5fb46SQu Wenruo static ssize_t btrfs_qgroup_rsv_show_##_name(struct kobject *qgroup_kobj,	\
185949e5fb46SQu Wenruo 					     struct kobj_attribute *a,		\
186049e5fb46SQu Wenruo 					     char *buf)				\
186149e5fb46SQu Wenruo {										\
186249e5fb46SQu Wenruo 	struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj);	\
186349e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(qgroup_kobj,			\
186449e5fb46SQu Wenruo 			struct btrfs_qgroup, kobj);				\
186549e5fb46SQu Wenruo 	return btrfs_show_u64(&qgroup->rsv.values[_type],			\
186649e5fb46SQu Wenruo 			&fs_info->qgroup_lock, buf);				\
186749e5fb46SQu Wenruo }										\
186849e5fb46SQu Wenruo BTRFS_ATTR(qgroup, rsv_##_name, btrfs_qgroup_rsv_show_##_name)
186949e5fb46SQu Wenruo 
187049e5fb46SQu Wenruo QGROUP_ATTR(rfer, referenced);
187149e5fb46SQu Wenruo QGROUP_ATTR(excl, exclusive);
187249e5fb46SQu Wenruo QGROUP_ATTR(max_rfer, max_referenced);
187349e5fb46SQu Wenruo QGROUP_ATTR(max_excl, max_exclusive);
187449e5fb46SQu Wenruo QGROUP_ATTR(lim_flags, limit_flags);
187549e5fb46SQu Wenruo QGROUP_RSV_ATTR(data, BTRFS_QGROUP_RSV_DATA);
187649e5fb46SQu Wenruo QGROUP_RSV_ATTR(meta_pertrans, BTRFS_QGROUP_RSV_META_PERTRANS);
187749e5fb46SQu Wenruo QGROUP_RSV_ATTR(meta_prealloc, BTRFS_QGROUP_RSV_META_PREALLOC);
187849e5fb46SQu Wenruo 
1879e7849e33SAnand Jain /*
1880e7849e33SAnand Jain  * Qgroup information.
1881e7849e33SAnand Jain  *
1882e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/qgroups/<level>_<qgroupid>/
1883e7849e33SAnand Jain  */
188449e5fb46SQu Wenruo static struct attribute *qgroup_attrs[] = {
188549e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, referenced),
188649e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, exclusive),
188749e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, max_referenced),
188849e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, max_exclusive),
188949e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, limit_flags),
189049e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_data),
189149e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_meta_pertrans),
189249e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_meta_prealloc),
189349e5fb46SQu Wenruo 	NULL
189449e5fb46SQu Wenruo };
189549e5fb46SQu Wenruo ATTRIBUTE_GROUPS(qgroup);
189649e5fb46SQu Wenruo 
189749e5fb46SQu Wenruo static void qgroup_release(struct kobject *kobj)
189849e5fb46SQu Wenruo {
189949e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(kobj, struct btrfs_qgroup, kobj);
190049e5fb46SQu Wenruo 
190149e5fb46SQu Wenruo 	memset(&qgroup->kobj, 0, sizeof(*kobj));
190249e5fb46SQu Wenruo }
190349e5fb46SQu Wenruo 
190449e5fb46SQu Wenruo static struct kobj_type qgroup_ktype = {
190549e5fb46SQu Wenruo 	.sysfs_ops = &kobj_sysfs_ops,
190649e5fb46SQu Wenruo 	.release = qgroup_release,
190749e5fb46SQu Wenruo 	.default_groups = qgroup_groups,
190849e5fb46SQu Wenruo };
190949e5fb46SQu Wenruo 
191049e5fb46SQu Wenruo int btrfs_sysfs_add_one_qgroup(struct btrfs_fs_info *fs_info,
191149e5fb46SQu Wenruo 				struct btrfs_qgroup *qgroup)
191249e5fb46SQu Wenruo {
191349e5fb46SQu Wenruo 	struct kobject *qgroups_kobj = fs_info->qgroups_kobj;
191449e5fb46SQu Wenruo 	int ret;
191549e5fb46SQu Wenruo 
191649e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
191749e5fb46SQu Wenruo 		return 0;
191849e5fb46SQu Wenruo 	if (qgroup->kobj.state_initialized)
191949e5fb46SQu Wenruo 		return 0;
192049e5fb46SQu Wenruo 	if (!qgroups_kobj)
192149e5fb46SQu Wenruo 		return -EINVAL;
192249e5fb46SQu Wenruo 
192349e5fb46SQu Wenruo 	ret = kobject_init_and_add(&qgroup->kobj, &qgroup_ktype, qgroups_kobj,
192449e5fb46SQu Wenruo 			"%hu_%llu", btrfs_qgroup_level(qgroup->qgroupid),
192549e5fb46SQu Wenruo 			btrfs_qgroup_subvolid(qgroup->qgroupid));
192649e5fb46SQu Wenruo 	if (ret < 0)
192749e5fb46SQu Wenruo 		kobject_put(&qgroup->kobj);
192849e5fb46SQu Wenruo 
192949e5fb46SQu Wenruo 	return ret;
193049e5fb46SQu Wenruo }
193149e5fb46SQu Wenruo 
193249e5fb46SQu Wenruo void btrfs_sysfs_del_qgroups(struct btrfs_fs_info *fs_info)
193349e5fb46SQu Wenruo {
193449e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup;
193549e5fb46SQu Wenruo 	struct btrfs_qgroup *next;
193649e5fb46SQu Wenruo 
193749e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
193849e5fb46SQu Wenruo 		return;
193949e5fb46SQu Wenruo 
194049e5fb46SQu Wenruo 	rbtree_postorder_for_each_entry_safe(qgroup, next,
194149e5fb46SQu Wenruo 					     &fs_info->qgroup_tree, node)
194249e5fb46SQu Wenruo 		btrfs_sysfs_del_one_qgroup(fs_info, qgroup);
194362ab2cc0SQu Wenruo 	if (fs_info->qgroups_kobj) {
194449e5fb46SQu Wenruo 		kobject_del(fs_info->qgroups_kobj);
194549e5fb46SQu Wenruo 		kobject_put(fs_info->qgroups_kobj);
194649e5fb46SQu Wenruo 		fs_info->qgroups_kobj = NULL;
194749e5fb46SQu Wenruo 	}
194862ab2cc0SQu Wenruo }
194949e5fb46SQu Wenruo 
195049e5fb46SQu Wenruo /* Called when qgroups get initialized, thus there is no need for locking */
195149e5fb46SQu Wenruo int btrfs_sysfs_add_qgroups(struct btrfs_fs_info *fs_info)
195249e5fb46SQu Wenruo {
195349e5fb46SQu Wenruo 	struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj;
195449e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup;
195549e5fb46SQu Wenruo 	struct btrfs_qgroup *next;
195649e5fb46SQu Wenruo 	int ret = 0;
195749e5fb46SQu Wenruo 
195849e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
195949e5fb46SQu Wenruo 		return 0;
196049e5fb46SQu Wenruo 
196149e5fb46SQu Wenruo 	ASSERT(fsid_kobj);
196249e5fb46SQu Wenruo 	if (fs_info->qgroups_kobj)
196349e5fb46SQu Wenruo 		return 0;
196449e5fb46SQu Wenruo 
196549e5fb46SQu Wenruo 	fs_info->qgroups_kobj = kobject_create_and_add("qgroups", fsid_kobj);
196649e5fb46SQu Wenruo 	if (!fs_info->qgroups_kobj) {
196749e5fb46SQu Wenruo 		ret = -ENOMEM;
196849e5fb46SQu Wenruo 		goto out;
196949e5fb46SQu Wenruo 	}
197049e5fb46SQu Wenruo 	rbtree_postorder_for_each_entry_safe(qgroup, next,
197149e5fb46SQu Wenruo 					     &fs_info->qgroup_tree, node) {
197249e5fb46SQu Wenruo 		ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
197349e5fb46SQu Wenruo 		if (ret < 0)
197449e5fb46SQu Wenruo 			goto out;
197549e5fb46SQu Wenruo 	}
197649e5fb46SQu Wenruo 
197749e5fb46SQu Wenruo out:
197849e5fb46SQu Wenruo 	if (ret < 0)
197949e5fb46SQu Wenruo 		btrfs_sysfs_del_qgroups(fs_info);
198049e5fb46SQu Wenruo 	return ret;
198149e5fb46SQu Wenruo }
198249e5fb46SQu Wenruo 
198349e5fb46SQu Wenruo void btrfs_sysfs_del_one_qgroup(struct btrfs_fs_info *fs_info,
198449e5fb46SQu Wenruo 				struct btrfs_qgroup *qgroup)
198549e5fb46SQu Wenruo {
198649e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
198749e5fb46SQu Wenruo 		return;
198849e5fb46SQu Wenruo 
198949e5fb46SQu Wenruo 	if (qgroup->kobj.state_initialized) {
199049e5fb46SQu Wenruo 		kobject_del(&qgroup->kobj);
199149e5fb46SQu Wenruo 		kobject_put(&qgroup->kobj);
199249e5fb46SQu Wenruo 	}
199349e5fb46SQu Wenruo }
1994444e7516SDavid Sterba 
1995444e7516SDavid Sterba /*
1996444e7516SDavid Sterba  * Change per-fs features in /sys/fs/btrfs/UUID/features to match current
1997444e7516SDavid Sterba  * values in superblock. Call after any changes to incompat/compat_ro flags
1998444e7516SDavid Sterba  */
1999444e7516SDavid Sterba void btrfs_sysfs_feature_update(struct btrfs_fs_info *fs_info,
2000444e7516SDavid Sterba 		u64 bit, enum btrfs_feature_set set)
2001444e7516SDavid Sterba {
2002444e7516SDavid Sterba 	struct btrfs_fs_devices *fs_devs;
2003444e7516SDavid Sterba 	struct kobject *fsid_kobj;
200424646481SLeon Romanovsky 	u64 __maybe_unused features;
200524646481SLeon Romanovsky 	int __maybe_unused ret;
2006444e7516SDavid Sterba 
2007444e7516SDavid Sterba 	if (!fs_info)
2008444e7516SDavid Sterba 		return;
2009444e7516SDavid Sterba 
201024646481SLeon Romanovsky 	/*
201124646481SLeon Romanovsky 	 * See 14e46e04958df74 and e410e34fad913dd, feature bit updates are not
201224646481SLeon Romanovsky 	 * safe when called from some contexts (eg. balance)
201324646481SLeon Romanovsky 	 */
2014444e7516SDavid Sterba 	features = get_features(fs_info, set);
2015444e7516SDavid Sterba 	ASSERT(bit & supported_feature_masks[set]);
2016444e7516SDavid Sterba 
2017444e7516SDavid Sterba 	fs_devs = fs_info->fs_devices;
2018444e7516SDavid Sterba 	fsid_kobj = &fs_devs->fsid_kobj;
2019444e7516SDavid Sterba 
2020bf609206SDavid Sterba 	if (!fsid_kobj->state_initialized)
2021bf609206SDavid Sterba 		return;
2022bf609206SDavid Sterba 
2023444e7516SDavid Sterba 	/*
2024444e7516SDavid Sterba 	 * FIXME: this is too heavy to update just one value, ideally we'd like
2025444e7516SDavid Sterba 	 * to use sysfs_update_group but some refactoring is needed first.
2026444e7516SDavid Sterba 	 */
2027444e7516SDavid Sterba 	sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group);
2028444e7516SDavid Sterba 	ret = sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group);
2029444e7516SDavid Sterba }
2030444e7516SDavid Sterba 
2031f5c29bd9SLiu Bo int __init btrfs_init_sysfs(void)
203258176a96SJosef Bacik {
2033079b72bcSJeff Mahoney 	int ret;
20341bae3098SDavid Sterba 
2035e3fe4e71SGreg KH 	btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
2036e3fe4e71SGreg KH 	if (!btrfs_kset)
2037e3fe4e71SGreg KH 		return -ENOMEM;
2038079b72bcSJeff Mahoney 
20391bae3098SDavid Sterba 	init_feature_attrs();
20401bae3098SDavid Sterba 	ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
2041001a648dSFilipe Manana 	if (ret)
2042001a648dSFilipe Manana 		goto out2;
2043f902bd3aSMisono Tomohiro 	ret = sysfs_merge_group(&btrfs_kset->kobj,
2044f902bd3aSMisono Tomohiro 				&btrfs_static_feature_attr_group);
2045f902bd3aSMisono Tomohiro 	if (ret)
2046f902bd3aSMisono Tomohiro 		goto out_remove_group;
2047001a648dSFilipe Manana 
20486e369febSDavid Sterba #ifdef CONFIG_BTRFS_DEBUG
20496e369febSDavid Sterba 	ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group);
20506e369febSDavid Sterba 	if (ret)
20516e369febSDavid Sterba 		goto out2;
20526e369febSDavid Sterba #endif
20536e369febSDavid Sterba 
2054001a648dSFilipe Manana 	return 0;
2055f902bd3aSMisono Tomohiro 
2056f902bd3aSMisono Tomohiro out_remove_group:
2057f902bd3aSMisono Tomohiro 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
2058001a648dSFilipe Manana out2:
2059001a648dSFilipe Manana 	kset_unregister(btrfs_kset);
20601bae3098SDavid Sterba 
20611bae3098SDavid Sterba 	return ret;
206258176a96SJosef Bacik }
206358176a96SJosef Bacik 
2064e67c718bSDavid Sterba void __cold btrfs_exit_sysfs(void)
206558176a96SJosef Bacik {
2066f902bd3aSMisono Tomohiro 	sysfs_unmerge_group(&btrfs_kset->kobj,
2067f902bd3aSMisono Tomohiro 			    &btrfs_static_feature_attr_group);
2068079b72bcSJeff Mahoney 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
206971e8978eSDennis Zhou #ifdef CONFIG_BTRFS_DEBUG
207071e8978eSDennis Zhou 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group);
207171e8978eSDennis Zhou #endif
2072e3fe4e71SGreg KH 	kset_unregister(btrfs_kset);
207358176a96SJosef Bacik }
207455d47414SChris Mason 
2075