xref: /openbmc/linux/fs/btrfs/sysfs.c (revision 2c7d2a23)
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
287*2c7d2a23SJosef Bacik /* Remove once support for zoned allocation is feature complete */
2887b3d5a90SNaohiro Aota BTRFS_FEAT_ATTR_INCOMPAT(zoned, ZONED);
289*2c7d2a23SJosef Bacik /* Remove once support for extent tree v2 is feature complete */
290*2c7d2a23SJosef 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),
319*2c7d2a23SJosef 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;
92566a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_ADD:
92666a2823cSGoldwyn Rodrigues 			str = "device add\n";
92766a2823cSGoldwyn Rodrigues 			break;
92866a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_REMOVE:
92966a2823cSGoldwyn Rodrigues 			str = "device remove\n";
93066a2823cSGoldwyn Rodrigues 			break;
93166a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_REPLACE:
93266a2823cSGoldwyn Rodrigues 			str = "device replace\n";
93366a2823cSGoldwyn Rodrigues 			break;
93466a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_RESIZE:
93566a2823cSGoldwyn Rodrigues 			str = "resize\n";
93666a2823cSGoldwyn Rodrigues 			break;
93766a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_SWAP_ACTIVATE:
93866a2823cSGoldwyn Rodrigues 			str = "swap activate\n";
93966a2823cSGoldwyn Rodrigues 			break;
94066a2823cSGoldwyn Rodrigues 		default:
94166a2823cSGoldwyn Rodrigues 			str = "UNKNOWN\n";
94266a2823cSGoldwyn Rodrigues 			break;
94366a2823cSGoldwyn Rodrigues 	}
944020e5277SAnand Jain 	return sysfs_emit(buf, "%s", str);
94566a2823cSGoldwyn Rodrigues }
94666a2823cSGoldwyn Rodrigues BTRFS_ATTR(, exclusive_operation, btrfs_exclusive_operation_show);
94766a2823cSGoldwyn Rodrigues 
948089c8b05SAnand Jain static ssize_t btrfs_generation_show(struct kobject *kobj,
949089c8b05SAnand Jain 				     struct kobj_attribute *a, char *buf)
950089c8b05SAnand Jain {
951089c8b05SAnand Jain 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
952089c8b05SAnand Jain 
953020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", fs_info->generation);
954089c8b05SAnand Jain }
955089c8b05SAnand Jain BTRFS_ATTR(, generation, btrfs_generation_show);
956089c8b05SAnand Jain 
957aaefed20SAnand Jain /*
958aaefed20SAnand Jain  * Look for an exact string @string in @buffer with possible leading or
959aaefed20SAnand Jain  * trailing whitespace
960aaefed20SAnand Jain  */
961aaefed20SAnand Jain static bool strmatch(const char *buffer, const char *string)
962aaefed20SAnand Jain {
963aaefed20SAnand Jain 	const size_t len = strlen(string);
964aaefed20SAnand Jain 
965aaefed20SAnand Jain 	/* Skip leading whitespace */
966aaefed20SAnand Jain 	buffer = skip_spaces(buffer);
967aaefed20SAnand Jain 
968aaefed20SAnand Jain 	/* Match entire string, check if the rest is whitespace or empty */
969aaefed20SAnand Jain 	if (strncmp(string, buffer, len) == 0 &&
970aaefed20SAnand Jain 	    strlen(skip_spaces(buffer + len)) == 0)
971aaefed20SAnand Jain 		return true;
972aaefed20SAnand Jain 
973aaefed20SAnand Jain 	return false;
974aaefed20SAnand Jain }
975aaefed20SAnand Jain 
9763d8cc17aSAnand Jain static const char * const btrfs_read_policy_name[] = { "pid" };
9773d8cc17aSAnand Jain 
9783d8cc17aSAnand Jain static ssize_t btrfs_read_policy_show(struct kobject *kobj,
9793d8cc17aSAnand Jain 				      struct kobj_attribute *a, char *buf)
9803d8cc17aSAnand Jain {
9813d8cc17aSAnand Jain 	struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
9823d8cc17aSAnand Jain 	ssize_t ret = 0;
9833d8cc17aSAnand Jain 	int i;
9843d8cc17aSAnand Jain 
9853d8cc17aSAnand Jain 	for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
9863d8cc17aSAnand Jain 		if (fs_devices->read_policy == i)
9873d8cc17aSAnand Jain 			ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s[%s]",
9883d8cc17aSAnand Jain 					 (ret == 0 ? "" : " "),
9893d8cc17aSAnand Jain 					 btrfs_read_policy_name[i]);
9903d8cc17aSAnand Jain 		else
9913d8cc17aSAnand Jain 			ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s%s",
9923d8cc17aSAnand Jain 					 (ret == 0 ? "" : " "),
9933d8cc17aSAnand Jain 					 btrfs_read_policy_name[i]);
9943d8cc17aSAnand Jain 	}
9953d8cc17aSAnand Jain 
9963d8cc17aSAnand Jain 	ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
9973d8cc17aSAnand Jain 
9983d8cc17aSAnand Jain 	return ret;
9993d8cc17aSAnand Jain }
10003d8cc17aSAnand Jain 
10013d8cc17aSAnand Jain static ssize_t btrfs_read_policy_store(struct kobject *kobj,
10023d8cc17aSAnand Jain 				       struct kobj_attribute *a,
10033d8cc17aSAnand Jain 				       const char *buf, size_t len)
10043d8cc17aSAnand Jain {
10053d8cc17aSAnand Jain 	struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
10063d8cc17aSAnand Jain 	int i;
10073d8cc17aSAnand Jain 
10083d8cc17aSAnand Jain 	for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
10093d8cc17aSAnand Jain 		if (strmatch(buf, btrfs_read_policy_name[i])) {
10103d8cc17aSAnand Jain 			if (i != fs_devices->read_policy) {
10113d8cc17aSAnand Jain 				fs_devices->read_policy = i;
10123d8cc17aSAnand Jain 				btrfs_info(fs_devices->fs_info,
10133d8cc17aSAnand Jain 					   "read policy set to '%s'",
10143d8cc17aSAnand Jain 					   btrfs_read_policy_name[i]);
10153d8cc17aSAnand Jain 			}
10163d8cc17aSAnand Jain 			return len;
10173d8cc17aSAnand Jain 		}
10183d8cc17aSAnand Jain 	}
10193d8cc17aSAnand Jain 
10203d8cc17aSAnand Jain 	return -EINVAL;
10213d8cc17aSAnand Jain }
10223d8cc17aSAnand Jain BTRFS_ATTR_RW(, read_policy, btrfs_read_policy_show, btrfs_read_policy_store);
10233d8cc17aSAnand Jain 
102418bb8bbfSJohannes Thumshirn static ssize_t btrfs_bg_reclaim_threshold_show(struct kobject *kobj,
102518bb8bbfSJohannes Thumshirn 					       struct kobj_attribute *a,
102618bb8bbfSJohannes Thumshirn 					       char *buf)
102718bb8bbfSJohannes Thumshirn {
102818bb8bbfSJohannes Thumshirn 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
102918bb8bbfSJohannes Thumshirn 	ssize_t ret;
103018bb8bbfSJohannes Thumshirn 
1031020e5277SAnand Jain 	ret = sysfs_emit(buf, "%d\n", READ_ONCE(fs_info->bg_reclaim_threshold));
103218bb8bbfSJohannes Thumshirn 
103318bb8bbfSJohannes Thumshirn 	return ret;
103418bb8bbfSJohannes Thumshirn }
103518bb8bbfSJohannes Thumshirn 
103618bb8bbfSJohannes Thumshirn static ssize_t btrfs_bg_reclaim_threshold_store(struct kobject *kobj,
103718bb8bbfSJohannes Thumshirn 						struct kobj_attribute *a,
103818bb8bbfSJohannes Thumshirn 						const char *buf, size_t len)
103918bb8bbfSJohannes Thumshirn {
104018bb8bbfSJohannes Thumshirn 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
104118bb8bbfSJohannes Thumshirn 	int thresh;
104218bb8bbfSJohannes Thumshirn 	int ret;
104318bb8bbfSJohannes Thumshirn 
104418bb8bbfSJohannes Thumshirn 	ret = kstrtoint(buf, 10, &thresh);
104518bb8bbfSJohannes Thumshirn 	if (ret)
104618bb8bbfSJohannes Thumshirn 		return ret;
104718bb8bbfSJohannes Thumshirn 
104877233c2dSJohannes Thumshirn 	if (thresh != 0 && (thresh <= 50 || thresh > 100))
104918bb8bbfSJohannes Thumshirn 		return -EINVAL;
105018bb8bbfSJohannes Thumshirn 
105177233c2dSJohannes Thumshirn 	WRITE_ONCE(fs_info->bg_reclaim_threshold, thresh);
105218bb8bbfSJohannes Thumshirn 
105318bb8bbfSJohannes Thumshirn 	return len;
105418bb8bbfSJohannes Thumshirn }
105518bb8bbfSJohannes Thumshirn BTRFS_ATTR_RW(, bg_reclaim_threshold, btrfs_bg_reclaim_threshold_show,
105618bb8bbfSJohannes Thumshirn 	      btrfs_bg_reclaim_threshold_store);
105718bb8bbfSJohannes Thumshirn 
1058e7849e33SAnand Jain /*
1059e7849e33SAnand Jain  * Per-filesystem information and stats.
1060e7849e33SAnand Jain  *
1061e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/
1062e7849e33SAnand Jain  */
10630dd2906fSAnand Jain static const struct attribute *btrfs_attrs[] = {
1064a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, label),
1065a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, nodesize),
1066a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, sectorsize),
1067a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, clone_alignment),
1068a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, quota_override),
106956f20f40SNikolay Borisov 	BTRFS_ATTR_PTR(, metadata_uuid),
107041e6d2a8SJohannes Thumshirn 	BTRFS_ATTR_PTR(, checksum),
107166a2823cSGoldwyn Rodrigues 	BTRFS_ATTR_PTR(, exclusive_operation),
1072089c8b05SAnand Jain 	BTRFS_ATTR_PTR(, generation),
10733d8cc17aSAnand Jain 	BTRFS_ATTR_PTR(, read_policy),
107418bb8bbfSJohannes Thumshirn 	BTRFS_ATTR_PTR(, bg_reclaim_threshold),
1075f8ba9c11SJeff Mahoney 	NULL,
1076f8ba9c11SJeff Mahoney };
1077f8ba9c11SJeff Mahoney 
1078c1b7e474SAnand Jain static void btrfs_release_fsid_kobj(struct kobject *kobj)
1079510d7360SJeff Mahoney {
10802e7910d6SAnand Jain 	struct btrfs_fs_devices *fs_devs = to_fs_devs(kobj);
1081248d200dSAnand Jain 
1082c1b7e474SAnand Jain 	memset(&fs_devs->fsid_kobj, 0, sizeof(struct kobject));
10832e7910d6SAnand Jain 	complete(&fs_devs->kobj_unregister);
1084510d7360SJeff Mahoney }
1085510d7360SJeff Mahoney 
1086510d7360SJeff Mahoney static struct kobj_type btrfs_ktype = {
1087510d7360SJeff Mahoney 	.sysfs_ops	= &kobj_sysfs_ops,
1088c1b7e474SAnand Jain 	.release	= btrfs_release_fsid_kobj,
1089510d7360SJeff Mahoney };
1090510d7360SJeff Mahoney 
10912e7910d6SAnand Jain static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj)
10922e7910d6SAnand Jain {
10932e7910d6SAnand Jain 	if (kobj->ktype != &btrfs_ktype)
10942e7910d6SAnand Jain 		return NULL;
1095c1b7e474SAnand Jain 	return container_of(kobj, struct btrfs_fs_devices, fsid_kobj);
10962e7910d6SAnand Jain }
10972e7910d6SAnand Jain 
1098510d7360SJeff Mahoney static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj)
1099510d7360SJeff Mahoney {
1100510d7360SJeff Mahoney 	if (kobj->ktype != &btrfs_ktype)
1101510d7360SJeff Mahoney 		return NULL;
11022e7910d6SAnand Jain 	return to_fs_devs(kobj)->fs_info;
1103510d7360SJeff Mahoney }
110458176a96SJosef Bacik 
1105e453d989SJeff Mahoney #define NUM_FEATURE_BITS 64
11066c52157fSTomohiro Misono #define BTRFS_FEATURE_NAME_MAX 13
11076c52157fSTomohiro Misono static char btrfs_unknown_feature_names[FEAT_MAX][NUM_FEATURE_BITS][BTRFS_FEATURE_NAME_MAX];
11086c52157fSTomohiro Misono static struct btrfs_feature_attr btrfs_feature_attrs[FEAT_MAX][NUM_FEATURE_BITS];
1109e453d989SJeff Mahoney 
11106c52157fSTomohiro Misono static const u64 supported_feature_masks[FEAT_MAX] = {
1111e453d989SJeff Mahoney 	[FEAT_COMPAT]    = BTRFS_FEATURE_COMPAT_SUPP,
1112e453d989SJeff Mahoney 	[FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP,
1113e453d989SJeff Mahoney 	[FEAT_INCOMPAT]  = BTRFS_FEATURE_INCOMPAT_SUPP,
1114e453d989SJeff Mahoney };
1115e453d989SJeff Mahoney 
1116e453d989SJeff Mahoney static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add)
11175ac1d209SJeff Mahoney {
1118e453d989SJeff Mahoney 	int set;
1119e453d989SJeff Mahoney 
1120e453d989SJeff Mahoney 	for (set = 0; set < FEAT_MAX; set++) {
1121e453d989SJeff Mahoney 		int i;
1122e453d989SJeff Mahoney 		struct attribute *attrs[2];
1123e453d989SJeff Mahoney 		struct attribute_group agroup = {
1124e453d989SJeff Mahoney 			.name = "features",
1125e453d989SJeff Mahoney 			.attrs = attrs,
1126e453d989SJeff Mahoney 		};
1127e453d989SJeff Mahoney 		u64 features = get_features(fs_info, set);
1128e453d989SJeff Mahoney 		features &= ~supported_feature_masks[set];
1129e453d989SJeff Mahoney 
1130e453d989SJeff Mahoney 		if (!features)
1131e453d989SJeff Mahoney 			continue;
1132e453d989SJeff Mahoney 
1133e453d989SJeff Mahoney 		attrs[1] = NULL;
1134e453d989SJeff Mahoney 		for (i = 0; i < NUM_FEATURE_BITS; i++) {
1135e453d989SJeff Mahoney 			struct btrfs_feature_attr *fa;
1136e453d989SJeff Mahoney 
1137e453d989SJeff Mahoney 			if (!(features & (1ULL << i)))
1138e453d989SJeff Mahoney 				continue;
1139e453d989SJeff Mahoney 
1140e453d989SJeff Mahoney 			fa = &btrfs_feature_attrs[set][i];
1141e453d989SJeff Mahoney 			attrs[0] = &fa->kobj_attr.attr;
1142e453d989SJeff Mahoney 			if (add) {
1143e453d989SJeff Mahoney 				int ret;
1144c1b7e474SAnand Jain 				ret = sysfs_merge_group(&fs_info->fs_devices->fsid_kobj,
1145e453d989SJeff Mahoney 							&agroup);
1146e453d989SJeff Mahoney 				if (ret)
1147e453d989SJeff Mahoney 					return ret;
1148e453d989SJeff Mahoney 			} else
1149c1b7e474SAnand Jain 				sysfs_unmerge_group(&fs_info->fs_devices->fsid_kobj,
1150e453d989SJeff Mahoney 						    &agroup);
1151e453d989SJeff Mahoney 		}
1152e453d989SJeff Mahoney 
1153e453d989SJeff Mahoney 	}
1154e453d989SJeff Mahoney 	return 0;
1155e453d989SJeff Mahoney }
1156e453d989SJeff Mahoney 
11572e3e1281SAnand Jain static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs)
1158e453d989SJeff Mahoney {
1159a013d141SAnand Jain 	if (fs_devs->devinfo_kobj) {
1160a013d141SAnand Jain 		kobject_del(fs_devs->devinfo_kobj);
1161a013d141SAnand Jain 		kobject_put(fs_devs->devinfo_kobj);
1162a013d141SAnand Jain 		fs_devs->devinfo_kobj = NULL;
1163a013d141SAnand Jain 	}
1164a013d141SAnand Jain 
1165b5501504SAnand Jain 	if (fs_devs->devices_kobj) {
1166b5501504SAnand Jain 		kobject_del(fs_devs->devices_kobj);
1167b5501504SAnand Jain 		kobject_put(fs_devs->devices_kobj);
1168b5501504SAnand Jain 		fs_devs->devices_kobj = NULL;
1169aaf13305SAnand Jain 	}
1170aaf13305SAnand Jain 
1171c1b7e474SAnand Jain 	if (fs_devs->fsid_kobj.state_initialized) {
1172c1b7e474SAnand Jain 		kobject_del(&fs_devs->fsid_kobj);
1173c1b7e474SAnand Jain 		kobject_put(&fs_devs->fsid_kobj);
11742e7910d6SAnand Jain 		wait_for_completion(&fs_devs->kobj_unregister);
11755ac1d209SJeff Mahoney 	}
1176f90fc547SAnand Jain }
11775ac1d209SJeff Mahoney 
11782e3e1281SAnand Jain /* when fs_devs is NULL it will remove all fsid kobject */
11791d1c1be3SAnand Jain void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs)
11802e3e1281SAnand Jain {
11812e3e1281SAnand Jain 	struct list_head *fs_uuids = btrfs_get_fs_uuids();
11822e3e1281SAnand Jain 
11832e3e1281SAnand Jain 	if (fs_devs) {
11842e3e1281SAnand Jain 		__btrfs_sysfs_remove_fsid(fs_devs);
11852e3e1281SAnand Jain 		return;
11862e3e1281SAnand Jain 	}
11872e3e1281SAnand Jain 
1188c4babc5eSAnand Jain 	list_for_each_entry(fs_devs, fs_uuids, fs_list) {
11892e3e1281SAnand Jain 		__btrfs_sysfs_remove_fsid(fs_devs);
11902e3e1281SAnand Jain 	}
11912e3e1281SAnand Jain }
11922e3e1281SAnand Jain 
119353f8a74cSAnand Jain static void btrfs_sysfs_remove_fs_devices(struct btrfs_fs_devices *fs_devices)
119453f8a74cSAnand Jain {
119553f8a74cSAnand Jain 	struct btrfs_device *device;
119630b0e4e0SAnand Jain 	struct btrfs_fs_devices *seed;
119753f8a74cSAnand Jain 
119853f8a74cSAnand Jain 	list_for_each_entry(device, &fs_devices->devices, dev_list)
119953f8a74cSAnand Jain 		btrfs_sysfs_remove_device(device);
120030b0e4e0SAnand Jain 
120130b0e4e0SAnand Jain 	list_for_each_entry(seed, &fs_devices->seed_list, seed_list) {
120230b0e4e0SAnand Jain 		list_for_each_entry(device, &seed->devices, dev_list)
120330b0e4e0SAnand Jain 			btrfs_sysfs_remove_device(device);
120430b0e4e0SAnand Jain 	}
120553f8a74cSAnand Jain }
120653f8a74cSAnand Jain 
12076618a59bSAnand Jain void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info)
1208e453d989SJeff Mahoney {
12093092c68fSNikolay Borisov 	struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj;
12103092c68fSNikolay Borisov 
12113092c68fSNikolay Borisov 	sysfs_remove_link(fsid_kobj, "bdi");
12123092c68fSNikolay Borisov 
1213e453d989SJeff Mahoney 	if (fs_info->space_info_kobj) {
1214e453d989SJeff Mahoney 		sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs);
1215e453d989SJeff Mahoney 		kobject_del(fs_info->space_info_kobj);
1216e453d989SJeff Mahoney 		kobject_put(fs_info->space_info_kobj);
1217e453d989SJeff Mahoney 	}
121871e8978eSDennis Zhou #ifdef CONFIG_BTRFS_DEBUG
1219e4faab84SDennis Zhou 	if (fs_info->discard_debug_kobj) {
1220e4faab84SDennis Zhou 		sysfs_remove_files(fs_info->discard_debug_kobj,
1221e4faab84SDennis Zhou 				   discard_debug_attrs);
1222e4faab84SDennis Zhou 		kobject_del(fs_info->discard_debug_kobj);
1223e4faab84SDennis Zhou 		kobject_put(fs_info->discard_debug_kobj);
1224e4faab84SDennis Zhou 	}
122593945cb4SDennis Zhou 	if (fs_info->debug_kobj) {
122693945cb4SDennis Zhou 		sysfs_remove_files(fs_info->debug_kobj, btrfs_debug_mount_attrs);
122793945cb4SDennis Zhou 		kobject_del(fs_info->debug_kobj);
122893945cb4SDennis Zhou 		kobject_put(fs_info->debug_kobj);
122993945cb4SDennis Zhou 	}
123071e8978eSDennis Zhou #endif
1231e453d989SJeff Mahoney 	addrm_unknown_feature_attrs(fs_info, false);
12323092c68fSNikolay Borisov 	sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group);
12333092c68fSNikolay Borisov 	sysfs_remove_files(fsid_kobj, btrfs_attrs);
123453f8a74cSAnand Jain 	btrfs_sysfs_remove_fs_devices(fs_info->fs_devices);
1235e453d989SJeff Mahoney }
1236e453d989SJeff Mahoney 
1237f10152bcSDavid Sterba static const char * const btrfs_feature_set_names[FEAT_MAX] = {
123879da4fa4SJeff Mahoney 	[FEAT_COMPAT]	 = "compat",
123979da4fa4SJeff Mahoney 	[FEAT_COMPAT_RO] = "compat_ro",
124079da4fa4SJeff Mahoney 	[FEAT_INCOMPAT]	 = "incompat",
124179da4fa4SJeff Mahoney };
124279da4fa4SJeff Mahoney 
12439e6df7ceSDavid Sterba const char *btrfs_feature_set_name(enum btrfs_feature_set set)
1244f10152bcSDavid Sterba {
1245f10152bcSDavid Sterba 	return btrfs_feature_set_names[set];
1246f10152bcSDavid Sterba }
1247f10152bcSDavid Sterba 
12483b02a68aSJeff Mahoney char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags)
12493b02a68aSJeff Mahoney {
12503b02a68aSJeff Mahoney 	size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */
12513b02a68aSJeff Mahoney 	int len = 0;
12523b02a68aSJeff Mahoney 	int i;
12533b02a68aSJeff Mahoney 	char *str;
12543b02a68aSJeff Mahoney 
12553b02a68aSJeff Mahoney 	str = kmalloc(bufsize, GFP_KERNEL);
12563b02a68aSJeff Mahoney 	if (!str)
12573b02a68aSJeff Mahoney 		return str;
12583b02a68aSJeff Mahoney 
12593b02a68aSJeff Mahoney 	for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
12603b02a68aSJeff Mahoney 		const char *name;
12613b02a68aSJeff Mahoney 
12623b02a68aSJeff Mahoney 		if (!(flags & (1ULL << i)))
12633b02a68aSJeff Mahoney 			continue;
12643b02a68aSJeff Mahoney 
12653b02a68aSJeff Mahoney 		name = btrfs_feature_attrs[set][i].kobj_attr.attr.name;
1266abdd9febSTakashi Iwai 		len += scnprintf(str + len, bufsize - len, "%s%s",
12673b02a68aSJeff Mahoney 				len ? "," : "", name);
12683b02a68aSJeff Mahoney 	}
12693b02a68aSJeff Mahoney 
12703b02a68aSJeff Mahoney 	return str;
12713b02a68aSJeff Mahoney }
12723b02a68aSJeff Mahoney 
127379da4fa4SJeff Mahoney static void init_feature_attrs(void)
127479da4fa4SJeff Mahoney {
127579da4fa4SJeff Mahoney 	struct btrfs_feature_attr *fa;
127679da4fa4SJeff Mahoney 	int set, i;
127779da4fa4SJeff Mahoney 
127879da4fa4SJeff Mahoney 	BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names) !=
127979da4fa4SJeff Mahoney 		     ARRAY_SIZE(btrfs_feature_attrs));
128079da4fa4SJeff Mahoney 	BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) !=
128179da4fa4SJeff Mahoney 		     ARRAY_SIZE(btrfs_feature_attrs[0]));
128279da4fa4SJeff Mahoney 
12833b02a68aSJeff Mahoney 	memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs));
12843b02a68aSJeff Mahoney 	memset(btrfs_unknown_feature_names, 0,
12853b02a68aSJeff Mahoney 	       sizeof(btrfs_unknown_feature_names));
12863b02a68aSJeff Mahoney 
128779da4fa4SJeff Mahoney 	for (i = 0; btrfs_supported_feature_attrs[i]; i++) {
128879da4fa4SJeff Mahoney 		struct btrfs_feature_attr *sfa;
128979da4fa4SJeff Mahoney 		struct attribute *a = btrfs_supported_feature_attrs[i];
12903b02a68aSJeff Mahoney 		int bit;
129179da4fa4SJeff Mahoney 		sfa = attr_to_btrfs_feature_attr(a);
12923b02a68aSJeff Mahoney 		bit = ilog2(sfa->feature_bit);
12933b02a68aSJeff Mahoney 		fa = &btrfs_feature_attrs[sfa->feature_set][bit];
129479da4fa4SJeff Mahoney 
129579da4fa4SJeff Mahoney 		fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name;
129679da4fa4SJeff Mahoney 	}
129779da4fa4SJeff Mahoney 
129879da4fa4SJeff Mahoney 	for (set = 0; set < FEAT_MAX; set++) {
129979da4fa4SJeff Mahoney 		for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
130079da4fa4SJeff Mahoney 			char *name = btrfs_unknown_feature_names[set][i];
130179da4fa4SJeff Mahoney 			fa = &btrfs_feature_attrs[set][i];
130279da4fa4SJeff Mahoney 
130379da4fa4SJeff Mahoney 			if (fa->kobj_attr.attr.name)
130479da4fa4SJeff Mahoney 				continue;
130579da4fa4SJeff Mahoney 
13066c52157fSTomohiro Misono 			snprintf(name, BTRFS_FEATURE_NAME_MAX, "%s:%u",
130779da4fa4SJeff Mahoney 				 btrfs_feature_set_names[set], i);
130879da4fa4SJeff Mahoney 
130979da4fa4SJeff Mahoney 			fa->kobj_attr.attr.name = name;
131079da4fa4SJeff Mahoney 			fa->kobj_attr.attr.mode = S_IRUGO;
131179da4fa4SJeff Mahoney 			fa->feature_set = set;
131279da4fa4SJeff Mahoney 			fa->feature_bit = 1ULL << i;
131379da4fa4SJeff Mahoney 		}
131479da4fa4SJeff Mahoney 	}
131579da4fa4SJeff Mahoney }
131679da4fa4SJeff Mahoney 
131732a9991fSDavid Sterba /*
131832a9991fSDavid Sterba  * Create a sysfs entry for a given block group type at path
131932a9991fSDavid Sterba  * /sys/fs/btrfs/UUID/allocation/data/TYPE
132032a9991fSDavid Sterba  */
132132da5386SDavid Sterba void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache)
132232a9991fSDavid Sterba {
132332a9991fSDavid Sterba 	struct btrfs_fs_info *fs_info = cache->fs_info;
132432a9991fSDavid Sterba 	struct btrfs_space_info *space_info = cache->space_info;
132532a9991fSDavid Sterba 	struct raid_kobject *rkobj;
132632a9991fSDavid Sterba 	const int index = btrfs_bg_flags_to_raid_index(cache->flags);
132732a9991fSDavid Sterba 	unsigned int nofs_flag;
132832a9991fSDavid Sterba 	int ret;
132932a9991fSDavid Sterba 
133032a9991fSDavid Sterba 	/*
133132a9991fSDavid Sterba 	 * Setup a NOFS context because kobject_add(), deep in its call chain,
133232a9991fSDavid Sterba 	 * does GFP_KERNEL allocations, and we are often called in a context
133332a9991fSDavid Sterba 	 * where if reclaim is triggered we can deadlock (we are either holding
133432a9991fSDavid Sterba 	 * a transaction handle or some lock required for a transaction
133532a9991fSDavid Sterba 	 * commit).
133632a9991fSDavid Sterba 	 */
133732a9991fSDavid Sterba 	nofs_flag = memalloc_nofs_save();
133832a9991fSDavid Sterba 
133932a9991fSDavid Sterba 	rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS);
134032a9991fSDavid Sterba 	if (!rkobj) {
134132a9991fSDavid Sterba 		memalloc_nofs_restore(nofs_flag);
134232a9991fSDavid Sterba 		btrfs_warn(cache->fs_info,
134332a9991fSDavid Sterba 				"couldn't alloc memory for raid level kobject");
134432a9991fSDavid Sterba 		return;
134532a9991fSDavid Sterba 	}
134632a9991fSDavid Sterba 
134732a9991fSDavid Sterba 	rkobj->flags = cache->flags;
134832a9991fSDavid Sterba 	kobject_init(&rkobj->kobj, &btrfs_raid_ktype);
134949ea112dSJosef Bacik 
135049ea112dSJosef Bacik 	/*
135149ea112dSJosef Bacik 	 * We call this either on mount, or if we've created a block group for a
135249ea112dSJosef Bacik 	 * new index type while running (i.e. when restriping).  The running
135349ea112dSJosef Bacik 	 * case is tricky because we could race with other threads, so we need
135449ea112dSJosef Bacik 	 * to have this check to make sure we didn't already init the kobject.
135549ea112dSJosef Bacik 	 *
135649ea112dSJosef Bacik 	 * We don't have to protect on the free side because it only happens on
135749ea112dSJosef Bacik 	 * unmount.
135849ea112dSJosef Bacik 	 */
135949ea112dSJosef Bacik 	spin_lock(&space_info->lock);
136049ea112dSJosef Bacik 	if (space_info->block_group_kobjs[index]) {
136149ea112dSJosef Bacik 		spin_unlock(&space_info->lock);
136249ea112dSJosef Bacik 		kobject_put(&rkobj->kobj);
136349ea112dSJosef Bacik 		return;
136449ea112dSJosef Bacik 	} else {
136549ea112dSJosef Bacik 		space_info->block_group_kobjs[index] = &rkobj->kobj;
136649ea112dSJosef Bacik 	}
136749ea112dSJosef Bacik 	spin_unlock(&space_info->lock);
136849ea112dSJosef Bacik 
136932a9991fSDavid Sterba 	ret = kobject_add(&rkobj->kobj, &space_info->kobj, "%s",
137032a9991fSDavid Sterba 			  btrfs_bg_type_to_raid_name(rkobj->flags));
137132a9991fSDavid Sterba 	memalloc_nofs_restore(nofs_flag);
137232a9991fSDavid Sterba 	if (ret) {
137349ea112dSJosef Bacik 		spin_lock(&space_info->lock);
137449ea112dSJosef Bacik 		space_info->block_group_kobjs[index] = NULL;
137549ea112dSJosef Bacik 		spin_unlock(&space_info->lock);
137632a9991fSDavid Sterba 		kobject_put(&rkobj->kobj);
137732a9991fSDavid Sterba 		btrfs_warn(fs_info,
137832a9991fSDavid Sterba 			"failed to add kobject for block cache, ignoring");
137932a9991fSDavid Sterba 		return;
138032a9991fSDavid Sterba 	}
138132a9991fSDavid Sterba }
138232a9991fSDavid Sterba 
1383b5865babSDavid Sterba /*
1384b5865babSDavid Sterba  * Remove sysfs directories for all block group types of a given space info and
1385b5865babSDavid Sterba  * the space info as well
1386b5865babSDavid Sterba  */
1387b5865babSDavid Sterba void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info)
1388b5865babSDavid Sterba {
1389b5865babSDavid Sterba 	int i;
1390b5865babSDavid Sterba 
1391b5865babSDavid Sterba 	for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
1392b5865babSDavid Sterba 		struct kobject *kobj;
1393b5865babSDavid Sterba 
1394b5865babSDavid Sterba 		kobj = space_info->block_group_kobjs[i];
1395b5865babSDavid Sterba 		space_info->block_group_kobjs[i] = NULL;
1396b5865babSDavid Sterba 		if (kobj) {
1397b5865babSDavid Sterba 			kobject_del(kobj);
1398b5865babSDavid Sterba 			kobject_put(kobj);
1399b5865babSDavid Sterba 		}
1400b5865babSDavid Sterba 	}
1401b5865babSDavid Sterba 	kobject_del(&space_info->kobj);
1402b5865babSDavid Sterba 	kobject_put(&space_info->kobj);
1403b5865babSDavid Sterba }
1404b5865babSDavid Sterba 
1405b882327aSDavid Sterba static const char *alloc_name(u64 flags)
1406b882327aSDavid Sterba {
1407b882327aSDavid Sterba 	switch (flags) {
1408b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA:
1409b882327aSDavid Sterba 		return "mixed";
1410b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_METADATA:
1411b882327aSDavid Sterba 		return "metadata";
1412b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_DATA:
1413b882327aSDavid Sterba 		return "data";
1414b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_SYSTEM:
1415b882327aSDavid Sterba 		return "system";
1416b882327aSDavid Sterba 	default:
1417b882327aSDavid Sterba 		WARN_ON(1);
1418b882327aSDavid Sterba 		return "invalid-combination";
1419445d8ab5STom Rix 	}
1420b882327aSDavid Sterba }
1421b882327aSDavid Sterba 
1422b882327aSDavid Sterba /*
1423b882327aSDavid Sterba  * Create a sysfs entry for a space info type at path
1424b882327aSDavid Sterba  * /sys/fs/btrfs/UUID/allocation/TYPE
1425b882327aSDavid Sterba  */
1426b882327aSDavid Sterba int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info,
1427b882327aSDavid Sterba 				    struct btrfs_space_info *space_info)
1428b882327aSDavid Sterba {
1429b882327aSDavid Sterba 	int ret;
1430b882327aSDavid Sterba 
1431b882327aSDavid Sterba 	ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype,
1432b882327aSDavid Sterba 				   fs_info->space_info_kobj, "%s",
1433b882327aSDavid Sterba 				   alloc_name(space_info->flags));
1434b882327aSDavid Sterba 	if (ret) {
1435b882327aSDavid Sterba 		kobject_put(&space_info->kobj);
1436b882327aSDavid Sterba 		return ret;
1437b882327aSDavid Sterba 	}
1438b882327aSDavid Sterba 
1439b882327aSDavid Sterba 	return 0;
1440b882327aSDavid Sterba }
1441b882327aSDavid Sterba 
144253f8a74cSAnand Jain void btrfs_sysfs_remove_device(struct btrfs_device *device)
144399994cdeSAnand Jain {
1444985e233eSAnand Jain 	struct kobject *devices_kobj;
144599994cdeSAnand Jain 
1446985e233eSAnand Jain 	/*
1447985e233eSAnand Jain 	 * Seed fs_devices devices_kobj aren't used, fetch kobject from the
1448985e233eSAnand Jain 	 * fs_info::fs_devices.
1449985e233eSAnand Jain 	 */
1450985e233eSAnand Jain 	devices_kobj = device->fs_info->fs_devices->devices_kobj;
1451985e233eSAnand Jain 	ASSERT(devices_kobj);
145299994cdeSAnand Jain 
14538d65269fSChristoph Hellwig 	if (device->bdev)
14548d65269fSChristoph Hellwig 		sysfs_remove_link(devices_kobj, bdev_kobj(device->bdev)->name);
145599994cdeSAnand Jain 
1456985e233eSAnand Jain 	if (device->devid_kobj.state_initialized) {
1457985e233eSAnand Jain 		kobject_del(&device->devid_kobj);
1458985e233eSAnand Jain 		kobject_put(&device->devid_kobj);
1459985e233eSAnand Jain 		wait_for_completion(&device->kobj_unregister);
1460985e233eSAnand Jain 	}
1461b5ddcffaSAnand Jain }
1462668e48afSAnand Jain 
1463668e48afSAnand Jain static ssize_t btrfs_devinfo_in_fs_metadata_show(struct kobject *kobj,
1464668e48afSAnand Jain 					         struct kobj_attribute *a,
1465668e48afSAnand Jain 					         char *buf)
1466668e48afSAnand Jain {
1467668e48afSAnand Jain 	int val;
1468668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1469668e48afSAnand Jain 						   devid_kobj);
1470668e48afSAnand Jain 
1471668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
1472668e48afSAnand Jain 
1473020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1474668e48afSAnand Jain }
1475668e48afSAnand Jain BTRFS_ATTR(devid, in_fs_metadata, btrfs_devinfo_in_fs_metadata_show);
1476668e48afSAnand Jain 
147725864778SAnand Jain static ssize_t btrfs_devinfo_missing_show(struct kobject *kobj,
1478668e48afSAnand Jain 					struct kobj_attribute *a, char *buf)
1479668e48afSAnand Jain {
1480668e48afSAnand Jain 	int val;
1481668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1482668e48afSAnand Jain 						   devid_kobj);
1483668e48afSAnand Jain 
1484668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state);
1485668e48afSAnand Jain 
1486020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1487668e48afSAnand Jain }
148825864778SAnand Jain BTRFS_ATTR(devid, missing, btrfs_devinfo_missing_show);
1489668e48afSAnand Jain 
1490668e48afSAnand Jain static ssize_t btrfs_devinfo_replace_target_show(struct kobject *kobj,
1491668e48afSAnand Jain 					         struct kobj_attribute *a,
1492668e48afSAnand Jain 					         char *buf)
1493668e48afSAnand Jain {
1494668e48afSAnand Jain 	int val;
1495668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1496668e48afSAnand Jain 						   devid_kobj);
1497668e48afSAnand Jain 
1498668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state);
1499668e48afSAnand Jain 
1500020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1501668e48afSAnand Jain }
1502668e48afSAnand Jain BTRFS_ATTR(devid, replace_target, btrfs_devinfo_replace_target_show);
1503668e48afSAnand Jain 
1504eb3b5053SDavid Sterba static ssize_t btrfs_devinfo_scrub_speed_max_show(struct kobject *kobj,
1505eb3b5053SDavid Sterba 					     struct kobj_attribute *a,
1506eb3b5053SDavid Sterba 					     char *buf)
1507eb3b5053SDavid Sterba {
1508eb3b5053SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1509eb3b5053SDavid Sterba 						   devid_kobj);
1510eb3b5053SDavid Sterba 
1511020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", READ_ONCE(device->scrub_speed_max));
1512eb3b5053SDavid Sterba }
1513eb3b5053SDavid Sterba 
1514eb3b5053SDavid Sterba static ssize_t btrfs_devinfo_scrub_speed_max_store(struct kobject *kobj,
1515eb3b5053SDavid Sterba 					      struct kobj_attribute *a,
1516eb3b5053SDavid Sterba 					      const char *buf, size_t len)
1517eb3b5053SDavid Sterba {
1518eb3b5053SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1519eb3b5053SDavid Sterba 						   devid_kobj);
1520eb3b5053SDavid Sterba 	char *endptr;
1521eb3b5053SDavid Sterba 	unsigned long long limit;
1522eb3b5053SDavid Sterba 
1523eb3b5053SDavid Sterba 	limit = memparse(buf, &endptr);
1524eb3b5053SDavid Sterba 	WRITE_ONCE(device->scrub_speed_max, limit);
1525eb3b5053SDavid Sterba 	return len;
1526eb3b5053SDavid Sterba }
1527eb3b5053SDavid Sterba BTRFS_ATTR_RW(devid, scrub_speed_max, btrfs_devinfo_scrub_speed_max_show,
1528eb3b5053SDavid Sterba 	      btrfs_devinfo_scrub_speed_max_store);
1529eb3b5053SDavid Sterba 
1530668e48afSAnand Jain static ssize_t btrfs_devinfo_writeable_show(struct kobject *kobj,
1531668e48afSAnand Jain 					    struct kobj_attribute *a, char *buf)
1532668e48afSAnand Jain {
1533668e48afSAnand Jain 	int val;
1534668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1535668e48afSAnand Jain 						   devid_kobj);
1536668e48afSAnand Jain 
1537668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
1538668e48afSAnand Jain 
1539020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1540668e48afSAnand Jain }
1541668e48afSAnand Jain BTRFS_ATTR(devid, writeable, btrfs_devinfo_writeable_show);
1542668e48afSAnand Jain 
1543a26d60deSAnand Jain static ssize_t btrfs_devinfo_fsid_show(struct kobject *kobj,
1544a26d60deSAnand Jain 				       struct kobj_attribute *a, char *buf)
1545a26d60deSAnand Jain {
1546a26d60deSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1547a26d60deSAnand Jain 						   devid_kobj);
1548a26d60deSAnand Jain 
1549a26d60deSAnand Jain 	return sysfs_emit(buf, "%pU\n", device->fs_devices->fsid);
1550a26d60deSAnand Jain }
1551a26d60deSAnand Jain BTRFS_ATTR(devid, fsid, btrfs_devinfo_fsid_show);
1552a26d60deSAnand Jain 
1553da658b57SDavid Sterba static ssize_t btrfs_devinfo_error_stats_show(struct kobject *kobj,
1554da658b57SDavid Sterba 		struct kobj_attribute *a, char *buf)
1555da658b57SDavid Sterba {
1556da658b57SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1557da658b57SDavid Sterba 						   devid_kobj);
1558da658b57SDavid Sterba 
1559da658b57SDavid Sterba 	if (!device->dev_stats_valid)
1560020e5277SAnand Jain 		return sysfs_emit(buf, "invalid\n");
1561da658b57SDavid Sterba 
1562da658b57SDavid Sterba 	/*
1563da658b57SDavid Sterba 	 * Print all at once so we get a snapshot of all values from the same
1564da658b57SDavid Sterba 	 * time. Keep them in sync and in order of definition of
1565da658b57SDavid Sterba 	 * btrfs_dev_stat_values.
1566da658b57SDavid Sterba 	 */
1567020e5277SAnand Jain 	return sysfs_emit(buf,
1568da658b57SDavid Sterba 		"write_errs %d\n"
1569da658b57SDavid Sterba 		"read_errs %d\n"
1570da658b57SDavid Sterba 		"flush_errs %d\n"
1571da658b57SDavid Sterba 		"corruption_errs %d\n"
1572da658b57SDavid Sterba 		"generation_errs %d\n",
1573da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_WRITE_ERRS),
1574da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_READ_ERRS),
1575da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_FLUSH_ERRS),
1576da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_CORRUPTION_ERRS),
1577da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_GENERATION_ERRS));
1578da658b57SDavid Sterba }
1579da658b57SDavid Sterba BTRFS_ATTR(devid, error_stats, btrfs_devinfo_error_stats_show);
1580da658b57SDavid Sterba 
1581e7849e33SAnand Jain /*
1582e7849e33SAnand Jain  * Information about one device.
1583e7849e33SAnand Jain  *
1584e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/devinfo/<devid>/
1585e7849e33SAnand Jain  */
1586668e48afSAnand Jain static struct attribute *devid_attrs[] = {
1587da658b57SDavid Sterba 	BTRFS_ATTR_PTR(devid, error_stats),
1588a26d60deSAnand Jain 	BTRFS_ATTR_PTR(devid, fsid),
1589668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, in_fs_metadata),
1590668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, missing),
1591668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, replace_target),
1592eb3b5053SDavid Sterba 	BTRFS_ATTR_PTR(devid, scrub_speed_max),
1593668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, writeable),
1594668e48afSAnand Jain 	NULL
1595668e48afSAnand Jain };
1596668e48afSAnand Jain ATTRIBUTE_GROUPS(devid);
1597668e48afSAnand Jain 
1598668e48afSAnand Jain static void btrfs_release_devid_kobj(struct kobject *kobj)
1599668e48afSAnand Jain {
1600668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1601668e48afSAnand Jain 						   devid_kobj);
1602668e48afSAnand Jain 
1603668e48afSAnand Jain 	memset(&device->devid_kobj, 0, sizeof(struct kobject));
1604668e48afSAnand Jain 	complete(&device->kobj_unregister);
1605668e48afSAnand Jain }
1606668e48afSAnand Jain 
1607668e48afSAnand Jain static struct kobj_type devid_ktype = {
1608668e48afSAnand Jain 	.sysfs_ops	= &kobj_sysfs_ops,
1609668e48afSAnand Jain 	.default_groups = devid_groups,
1610668e48afSAnand Jain 	.release	= btrfs_release_devid_kobj,
1611668e48afSAnand Jain };
1612668e48afSAnand Jain 
1613cd36da2eSAnand Jain int btrfs_sysfs_add_device(struct btrfs_device *device)
161429e5be24SJeff Mahoney {
1615178a16c9SAnand Jain 	int ret;
1616a47bd78dSJosef Bacik 	unsigned int nofs_flag;
1617178a16c9SAnand Jain 	struct kobject *devices_kobj;
1618178a16c9SAnand Jain 	struct kobject *devinfo_kobj;
1619178a16c9SAnand Jain 
1620178a16c9SAnand Jain 	/*
1621178a16c9SAnand Jain 	 * Make sure we use the fs_info::fs_devices to fetch the kobjects even
1622178a16c9SAnand Jain 	 * for the seed fs_devices
1623178a16c9SAnand Jain 	 */
1624178a16c9SAnand Jain 	devices_kobj = device->fs_info->fs_devices->devices_kobj;
1625178a16c9SAnand Jain 	devinfo_kobj = device->fs_info->fs_devices->devinfo_kobj;
1626178a16c9SAnand Jain 	ASSERT(devices_kobj);
1627178a16c9SAnand Jain 	ASSERT(devinfo_kobj);
162829e5be24SJeff Mahoney 
1629a47bd78dSJosef Bacik 	nofs_flag = memalloc_nofs_save();
1630f085381eSAnand Jain 
1631178a16c9SAnand Jain 	if (device->bdev) {
16328d65269fSChristoph Hellwig 		struct kobject *disk_kobj = bdev_kobj(device->bdev);
163329e5be24SJeff Mahoney 
1634178a16c9SAnand Jain 		ret = sysfs_create_link(devices_kobj, disk_kobj, disk_kobj->name);
1635178a16c9SAnand Jain 		if (ret) {
1636178a16c9SAnand Jain 			btrfs_warn(device->fs_info,
1637178a16c9SAnand Jain 				"creating sysfs device link for devid %llu failed: %d",
1638178a16c9SAnand Jain 				device->devid, ret);
1639178a16c9SAnand Jain 			goto out;
1640178a16c9SAnand Jain 		}
164129e5be24SJeff Mahoney 	}
164229e5be24SJeff Mahoney 
1643178a16c9SAnand Jain 	init_completion(&device->kobj_unregister);
1644178a16c9SAnand Jain 	ret = kobject_init_and_add(&device->devid_kobj, &devid_ktype,
1645178a16c9SAnand Jain 				   devinfo_kobj, "%llu", device->devid);
1646178a16c9SAnand Jain 	if (ret) {
1647178a16c9SAnand Jain 		kobject_put(&device->devid_kobj);
1648178a16c9SAnand Jain 		btrfs_warn(device->fs_info,
1649178a16c9SAnand Jain 			   "devinfo init for devid %llu failed: %d",
1650178a16c9SAnand Jain 			   device->devid, ret);
1651668e48afSAnand Jain 	}
1652178a16c9SAnand Jain 
1653178a16c9SAnand Jain out:
1654a47bd78dSJosef Bacik 	memalloc_nofs_restore(nofs_flag);
1655178a16c9SAnand Jain 	return ret;
1656178a16c9SAnand Jain }
1657668e48afSAnand Jain 
1658cd36da2eSAnand Jain static int btrfs_sysfs_add_fs_devices(struct btrfs_fs_devices *fs_devices)
1659178a16c9SAnand Jain {
1660178a16c9SAnand Jain 	int ret;
1661cd36da2eSAnand Jain 	struct btrfs_device *device;
166230b0e4e0SAnand Jain 	struct btrfs_fs_devices *seed;
1663178a16c9SAnand Jain 
1664178a16c9SAnand Jain 	list_for_each_entry(device, &fs_devices->devices, dev_list) {
1665178a16c9SAnand Jain 		ret = btrfs_sysfs_add_device(device);
1666178a16c9SAnand Jain 		if (ret)
16677ad3912aSAnand Jain 			goto fail;
1668178a16c9SAnand Jain 	}
1669178a16c9SAnand Jain 
167030b0e4e0SAnand Jain 	list_for_each_entry(seed, &fs_devices->seed_list, seed_list) {
167130b0e4e0SAnand Jain 		list_for_each_entry(device, &seed->devices, dev_list) {
167230b0e4e0SAnand Jain 			ret = btrfs_sysfs_add_device(device);
167330b0e4e0SAnand Jain 			if (ret)
16747ad3912aSAnand Jain 				goto fail;
167530b0e4e0SAnand Jain 		}
167630b0e4e0SAnand Jain 	}
167730b0e4e0SAnand Jain 
1678178a16c9SAnand Jain 	return 0;
16797ad3912aSAnand Jain 
16807ad3912aSAnand Jain fail:
16817ad3912aSAnand Jain 	btrfs_sysfs_remove_fs_devices(fs_devices);
16827ad3912aSAnand Jain 	return ret;
168329e5be24SJeff Mahoney }
168429e5be24SJeff Mahoney 
16855b28692eSDavid Sterba void btrfs_kobject_uevent(struct block_device *bdev, enum kobject_action action)
16865b28692eSDavid Sterba {
16875b28692eSDavid Sterba 	int ret;
16885b28692eSDavid Sterba 
16895b28692eSDavid Sterba 	ret = kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, action);
16905b28692eSDavid Sterba 	if (ret)
16915b28692eSDavid Sterba 		pr_warn("BTRFS: Sending event '%d' to kobject: '%s' (%p): failed\n",
16925b28692eSDavid Sterba 			action, kobject_name(&disk_to_dev(bdev->bd_disk)->kobj),
16935b28692eSDavid Sterba 			&disk_to_dev(bdev->bd_disk)->kobj);
16945b28692eSDavid Sterba }
16955b28692eSDavid Sterba 
16968e560081SNikolay Borisov void btrfs_sysfs_update_sprout_fsid(struct btrfs_fs_devices *fs_devices)
16978e560081SNikolay Borisov 
1698f93c3997SDavid Sterba {
1699f93c3997SDavid Sterba 	char fsid_buf[BTRFS_UUID_UNPARSED_SIZE];
1700f93c3997SDavid Sterba 
1701f93c3997SDavid Sterba 	/*
1702f93c3997SDavid Sterba 	 * Sprouting changes fsid of the mounted filesystem, rename the fsid
1703f93c3997SDavid Sterba 	 * directory
1704f93c3997SDavid Sterba 	 */
17058e560081SNikolay Borisov 	snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU", fs_devices->fsid);
1706f93c3997SDavid Sterba 	if (kobject_rename(&fs_devices->fsid_kobj, fsid_buf))
1707f93c3997SDavid Sterba 		btrfs_warn(fs_devices->fs_info,
1708f93c3997SDavid Sterba 				"sysfs: failed to create fsid for sprout");
1709f93c3997SDavid Sterba }
1710f93c3997SDavid Sterba 
1711668e48afSAnand Jain void btrfs_sysfs_update_devid(struct btrfs_device *device)
1712668e48afSAnand Jain {
1713668e48afSAnand Jain 	char tmp[24];
1714668e48afSAnand Jain 
1715668e48afSAnand Jain 	snprintf(tmp, sizeof(tmp), "%llu", device->devid);
1716668e48afSAnand Jain 
1717668e48afSAnand Jain 	if (kobject_rename(&device->devid_kobj, tmp))
1718668e48afSAnand Jain 		btrfs_warn(device->fs_devices->fs_info,
1719668e48afSAnand Jain 			   "sysfs: failed to update devid for %llu",
1720668e48afSAnand Jain 			   device->devid);
1721668e48afSAnand Jain }
1722668e48afSAnand Jain 
1723510d7360SJeff Mahoney /* /sys/fs/btrfs/ entry */
1724510d7360SJeff Mahoney static struct kset *btrfs_kset;
1725510d7360SJeff Mahoney 
172672059215SAnand Jain /*
1727c6761a9eSAnand Jain  * Creates:
1728c6761a9eSAnand Jain  *		/sys/fs/btrfs/UUID
1729c6761a9eSAnand Jain  *
173072059215SAnand Jain  * Can be called by the device discovery thread.
173172059215SAnand Jain  */
1732c6761a9eSAnand Jain int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs)
17335ac1d209SJeff Mahoney {
17345ac1d209SJeff Mahoney 	int error;
17355ac1d209SJeff Mahoney 
17362e7910d6SAnand Jain 	init_completion(&fs_devs->kobj_unregister);
1737c1b7e474SAnand Jain 	fs_devs->fsid_kobj.kset = btrfs_kset;
1738c6761a9eSAnand Jain 	error = kobject_init_and_add(&fs_devs->fsid_kobj, &btrfs_ktype, NULL,
1739c6761a9eSAnand Jain 				     "%pU", fs_devs->fsid);
1740e3277335STobin C. Harding 	if (error) {
1741e3277335STobin C. Harding 		kobject_put(&fs_devs->fsid_kobj);
174272059215SAnand Jain 		return error;
174372059215SAnand Jain 	}
174472059215SAnand Jain 
1745bc036bb3SAnand Jain 	fs_devs->devices_kobj = kobject_create_and_add("devices",
1746bc036bb3SAnand Jain 						       &fs_devs->fsid_kobj);
1747bc036bb3SAnand Jain 	if (!fs_devs->devices_kobj) {
1748bc036bb3SAnand Jain 		btrfs_err(fs_devs->fs_info,
1749bc036bb3SAnand Jain 			  "failed to init sysfs device interface");
17501f6087e6SAnand Jain 		btrfs_sysfs_remove_fsid(fs_devs);
1751bc036bb3SAnand Jain 		return -ENOMEM;
1752bc036bb3SAnand Jain 	}
1753bc036bb3SAnand Jain 
1754a013d141SAnand Jain 	fs_devs->devinfo_kobj = kobject_create_and_add("devinfo",
1755a013d141SAnand Jain 						       &fs_devs->fsid_kobj);
1756a013d141SAnand Jain 	if (!fs_devs->devinfo_kobj) {
1757a013d141SAnand Jain 		btrfs_err(fs_devs->fs_info,
1758a013d141SAnand Jain 			  "failed to init sysfs devinfo kobject");
1759a013d141SAnand Jain 		btrfs_sysfs_remove_fsid(fs_devs);
1760a013d141SAnand Jain 		return -ENOMEM;
1761a013d141SAnand Jain 	}
1762a013d141SAnand Jain 
1763e3277335STobin C. Harding 	return 0;
1764e3277335STobin C. Harding }
1765e3277335STobin C. Harding 
176696f3136eSAnand Jain int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info)
176772059215SAnand Jain {
176872059215SAnand Jain 	int error;
17692e7910d6SAnand Jain 	struct btrfs_fs_devices *fs_devs = fs_info->fs_devices;
1770c1b7e474SAnand Jain 	struct kobject *fsid_kobj = &fs_devs->fsid_kobj;
177172059215SAnand Jain 
1772cd36da2eSAnand Jain 	error = btrfs_sysfs_add_fs_devices(fs_devs);
1773e453d989SJeff Mahoney 	if (error)
1774e453d989SJeff Mahoney 		return error;
1775510d7360SJeff Mahoney 
1776c1b7e474SAnand Jain 	error = sysfs_create_files(fsid_kobj, btrfs_attrs);
1777e453d989SJeff Mahoney 	if (error) {
177853f8a74cSAnand Jain 		btrfs_sysfs_remove_fs_devices(fs_devs);
1779e453d989SJeff Mahoney 		return error;
1780e453d989SJeff Mahoney 	}
178179da4fa4SJeff Mahoney 
1782c1b7e474SAnand Jain 	error = sysfs_create_group(fsid_kobj,
17830dd2906fSAnand Jain 				   &btrfs_feature_attr_group);
17840dd2906fSAnand Jain 	if (error)
17850dd2906fSAnand Jain 		goto failure;
17860dd2906fSAnand Jain 
17876e369febSDavid Sterba #ifdef CONFIG_BTRFS_DEBUG
178893945cb4SDennis Zhou 	fs_info->debug_kobj = kobject_create_and_add("debug", fsid_kobj);
178993945cb4SDennis Zhou 	if (!fs_info->debug_kobj) {
179093945cb4SDennis Zhou 		error = -ENOMEM;
179193945cb4SDennis Zhou 		goto failure;
179293945cb4SDennis Zhou 	}
179393945cb4SDennis Zhou 
179493945cb4SDennis Zhou 	error = sysfs_create_files(fs_info->debug_kobj, btrfs_debug_mount_attrs);
17956e369febSDavid Sterba 	if (error)
17966e369febSDavid Sterba 		goto failure;
1797e4faab84SDennis Zhou 
1798e4faab84SDennis Zhou 	/* Discard directory */
1799e4faab84SDennis Zhou 	fs_info->discard_debug_kobj = kobject_create_and_add("discard",
1800e4faab84SDennis Zhou 						     fs_info->debug_kobj);
1801e4faab84SDennis Zhou 	if (!fs_info->discard_debug_kobj) {
1802e4faab84SDennis Zhou 		error = -ENOMEM;
1803e4faab84SDennis Zhou 		goto failure;
1804e4faab84SDennis Zhou 	}
1805e4faab84SDennis Zhou 
1806e4faab84SDennis Zhou 	error = sysfs_create_files(fs_info->discard_debug_kobj,
1807e4faab84SDennis Zhou 				   discard_debug_attrs);
1808e4faab84SDennis Zhou 	if (error)
1809e4faab84SDennis Zhou 		goto failure;
18106e369febSDavid Sterba #endif
18116e369febSDavid Sterba 
1812e453d989SJeff Mahoney 	error = addrm_unknown_feature_attrs(fs_info, true);
181379da4fa4SJeff Mahoney 	if (error)
181479da4fa4SJeff Mahoney 		goto failure;
181579da4fa4SJeff Mahoney 
18163092c68fSNikolay Borisov 	error = sysfs_create_link(fsid_kobj, &fs_info->sb->s_bdi->dev->kobj, "bdi");
18173092c68fSNikolay Borisov 	if (error)
18183092c68fSNikolay Borisov 		goto failure;
18193092c68fSNikolay Borisov 
18206ab0a202SJeff Mahoney 	fs_info->space_info_kobj = kobject_create_and_add("allocation",
1821c1b7e474SAnand Jain 						  fsid_kobj);
18226ab0a202SJeff Mahoney 	if (!fs_info->space_info_kobj) {
18236ab0a202SJeff Mahoney 		error = -ENOMEM;
18246ab0a202SJeff Mahoney 		goto failure;
18256ab0a202SJeff Mahoney 	}
18266ab0a202SJeff Mahoney 
18276ab0a202SJeff Mahoney 	error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs);
18286ab0a202SJeff Mahoney 	if (error)
18296ab0a202SJeff Mahoney 		goto failure;
18306ab0a202SJeff Mahoney 
183179da4fa4SJeff Mahoney 	return 0;
183279da4fa4SJeff Mahoney failure:
18336618a59bSAnand Jain 	btrfs_sysfs_remove_mounted(fs_info);
18345ac1d209SJeff Mahoney 	return error;
18355ac1d209SJeff Mahoney }
18365ac1d209SJeff Mahoney 
183749e5fb46SQu Wenruo static inline struct btrfs_fs_info *qgroup_kobj_to_fs_info(struct kobject *kobj)
183849e5fb46SQu Wenruo {
183949e5fb46SQu Wenruo 	return to_fs_info(kobj->parent->parent);
184049e5fb46SQu Wenruo }
184149e5fb46SQu Wenruo 
184249e5fb46SQu Wenruo #define QGROUP_ATTR(_member, _show_name)					\
184349e5fb46SQu Wenruo static ssize_t btrfs_qgroup_show_##_member(struct kobject *qgroup_kobj,		\
184449e5fb46SQu Wenruo 					   struct kobj_attribute *a,		\
184549e5fb46SQu Wenruo 					   char *buf)				\
184649e5fb46SQu Wenruo {										\
184749e5fb46SQu Wenruo 	struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj);	\
184849e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(qgroup_kobj,			\
184949e5fb46SQu Wenruo 			struct btrfs_qgroup, kobj);				\
185049e5fb46SQu Wenruo 	return btrfs_show_u64(&qgroup->_member, &fs_info->qgroup_lock, buf);	\
185149e5fb46SQu Wenruo }										\
185249e5fb46SQu Wenruo BTRFS_ATTR(qgroup, _show_name, btrfs_qgroup_show_##_member)
185349e5fb46SQu Wenruo 
185449e5fb46SQu Wenruo #define QGROUP_RSV_ATTR(_name, _type)						\
185549e5fb46SQu Wenruo static ssize_t btrfs_qgroup_rsv_show_##_name(struct kobject *qgroup_kobj,	\
185649e5fb46SQu Wenruo 					     struct kobj_attribute *a,		\
185749e5fb46SQu Wenruo 					     char *buf)				\
185849e5fb46SQu Wenruo {										\
185949e5fb46SQu Wenruo 	struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj);	\
186049e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(qgroup_kobj,			\
186149e5fb46SQu Wenruo 			struct btrfs_qgroup, kobj);				\
186249e5fb46SQu Wenruo 	return btrfs_show_u64(&qgroup->rsv.values[_type],			\
186349e5fb46SQu Wenruo 			&fs_info->qgroup_lock, buf);				\
186449e5fb46SQu Wenruo }										\
186549e5fb46SQu Wenruo BTRFS_ATTR(qgroup, rsv_##_name, btrfs_qgroup_rsv_show_##_name)
186649e5fb46SQu Wenruo 
186749e5fb46SQu Wenruo QGROUP_ATTR(rfer, referenced);
186849e5fb46SQu Wenruo QGROUP_ATTR(excl, exclusive);
186949e5fb46SQu Wenruo QGROUP_ATTR(max_rfer, max_referenced);
187049e5fb46SQu Wenruo QGROUP_ATTR(max_excl, max_exclusive);
187149e5fb46SQu Wenruo QGROUP_ATTR(lim_flags, limit_flags);
187249e5fb46SQu Wenruo QGROUP_RSV_ATTR(data, BTRFS_QGROUP_RSV_DATA);
187349e5fb46SQu Wenruo QGROUP_RSV_ATTR(meta_pertrans, BTRFS_QGROUP_RSV_META_PERTRANS);
187449e5fb46SQu Wenruo QGROUP_RSV_ATTR(meta_prealloc, BTRFS_QGROUP_RSV_META_PREALLOC);
187549e5fb46SQu Wenruo 
1876e7849e33SAnand Jain /*
1877e7849e33SAnand Jain  * Qgroup information.
1878e7849e33SAnand Jain  *
1879e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/qgroups/<level>_<qgroupid>/
1880e7849e33SAnand Jain  */
188149e5fb46SQu Wenruo static struct attribute *qgroup_attrs[] = {
188249e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, referenced),
188349e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, exclusive),
188449e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, max_referenced),
188549e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, max_exclusive),
188649e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, limit_flags),
188749e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_data),
188849e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_meta_pertrans),
188949e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_meta_prealloc),
189049e5fb46SQu Wenruo 	NULL
189149e5fb46SQu Wenruo };
189249e5fb46SQu Wenruo ATTRIBUTE_GROUPS(qgroup);
189349e5fb46SQu Wenruo 
189449e5fb46SQu Wenruo static void qgroup_release(struct kobject *kobj)
189549e5fb46SQu Wenruo {
189649e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(kobj, struct btrfs_qgroup, kobj);
189749e5fb46SQu Wenruo 
189849e5fb46SQu Wenruo 	memset(&qgroup->kobj, 0, sizeof(*kobj));
189949e5fb46SQu Wenruo }
190049e5fb46SQu Wenruo 
190149e5fb46SQu Wenruo static struct kobj_type qgroup_ktype = {
190249e5fb46SQu Wenruo 	.sysfs_ops = &kobj_sysfs_ops,
190349e5fb46SQu Wenruo 	.release = qgroup_release,
190449e5fb46SQu Wenruo 	.default_groups = qgroup_groups,
190549e5fb46SQu Wenruo };
190649e5fb46SQu Wenruo 
190749e5fb46SQu Wenruo int btrfs_sysfs_add_one_qgroup(struct btrfs_fs_info *fs_info,
190849e5fb46SQu Wenruo 				struct btrfs_qgroup *qgroup)
190949e5fb46SQu Wenruo {
191049e5fb46SQu Wenruo 	struct kobject *qgroups_kobj = fs_info->qgroups_kobj;
191149e5fb46SQu Wenruo 	int ret;
191249e5fb46SQu Wenruo 
191349e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
191449e5fb46SQu Wenruo 		return 0;
191549e5fb46SQu Wenruo 	if (qgroup->kobj.state_initialized)
191649e5fb46SQu Wenruo 		return 0;
191749e5fb46SQu Wenruo 	if (!qgroups_kobj)
191849e5fb46SQu Wenruo 		return -EINVAL;
191949e5fb46SQu Wenruo 
192049e5fb46SQu Wenruo 	ret = kobject_init_and_add(&qgroup->kobj, &qgroup_ktype, qgroups_kobj,
192149e5fb46SQu Wenruo 			"%hu_%llu", btrfs_qgroup_level(qgroup->qgroupid),
192249e5fb46SQu Wenruo 			btrfs_qgroup_subvolid(qgroup->qgroupid));
192349e5fb46SQu Wenruo 	if (ret < 0)
192449e5fb46SQu Wenruo 		kobject_put(&qgroup->kobj);
192549e5fb46SQu Wenruo 
192649e5fb46SQu Wenruo 	return ret;
192749e5fb46SQu Wenruo }
192849e5fb46SQu Wenruo 
192949e5fb46SQu Wenruo void btrfs_sysfs_del_qgroups(struct btrfs_fs_info *fs_info)
193049e5fb46SQu Wenruo {
193149e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup;
193249e5fb46SQu Wenruo 	struct btrfs_qgroup *next;
193349e5fb46SQu Wenruo 
193449e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
193549e5fb46SQu Wenruo 		return;
193649e5fb46SQu Wenruo 
193749e5fb46SQu Wenruo 	rbtree_postorder_for_each_entry_safe(qgroup, next,
193849e5fb46SQu Wenruo 					     &fs_info->qgroup_tree, node)
193949e5fb46SQu Wenruo 		btrfs_sysfs_del_one_qgroup(fs_info, qgroup);
194062ab2cc0SQu Wenruo 	if (fs_info->qgroups_kobj) {
194149e5fb46SQu Wenruo 		kobject_del(fs_info->qgroups_kobj);
194249e5fb46SQu Wenruo 		kobject_put(fs_info->qgroups_kobj);
194349e5fb46SQu Wenruo 		fs_info->qgroups_kobj = NULL;
194449e5fb46SQu Wenruo 	}
194562ab2cc0SQu Wenruo }
194649e5fb46SQu Wenruo 
194749e5fb46SQu Wenruo /* Called when qgroups get initialized, thus there is no need for locking */
194849e5fb46SQu Wenruo int btrfs_sysfs_add_qgroups(struct btrfs_fs_info *fs_info)
194949e5fb46SQu Wenruo {
195049e5fb46SQu Wenruo 	struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj;
195149e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup;
195249e5fb46SQu Wenruo 	struct btrfs_qgroup *next;
195349e5fb46SQu Wenruo 	int ret = 0;
195449e5fb46SQu Wenruo 
195549e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
195649e5fb46SQu Wenruo 		return 0;
195749e5fb46SQu Wenruo 
195849e5fb46SQu Wenruo 	ASSERT(fsid_kobj);
195949e5fb46SQu Wenruo 	if (fs_info->qgroups_kobj)
196049e5fb46SQu Wenruo 		return 0;
196149e5fb46SQu Wenruo 
196249e5fb46SQu Wenruo 	fs_info->qgroups_kobj = kobject_create_and_add("qgroups", fsid_kobj);
196349e5fb46SQu Wenruo 	if (!fs_info->qgroups_kobj) {
196449e5fb46SQu Wenruo 		ret = -ENOMEM;
196549e5fb46SQu Wenruo 		goto out;
196649e5fb46SQu Wenruo 	}
196749e5fb46SQu Wenruo 	rbtree_postorder_for_each_entry_safe(qgroup, next,
196849e5fb46SQu Wenruo 					     &fs_info->qgroup_tree, node) {
196949e5fb46SQu Wenruo 		ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
197049e5fb46SQu Wenruo 		if (ret < 0)
197149e5fb46SQu Wenruo 			goto out;
197249e5fb46SQu Wenruo 	}
197349e5fb46SQu Wenruo 
197449e5fb46SQu Wenruo out:
197549e5fb46SQu Wenruo 	if (ret < 0)
197649e5fb46SQu Wenruo 		btrfs_sysfs_del_qgroups(fs_info);
197749e5fb46SQu Wenruo 	return ret;
197849e5fb46SQu Wenruo }
197949e5fb46SQu Wenruo 
198049e5fb46SQu Wenruo void btrfs_sysfs_del_one_qgroup(struct btrfs_fs_info *fs_info,
198149e5fb46SQu Wenruo 				struct btrfs_qgroup *qgroup)
198249e5fb46SQu Wenruo {
198349e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
198449e5fb46SQu Wenruo 		return;
198549e5fb46SQu Wenruo 
198649e5fb46SQu Wenruo 	if (qgroup->kobj.state_initialized) {
198749e5fb46SQu Wenruo 		kobject_del(&qgroup->kobj);
198849e5fb46SQu Wenruo 		kobject_put(&qgroup->kobj);
198949e5fb46SQu Wenruo 	}
199049e5fb46SQu Wenruo }
1991444e7516SDavid Sterba 
1992444e7516SDavid Sterba /*
1993444e7516SDavid Sterba  * Change per-fs features in /sys/fs/btrfs/UUID/features to match current
1994444e7516SDavid Sterba  * values in superblock. Call after any changes to incompat/compat_ro flags
1995444e7516SDavid Sterba  */
1996444e7516SDavid Sterba void btrfs_sysfs_feature_update(struct btrfs_fs_info *fs_info,
1997444e7516SDavid Sterba 		u64 bit, enum btrfs_feature_set set)
1998444e7516SDavid Sterba {
1999444e7516SDavid Sterba 	struct btrfs_fs_devices *fs_devs;
2000444e7516SDavid Sterba 	struct kobject *fsid_kobj;
200124646481SLeon Romanovsky 	u64 __maybe_unused features;
200224646481SLeon Romanovsky 	int __maybe_unused ret;
2003444e7516SDavid Sterba 
2004444e7516SDavid Sterba 	if (!fs_info)
2005444e7516SDavid Sterba 		return;
2006444e7516SDavid Sterba 
200724646481SLeon Romanovsky 	/*
200824646481SLeon Romanovsky 	 * See 14e46e04958df74 and e410e34fad913dd, feature bit updates are not
200924646481SLeon Romanovsky 	 * safe when called from some contexts (eg. balance)
201024646481SLeon Romanovsky 	 */
2011444e7516SDavid Sterba 	features = get_features(fs_info, set);
2012444e7516SDavid Sterba 	ASSERT(bit & supported_feature_masks[set]);
2013444e7516SDavid Sterba 
2014444e7516SDavid Sterba 	fs_devs = fs_info->fs_devices;
2015444e7516SDavid Sterba 	fsid_kobj = &fs_devs->fsid_kobj;
2016444e7516SDavid Sterba 
2017bf609206SDavid Sterba 	if (!fsid_kobj->state_initialized)
2018bf609206SDavid Sterba 		return;
2019bf609206SDavid Sterba 
2020444e7516SDavid Sterba 	/*
2021444e7516SDavid Sterba 	 * FIXME: this is too heavy to update just one value, ideally we'd like
2022444e7516SDavid Sterba 	 * to use sysfs_update_group but some refactoring is needed first.
2023444e7516SDavid Sterba 	 */
2024444e7516SDavid Sterba 	sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group);
2025444e7516SDavid Sterba 	ret = sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group);
2026444e7516SDavid Sterba }
2027444e7516SDavid Sterba 
2028f5c29bd9SLiu Bo int __init btrfs_init_sysfs(void)
202958176a96SJosef Bacik {
2030079b72bcSJeff Mahoney 	int ret;
20311bae3098SDavid Sterba 
2032e3fe4e71SGreg KH 	btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
2033e3fe4e71SGreg KH 	if (!btrfs_kset)
2034e3fe4e71SGreg KH 		return -ENOMEM;
2035079b72bcSJeff Mahoney 
20361bae3098SDavid Sterba 	init_feature_attrs();
20371bae3098SDavid Sterba 	ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
2038001a648dSFilipe Manana 	if (ret)
2039001a648dSFilipe Manana 		goto out2;
2040f902bd3aSMisono Tomohiro 	ret = sysfs_merge_group(&btrfs_kset->kobj,
2041f902bd3aSMisono Tomohiro 				&btrfs_static_feature_attr_group);
2042f902bd3aSMisono Tomohiro 	if (ret)
2043f902bd3aSMisono Tomohiro 		goto out_remove_group;
2044001a648dSFilipe Manana 
20456e369febSDavid Sterba #ifdef CONFIG_BTRFS_DEBUG
20466e369febSDavid Sterba 	ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group);
20476e369febSDavid Sterba 	if (ret)
20486e369febSDavid Sterba 		goto out2;
20496e369febSDavid Sterba #endif
20506e369febSDavid Sterba 
2051001a648dSFilipe Manana 	return 0;
2052f902bd3aSMisono Tomohiro 
2053f902bd3aSMisono Tomohiro out_remove_group:
2054f902bd3aSMisono Tomohiro 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
2055001a648dSFilipe Manana out2:
2056001a648dSFilipe Manana 	kset_unregister(btrfs_kset);
20571bae3098SDavid Sterba 
20581bae3098SDavid Sterba 	return ret;
205958176a96SJosef Bacik }
206058176a96SJosef Bacik 
2061e67c718bSDavid Sterba void __cold btrfs_exit_sysfs(void)
206258176a96SJosef Bacik {
2063f902bd3aSMisono Tomohiro 	sysfs_unmerge_group(&btrfs_kset->kobj,
2064f902bd3aSMisono Tomohiro 			    &btrfs_static_feature_attr_group);
2065079b72bcSJeff Mahoney 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
206671e8978eSDennis Zhou #ifdef CONFIG_BTRFS_DEBUG
206771e8978eSDennis Zhou 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group);
206871e8978eSDennis Zhou #endif
2069e3fe4e71SGreg KH 	kset_unregister(btrfs_kset);
207058176a96SJosef Bacik }
207155d47414SChris Mason 
2072