xref: /openbmc/linux/fs/btrfs/sysfs.c (revision 020e5277)
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 
180*020e5277SAnand 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 /* Remove once support for zoned allocation is feature complete */
2877b3d5a90SNaohiro Aota #ifdef CONFIG_BTRFS_DEBUG
2887b3d5a90SNaohiro Aota BTRFS_FEAT_ATTR_INCOMPAT(zoned, ZONED);
2897b3d5a90SNaohiro Aota #endif
29014605409SBoris Burkov #ifdef CONFIG_FS_VERITY
29114605409SBoris Burkov BTRFS_FEAT_ATTR_COMPAT_RO(verity, VERITY);
29214605409SBoris Burkov #endif
293079b72bcSJeff Mahoney 
294e7849e33SAnand Jain /*
295e7849e33SAnand Jain  * Features which depend on feature bits and may differ between each fs.
296e7849e33SAnand Jain  *
297e7849e33SAnand Jain  * /sys/fs/btrfs/features      - all available features implemeted by this version
298e7849e33SAnand Jain  * /sys/fs/btrfs/UUID/features - features of the fs which are enabled or
299e7849e33SAnand Jain  *                               can be changed on a mounted filesystem.
300e7849e33SAnand Jain  */
301079b72bcSJeff Mahoney static struct attribute *btrfs_supported_feature_attrs[] = {
302079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(mixed_backref),
303079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(default_subvol),
304079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(mixed_groups),
305079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(compress_lzo),
3065c1aab1dSNick Terrell 	BTRFS_FEAT_ATTR_PTR(compress_zstd),
307079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(big_metadata),
308079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(extended_iref),
309079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(raid56),
310079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(skinny_metadata),
311c736c095SDavid Sterba 	BTRFS_FEAT_ATTR_PTR(no_holes),
31256f20f40SNikolay Borisov 	BTRFS_FEAT_ATTR_PTR(metadata_uuid),
3133b5bb73bSDavid Sterba 	BTRFS_FEAT_ATTR_PTR(free_space_tree),
314cfbb825cSDavid Sterba 	BTRFS_FEAT_ATTR_PTR(raid1c34),
3157b3d5a90SNaohiro Aota #ifdef CONFIG_BTRFS_DEBUG
3167b3d5a90SNaohiro Aota 	BTRFS_FEAT_ATTR_PTR(zoned),
3177b3d5a90SNaohiro Aota #endif
31814605409SBoris Burkov #ifdef CONFIG_FS_VERITY
31914605409SBoris Burkov 	BTRFS_FEAT_ATTR_PTR(verity),
32014605409SBoris Burkov #endif
321079b72bcSJeff Mahoney 	NULL
322079b72bcSJeff Mahoney };
323079b72bcSJeff Mahoney 
324079b72bcSJeff Mahoney static const struct attribute_group btrfs_feature_attr_group = {
325079b72bcSJeff Mahoney 	.name = "features",
326510d7360SJeff Mahoney 	.is_visible = btrfs_feature_visible,
327079b72bcSJeff Mahoney 	.attrs = btrfs_supported_feature_attrs,
328079b72bcSJeff Mahoney };
32958176a96SJosef Bacik 
330f902bd3aSMisono Tomohiro static ssize_t rmdir_subvol_show(struct kobject *kobj,
331f902bd3aSMisono Tomohiro 				 struct kobj_attribute *ka, char *buf)
332f902bd3aSMisono Tomohiro {
333*020e5277SAnand Jain 	return sysfs_emit(buf, "0\n");
334f902bd3aSMisono Tomohiro }
335f902bd3aSMisono Tomohiro BTRFS_ATTR(static_feature, rmdir_subvol, rmdir_subvol_show);
336f902bd3aSMisono Tomohiro 
337f7cea56cSDavid Sterba static ssize_t supported_checksums_show(struct kobject *kobj,
338f7cea56cSDavid Sterba 					struct kobj_attribute *a, char *buf)
339f7cea56cSDavid Sterba {
340f7cea56cSDavid Sterba 	ssize_t ret = 0;
341f7cea56cSDavid Sterba 	int i;
342f7cea56cSDavid Sterba 
343f7cea56cSDavid Sterba 	for (i = 0; i < btrfs_get_num_csums(); i++) {
344f7cea56cSDavid Sterba 		/*
345f7cea56cSDavid Sterba 		 * This "trick" only works as long as 'enum btrfs_csum_type' has
346f7cea56cSDavid Sterba 		 * no holes in it
347f7cea56cSDavid Sterba 		 */
348*020e5277SAnand Jain 		ret += sysfs_emit_at(buf, ret, "%s%s", (i == 0 ? "" : " "),
349*020e5277SAnand Jain 				     btrfs_super_csum_name(i));
350f7cea56cSDavid Sterba 
351f7cea56cSDavid Sterba 	}
352f7cea56cSDavid Sterba 
353*020e5277SAnand Jain 	ret += sysfs_emit_at(buf, ret, "\n");
354f7cea56cSDavid Sterba 	return ret;
355f7cea56cSDavid Sterba }
356f7cea56cSDavid Sterba BTRFS_ATTR(static_feature, supported_checksums, supported_checksums_show);
357f7cea56cSDavid Sterba 
3587573df55SOmar Sandoval static ssize_t send_stream_version_show(struct kobject *kobj,
3597573df55SOmar Sandoval 					struct kobj_attribute *ka, char *buf)
3607573df55SOmar Sandoval {
361*020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", BTRFS_SEND_STREAM_VERSION);
3627573df55SOmar Sandoval }
3637573df55SOmar Sandoval BTRFS_ATTR(static_feature, send_stream_version, send_stream_version_show);
3647573df55SOmar Sandoval 
365ceafe3ccSJosef Bacik static const char *rescue_opts[] = {
366ceafe3ccSJosef Bacik 	"usebackuproot",
367ceafe3ccSJosef Bacik 	"nologreplay",
36842437a63SJosef Bacik 	"ignorebadroots",
369882dbe0cSJosef Bacik 	"ignoredatacsums",
3709037d3cbSJosef Bacik 	"all",
371ceafe3ccSJosef Bacik };
372ceafe3ccSJosef Bacik 
373ceafe3ccSJosef Bacik static ssize_t supported_rescue_options_show(struct kobject *kobj,
374ceafe3ccSJosef Bacik 					     struct kobj_attribute *a,
375ceafe3ccSJosef Bacik 					     char *buf)
376ceafe3ccSJosef Bacik {
377ceafe3ccSJosef Bacik 	ssize_t ret = 0;
378ceafe3ccSJosef Bacik 	int i;
379ceafe3ccSJosef Bacik 
380ceafe3ccSJosef Bacik 	for (i = 0; i < ARRAY_SIZE(rescue_opts); i++)
381*020e5277SAnand Jain 		ret += sysfs_emit_at(buf, ret, "%s%s", (i ? " " : ""), rescue_opts[i]);
382*020e5277SAnand Jain 	ret += sysfs_emit_at(buf, ret, "\n");
383ceafe3ccSJosef Bacik 	return ret;
384ceafe3ccSJosef Bacik }
385ceafe3ccSJosef Bacik BTRFS_ATTR(static_feature, supported_rescue_options,
386ceafe3ccSJosef Bacik 	   supported_rescue_options_show);
387ceafe3ccSJosef Bacik 
388fc57ad8dSQu Wenruo static ssize_t supported_sectorsizes_show(struct kobject *kobj,
389fc57ad8dSQu Wenruo 					  struct kobj_attribute *a,
390fc57ad8dSQu Wenruo 					  char *buf)
391fc57ad8dSQu Wenruo {
392fc57ad8dSQu Wenruo 	ssize_t ret = 0;
393fc57ad8dSQu Wenruo 
39495ea0486SQu Wenruo 	/* 4K sector size is also supported with 64K page size */
39595ea0486SQu Wenruo 	if (PAGE_SIZE == SZ_64K)
396*020e5277SAnand Jain 		ret += sysfs_emit_at(buf, ret, "%u ", SZ_4K);
39795ea0486SQu Wenruo 
398fc57ad8dSQu Wenruo 	/* Only sectorsize == PAGE_SIZE is now supported */
399*020e5277SAnand Jain 	ret += sysfs_emit_at(buf, ret, "%lu\n", PAGE_SIZE);
400fc57ad8dSQu Wenruo 
401fc57ad8dSQu Wenruo 	return ret;
402fc57ad8dSQu Wenruo }
403fc57ad8dSQu Wenruo BTRFS_ATTR(static_feature, supported_sectorsizes,
404fc57ad8dSQu Wenruo 	   supported_sectorsizes_show);
405fc57ad8dSQu Wenruo 
406e7849e33SAnand Jain /*
407e7849e33SAnand Jain  * Features which only depend on kernel version.
408e7849e33SAnand Jain  *
409e7849e33SAnand Jain  * These are listed in /sys/fs/btrfs/features along with
410e7849e33SAnand Jain  * btrfs_supported_feature_attrs.
411e7849e33SAnand Jain  */
412f902bd3aSMisono Tomohiro static struct attribute *btrfs_supported_static_feature_attrs[] = {
413f902bd3aSMisono Tomohiro 	BTRFS_ATTR_PTR(static_feature, rmdir_subvol),
414f7cea56cSDavid Sterba 	BTRFS_ATTR_PTR(static_feature, supported_checksums),
4157573df55SOmar Sandoval 	BTRFS_ATTR_PTR(static_feature, send_stream_version),
416ceafe3ccSJosef Bacik 	BTRFS_ATTR_PTR(static_feature, supported_rescue_options),
417fc57ad8dSQu Wenruo 	BTRFS_ATTR_PTR(static_feature, supported_sectorsizes),
418f902bd3aSMisono Tomohiro 	NULL
419f902bd3aSMisono Tomohiro };
420f902bd3aSMisono Tomohiro 
421f902bd3aSMisono Tomohiro static const struct attribute_group btrfs_static_feature_attr_group = {
422f902bd3aSMisono Tomohiro 	.name = "features",
423f902bd3aSMisono Tomohiro 	.attrs = btrfs_supported_static_feature_attrs,
424f902bd3aSMisono Tomohiro };
425f902bd3aSMisono Tomohiro 
4266e369febSDavid Sterba #ifdef CONFIG_BTRFS_DEBUG
4276e369febSDavid Sterba 
4286e369febSDavid Sterba /*
429e4faab84SDennis Zhou  * Discard statistics and tunables
430e4faab84SDennis Zhou  */
431dfb79ddbSDennis Zhou #define discard_to_fs_info(_kobj)	to_fs_info((_kobj)->parent->parent)
432dfb79ddbSDennis Zhou 
4335dc7c10bSDennis Zhou static ssize_t btrfs_discardable_bytes_show(struct kobject *kobj,
4345dc7c10bSDennis Zhou 					    struct kobj_attribute *a,
4355dc7c10bSDennis Zhou 					    char *buf)
4365dc7c10bSDennis Zhou {
4375dc7c10bSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4385dc7c10bSDennis Zhou 
439*020e5277SAnand Jain 	return sysfs_emit(buf, "%lld\n",
4405dc7c10bSDennis Zhou 			atomic64_read(&fs_info->discard_ctl.discardable_bytes));
4415dc7c10bSDennis Zhou }
4425dc7c10bSDennis Zhou BTRFS_ATTR(discard, discardable_bytes, btrfs_discardable_bytes_show);
4435dc7c10bSDennis Zhou 
444dfb79ddbSDennis Zhou static ssize_t btrfs_discardable_extents_show(struct kobject *kobj,
445dfb79ddbSDennis Zhou 					      struct kobj_attribute *a,
446dfb79ddbSDennis Zhou 					      char *buf)
447dfb79ddbSDennis Zhou {
448dfb79ddbSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
449dfb79ddbSDennis Zhou 
450*020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n",
451dfb79ddbSDennis Zhou 			atomic_read(&fs_info->discard_ctl.discardable_extents));
452dfb79ddbSDennis Zhou }
453dfb79ddbSDennis Zhou BTRFS_ATTR(discard, discardable_extents, btrfs_discardable_extents_show);
454dfb79ddbSDennis Zhou 
4559ddf648fSDennis Zhou static ssize_t btrfs_discard_bitmap_bytes_show(struct kobject *kobj,
4569ddf648fSDennis Zhou 					       struct kobj_attribute *a,
4579ddf648fSDennis Zhou 					       char *buf)
4589ddf648fSDennis Zhou {
4599ddf648fSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4609ddf648fSDennis Zhou 
461*020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n",
4629ddf648fSDennis Zhou 			  fs_info->discard_ctl.discard_bitmap_bytes);
4639ddf648fSDennis Zhou }
4649ddf648fSDennis Zhou BTRFS_ATTR(discard, discard_bitmap_bytes, btrfs_discard_bitmap_bytes_show);
4659ddf648fSDennis Zhou 
4669ddf648fSDennis Zhou static ssize_t btrfs_discard_bytes_saved_show(struct kobject *kobj,
4679ddf648fSDennis Zhou 					      struct kobj_attribute *a,
4689ddf648fSDennis Zhou 					      char *buf)
4699ddf648fSDennis Zhou {
4709ddf648fSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4719ddf648fSDennis Zhou 
472*020e5277SAnand Jain 	return sysfs_emit(buf, "%lld\n",
4739ddf648fSDennis Zhou 		atomic64_read(&fs_info->discard_ctl.discard_bytes_saved));
4749ddf648fSDennis Zhou }
4759ddf648fSDennis Zhou BTRFS_ATTR(discard, discard_bytes_saved, btrfs_discard_bytes_saved_show);
4769ddf648fSDennis Zhou 
4779ddf648fSDennis Zhou static ssize_t btrfs_discard_extent_bytes_show(struct kobject *kobj,
4789ddf648fSDennis Zhou 					       struct kobj_attribute *a,
4799ddf648fSDennis Zhou 					       char *buf)
4809ddf648fSDennis Zhou {
4819ddf648fSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4829ddf648fSDennis Zhou 
483*020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n",
4849ddf648fSDennis Zhou 			  fs_info->discard_ctl.discard_extent_bytes);
4859ddf648fSDennis Zhou }
4869ddf648fSDennis Zhou BTRFS_ATTR(discard, discard_extent_bytes, btrfs_discard_extent_bytes_show);
4879ddf648fSDennis Zhou 
488a2309300SDennis Zhou static ssize_t btrfs_discard_iops_limit_show(struct kobject *kobj,
489a2309300SDennis Zhou 					     struct kobj_attribute *a,
490a2309300SDennis Zhou 					     char *buf)
491a2309300SDennis Zhou {
492a2309300SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
493a2309300SDennis Zhou 
494*020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n",
495a2309300SDennis Zhou 			  READ_ONCE(fs_info->discard_ctl.iops_limit));
496a2309300SDennis Zhou }
497a2309300SDennis Zhou 
498a2309300SDennis Zhou static ssize_t btrfs_discard_iops_limit_store(struct kobject *kobj,
499a2309300SDennis Zhou 					      struct kobj_attribute *a,
500a2309300SDennis Zhou 					      const char *buf, size_t len)
501a2309300SDennis Zhou {
502a2309300SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
503a2309300SDennis Zhou 	struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl;
504a2309300SDennis Zhou 	u32 iops_limit;
505a2309300SDennis Zhou 	int ret;
506a2309300SDennis Zhou 
507a2309300SDennis Zhou 	ret = kstrtou32(buf, 10, &iops_limit);
508a2309300SDennis Zhou 	if (ret)
509a2309300SDennis Zhou 		return -EINVAL;
510a2309300SDennis Zhou 
511a2309300SDennis Zhou 	WRITE_ONCE(discard_ctl->iops_limit, iops_limit);
5123e48d8d2SPavel Begunkov 	btrfs_discard_calc_delay(discard_ctl);
5133e48d8d2SPavel Begunkov 	btrfs_discard_schedule_work(discard_ctl, true);
514a2309300SDennis Zhou 	return len;
515a2309300SDennis Zhou }
516a2309300SDennis Zhou BTRFS_ATTR_RW(discard, iops_limit, btrfs_discard_iops_limit_show,
517a2309300SDennis Zhou 	      btrfs_discard_iops_limit_store);
518a2309300SDennis Zhou 
519e93591bbSDennis Zhou static ssize_t btrfs_discard_kbps_limit_show(struct kobject *kobj,
520e93591bbSDennis Zhou 					     struct kobj_attribute *a,
521e93591bbSDennis Zhou 					     char *buf)
522e93591bbSDennis Zhou {
523e93591bbSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
524e93591bbSDennis Zhou 
525*020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n",
526e93591bbSDennis Zhou 			  READ_ONCE(fs_info->discard_ctl.kbps_limit));
527e93591bbSDennis Zhou }
528e93591bbSDennis Zhou 
529e93591bbSDennis Zhou static ssize_t btrfs_discard_kbps_limit_store(struct kobject *kobj,
530e93591bbSDennis Zhou 					      struct kobj_attribute *a,
531e93591bbSDennis Zhou 					      const char *buf, size_t len)
532e93591bbSDennis Zhou {
533e93591bbSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
534e93591bbSDennis Zhou 	struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl;
535e93591bbSDennis Zhou 	u32 kbps_limit;
536e93591bbSDennis Zhou 	int ret;
537e93591bbSDennis Zhou 
538e93591bbSDennis Zhou 	ret = kstrtou32(buf, 10, &kbps_limit);
539e93591bbSDennis Zhou 	if (ret)
540e93591bbSDennis Zhou 		return -EINVAL;
541e93591bbSDennis Zhou 
542e93591bbSDennis Zhou 	WRITE_ONCE(discard_ctl->kbps_limit, kbps_limit);
5433e48d8d2SPavel Begunkov 	btrfs_discard_schedule_work(discard_ctl, true);
544e93591bbSDennis Zhou 	return len;
545e93591bbSDennis Zhou }
546e93591bbSDennis Zhou BTRFS_ATTR_RW(discard, kbps_limit, btrfs_discard_kbps_limit_show,
547e93591bbSDennis Zhou 	      btrfs_discard_kbps_limit_store);
548e93591bbSDennis Zhou 
54919b2a2c7SDennis Zhou static ssize_t btrfs_discard_max_discard_size_show(struct kobject *kobj,
55019b2a2c7SDennis Zhou 						   struct kobj_attribute *a,
55119b2a2c7SDennis Zhou 						   char *buf)
55219b2a2c7SDennis Zhou {
55319b2a2c7SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
55419b2a2c7SDennis Zhou 
555*020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n",
55619b2a2c7SDennis Zhou 			  READ_ONCE(fs_info->discard_ctl.max_discard_size));
55719b2a2c7SDennis Zhou }
55819b2a2c7SDennis Zhou 
55919b2a2c7SDennis Zhou static ssize_t btrfs_discard_max_discard_size_store(struct kobject *kobj,
56019b2a2c7SDennis Zhou 						    struct kobj_attribute *a,
56119b2a2c7SDennis Zhou 						    const char *buf, size_t len)
56219b2a2c7SDennis Zhou {
56319b2a2c7SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
56419b2a2c7SDennis Zhou 	struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl;
56519b2a2c7SDennis Zhou 	u64 max_discard_size;
56619b2a2c7SDennis Zhou 	int ret;
56719b2a2c7SDennis Zhou 
56819b2a2c7SDennis Zhou 	ret = kstrtou64(buf, 10, &max_discard_size);
56919b2a2c7SDennis Zhou 	if (ret)
57019b2a2c7SDennis Zhou 		return -EINVAL;
57119b2a2c7SDennis Zhou 
57219b2a2c7SDennis Zhou 	WRITE_ONCE(discard_ctl->max_discard_size, max_discard_size);
57319b2a2c7SDennis Zhou 
57419b2a2c7SDennis Zhou 	return len;
57519b2a2c7SDennis Zhou }
57619b2a2c7SDennis Zhou BTRFS_ATTR_RW(discard, max_discard_size, btrfs_discard_max_discard_size_show,
57719b2a2c7SDennis Zhou 	      btrfs_discard_max_discard_size_store);
57819b2a2c7SDennis Zhou 
579e7849e33SAnand Jain /*
580e7849e33SAnand Jain  * Per-filesystem debugging of discard (when mounted with discard=async).
581e7849e33SAnand Jain  *
582e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/debug/discard/
583e7849e33SAnand Jain  */
584e4faab84SDennis Zhou static const struct attribute *discard_debug_attrs[] = {
5855dc7c10bSDennis Zhou 	BTRFS_ATTR_PTR(discard, discardable_bytes),
586dfb79ddbSDennis Zhou 	BTRFS_ATTR_PTR(discard, discardable_extents),
5879ddf648fSDennis Zhou 	BTRFS_ATTR_PTR(discard, discard_bitmap_bytes),
5889ddf648fSDennis Zhou 	BTRFS_ATTR_PTR(discard, discard_bytes_saved),
5899ddf648fSDennis Zhou 	BTRFS_ATTR_PTR(discard, discard_extent_bytes),
590a2309300SDennis Zhou 	BTRFS_ATTR_PTR(discard, iops_limit),
591e93591bbSDennis Zhou 	BTRFS_ATTR_PTR(discard, kbps_limit),
59219b2a2c7SDennis Zhou 	BTRFS_ATTR_PTR(discard, max_discard_size),
593e4faab84SDennis Zhou 	NULL,
594e4faab84SDennis Zhou };
595e4faab84SDennis Zhou 
596e4faab84SDennis Zhou /*
597e7849e33SAnand Jain  * Per-filesystem runtime debugging exported via sysfs.
5986e369febSDavid Sterba  *
599e7849e33SAnand Jain  * Path: /sys/fs/btrfs/UUID/debug/
6006e369febSDavid Sterba  */
60193945cb4SDennis Zhou static const struct attribute *btrfs_debug_mount_attrs[] = {
60293945cb4SDennis Zhou 	NULL,
60393945cb4SDennis Zhou };
60493945cb4SDennis Zhou 
605e7849e33SAnand Jain /*
606e7849e33SAnand Jain  * Runtime debugging exported via sysfs, applies to all mounted filesystems.
607e7849e33SAnand Jain  *
608e7849e33SAnand Jain  * Path: /sys/fs/btrfs/debug
609e7849e33SAnand Jain  */
6106e369febSDavid Sterba static struct attribute *btrfs_debug_feature_attrs[] = {
6116e369febSDavid Sterba 	NULL
6126e369febSDavid Sterba };
6136e369febSDavid Sterba 
6146e369febSDavid Sterba static const struct attribute_group btrfs_debug_feature_attr_group = {
6156e369febSDavid Sterba 	.name = "debug",
6166e369febSDavid Sterba 	.attrs = btrfs_debug_feature_attrs,
6176e369febSDavid Sterba };
6186e369febSDavid Sterba 
6196e369febSDavid Sterba #endif
6206e369febSDavid Sterba 
6216ab0a202SJeff Mahoney static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf)
6226ab0a202SJeff Mahoney {
6236ab0a202SJeff Mahoney 	u64 val;
6246ab0a202SJeff Mahoney 	if (lock)
6256ab0a202SJeff Mahoney 		spin_lock(lock);
6266ab0a202SJeff Mahoney 	val = *value_ptr;
6276ab0a202SJeff Mahoney 	if (lock)
6286ab0a202SJeff Mahoney 		spin_unlock(lock);
629*020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", val);
6306ab0a202SJeff Mahoney }
6316ab0a202SJeff Mahoney 
6326ab0a202SJeff Mahoney static ssize_t global_rsv_size_show(struct kobject *kobj,
6336ab0a202SJeff Mahoney 				    struct kobj_attribute *ka, char *buf)
6346ab0a202SJeff Mahoney {
6356ab0a202SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
6366ab0a202SJeff Mahoney 	struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
6376ab0a202SJeff Mahoney 	return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf);
6386ab0a202SJeff Mahoney }
639a969f4ccSHans van Kranenburg BTRFS_ATTR(allocation, global_rsv_size, global_rsv_size_show);
6406ab0a202SJeff Mahoney 
6416ab0a202SJeff Mahoney static ssize_t global_rsv_reserved_show(struct kobject *kobj,
6426ab0a202SJeff Mahoney 					struct kobj_attribute *a, char *buf)
6436ab0a202SJeff Mahoney {
6446ab0a202SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
6456ab0a202SJeff Mahoney 	struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
6466ab0a202SJeff Mahoney 	return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf);
6476ab0a202SJeff Mahoney }
648a969f4ccSHans van Kranenburg BTRFS_ATTR(allocation, global_rsv_reserved, global_rsv_reserved_show);
6496ab0a202SJeff Mahoney 
6506ab0a202SJeff Mahoney #define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj)
651c1895442SJeff Mahoney #define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj)
6526ab0a202SJeff Mahoney 
6536ab0a202SJeff Mahoney static ssize_t raid_bytes_show(struct kobject *kobj,
6546ab0a202SJeff Mahoney 			       struct kobj_attribute *attr, char *buf);
655a969f4ccSHans van Kranenburg BTRFS_ATTR(raid, total_bytes, raid_bytes_show);
656a969f4ccSHans van Kranenburg BTRFS_ATTR(raid, used_bytes, raid_bytes_show);
6576ab0a202SJeff Mahoney 
6586ab0a202SJeff Mahoney static ssize_t raid_bytes_show(struct kobject *kobj,
6596ab0a202SJeff Mahoney 			       struct kobj_attribute *attr, char *buf)
6606ab0a202SJeff Mahoney 
6616ab0a202SJeff Mahoney {
6626ab0a202SJeff Mahoney 	struct btrfs_space_info *sinfo = to_space_info(kobj->parent);
66332da5386SDavid Sterba 	struct btrfs_block_group *block_group;
66475cb379dSJeff Mahoney 	int index = btrfs_bg_flags_to_raid_index(to_raid_kobj(kobj)->flags);
6656ab0a202SJeff Mahoney 	u64 val = 0;
6666ab0a202SJeff Mahoney 
6676ab0a202SJeff Mahoney 	down_read(&sinfo->groups_sem);
6686ab0a202SJeff Mahoney 	list_for_each_entry(block_group, &sinfo->block_groups[index], list) {
669a969f4ccSHans van Kranenburg 		if (&attr->attr == BTRFS_ATTR_PTR(raid, total_bytes))
670b3470b5dSDavid Sterba 			val += block_group->length;
6716ab0a202SJeff Mahoney 		else
672bf38be65SDavid Sterba 			val += block_group->used;
6736ab0a202SJeff Mahoney 	}
6746ab0a202SJeff Mahoney 	up_read(&sinfo->groups_sem);
675*020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", val);
6766ab0a202SJeff Mahoney }
6776ab0a202SJeff Mahoney 
678e7849e33SAnand Jain /*
679e7849e33SAnand Jain  * Allocation information about block group profiles.
680e7849e33SAnand Jain  *
681e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/allocation/<bg-type>/<bg-profile>/
682e7849e33SAnand Jain  */
6837c7e3014SKimberly Brown static struct attribute *raid_attrs[] = {
684a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(raid, total_bytes),
685a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(raid, used_bytes),
6866ab0a202SJeff Mahoney 	NULL
6876ab0a202SJeff Mahoney };
6887c7e3014SKimberly Brown ATTRIBUTE_GROUPS(raid);
6896ab0a202SJeff Mahoney 
6906ab0a202SJeff Mahoney static void release_raid_kobj(struct kobject *kobj)
6916ab0a202SJeff Mahoney {
692c1895442SJeff Mahoney 	kfree(to_raid_kobj(kobj));
6936ab0a202SJeff Mahoney }
6946ab0a202SJeff Mahoney 
695536ea45cSDavid Sterba static struct kobj_type btrfs_raid_ktype = {
6966ab0a202SJeff Mahoney 	.sysfs_ops = &kobj_sysfs_ops,
6976ab0a202SJeff Mahoney 	.release = release_raid_kobj,
6987c7e3014SKimberly Brown 	.default_groups = raid_groups,
6996ab0a202SJeff Mahoney };
7006ab0a202SJeff Mahoney 
7016ab0a202SJeff Mahoney #define SPACE_INFO_ATTR(field)						\
7026ab0a202SJeff Mahoney static ssize_t btrfs_space_info_show_##field(struct kobject *kobj,	\
7036ab0a202SJeff Mahoney 					     struct kobj_attribute *a,	\
7046ab0a202SJeff Mahoney 					     char *buf)			\
7056ab0a202SJeff Mahoney {									\
7066ab0a202SJeff Mahoney 	struct btrfs_space_info *sinfo = to_space_info(kobj);		\
7076ab0a202SJeff Mahoney 	return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf);	\
7086ab0a202SJeff Mahoney }									\
709a969f4ccSHans van Kranenburg BTRFS_ATTR(space_info, field, btrfs_space_info_show_##field)
7106ab0a202SJeff Mahoney 
7116ab0a202SJeff Mahoney SPACE_INFO_ATTR(flags);
7126ab0a202SJeff Mahoney SPACE_INFO_ATTR(total_bytes);
7136ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_used);
7146ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_pinned);
7156ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_reserved);
7166ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_may_use);
717c1fd5c30SWang Xiaoguang SPACE_INFO_ATTR(bytes_readonly);
718169e0da9SNaohiro Aota SPACE_INFO_ATTR(bytes_zone_unusable);
7196ab0a202SJeff Mahoney SPACE_INFO_ATTR(disk_used);
7206ab0a202SJeff Mahoney SPACE_INFO_ATTR(disk_total);
7216ab0a202SJeff Mahoney 
722e7849e33SAnand Jain /*
723e7849e33SAnand Jain  * Allocation information about block group types.
724e7849e33SAnand Jain  *
725e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/allocation/<bg-type>/
726e7849e33SAnand Jain  */
7276ab0a202SJeff Mahoney static struct attribute *space_info_attrs[] = {
728a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, flags),
729a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, total_bytes),
730a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_used),
731a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_pinned),
732a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_reserved),
733a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_may_use),
734a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_readonly),
735169e0da9SNaohiro Aota 	BTRFS_ATTR_PTR(space_info, bytes_zone_unusable),
736a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, disk_used),
737a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, disk_total),
7386ab0a202SJeff Mahoney 	NULL,
7396ab0a202SJeff Mahoney };
7407c7e3014SKimberly Brown ATTRIBUTE_GROUPS(space_info);
7416ab0a202SJeff Mahoney 
7426ab0a202SJeff Mahoney static void space_info_release(struct kobject *kobj)
7436ab0a202SJeff Mahoney {
7446ab0a202SJeff Mahoney 	struct btrfs_space_info *sinfo = to_space_info(kobj);
7456ab0a202SJeff Mahoney 	kfree(sinfo);
7466ab0a202SJeff Mahoney }
7476ab0a202SJeff Mahoney 
74827992d01SDavid Sterba static struct kobj_type space_info_ktype = {
7496ab0a202SJeff Mahoney 	.sysfs_ops = &kobj_sysfs_ops,
7506ab0a202SJeff Mahoney 	.release = space_info_release,
7517c7e3014SKimberly Brown 	.default_groups = space_info_groups,
7526ab0a202SJeff Mahoney };
7536ab0a202SJeff Mahoney 
754e7849e33SAnand Jain /*
755e7849e33SAnand Jain  * Allocation information about block groups.
756e7849e33SAnand Jain  *
757e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/allocation/
758e7849e33SAnand Jain  */
7596ab0a202SJeff Mahoney static const struct attribute *allocation_attrs[] = {
760a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(allocation, global_rsv_reserved),
761a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(allocation, global_rsv_size),
7626ab0a202SJeff Mahoney 	NULL,
7636ab0a202SJeff Mahoney };
7646ab0a202SJeff Mahoney 
765f8ba9c11SJeff Mahoney static ssize_t btrfs_label_show(struct kobject *kobj,
766f8ba9c11SJeff Mahoney 				struct kobj_attribute *a, char *buf)
767f8ba9c11SJeff Mahoney {
768f8ba9c11SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
76948fcc3ffSSatoru Takeuchi 	char *label = fs_info->super_copy->label;
770ee17fc80SDavid Sterba 	ssize_t ret;
771ee17fc80SDavid Sterba 
772ee17fc80SDavid Sterba 	spin_lock(&fs_info->super_lock);
773*020e5277SAnand Jain 	ret = sysfs_emit(buf, label[0] ? "%s\n" : "%s", label);
774ee17fc80SDavid Sterba 	spin_unlock(&fs_info->super_lock);
775ee17fc80SDavid Sterba 
776ee17fc80SDavid Sterba 	return ret;
777f8ba9c11SJeff Mahoney }
778f8ba9c11SJeff Mahoney 
779f8ba9c11SJeff Mahoney static ssize_t btrfs_label_store(struct kobject *kobj,
780f8ba9c11SJeff Mahoney 				 struct kobj_attribute *a,
781f8ba9c11SJeff Mahoney 				 const char *buf, size_t len)
782f8ba9c11SJeff Mahoney {
783f8ba9c11SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
78448fcc3ffSSatoru Takeuchi 	size_t p_len;
785f8ba9c11SJeff Mahoney 
78666ac9fe7SDavid Sterba 	if (!fs_info)
78766ac9fe7SDavid Sterba 		return -EPERM;
78866ac9fe7SDavid Sterba 
789bc98a42cSDavid Howells 	if (sb_rdonly(fs_info->sb))
79079aec2b8SAnand Jain 		return -EROFS;
79179aec2b8SAnand Jain 
79248fcc3ffSSatoru Takeuchi 	/*
79348fcc3ffSSatoru Takeuchi 	 * p_len is the len until the first occurrence of either
79448fcc3ffSSatoru Takeuchi 	 * '\n' or '\0'
79548fcc3ffSSatoru Takeuchi 	 */
79648fcc3ffSSatoru Takeuchi 	p_len = strcspn(buf, "\n");
79748fcc3ffSSatoru Takeuchi 
79848fcc3ffSSatoru Takeuchi 	if (p_len >= BTRFS_LABEL_SIZE)
799f8ba9c11SJeff Mahoney 		return -EINVAL;
800f8ba9c11SJeff Mahoney 
801a6f69dc8SDavid Sterba 	spin_lock(&fs_info->super_lock);
80248fcc3ffSSatoru Takeuchi 	memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE);
80348fcc3ffSSatoru Takeuchi 	memcpy(fs_info->super_copy->label, buf, p_len);
804a6f69dc8SDavid Sterba 	spin_unlock(&fs_info->super_lock);
805f8ba9c11SJeff Mahoney 
806a6f69dc8SDavid Sterba 	/*
807a6f69dc8SDavid Sterba 	 * We don't want to do full transaction commit from inside sysfs
808a6f69dc8SDavid Sterba 	 */
809a6f69dc8SDavid Sterba 	btrfs_set_pending(fs_info, COMMIT);
810a6f69dc8SDavid Sterba 	wake_up_process(fs_info->transaction_kthread);
811a6f69dc8SDavid Sterba 
812f8ba9c11SJeff Mahoney 	return len;
813f8ba9c11SJeff Mahoney }
814a969f4ccSHans van Kranenburg BTRFS_ATTR_RW(, label, btrfs_label_show, btrfs_label_store);
815f8ba9c11SJeff Mahoney 
816df93589aSDavid Sterba static ssize_t btrfs_nodesize_show(struct kobject *kobj,
817df93589aSDavid Sterba 				struct kobj_attribute *a, char *buf)
818df93589aSDavid Sterba {
819df93589aSDavid Sterba 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
820df93589aSDavid Sterba 
821*020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n", fs_info->super_copy->nodesize);
822df93589aSDavid Sterba }
823df93589aSDavid Sterba 
824a969f4ccSHans van Kranenburg BTRFS_ATTR(, nodesize, btrfs_nodesize_show);
825df93589aSDavid Sterba 
826df93589aSDavid Sterba static ssize_t btrfs_sectorsize_show(struct kobject *kobj,
827df93589aSDavid Sterba 				struct kobj_attribute *a, char *buf)
828df93589aSDavid Sterba {
829df93589aSDavid Sterba 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
830df93589aSDavid Sterba 
831*020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n", fs_info->super_copy->sectorsize);
832df93589aSDavid Sterba }
833df93589aSDavid Sterba 
834a969f4ccSHans van Kranenburg BTRFS_ATTR(, sectorsize, btrfs_sectorsize_show);
835df93589aSDavid Sterba 
836df93589aSDavid Sterba static ssize_t btrfs_clone_alignment_show(struct kobject *kobj,
837df93589aSDavid Sterba 				struct kobj_attribute *a, char *buf)
838df93589aSDavid Sterba {
839df93589aSDavid Sterba 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
840df93589aSDavid Sterba 
841*020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n", fs_info->super_copy->sectorsize);
842df93589aSDavid Sterba }
843df93589aSDavid Sterba 
844a969f4ccSHans van Kranenburg BTRFS_ATTR(, clone_alignment, btrfs_clone_alignment_show);
845df93589aSDavid Sterba 
8462723480aSSargun Dhillon static ssize_t quota_override_show(struct kobject *kobj,
8472723480aSSargun Dhillon 				   struct kobj_attribute *a, char *buf)
8482723480aSSargun Dhillon {
8492723480aSSargun Dhillon 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
8502723480aSSargun Dhillon 	int quota_override;
8512723480aSSargun Dhillon 
8522723480aSSargun Dhillon 	quota_override = test_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags);
853*020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", quota_override);
8542723480aSSargun Dhillon }
8552723480aSSargun Dhillon 
8562723480aSSargun Dhillon static ssize_t quota_override_store(struct kobject *kobj,
8572723480aSSargun Dhillon 				    struct kobj_attribute *a,
8582723480aSSargun Dhillon 				    const char *buf, size_t len)
8592723480aSSargun Dhillon {
8602723480aSSargun Dhillon 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
8612723480aSSargun Dhillon 	unsigned long knob;
8622723480aSSargun Dhillon 	int err;
8632723480aSSargun Dhillon 
8642723480aSSargun Dhillon 	if (!fs_info)
8652723480aSSargun Dhillon 		return -EPERM;
8662723480aSSargun Dhillon 
8672723480aSSargun Dhillon 	if (!capable(CAP_SYS_RESOURCE))
8682723480aSSargun Dhillon 		return -EPERM;
8692723480aSSargun Dhillon 
8702723480aSSargun Dhillon 	err = kstrtoul(buf, 10, &knob);
8712723480aSSargun Dhillon 	if (err)
8722723480aSSargun Dhillon 		return err;
8732723480aSSargun Dhillon 	if (knob > 1)
8742723480aSSargun Dhillon 		return -EINVAL;
8752723480aSSargun Dhillon 
8762723480aSSargun Dhillon 	if (knob)
8772723480aSSargun Dhillon 		set_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags);
8782723480aSSargun Dhillon 	else
8792723480aSSargun Dhillon 		clear_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags);
8802723480aSSargun Dhillon 
8812723480aSSargun Dhillon 	return len;
8822723480aSSargun Dhillon }
8832723480aSSargun Dhillon 
884a969f4ccSHans van Kranenburg BTRFS_ATTR_RW(, quota_override, quota_override_show, quota_override_store);
8852723480aSSargun Dhillon 
88656f20f40SNikolay Borisov static ssize_t btrfs_metadata_uuid_show(struct kobject *kobj,
88756f20f40SNikolay Borisov 				struct kobj_attribute *a, char *buf)
88856f20f40SNikolay Borisov {
88956f20f40SNikolay Borisov 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
89056f20f40SNikolay Borisov 
891*020e5277SAnand Jain 	return sysfs_emit(buf, "%pU\n", fs_info->fs_devices->metadata_uuid);
89256f20f40SNikolay Borisov }
89356f20f40SNikolay Borisov 
89456f20f40SNikolay Borisov BTRFS_ATTR(, metadata_uuid, btrfs_metadata_uuid_show);
89556f20f40SNikolay Borisov 
89641e6d2a8SJohannes Thumshirn static ssize_t btrfs_checksum_show(struct kobject *kobj,
89741e6d2a8SJohannes Thumshirn 				   struct kobj_attribute *a, char *buf)
89841e6d2a8SJohannes Thumshirn {
89941e6d2a8SJohannes Thumshirn 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
90041e6d2a8SJohannes Thumshirn 	u16 csum_type = btrfs_super_csum_type(fs_info->super_copy);
90141e6d2a8SJohannes Thumshirn 
902*020e5277SAnand Jain 	return sysfs_emit(buf, "%s (%s)\n",
90341e6d2a8SJohannes Thumshirn 			  btrfs_super_csum_name(csum_type),
90441e6d2a8SJohannes Thumshirn 			  crypto_shash_driver_name(fs_info->csum_shash));
90541e6d2a8SJohannes Thumshirn }
90641e6d2a8SJohannes Thumshirn 
90741e6d2a8SJohannes Thumshirn BTRFS_ATTR(, checksum, btrfs_checksum_show);
90841e6d2a8SJohannes Thumshirn 
90966a2823cSGoldwyn Rodrigues static ssize_t btrfs_exclusive_operation_show(struct kobject *kobj,
91066a2823cSGoldwyn Rodrigues 		struct kobj_attribute *a, char *buf)
91166a2823cSGoldwyn Rodrigues {
91266a2823cSGoldwyn Rodrigues 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
91366a2823cSGoldwyn Rodrigues 	const char *str;
91466a2823cSGoldwyn Rodrigues 
91566a2823cSGoldwyn Rodrigues 	switch (READ_ONCE(fs_info->exclusive_operation)) {
91666a2823cSGoldwyn Rodrigues 		case  BTRFS_EXCLOP_NONE:
91766a2823cSGoldwyn Rodrigues 			str = "none\n";
91866a2823cSGoldwyn Rodrigues 			break;
91966a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_BALANCE:
92066a2823cSGoldwyn Rodrigues 			str = "balance\n";
92166a2823cSGoldwyn Rodrigues 			break;
92266a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_ADD:
92366a2823cSGoldwyn Rodrigues 			str = "device add\n";
92466a2823cSGoldwyn Rodrigues 			break;
92566a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_REMOVE:
92666a2823cSGoldwyn Rodrigues 			str = "device remove\n";
92766a2823cSGoldwyn Rodrigues 			break;
92866a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_REPLACE:
92966a2823cSGoldwyn Rodrigues 			str = "device replace\n";
93066a2823cSGoldwyn Rodrigues 			break;
93166a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_RESIZE:
93266a2823cSGoldwyn Rodrigues 			str = "resize\n";
93366a2823cSGoldwyn Rodrigues 			break;
93466a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_SWAP_ACTIVATE:
93566a2823cSGoldwyn Rodrigues 			str = "swap activate\n";
93666a2823cSGoldwyn Rodrigues 			break;
93766a2823cSGoldwyn Rodrigues 		default:
93866a2823cSGoldwyn Rodrigues 			str = "UNKNOWN\n";
93966a2823cSGoldwyn Rodrigues 			break;
94066a2823cSGoldwyn Rodrigues 	}
941*020e5277SAnand Jain 	return sysfs_emit(buf, "%s", str);
94266a2823cSGoldwyn Rodrigues }
94366a2823cSGoldwyn Rodrigues BTRFS_ATTR(, exclusive_operation, btrfs_exclusive_operation_show);
94466a2823cSGoldwyn Rodrigues 
945089c8b05SAnand Jain static ssize_t btrfs_generation_show(struct kobject *kobj,
946089c8b05SAnand Jain 				     struct kobj_attribute *a, char *buf)
947089c8b05SAnand Jain {
948089c8b05SAnand Jain 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
949089c8b05SAnand Jain 
950*020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", fs_info->generation);
951089c8b05SAnand Jain }
952089c8b05SAnand Jain BTRFS_ATTR(, generation, btrfs_generation_show);
953089c8b05SAnand Jain 
954aaefed20SAnand Jain /*
955aaefed20SAnand Jain  * Look for an exact string @string in @buffer with possible leading or
956aaefed20SAnand Jain  * trailing whitespace
957aaefed20SAnand Jain  */
958aaefed20SAnand Jain static bool strmatch(const char *buffer, const char *string)
959aaefed20SAnand Jain {
960aaefed20SAnand Jain 	const size_t len = strlen(string);
961aaefed20SAnand Jain 
962aaefed20SAnand Jain 	/* Skip leading whitespace */
963aaefed20SAnand Jain 	buffer = skip_spaces(buffer);
964aaefed20SAnand Jain 
965aaefed20SAnand Jain 	/* Match entire string, check if the rest is whitespace or empty */
966aaefed20SAnand Jain 	if (strncmp(string, buffer, len) == 0 &&
967aaefed20SAnand Jain 	    strlen(skip_spaces(buffer + len)) == 0)
968aaefed20SAnand Jain 		return true;
969aaefed20SAnand Jain 
970aaefed20SAnand Jain 	return false;
971aaefed20SAnand Jain }
972aaefed20SAnand Jain 
9733d8cc17aSAnand Jain static const char * const btrfs_read_policy_name[] = { "pid" };
9743d8cc17aSAnand Jain 
9753d8cc17aSAnand Jain static ssize_t btrfs_read_policy_show(struct kobject *kobj,
9763d8cc17aSAnand Jain 				      struct kobj_attribute *a, char *buf)
9773d8cc17aSAnand Jain {
9783d8cc17aSAnand Jain 	struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
9793d8cc17aSAnand Jain 	ssize_t ret = 0;
9803d8cc17aSAnand Jain 	int i;
9813d8cc17aSAnand Jain 
9823d8cc17aSAnand Jain 	for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
9833d8cc17aSAnand Jain 		if (fs_devices->read_policy == i)
9843d8cc17aSAnand Jain 			ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s[%s]",
9853d8cc17aSAnand Jain 					 (ret == 0 ? "" : " "),
9863d8cc17aSAnand Jain 					 btrfs_read_policy_name[i]);
9873d8cc17aSAnand Jain 		else
9883d8cc17aSAnand Jain 			ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s%s",
9893d8cc17aSAnand Jain 					 (ret == 0 ? "" : " "),
9903d8cc17aSAnand Jain 					 btrfs_read_policy_name[i]);
9913d8cc17aSAnand Jain 	}
9923d8cc17aSAnand Jain 
9933d8cc17aSAnand Jain 	ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
9943d8cc17aSAnand Jain 
9953d8cc17aSAnand Jain 	return ret;
9963d8cc17aSAnand Jain }
9973d8cc17aSAnand Jain 
9983d8cc17aSAnand Jain static ssize_t btrfs_read_policy_store(struct kobject *kobj,
9993d8cc17aSAnand Jain 				       struct kobj_attribute *a,
10003d8cc17aSAnand Jain 				       const char *buf, size_t len)
10013d8cc17aSAnand Jain {
10023d8cc17aSAnand Jain 	struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
10033d8cc17aSAnand Jain 	int i;
10043d8cc17aSAnand Jain 
10053d8cc17aSAnand Jain 	for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
10063d8cc17aSAnand Jain 		if (strmatch(buf, btrfs_read_policy_name[i])) {
10073d8cc17aSAnand Jain 			if (i != fs_devices->read_policy) {
10083d8cc17aSAnand Jain 				fs_devices->read_policy = i;
10093d8cc17aSAnand Jain 				btrfs_info(fs_devices->fs_info,
10103d8cc17aSAnand Jain 					   "read policy set to '%s'",
10113d8cc17aSAnand Jain 					   btrfs_read_policy_name[i]);
10123d8cc17aSAnand Jain 			}
10133d8cc17aSAnand Jain 			return len;
10143d8cc17aSAnand Jain 		}
10153d8cc17aSAnand Jain 	}
10163d8cc17aSAnand Jain 
10173d8cc17aSAnand Jain 	return -EINVAL;
10183d8cc17aSAnand Jain }
10193d8cc17aSAnand Jain BTRFS_ATTR_RW(, read_policy, btrfs_read_policy_show, btrfs_read_policy_store);
10203d8cc17aSAnand Jain 
102118bb8bbfSJohannes Thumshirn static ssize_t btrfs_bg_reclaim_threshold_show(struct kobject *kobj,
102218bb8bbfSJohannes Thumshirn 					       struct kobj_attribute *a,
102318bb8bbfSJohannes Thumshirn 					       char *buf)
102418bb8bbfSJohannes Thumshirn {
102518bb8bbfSJohannes Thumshirn 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
102618bb8bbfSJohannes Thumshirn 	ssize_t ret;
102718bb8bbfSJohannes Thumshirn 
1028*020e5277SAnand Jain 	ret = sysfs_emit(buf, "%d\n", READ_ONCE(fs_info->bg_reclaim_threshold));
102918bb8bbfSJohannes Thumshirn 
103018bb8bbfSJohannes Thumshirn 	return ret;
103118bb8bbfSJohannes Thumshirn }
103218bb8bbfSJohannes Thumshirn 
103318bb8bbfSJohannes Thumshirn static ssize_t btrfs_bg_reclaim_threshold_store(struct kobject *kobj,
103418bb8bbfSJohannes Thumshirn 						struct kobj_attribute *a,
103518bb8bbfSJohannes Thumshirn 						const char *buf, size_t len)
103618bb8bbfSJohannes Thumshirn {
103718bb8bbfSJohannes Thumshirn 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
103818bb8bbfSJohannes Thumshirn 	int thresh;
103918bb8bbfSJohannes Thumshirn 	int ret;
104018bb8bbfSJohannes Thumshirn 
104118bb8bbfSJohannes Thumshirn 	ret = kstrtoint(buf, 10, &thresh);
104218bb8bbfSJohannes Thumshirn 	if (ret)
104318bb8bbfSJohannes Thumshirn 		return ret;
104418bb8bbfSJohannes Thumshirn 
104577233c2dSJohannes Thumshirn 	if (thresh != 0 && (thresh <= 50 || thresh > 100))
104618bb8bbfSJohannes Thumshirn 		return -EINVAL;
104718bb8bbfSJohannes Thumshirn 
104877233c2dSJohannes Thumshirn 	WRITE_ONCE(fs_info->bg_reclaim_threshold, thresh);
104918bb8bbfSJohannes Thumshirn 
105018bb8bbfSJohannes Thumshirn 	return len;
105118bb8bbfSJohannes Thumshirn }
105218bb8bbfSJohannes Thumshirn BTRFS_ATTR_RW(, bg_reclaim_threshold, btrfs_bg_reclaim_threshold_show,
105318bb8bbfSJohannes Thumshirn 	      btrfs_bg_reclaim_threshold_store);
105418bb8bbfSJohannes Thumshirn 
1055e7849e33SAnand Jain /*
1056e7849e33SAnand Jain  * Per-filesystem information and stats.
1057e7849e33SAnand Jain  *
1058e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/
1059e7849e33SAnand Jain  */
10600dd2906fSAnand Jain static const struct attribute *btrfs_attrs[] = {
1061a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, label),
1062a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, nodesize),
1063a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, sectorsize),
1064a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, clone_alignment),
1065a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, quota_override),
106656f20f40SNikolay Borisov 	BTRFS_ATTR_PTR(, metadata_uuid),
106741e6d2a8SJohannes Thumshirn 	BTRFS_ATTR_PTR(, checksum),
106866a2823cSGoldwyn Rodrigues 	BTRFS_ATTR_PTR(, exclusive_operation),
1069089c8b05SAnand Jain 	BTRFS_ATTR_PTR(, generation),
10703d8cc17aSAnand Jain 	BTRFS_ATTR_PTR(, read_policy),
107118bb8bbfSJohannes Thumshirn 	BTRFS_ATTR_PTR(, bg_reclaim_threshold),
1072f8ba9c11SJeff Mahoney 	NULL,
1073f8ba9c11SJeff Mahoney };
1074f8ba9c11SJeff Mahoney 
1075c1b7e474SAnand Jain static void btrfs_release_fsid_kobj(struct kobject *kobj)
1076510d7360SJeff Mahoney {
10772e7910d6SAnand Jain 	struct btrfs_fs_devices *fs_devs = to_fs_devs(kobj);
1078248d200dSAnand Jain 
1079c1b7e474SAnand Jain 	memset(&fs_devs->fsid_kobj, 0, sizeof(struct kobject));
10802e7910d6SAnand Jain 	complete(&fs_devs->kobj_unregister);
1081510d7360SJeff Mahoney }
1082510d7360SJeff Mahoney 
1083510d7360SJeff Mahoney static struct kobj_type btrfs_ktype = {
1084510d7360SJeff Mahoney 	.sysfs_ops	= &kobj_sysfs_ops,
1085c1b7e474SAnand Jain 	.release	= btrfs_release_fsid_kobj,
1086510d7360SJeff Mahoney };
1087510d7360SJeff Mahoney 
10882e7910d6SAnand Jain static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj)
10892e7910d6SAnand Jain {
10902e7910d6SAnand Jain 	if (kobj->ktype != &btrfs_ktype)
10912e7910d6SAnand Jain 		return NULL;
1092c1b7e474SAnand Jain 	return container_of(kobj, struct btrfs_fs_devices, fsid_kobj);
10932e7910d6SAnand Jain }
10942e7910d6SAnand Jain 
1095510d7360SJeff Mahoney static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj)
1096510d7360SJeff Mahoney {
1097510d7360SJeff Mahoney 	if (kobj->ktype != &btrfs_ktype)
1098510d7360SJeff Mahoney 		return NULL;
10992e7910d6SAnand Jain 	return to_fs_devs(kobj)->fs_info;
1100510d7360SJeff Mahoney }
110158176a96SJosef Bacik 
1102e453d989SJeff Mahoney #define NUM_FEATURE_BITS 64
11036c52157fSTomohiro Misono #define BTRFS_FEATURE_NAME_MAX 13
11046c52157fSTomohiro Misono static char btrfs_unknown_feature_names[FEAT_MAX][NUM_FEATURE_BITS][BTRFS_FEATURE_NAME_MAX];
11056c52157fSTomohiro Misono static struct btrfs_feature_attr btrfs_feature_attrs[FEAT_MAX][NUM_FEATURE_BITS];
1106e453d989SJeff Mahoney 
11076c52157fSTomohiro Misono static const u64 supported_feature_masks[FEAT_MAX] = {
1108e453d989SJeff Mahoney 	[FEAT_COMPAT]    = BTRFS_FEATURE_COMPAT_SUPP,
1109e453d989SJeff Mahoney 	[FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP,
1110e453d989SJeff Mahoney 	[FEAT_INCOMPAT]  = BTRFS_FEATURE_INCOMPAT_SUPP,
1111e453d989SJeff Mahoney };
1112e453d989SJeff Mahoney 
1113e453d989SJeff Mahoney static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add)
11145ac1d209SJeff Mahoney {
1115e453d989SJeff Mahoney 	int set;
1116e453d989SJeff Mahoney 
1117e453d989SJeff Mahoney 	for (set = 0; set < FEAT_MAX; set++) {
1118e453d989SJeff Mahoney 		int i;
1119e453d989SJeff Mahoney 		struct attribute *attrs[2];
1120e453d989SJeff Mahoney 		struct attribute_group agroup = {
1121e453d989SJeff Mahoney 			.name = "features",
1122e453d989SJeff Mahoney 			.attrs = attrs,
1123e453d989SJeff Mahoney 		};
1124e453d989SJeff Mahoney 		u64 features = get_features(fs_info, set);
1125e453d989SJeff Mahoney 		features &= ~supported_feature_masks[set];
1126e453d989SJeff Mahoney 
1127e453d989SJeff Mahoney 		if (!features)
1128e453d989SJeff Mahoney 			continue;
1129e453d989SJeff Mahoney 
1130e453d989SJeff Mahoney 		attrs[1] = NULL;
1131e453d989SJeff Mahoney 		for (i = 0; i < NUM_FEATURE_BITS; i++) {
1132e453d989SJeff Mahoney 			struct btrfs_feature_attr *fa;
1133e453d989SJeff Mahoney 
1134e453d989SJeff Mahoney 			if (!(features & (1ULL << i)))
1135e453d989SJeff Mahoney 				continue;
1136e453d989SJeff Mahoney 
1137e453d989SJeff Mahoney 			fa = &btrfs_feature_attrs[set][i];
1138e453d989SJeff Mahoney 			attrs[0] = &fa->kobj_attr.attr;
1139e453d989SJeff Mahoney 			if (add) {
1140e453d989SJeff Mahoney 				int ret;
1141c1b7e474SAnand Jain 				ret = sysfs_merge_group(&fs_info->fs_devices->fsid_kobj,
1142e453d989SJeff Mahoney 							&agroup);
1143e453d989SJeff Mahoney 				if (ret)
1144e453d989SJeff Mahoney 					return ret;
1145e453d989SJeff Mahoney 			} else
1146c1b7e474SAnand Jain 				sysfs_unmerge_group(&fs_info->fs_devices->fsid_kobj,
1147e453d989SJeff Mahoney 						    &agroup);
1148e453d989SJeff Mahoney 		}
1149e453d989SJeff Mahoney 
1150e453d989SJeff Mahoney 	}
1151e453d989SJeff Mahoney 	return 0;
1152e453d989SJeff Mahoney }
1153e453d989SJeff Mahoney 
11542e3e1281SAnand Jain static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs)
1155e453d989SJeff Mahoney {
1156a013d141SAnand Jain 	if (fs_devs->devinfo_kobj) {
1157a013d141SAnand Jain 		kobject_del(fs_devs->devinfo_kobj);
1158a013d141SAnand Jain 		kobject_put(fs_devs->devinfo_kobj);
1159a013d141SAnand Jain 		fs_devs->devinfo_kobj = NULL;
1160a013d141SAnand Jain 	}
1161a013d141SAnand Jain 
1162b5501504SAnand Jain 	if (fs_devs->devices_kobj) {
1163b5501504SAnand Jain 		kobject_del(fs_devs->devices_kobj);
1164b5501504SAnand Jain 		kobject_put(fs_devs->devices_kobj);
1165b5501504SAnand Jain 		fs_devs->devices_kobj = NULL;
1166aaf13305SAnand Jain 	}
1167aaf13305SAnand Jain 
1168c1b7e474SAnand Jain 	if (fs_devs->fsid_kobj.state_initialized) {
1169c1b7e474SAnand Jain 		kobject_del(&fs_devs->fsid_kobj);
1170c1b7e474SAnand Jain 		kobject_put(&fs_devs->fsid_kobj);
11712e7910d6SAnand Jain 		wait_for_completion(&fs_devs->kobj_unregister);
11725ac1d209SJeff Mahoney 	}
1173f90fc547SAnand Jain }
11745ac1d209SJeff Mahoney 
11752e3e1281SAnand Jain /* when fs_devs is NULL it will remove all fsid kobject */
11761d1c1be3SAnand Jain void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs)
11772e3e1281SAnand Jain {
11782e3e1281SAnand Jain 	struct list_head *fs_uuids = btrfs_get_fs_uuids();
11792e3e1281SAnand Jain 
11802e3e1281SAnand Jain 	if (fs_devs) {
11812e3e1281SAnand Jain 		__btrfs_sysfs_remove_fsid(fs_devs);
11822e3e1281SAnand Jain 		return;
11832e3e1281SAnand Jain 	}
11842e3e1281SAnand Jain 
1185c4babc5eSAnand Jain 	list_for_each_entry(fs_devs, fs_uuids, fs_list) {
11862e3e1281SAnand Jain 		__btrfs_sysfs_remove_fsid(fs_devs);
11872e3e1281SAnand Jain 	}
11882e3e1281SAnand Jain }
11892e3e1281SAnand Jain 
119053f8a74cSAnand Jain static void btrfs_sysfs_remove_fs_devices(struct btrfs_fs_devices *fs_devices)
119153f8a74cSAnand Jain {
119253f8a74cSAnand Jain 	struct btrfs_device *device;
119330b0e4e0SAnand Jain 	struct btrfs_fs_devices *seed;
119453f8a74cSAnand Jain 
119553f8a74cSAnand Jain 	list_for_each_entry(device, &fs_devices->devices, dev_list)
119653f8a74cSAnand Jain 		btrfs_sysfs_remove_device(device);
119730b0e4e0SAnand Jain 
119830b0e4e0SAnand Jain 	list_for_each_entry(seed, &fs_devices->seed_list, seed_list) {
119930b0e4e0SAnand Jain 		list_for_each_entry(device, &seed->devices, dev_list)
120030b0e4e0SAnand Jain 			btrfs_sysfs_remove_device(device);
120130b0e4e0SAnand Jain 	}
120253f8a74cSAnand Jain }
120353f8a74cSAnand Jain 
12046618a59bSAnand Jain void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info)
1205e453d989SJeff Mahoney {
12063092c68fSNikolay Borisov 	struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj;
12073092c68fSNikolay Borisov 
12083092c68fSNikolay Borisov 	sysfs_remove_link(fsid_kobj, "bdi");
12093092c68fSNikolay Borisov 
1210e453d989SJeff Mahoney 	if (fs_info->space_info_kobj) {
1211e453d989SJeff Mahoney 		sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs);
1212e453d989SJeff Mahoney 		kobject_del(fs_info->space_info_kobj);
1213e453d989SJeff Mahoney 		kobject_put(fs_info->space_info_kobj);
1214e453d989SJeff Mahoney 	}
121571e8978eSDennis Zhou #ifdef CONFIG_BTRFS_DEBUG
1216e4faab84SDennis Zhou 	if (fs_info->discard_debug_kobj) {
1217e4faab84SDennis Zhou 		sysfs_remove_files(fs_info->discard_debug_kobj,
1218e4faab84SDennis Zhou 				   discard_debug_attrs);
1219e4faab84SDennis Zhou 		kobject_del(fs_info->discard_debug_kobj);
1220e4faab84SDennis Zhou 		kobject_put(fs_info->discard_debug_kobj);
1221e4faab84SDennis Zhou 	}
122293945cb4SDennis Zhou 	if (fs_info->debug_kobj) {
122393945cb4SDennis Zhou 		sysfs_remove_files(fs_info->debug_kobj, btrfs_debug_mount_attrs);
122493945cb4SDennis Zhou 		kobject_del(fs_info->debug_kobj);
122593945cb4SDennis Zhou 		kobject_put(fs_info->debug_kobj);
122693945cb4SDennis Zhou 	}
122771e8978eSDennis Zhou #endif
1228e453d989SJeff Mahoney 	addrm_unknown_feature_attrs(fs_info, false);
12293092c68fSNikolay Borisov 	sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group);
12303092c68fSNikolay Borisov 	sysfs_remove_files(fsid_kobj, btrfs_attrs);
123153f8a74cSAnand Jain 	btrfs_sysfs_remove_fs_devices(fs_info->fs_devices);
1232e453d989SJeff Mahoney }
1233e453d989SJeff Mahoney 
1234f10152bcSDavid Sterba static const char * const btrfs_feature_set_names[FEAT_MAX] = {
123579da4fa4SJeff Mahoney 	[FEAT_COMPAT]	 = "compat",
123679da4fa4SJeff Mahoney 	[FEAT_COMPAT_RO] = "compat_ro",
123779da4fa4SJeff Mahoney 	[FEAT_INCOMPAT]	 = "incompat",
123879da4fa4SJeff Mahoney };
123979da4fa4SJeff Mahoney 
12409e6df7ceSDavid Sterba const char *btrfs_feature_set_name(enum btrfs_feature_set set)
1241f10152bcSDavid Sterba {
1242f10152bcSDavid Sterba 	return btrfs_feature_set_names[set];
1243f10152bcSDavid Sterba }
1244f10152bcSDavid Sterba 
12453b02a68aSJeff Mahoney char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags)
12463b02a68aSJeff Mahoney {
12473b02a68aSJeff Mahoney 	size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */
12483b02a68aSJeff Mahoney 	int len = 0;
12493b02a68aSJeff Mahoney 	int i;
12503b02a68aSJeff Mahoney 	char *str;
12513b02a68aSJeff Mahoney 
12523b02a68aSJeff Mahoney 	str = kmalloc(bufsize, GFP_KERNEL);
12533b02a68aSJeff Mahoney 	if (!str)
12543b02a68aSJeff Mahoney 		return str;
12553b02a68aSJeff Mahoney 
12563b02a68aSJeff Mahoney 	for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
12573b02a68aSJeff Mahoney 		const char *name;
12583b02a68aSJeff Mahoney 
12593b02a68aSJeff Mahoney 		if (!(flags & (1ULL << i)))
12603b02a68aSJeff Mahoney 			continue;
12613b02a68aSJeff Mahoney 
12623b02a68aSJeff Mahoney 		name = btrfs_feature_attrs[set][i].kobj_attr.attr.name;
1263abdd9febSTakashi Iwai 		len += scnprintf(str + len, bufsize - len, "%s%s",
12643b02a68aSJeff Mahoney 				len ? "," : "", name);
12653b02a68aSJeff Mahoney 	}
12663b02a68aSJeff Mahoney 
12673b02a68aSJeff Mahoney 	return str;
12683b02a68aSJeff Mahoney }
12693b02a68aSJeff Mahoney 
127079da4fa4SJeff Mahoney static void init_feature_attrs(void)
127179da4fa4SJeff Mahoney {
127279da4fa4SJeff Mahoney 	struct btrfs_feature_attr *fa;
127379da4fa4SJeff Mahoney 	int set, i;
127479da4fa4SJeff Mahoney 
127579da4fa4SJeff Mahoney 	BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names) !=
127679da4fa4SJeff Mahoney 		     ARRAY_SIZE(btrfs_feature_attrs));
127779da4fa4SJeff Mahoney 	BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) !=
127879da4fa4SJeff Mahoney 		     ARRAY_SIZE(btrfs_feature_attrs[0]));
127979da4fa4SJeff Mahoney 
12803b02a68aSJeff Mahoney 	memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs));
12813b02a68aSJeff Mahoney 	memset(btrfs_unknown_feature_names, 0,
12823b02a68aSJeff Mahoney 	       sizeof(btrfs_unknown_feature_names));
12833b02a68aSJeff Mahoney 
128479da4fa4SJeff Mahoney 	for (i = 0; btrfs_supported_feature_attrs[i]; i++) {
128579da4fa4SJeff Mahoney 		struct btrfs_feature_attr *sfa;
128679da4fa4SJeff Mahoney 		struct attribute *a = btrfs_supported_feature_attrs[i];
12873b02a68aSJeff Mahoney 		int bit;
128879da4fa4SJeff Mahoney 		sfa = attr_to_btrfs_feature_attr(a);
12893b02a68aSJeff Mahoney 		bit = ilog2(sfa->feature_bit);
12903b02a68aSJeff Mahoney 		fa = &btrfs_feature_attrs[sfa->feature_set][bit];
129179da4fa4SJeff Mahoney 
129279da4fa4SJeff Mahoney 		fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name;
129379da4fa4SJeff Mahoney 	}
129479da4fa4SJeff Mahoney 
129579da4fa4SJeff Mahoney 	for (set = 0; set < FEAT_MAX; set++) {
129679da4fa4SJeff Mahoney 		for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
129779da4fa4SJeff Mahoney 			char *name = btrfs_unknown_feature_names[set][i];
129879da4fa4SJeff Mahoney 			fa = &btrfs_feature_attrs[set][i];
129979da4fa4SJeff Mahoney 
130079da4fa4SJeff Mahoney 			if (fa->kobj_attr.attr.name)
130179da4fa4SJeff Mahoney 				continue;
130279da4fa4SJeff Mahoney 
13036c52157fSTomohiro Misono 			snprintf(name, BTRFS_FEATURE_NAME_MAX, "%s:%u",
130479da4fa4SJeff Mahoney 				 btrfs_feature_set_names[set], i);
130579da4fa4SJeff Mahoney 
130679da4fa4SJeff Mahoney 			fa->kobj_attr.attr.name = name;
130779da4fa4SJeff Mahoney 			fa->kobj_attr.attr.mode = S_IRUGO;
130879da4fa4SJeff Mahoney 			fa->feature_set = set;
130979da4fa4SJeff Mahoney 			fa->feature_bit = 1ULL << i;
131079da4fa4SJeff Mahoney 		}
131179da4fa4SJeff Mahoney 	}
131279da4fa4SJeff Mahoney }
131379da4fa4SJeff Mahoney 
131432a9991fSDavid Sterba /*
131532a9991fSDavid Sterba  * Create a sysfs entry for a given block group type at path
131632a9991fSDavid Sterba  * /sys/fs/btrfs/UUID/allocation/data/TYPE
131732a9991fSDavid Sterba  */
131832da5386SDavid Sterba void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache)
131932a9991fSDavid Sterba {
132032a9991fSDavid Sterba 	struct btrfs_fs_info *fs_info = cache->fs_info;
132132a9991fSDavid Sterba 	struct btrfs_space_info *space_info = cache->space_info;
132232a9991fSDavid Sterba 	struct raid_kobject *rkobj;
132332a9991fSDavid Sterba 	const int index = btrfs_bg_flags_to_raid_index(cache->flags);
132432a9991fSDavid Sterba 	unsigned int nofs_flag;
132532a9991fSDavid Sterba 	int ret;
132632a9991fSDavid Sterba 
132732a9991fSDavid Sterba 	/*
132832a9991fSDavid Sterba 	 * Setup a NOFS context because kobject_add(), deep in its call chain,
132932a9991fSDavid Sterba 	 * does GFP_KERNEL allocations, and we are often called in a context
133032a9991fSDavid Sterba 	 * where if reclaim is triggered we can deadlock (we are either holding
133132a9991fSDavid Sterba 	 * a transaction handle or some lock required for a transaction
133232a9991fSDavid Sterba 	 * commit).
133332a9991fSDavid Sterba 	 */
133432a9991fSDavid Sterba 	nofs_flag = memalloc_nofs_save();
133532a9991fSDavid Sterba 
133632a9991fSDavid Sterba 	rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS);
133732a9991fSDavid Sterba 	if (!rkobj) {
133832a9991fSDavid Sterba 		memalloc_nofs_restore(nofs_flag);
133932a9991fSDavid Sterba 		btrfs_warn(cache->fs_info,
134032a9991fSDavid Sterba 				"couldn't alloc memory for raid level kobject");
134132a9991fSDavid Sterba 		return;
134232a9991fSDavid Sterba 	}
134332a9991fSDavid Sterba 
134432a9991fSDavid Sterba 	rkobj->flags = cache->flags;
134532a9991fSDavid Sterba 	kobject_init(&rkobj->kobj, &btrfs_raid_ktype);
134649ea112dSJosef Bacik 
134749ea112dSJosef Bacik 	/*
134849ea112dSJosef Bacik 	 * We call this either on mount, or if we've created a block group for a
134949ea112dSJosef Bacik 	 * new index type while running (i.e. when restriping).  The running
135049ea112dSJosef Bacik 	 * case is tricky because we could race with other threads, so we need
135149ea112dSJosef Bacik 	 * to have this check to make sure we didn't already init the kobject.
135249ea112dSJosef Bacik 	 *
135349ea112dSJosef Bacik 	 * We don't have to protect on the free side because it only happens on
135449ea112dSJosef Bacik 	 * unmount.
135549ea112dSJosef Bacik 	 */
135649ea112dSJosef Bacik 	spin_lock(&space_info->lock);
135749ea112dSJosef Bacik 	if (space_info->block_group_kobjs[index]) {
135849ea112dSJosef Bacik 		spin_unlock(&space_info->lock);
135949ea112dSJosef Bacik 		kobject_put(&rkobj->kobj);
136049ea112dSJosef Bacik 		return;
136149ea112dSJosef Bacik 	} else {
136249ea112dSJosef Bacik 		space_info->block_group_kobjs[index] = &rkobj->kobj;
136349ea112dSJosef Bacik 	}
136449ea112dSJosef Bacik 	spin_unlock(&space_info->lock);
136549ea112dSJosef Bacik 
136632a9991fSDavid Sterba 	ret = kobject_add(&rkobj->kobj, &space_info->kobj, "%s",
136732a9991fSDavid Sterba 			  btrfs_bg_type_to_raid_name(rkobj->flags));
136832a9991fSDavid Sterba 	memalloc_nofs_restore(nofs_flag);
136932a9991fSDavid Sterba 	if (ret) {
137049ea112dSJosef Bacik 		spin_lock(&space_info->lock);
137149ea112dSJosef Bacik 		space_info->block_group_kobjs[index] = NULL;
137249ea112dSJosef Bacik 		spin_unlock(&space_info->lock);
137332a9991fSDavid Sterba 		kobject_put(&rkobj->kobj);
137432a9991fSDavid Sterba 		btrfs_warn(fs_info,
137532a9991fSDavid Sterba 			"failed to add kobject for block cache, ignoring");
137632a9991fSDavid Sterba 		return;
137732a9991fSDavid Sterba 	}
137832a9991fSDavid Sterba }
137932a9991fSDavid Sterba 
1380b5865babSDavid Sterba /*
1381b5865babSDavid Sterba  * Remove sysfs directories for all block group types of a given space info and
1382b5865babSDavid Sterba  * the space info as well
1383b5865babSDavid Sterba  */
1384b5865babSDavid Sterba void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info)
1385b5865babSDavid Sterba {
1386b5865babSDavid Sterba 	int i;
1387b5865babSDavid Sterba 
1388b5865babSDavid Sterba 	for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
1389b5865babSDavid Sterba 		struct kobject *kobj;
1390b5865babSDavid Sterba 
1391b5865babSDavid Sterba 		kobj = space_info->block_group_kobjs[i];
1392b5865babSDavid Sterba 		space_info->block_group_kobjs[i] = NULL;
1393b5865babSDavid Sterba 		if (kobj) {
1394b5865babSDavid Sterba 			kobject_del(kobj);
1395b5865babSDavid Sterba 			kobject_put(kobj);
1396b5865babSDavid Sterba 		}
1397b5865babSDavid Sterba 	}
1398b5865babSDavid Sterba 	kobject_del(&space_info->kobj);
1399b5865babSDavid Sterba 	kobject_put(&space_info->kobj);
1400b5865babSDavid Sterba }
1401b5865babSDavid Sterba 
1402b882327aSDavid Sterba static const char *alloc_name(u64 flags)
1403b882327aSDavid Sterba {
1404b882327aSDavid Sterba 	switch (flags) {
1405b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA:
1406b882327aSDavid Sterba 		return "mixed";
1407b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_METADATA:
1408b882327aSDavid Sterba 		return "metadata";
1409b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_DATA:
1410b882327aSDavid Sterba 		return "data";
1411b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_SYSTEM:
1412b882327aSDavid Sterba 		return "system";
1413b882327aSDavid Sterba 	default:
1414b882327aSDavid Sterba 		WARN_ON(1);
1415b882327aSDavid Sterba 		return "invalid-combination";
1416445d8ab5STom Rix 	}
1417b882327aSDavid Sterba }
1418b882327aSDavid Sterba 
1419b882327aSDavid Sterba /*
1420b882327aSDavid Sterba  * Create a sysfs entry for a space info type at path
1421b882327aSDavid Sterba  * /sys/fs/btrfs/UUID/allocation/TYPE
1422b882327aSDavid Sterba  */
1423b882327aSDavid Sterba int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info,
1424b882327aSDavid Sterba 				    struct btrfs_space_info *space_info)
1425b882327aSDavid Sterba {
1426b882327aSDavid Sterba 	int ret;
1427b882327aSDavid Sterba 
1428b882327aSDavid Sterba 	ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype,
1429b882327aSDavid Sterba 				   fs_info->space_info_kobj, "%s",
1430b882327aSDavid Sterba 				   alloc_name(space_info->flags));
1431b882327aSDavid Sterba 	if (ret) {
1432b882327aSDavid Sterba 		kobject_put(&space_info->kobj);
1433b882327aSDavid Sterba 		return ret;
1434b882327aSDavid Sterba 	}
1435b882327aSDavid Sterba 
1436b882327aSDavid Sterba 	return 0;
1437b882327aSDavid Sterba }
1438b882327aSDavid Sterba 
143953f8a74cSAnand Jain void btrfs_sysfs_remove_device(struct btrfs_device *device)
144099994cdeSAnand Jain {
1441985e233eSAnand Jain 	struct kobject *devices_kobj;
144299994cdeSAnand Jain 
1443985e233eSAnand Jain 	/*
1444985e233eSAnand Jain 	 * Seed fs_devices devices_kobj aren't used, fetch kobject from the
1445985e233eSAnand Jain 	 * fs_info::fs_devices.
1446985e233eSAnand Jain 	 */
1447985e233eSAnand Jain 	devices_kobj = device->fs_info->fs_devices->devices_kobj;
1448985e233eSAnand Jain 	ASSERT(devices_kobj);
144999994cdeSAnand Jain 
14508d65269fSChristoph Hellwig 	if (device->bdev)
14518d65269fSChristoph Hellwig 		sysfs_remove_link(devices_kobj, bdev_kobj(device->bdev)->name);
145299994cdeSAnand Jain 
1453985e233eSAnand Jain 	if (device->devid_kobj.state_initialized) {
1454985e233eSAnand Jain 		kobject_del(&device->devid_kobj);
1455985e233eSAnand Jain 		kobject_put(&device->devid_kobj);
1456985e233eSAnand Jain 		wait_for_completion(&device->kobj_unregister);
1457985e233eSAnand Jain 	}
1458b5ddcffaSAnand Jain }
1459668e48afSAnand Jain 
1460668e48afSAnand Jain static ssize_t btrfs_devinfo_in_fs_metadata_show(struct kobject *kobj,
1461668e48afSAnand Jain 					         struct kobj_attribute *a,
1462668e48afSAnand Jain 					         char *buf)
1463668e48afSAnand Jain {
1464668e48afSAnand Jain 	int val;
1465668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1466668e48afSAnand Jain 						   devid_kobj);
1467668e48afSAnand Jain 
1468668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
1469668e48afSAnand Jain 
1470*020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1471668e48afSAnand Jain }
1472668e48afSAnand Jain BTRFS_ATTR(devid, in_fs_metadata, btrfs_devinfo_in_fs_metadata_show);
1473668e48afSAnand Jain 
147425864778SAnand Jain static ssize_t btrfs_devinfo_missing_show(struct kobject *kobj,
1475668e48afSAnand Jain 					struct kobj_attribute *a, char *buf)
1476668e48afSAnand Jain {
1477668e48afSAnand Jain 	int val;
1478668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1479668e48afSAnand Jain 						   devid_kobj);
1480668e48afSAnand Jain 
1481668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state);
1482668e48afSAnand Jain 
1483*020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1484668e48afSAnand Jain }
148525864778SAnand Jain BTRFS_ATTR(devid, missing, btrfs_devinfo_missing_show);
1486668e48afSAnand Jain 
1487668e48afSAnand Jain static ssize_t btrfs_devinfo_replace_target_show(struct kobject *kobj,
1488668e48afSAnand Jain 					         struct kobj_attribute *a,
1489668e48afSAnand Jain 					         char *buf)
1490668e48afSAnand Jain {
1491668e48afSAnand Jain 	int val;
1492668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1493668e48afSAnand Jain 						   devid_kobj);
1494668e48afSAnand Jain 
1495668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state);
1496668e48afSAnand Jain 
1497*020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1498668e48afSAnand Jain }
1499668e48afSAnand Jain BTRFS_ATTR(devid, replace_target, btrfs_devinfo_replace_target_show);
1500668e48afSAnand Jain 
1501eb3b5053SDavid Sterba static ssize_t btrfs_devinfo_scrub_speed_max_show(struct kobject *kobj,
1502eb3b5053SDavid Sterba 					     struct kobj_attribute *a,
1503eb3b5053SDavid Sterba 					     char *buf)
1504eb3b5053SDavid Sterba {
1505eb3b5053SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1506eb3b5053SDavid Sterba 						   devid_kobj);
1507eb3b5053SDavid Sterba 
1508*020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", READ_ONCE(device->scrub_speed_max));
1509eb3b5053SDavid Sterba }
1510eb3b5053SDavid Sterba 
1511eb3b5053SDavid Sterba static ssize_t btrfs_devinfo_scrub_speed_max_store(struct kobject *kobj,
1512eb3b5053SDavid Sterba 					      struct kobj_attribute *a,
1513eb3b5053SDavid Sterba 					      const char *buf, size_t len)
1514eb3b5053SDavid Sterba {
1515eb3b5053SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1516eb3b5053SDavid Sterba 						   devid_kobj);
1517eb3b5053SDavid Sterba 	char *endptr;
1518eb3b5053SDavid Sterba 	unsigned long long limit;
1519eb3b5053SDavid Sterba 
1520eb3b5053SDavid Sterba 	limit = memparse(buf, &endptr);
1521eb3b5053SDavid Sterba 	WRITE_ONCE(device->scrub_speed_max, limit);
1522eb3b5053SDavid Sterba 	return len;
1523eb3b5053SDavid Sterba }
1524eb3b5053SDavid Sterba BTRFS_ATTR_RW(devid, scrub_speed_max, btrfs_devinfo_scrub_speed_max_show,
1525eb3b5053SDavid Sterba 	      btrfs_devinfo_scrub_speed_max_store);
1526eb3b5053SDavid Sterba 
1527668e48afSAnand Jain static ssize_t btrfs_devinfo_writeable_show(struct kobject *kobj,
1528668e48afSAnand Jain 					    struct kobj_attribute *a, char *buf)
1529668e48afSAnand Jain {
1530668e48afSAnand Jain 	int val;
1531668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1532668e48afSAnand Jain 						   devid_kobj);
1533668e48afSAnand Jain 
1534668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
1535668e48afSAnand Jain 
1536*020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1537668e48afSAnand Jain }
1538668e48afSAnand Jain BTRFS_ATTR(devid, writeable, btrfs_devinfo_writeable_show);
1539668e48afSAnand Jain 
1540da658b57SDavid Sterba static ssize_t btrfs_devinfo_error_stats_show(struct kobject *kobj,
1541da658b57SDavid Sterba 		struct kobj_attribute *a, char *buf)
1542da658b57SDavid Sterba {
1543da658b57SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1544da658b57SDavid Sterba 						   devid_kobj);
1545da658b57SDavid Sterba 
1546da658b57SDavid Sterba 	if (!device->dev_stats_valid)
1547*020e5277SAnand Jain 		return sysfs_emit(buf, "invalid\n");
1548da658b57SDavid Sterba 
1549da658b57SDavid Sterba 	/*
1550da658b57SDavid Sterba 	 * Print all at once so we get a snapshot of all values from the same
1551da658b57SDavid Sterba 	 * time. Keep them in sync and in order of definition of
1552da658b57SDavid Sterba 	 * btrfs_dev_stat_values.
1553da658b57SDavid Sterba 	 */
1554*020e5277SAnand Jain 	return sysfs_emit(buf,
1555da658b57SDavid Sterba 		"write_errs %d\n"
1556da658b57SDavid Sterba 		"read_errs %d\n"
1557da658b57SDavid Sterba 		"flush_errs %d\n"
1558da658b57SDavid Sterba 		"corruption_errs %d\n"
1559da658b57SDavid Sterba 		"generation_errs %d\n",
1560da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_WRITE_ERRS),
1561da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_READ_ERRS),
1562da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_FLUSH_ERRS),
1563da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_CORRUPTION_ERRS),
1564da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_GENERATION_ERRS));
1565da658b57SDavid Sterba }
1566da658b57SDavid Sterba BTRFS_ATTR(devid, error_stats, btrfs_devinfo_error_stats_show);
1567da658b57SDavid Sterba 
1568e7849e33SAnand Jain /*
1569e7849e33SAnand Jain  * Information about one device.
1570e7849e33SAnand Jain  *
1571e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/devinfo/<devid>/
1572e7849e33SAnand Jain  */
1573668e48afSAnand Jain static struct attribute *devid_attrs[] = {
1574da658b57SDavid Sterba 	BTRFS_ATTR_PTR(devid, error_stats),
1575668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, in_fs_metadata),
1576668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, missing),
1577668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, replace_target),
1578eb3b5053SDavid Sterba 	BTRFS_ATTR_PTR(devid, scrub_speed_max),
1579668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, writeable),
1580668e48afSAnand Jain 	NULL
1581668e48afSAnand Jain };
1582668e48afSAnand Jain ATTRIBUTE_GROUPS(devid);
1583668e48afSAnand Jain 
1584668e48afSAnand Jain static void btrfs_release_devid_kobj(struct kobject *kobj)
1585668e48afSAnand Jain {
1586668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1587668e48afSAnand Jain 						   devid_kobj);
1588668e48afSAnand Jain 
1589668e48afSAnand Jain 	memset(&device->devid_kobj, 0, sizeof(struct kobject));
1590668e48afSAnand Jain 	complete(&device->kobj_unregister);
1591668e48afSAnand Jain }
1592668e48afSAnand Jain 
1593668e48afSAnand Jain static struct kobj_type devid_ktype = {
1594668e48afSAnand Jain 	.sysfs_ops	= &kobj_sysfs_ops,
1595668e48afSAnand Jain 	.default_groups = devid_groups,
1596668e48afSAnand Jain 	.release	= btrfs_release_devid_kobj,
1597668e48afSAnand Jain };
1598668e48afSAnand Jain 
1599cd36da2eSAnand Jain int btrfs_sysfs_add_device(struct btrfs_device *device)
160029e5be24SJeff Mahoney {
1601178a16c9SAnand Jain 	int ret;
1602a47bd78dSJosef Bacik 	unsigned int nofs_flag;
1603178a16c9SAnand Jain 	struct kobject *devices_kobj;
1604178a16c9SAnand Jain 	struct kobject *devinfo_kobj;
1605178a16c9SAnand Jain 
1606178a16c9SAnand Jain 	/*
1607178a16c9SAnand Jain 	 * Make sure we use the fs_info::fs_devices to fetch the kobjects even
1608178a16c9SAnand Jain 	 * for the seed fs_devices
1609178a16c9SAnand Jain 	 */
1610178a16c9SAnand Jain 	devices_kobj = device->fs_info->fs_devices->devices_kobj;
1611178a16c9SAnand Jain 	devinfo_kobj = device->fs_info->fs_devices->devinfo_kobj;
1612178a16c9SAnand Jain 	ASSERT(devices_kobj);
1613178a16c9SAnand Jain 	ASSERT(devinfo_kobj);
161429e5be24SJeff Mahoney 
1615a47bd78dSJosef Bacik 	nofs_flag = memalloc_nofs_save();
1616f085381eSAnand Jain 
1617178a16c9SAnand Jain 	if (device->bdev) {
16188d65269fSChristoph Hellwig 		struct kobject *disk_kobj = bdev_kobj(device->bdev);
161929e5be24SJeff Mahoney 
1620178a16c9SAnand Jain 		ret = sysfs_create_link(devices_kobj, disk_kobj, disk_kobj->name);
1621178a16c9SAnand Jain 		if (ret) {
1622178a16c9SAnand Jain 			btrfs_warn(device->fs_info,
1623178a16c9SAnand Jain 				"creating sysfs device link for devid %llu failed: %d",
1624178a16c9SAnand Jain 				device->devid, ret);
1625178a16c9SAnand Jain 			goto out;
1626178a16c9SAnand Jain 		}
162729e5be24SJeff Mahoney 	}
162829e5be24SJeff Mahoney 
1629178a16c9SAnand Jain 	init_completion(&device->kobj_unregister);
1630178a16c9SAnand Jain 	ret = kobject_init_and_add(&device->devid_kobj, &devid_ktype,
1631178a16c9SAnand Jain 				   devinfo_kobj, "%llu", device->devid);
1632178a16c9SAnand Jain 	if (ret) {
1633178a16c9SAnand Jain 		kobject_put(&device->devid_kobj);
1634178a16c9SAnand Jain 		btrfs_warn(device->fs_info,
1635178a16c9SAnand Jain 			   "devinfo init for devid %llu failed: %d",
1636178a16c9SAnand Jain 			   device->devid, ret);
1637668e48afSAnand Jain 	}
1638178a16c9SAnand Jain 
1639178a16c9SAnand Jain out:
1640a47bd78dSJosef Bacik 	memalloc_nofs_restore(nofs_flag);
1641178a16c9SAnand Jain 	return ret;
1642178a16c9SAnand Jain }
1643668e48afSAnand Jain 
1644cd36da2eSAnand Jain static int btrfs_sysfs_add_fs_devices(struct btrfs_fs_devices *fs_devices)
1645178a16c9SAnand Jain {
1646178a16c9SAnand Jain 	int ret;
1647cd36da2eSAnand Jain 	struct btrfs_device *device;
164830b0e4e0SAnand Jain 	struct btrfs_fs_devices *seed;
1649178a16c9SAnand Jain 
1650178a16c9SAnand Jain 	list_for_each_entry(device, &fs_devices->devices, dev_list) {
1651178a16c9SAnand Jain 		ret = btrfs_sysfs_add_device(device);
1652178a16c9SAnand Jain 		if (ret)
16537ad3912aSAnand Jain 			goto fail;
1654178a16c9SAnand Jain 	}
1655178a16c9SAnand Jain 
165630b0e4e0SAnand Jain 	list_for_each_entry(seed, &fs_devices->seed_list, seed_list) {
165730b0e4e0SAnand Jain 		list_for_each_entry(device, &seed->devices, dev_list) {
165830b0e4e0SAnand Jain 			ret = btrfs_sysfs_add_device(device);
165930b0e4e0SAnand Jain 			if (ret)
16607ad3912aSAnand Jain 				goto fail;
166130b0e4e0SAnand Jain 		}
166230b0e4e0SAnand Jain 	}
166330b0e4e0SAnand Jain 
1664178a16c9SAnand Jain 	return 0;
16657ad3912aSAnand Jain 
16667ad3912aSAnand Jain fail:
16677ad3912aSAnand Jain 	btrfs_sysfs_remove_fs_devices(fs_devices);
16687ad3912aSAnand Jain 	return ret;
166929e5be24SJeff Mahoney }
167029e5be24SJeff Mahoney 
16715b28692eSDavid Sterba void btrfs_kobject_uevent(struct block_device *bdev, enum kobject_action action)
16725b28692eSDavid Sterba {
16735b28692eSDavid Sterba 	int ret;
16745b28692eSDavid Sterba 
16755b28692eSDavid Sterba 	ret = kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, action);
16765b28692eSDavid Sterba 	if (ret)
16775b28692eSDavid Sterba 		pr_warn("BTRFS: Sending event '%d' to kobject: '%s' (%p): failed\n",
16785b28692eSDavid Sterba 			action, kobject_name(&disk_to_dev(bdev->bd_disk)->kobj),
16795b28692eSDavid Sterba 			&disk_to_dev(bdev->bd_disk)->kobj);
16805b28692eSDavid Sterba }
16815b28692eSDavid Sterba 
16828e560081SNikolay Borisov void btrfs_sysfs_update_sprout_fsid(struct btrfs_fs_devices *fs_devices)
16838e560081SNikolay Borisov 
1684f93c3997SDavid Sterba {
1685f93c3997SDavid Sterba 	char fsid_buf[BTRFS_UUID_UNPARSED_SIZE];
1686f93c3997SDavid Sterba 
1687f93c3997SDavid Sterba 	/*
1688f93c3997SDavid Sterba 	 * Sprouting changes fsid of the mounted filesystem, rename the fsid
1689f93c3997SDavid Sterba 	 * directory
1690f93c3997SDavid Sterba 	 */
16918e560081SNikolay Borisov 	snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU", fs_devices->fsid);
1692f93c3997SDavid Sterba 	if (kobject_rename(&fs_devices->fsid_kobj, fsid_buf))
1693f93c3997SDavid Sterba 		btrfs_warn(fs_devices->fs_info,
1694f93c3997SDavid Sterba 				"sysfs: failed to create fsid for sprout");
1695f93c3997SDavid Sterba }
1696f93c3997SDavid Sterba 
1697668e48afSAnand Jain void btrfs_sysfs_update_devid(struct btrfs_device *device)
1698668e48afSAnand Jain {
1699668e48afSAnand Jain 	char tmp[24];
1700668e48afSAnand Jain 
1701668e48afSAnand Jain 	snprintf(tmp, sizeof(tmp), "%llu", device->devid);
1702668e48afSAnand Jain 
1703668e48afSAnand Jain 	if (kobject_rename(&device->devid_kobj, tmp))
1704668e48afSAnand Jain 		btrfs_warn(device->fs_devices->fs_info,
1705668e48afSAnand Jain 			   "sysfs: failed to update devid for %llu",
1706668e48afSAnand Jain 			   device->devid);
1707668e48afSAnand Jain }
1708668e48afSAnand Jain 
1709510d7360SJeff Mahoney /* /sys/fs/btrfs/ entry */
1710510d7360SJeff Mahoney static struct kset *btrfs_kset;
1711510d7360SJeff Mahoney 
171272059215SAnand Jain /*
1713c6761a9eSAnand Jain  * Creates:
1714c6761a9eSAnand Jain  *		/sys/fs/btrfs/UUID
1715c6761a9eSAnand Jain  *
171672059215SAnand Jain  * Can be called by the device discovery thread.
171772059215SAnand Jain  */
1718c6761a9eSAnand Jain int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs)
17195ac1d209SJeff Mahoney {
17205ac1d209SJeff Mahoney 	int error;
17215ac1d209SJeff Mahoney 
17222e7910d6SAnand Jain 	init_completion(&fs_devs->kobj_unregister);
1723c1b7e474SAnand Jain 	fs_devs->fsid_kobj.kset = btrfs_kset;
1724c6761a9eSAnand Jain 	error = kobject_init_and_add(&fs_devs->fsid_kobj, &btrfs_ktype, NULL,
1725c6761a9eSAnand Jain 				     "%pU", fs_devs->fsid);
1726e3277335STobin C. Harding 	if (error) {
1727e3277335STobin C. Harding 		kobject_put(&fs_devs->fsid_kobj);
172872059215SAnand Jain 		return error;
172972059215SAnand Jain 	}
173072059215SAnand Jain 
1731bc036bb3SAnand Jain 	fs_devs->devices_kobj = kobject_create_and_add("devices",
1732bc036bb3SAnand Jain 						       &fs_devs->fsid_kobj);
1733bc036bb3SAnand Jain 	if (!fs_devs->devices_kobj) {
1734bc036bb3SAnand Jain 		btrfs_err(fs_devs->fs_info,
1735bc036bb3SAnand Jain 			  "failed to init sysfs device interface");
17361f6087e6SAnand Jain 		btrfs_sysfs_remove_fsid(fs_devs);
1737bc036bb3SAnand Jain 		return -ENOMEM;
1738bc036bb3SAnand Jain 	}
1739bc036bb3SAnand Jain 
1740a013d141SAnand Jain 	fs_devs->devinfo_kobj = kobject_create_and_add("devinfo",
1741a013d141SAnand Jain 						       &fs_devs->fsid_kobj);
1742a013d141SAnand Jain 	if (!fs_devs->devinfo_kobj) {
1743a013d141SAnand Jain 		btrfs_err(fs_devs->fs_info,
1744a013d141SAnand Jain 			  "failed to init sysfs devinfo kobject");
1745a013d141SAnand Jain 		btrfs_sysfs_remove_fsid(fs_devs);
1746a013d141SAnand Jain 		return -ENOMEM;
1747a013d141SAnand Jain 	}
1748a013d141SAnand Jain 
1749e3277335STobin C. Harding 	return 0;
1750e3277335STobin C. Harding }
1751e3277335STobin C. Harding 
175296f3136eSAnand Jain int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info)
175372059215SAnand Jain {
175472059215SAnand Jain 	int error;
17552e7910d6SAnand Jain 	struct btrfs_fs_devices *fs_devs = fs_info->fs_devices;
1756c1b7e474SAnand Jain 	struct kobject *fsid_kobj = &fs_devs->fsid_kobj;
175772059215SAnand Jain 
1758cd36da2eSAnand Jain 	error = btrfs_sysfs_add_fs_devices(fs_devs);
1759e453d989SJeff Mahoney 	if (error)
1760e453d989SJeff Mahoney 		return error;
1761510d7360SJeff Mahoney 
1762c1b7e474SAnand Jain 	error = sysfs_create_files(fsid_kobj, btrfs_attrs);
1763e453d989SJeff Mahoney 	if (error) {
176453f8a74cSAnand Jain 		btrfs_sysfs_remove_fs_devices(fs_devs);
1765e453d989SJeff Mahoney 		return error;
1766e453d989SJeff Mahoney 	}
176779da4fa4SJeff Mahoney 
1768c1b7e474SAnand Jain 	error = sysfs_create_group(fsid_kobj,
17690dd2906fSAnand Jain 				   &btrfs_feature_attr_group);
17700dd2906fSAnand Jain 	if (error)
17710dd2906fSAnand Jain 		goto failure;
17720dd2906fSAnand Jain 
17736e369febSDavid Sterba #ifdef CONFIG_BTRFS_DEBUG
177493945cb4SDennis Zhou 	fs_info->debug_kobj = kobject_create_and_add("debug", fsid_kobj);
177593945cb4SDennis Zhou 	if (!fs_info->debug_kobj) {
177693945cb4SDennis Zhou 		error = -ENOMEM;
177793945cb4SDennis Zhou 		goto failure;
177893945cb4SDennis Zhou 	}
177993945cb4SDennis Zhou 
178093945cb4SDennis Zhou 	error = sysfs_create_files(fs_info->debug_kobj, btrfs_debug_mount_attrs);
17816e369febSDavid Sterba 	if (error)
17826e369febSDavid Sterba 		goto failure;
1783e4faab84SDennis Zhou 
1784e4faab84SDennis Zhou 	/* Discard directory */
1785e4faab84SDennis Zhou 	fs_info->discard_debug_kobj = kobject_create_and_add("discard",
1786e4faab84SDennis Zhou 						     fs_info->debug_kobj);
1787e4faab84SDennis Zhou 	if (!fs_info->discard_debug_kobj) {
1788e4faab84SDennis Zhou 		error = -ENOMEM;
1789e4faab84SDennis Zhou 		goto failure;
1790e4faab84SDennis Zhou 	}
1791e4faab84SDennis Zhou 
1792e4faab84SDennis Zhou 	error = sysfs_create_files(fs_info->discard_debug_kobj,
1793e4faab84SDennis Zhou 				   discard_debug_attrs);
1794e4faab84SDennis Zhou 	if (error)
1795e4faab84SDennis Zhou 		goto failure;
17966e369febSDavid Sterba #endif
17976e369febSDavid Sterba 
1798e453d989SJeff Mahoney 	error = addrm_unknown_feature_attrs(fs_info, true);
179979da4fa4SJeff Mahoney 	if (error)
180079da4fa4SJeff Mahoney 		goto failure;
180179da4fa4SJeff Mahoney 
18023092c68fSNikolay Borisov 	error = sysfs_create_link(fsid_kobj, &fs_info->sb->s_bdi->dev->kobj, "bdi");
18033092c68fSNikolay Borisov 	if (error)
18043092c68fSNikolay Borisov 		goto failure;
18053092c68fSNikolay Borisov 
18066ab0a202SJeff Mahoney 	fs_info->space_info_kobj = kobject_create_and_add("allocation",
1807c1b7e474SAnand Jain 						  fsid_kobj);
18086ab0a202SJeff Mahoney 	if (!fs_info->space_info_kobj) {
18096ab0a202SJeff Mahoney 		error = -ENOMEM;
18106ab0a202SJeff Mahoney 		goto failure;
18116ab0a202SJeff Mahoney 	}
18126ab0a202SJeff Mahoney 
18136ab0a202SJeff Mahoney 	error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs);
18146ab0a202SJeff Mahoney 	if (error)
18156ab0a202SJeff Mahoney 		goto failure;
18166ab0a202SJeff Mahoney 
181779da4fa4SJeff Mahoney 	return 0;
181879da4fa4SJeff Mahoney failure:
18196618a59bSAnand Jain 	btrfs_sysfs_remove_mounted(fs_info);
18205ac1d209SJeff Mahoney 	return error;
18215ac1d209SJeff Mahoney }
18225ac1d209SJeff Mahoney 
182349e5fb46SQu Wenruo static inline struct btrfs_fs_info *qgroup_kobj_to_fs_info(struct kobject *kobj)
182449e5fb46SQu Wenruo {
182549e5fb46SQu Wenruo 	return to_fs_info(kobj->parent->parent);
182649e5fb46SQu Wenruo }
182749e5fb46SQu Wenruo 
182849e5fb46SQu Wenruo #define QGROUP_ATTR(_member, _show_name)					\
182949e5fb46SQu Wenruo static ssize_t btrfs_qgroup_show_##_member(struct kobject *qgroup_kobj,		\
183049e5fb46SQu Wenruo 					   struct kobj_attribute *a,		\
183149e5fb46SQu Wenruo 					   char *buf)				\
183249e5fb46SQu Wenruo {										\
183349e5fb46SQu Wenruo 	struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj);	\
183449e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(qgroup_kobj,			\
183549e5fb46SQu Wenruo 			struct btrfs_qgroup, kobj);				\
183649e5fb46SQu Wenruo 	return btrfs_show_u64(&qgroup->_member, &fs_info->qgroup_lock, buf);	\
183749e5fb46SQu Wenruo }										\
183849e5fb46SQu Wenruo BTRFS_ATTR(qgroup, _show_name, btrfs_qgroup_show_##_member)
183949e5fb46SQu Wenruo 
184049e5fb46SQu Wenruo #define QGROUP_RSV_ATTR(_name, _type)						\
184149e5fb46SQu Wenruo static ssize_t btrfs_qgroup_rsv_show_##_name(struct kobject *qgroup_kobj,	\
184249e5fb46SQu Wenruo 					     struct kobj_attribute *a,		\
184349e5fb46SQu Wenruo 					     char *buf)				\
184449e5fb46SQu Wenruo {										\
184549e5fb46SQu Wenruo 	struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj);	\
184649e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(qgroup_kobj,			\
184749e5fb46SQu Wenruo 			struct btrfs_qgroup, kobj);				\
184849e5fb46SQu Wenruo 	return btrfs_show_u64(&qgroup->rsv.values[_type],			\
184949e5fb46SQu Wenruo 			&fs_info->qgroup_lock, buf);				\
185049e5fb46SQu Wenruo }										\
185149e5fb46SQu Wenruo BTRFS_ATTR(qgroup, rsv_##_name, btrfs_qgroup_rsv_show_##_name)
185249e5fb46SQu Wenruo 
185349e5fb46SQu Wenruo QGROUP_ATTR(rfer, referenced);
185449e5fb46SQu Wenruo QGROUP_ATTR(excl, exclusive);
185549e5fb46SQu Wenruo QGROUP_ATTR(max_rfer, max_referenced);
185649e5fb46SQu Wenruo QGROUP_ATTR(max_excl, max_exclusive);
185749e5fb46SQu Wenruo QGROUP_ATTR(lim_flags, limit_flags);
185849e5fb46SQu Wenruo QGROUP_RSV_ATTR(data, BTRFS_QGROUP_RSV_DATA);
185949e5fb46SQu Wenruo QGROUP_RSV_ATTR(meta_pertrans, BTRFS_QGROUP_RSV_META_PERTRANS);
186049e5fb46SQu Wenruo QGROUP_RSV_ATTR(meta_prealloc, BTRFS_QGROUP_RSV_META_PREALLOC);
186149e5fb46SQu Wenruo 
1862e7849e33SAnand Jain /*
1863e7849e33SAnand Jain  * Qgroup information.
1864e7849e33SAnand Jain  *
1865e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/qgroups/<level>_<qgroupid>/
1866e7849e33SAnand Jain  */
186749e5fb46SQu Wenruo static struct attribute *qgroup_attrs[] = {
186849e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, referenced),
186949e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, exclusive),
187049e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, max_referenced),
187149e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, max_exclusive),
187249e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, limit_flags),
187349e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_data),
187449e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_meta_pertrans),
187549e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_meta_prealloc),
187649e5fb46SQu Wenruo 	NULL
187749e5fb46SQu Wenruo };
187849e5fb46SQu Wenruo ATTRIBUTE_GROUPS(qgroup);
187949e5fb46SQu Wenruo 
188049e5fb46SQu Wenruo static void qgroup_release(struct kobject *kobj)
188149e5fb46SQu Wenruo {
188249e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(kobj, struct btrfs_qgroup, kobj);
188349e5fb46SQu Wenruo 
188449e5fb46SQu Wenruo 	memset(&qgroup->kobj, 0, sizeof(*kobj));
188549e5fb46SQu Wenruo }
188649e5fb46SQu Wenruo 
188749e5fb46SQu Wenruo static struct kobj_type qgroup_ktype = {
188849e5fb46SQu Wenruo 	.sysfs_ops = &kobj_sysfs_ops,
188949e5fb46SQu Wenruo 	.release = qgroup_release,
189049e5fb46SQu Wenruo 	.default_groups = qgroup_groups,
189149e5fb46SQu Wenruo };
189249e5fb46SQu Wenruo 
189349e5fb46SQu Wenruo int btrfs_sysfs_add_one_qgroup(struct btrfs_fs_info *fs_info,
189449e5fb46SQu Wenruo 				struct btrfs_qgroup *qgroup)
189549e5fb46SQu Wenruo {
189649e5fb46SQu Wenruo 	struct kobject *qgroups_kobj = fs_info->qgroups_kobj;
189749e5fb46SQu Wenruo 	int ret;
189849e5fb46SQu Wenruo 
189949e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
190049e5fb46SQu Wenruo 		return 0;
190149e5fb46SQu Wenruo 	if (qgroup->kobj.state_initialized)
190249e5fb46SQu Wenruo 		return 0;
190349e5fb46SQu Wenruo 	if (!qgroups_kobj)
190449e5fb46SQu Wenruo 		return -EINVAL;
190549e5fb46SQu Wenruo 
190649e5fb46SQu Wenruo 	ret = kobject_init_and_add(&qgroup->kobj, &qgroup_ktype, qgroups_kobj,
190749e5fb46SQu Wenruo 			"%hu_%llu", btrfs_qgroup_level(qgroup->qgroupid),
190849e5fb46SQu Wenruo 			btrfs_qgroup_subvolid(qgroup->qgroupid));
190949e5fb46SQu Wenruo 	if (ret < 0)
191049e5fb46SQu Wenruo 		kobject_put(&qgroup->kobj);
191149e5fb46SQu Wenruo 
191249e5fb46SQu Wenruo 	return ret;
191349e5fb46SQu Wenruo }
191449e5fb46SQu Wenruo 
191549e5fb46SQu Wenruo void btrfs_sysfs_del_qgroups(struct btrfs_fs_info *fs_info)
191649e5fb46SQu Wenruo {
191749e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup;
191849e5fb46SQu Wenruo 	struct btrfs_qgroup *next;
191949e5fb46SQu Wenruo 
192049e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
192149e5fb46SQu Wenruo 		return;
192249e5fb46SQu Wenruo 
192349e5fb46SQu Wenruo 	rbtree_postorder_for_each_entry_safe(qgroup, next,
192449e5fb46SQu Wenruo 					     &fs_info->qgroup_tree, node)
192549e5fb46SQu Wenruo 		btrfs_sysfs_del_one_qgroup(fs_info, qgroup);
192662ab2cc0SQu Wenruo 	if (fs_info->qgroups_kobj) {
192749e5fb46SQu Wenruo 		kobject_del(fs_info->qgroups_kobj);
192849e5fb46SQu Wenruo 		kobject_put(fs_info->qgroups_kobj);
192949e5fb46SQu Wenruo 		fs_info->qgroups_kobj = NULL;
193049e5fb46SQu Wenruo 	}
193162ab2cc0SQu Wenruo }
193249e5fb46SQu Wenruo 
193349e5fb46SQu Wenruo /* Called when qgroups get initialized, thus there is no need for locking */
193449e5fb46SQu Wenruo int btrfs_sysfs_add_qgroups(struct btrfs_fs_info *fs_info)
193549e5fb46SQu Wenruo {
193649e5fb46SQu Wenruo 	struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj;
193749e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup;
193849e5fb46SQu Wenruo 	struct btrfs_qgroup *next;
193949e5fb46SQu Wenruo 	int ret = 0;
194049e5fb46SQu Wenruo 
194149e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
194249e5fb46SQu Wenruo 		return 0;
194349e5fb46SQu Wenruo 
194449e5fb46SQu Wenruo 	ASSERT(fsid_kobj);
194549e5fb46SQu Wenruo 	if (fs_info->qgroups_kobj)
194649e5fb46SQu Wenruo 		return 0;
194749e5fb46SQu Wenruo 
194849e5fb46SQu Wenruo 	fs_info->qgroups_kobj = kobject_create_and_add("qgroups", fsid_kobj);
194949e5fb46SQu Wenruo 	if (!fs_info->qgroups_kobj) {
195049e5fb46SQu Wenruo 		ret = -ENOMEM;
195149e5fb46SQu Wenruo 		goto out;
195249e5fb46SQu Wenruo 	}
195349e5fb46SQu Wenruo 	rbtree_postorder_for_each_entry_safe(qgroup, next,
195449e5fb46SQu Wenruo 					     &fs_info->qgroup_tree, node) {
195549e5fb46SQu Wenruo 		ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
195649e5fb46SQu Wenruo 		if (ret < 0)
195749e5fb46SQu Wenruo 			goto out;
195849e5fb46SQu Wenruo 	}
195949e5fb46SQu Wenruo 
196049e5fb46SQu Wenruo out:
196149e5fb46SQu Wenruo 	if (ret < 0)
196249e5fb46SQu Wenruo 		btrfs_sysfs_del_qgroups(fs_info);
196349e5fb46SQu Wenruo 	return ret;
196449e5fb46SQu Wenruo }
196549e5fb46SQu Wenruo 
196649e5fb46SQu Wenruo void btrfs_sysfs_del_one_qgroup(struct btrfs_fs_info *fs_info,
196749e5fb46SQu Wenruo 				struct btrfs_qgroup *qgroup)
196849e5fb46SQu Wenruo {
196949e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
197049e5fb46SQu Wenruo 		return;
197149e5fb46SQu Wenruo 
197249e5fb46SQu Wenruo 	if (qgroup->kobj.state_initialized) {
197349e5fb46SQu Wenruo 		kobject_del(&qgroup->kobj);
197449e5fb46SQu Wenruo 		kobject_put(&qgroup->kobj);
197549e5fb46SQu Wenruo 	}
197649e5fb46SQu Wenruo }
1977444e7516SDavid Sterba 
1978444e7516SDavid Sterba /*
1979444e7516SDavid Sterba  * Change per-fs features in /sys/fs/btrfs/UUID/features to match current
1980444e7516SDavid Sterba  * values in superblock. Call after any changes to incompat/compat_ro flags
1981444e7516SDavid Sterba  */
1982444e7516SDavid Sterba void btrfs_sysfs_feature_update(struct btrfs_fs_info *fs_info,
1983444e7516SDavid Sterba 		u64 bit, enum btrfs_feature_set set)
1984444e7516SDavid Sterba {
1985444e7516SDavid Sterba 	struct btrfs_fs_devices *fs_devs;
1986444e7516SDavid Sterba 	struct kobject *fsid_kobj;
198724646481SLeon Romanovsky 	u64 __maybe_unused features;
198824646481SLeon Romanovsky 	int __maybe_unused ret;
1989444e7516SDavid Sterba 
1990444e7516SDavid Sterba 	if (!fs_info)
1991444e7516SDavid Sterba 		return;
1992444e7516SDavid Sterba 
199324646481SLeon Romanovsky 	/*
199424646481SLeon Romanovsky 	 * See 14e46e04958df74 and e410e34fad913dd, feature bit updates are not
199524646481SLeon Romanovsky 	 * safe when called from some contexts (eg. balance)
199624646481SLeon Romanovsky 	 */
1997444e7516SDavid Sterba 	features = get_features(fs_info, set);
1998444e7516SDavid Sterba 	ASSERT(bit & supported_feature_masks[set]);
1999444e7516SDavid Sterba 
2000444e7516SDavid Sterba 	fs_devs = fs_info->fs_devices;
2001444e7516SDavid Sterba 	fsid_kobj = &fs_devs->fsid_kobj;
2002444e7516SDavid Sterba 
2003bf609206SDavid Sterba 	if (!fsid_kobj->state_initialized)
2004bf609206SDavid Sterba 		return;
2005bf609206SDavid Sterba 
2006444e7516SDavid Sterba 	/*
2007444e7516SDavid Sterba 	 * FIXME: this is too heavy to update just one value, ideally we'd like
2008444e7516SDavid Sterba 	 * to use sysfs_update_group but some refactoring is needed first.
2009444e7516SDavid Sterba 	 */
2010444e7516SDavid Sterba 	sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group);
2011444e7516SDavid Sterba 	ret = sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group);
2012444e7516SDavid Sterba }
2013444e7516SDavid Sterba 
2014f5c29bd9SLiu Bo int __init btrfs_init_sysfs(void)
201558176a96SJosef Bacik {
2016079b72bcSJeff Mahoney 	int ret;
20171bae3098SDavid Sterba 
2018e3fe4e71SGreg KH 	btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
2019e3fe4e71SGreg KH 	if (!btrfs_kset)
2020e3fe4e71SGreg KH 		return -ENOMEM;
2021079b72bcSJeff Mahoney 
20221bae3098SDavid Sterba 	init_feature_attrs();
20231bae3098SDavid Sterba 	ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
2024001a648dSFilipe Manana 	if (ret)
2025001a648dSFilipe Manana 		goto out2;
2026f902bd3aSMisono Tomohiro 	ret = sysfs_merge_group(&btrfs_kset->kobj,
2027f902bd3aSMisono Tomohiro 				&btrfs_static_feature_attr_group);
2028f902bd3aSMisono Tomohiro 	if (ret)
2029f902bd3aSMisono Tomohiro 		goto out_remove_group;
2030001a648dSFilipe Manana 
20316e369febSDavid Sterba #ifdef CONFIG_BTRFS_DEBUG
20326e369febSDavid Sterba 	ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group);
20336e369febSDavid Sterba 	if (ret)
20346e369febSDavid Sterba 		goto out2;
20356e369febSDavid Sterba #endif
20366e369febSDavid Sterba 
2037001a648dSFilipe Manana 	return 0;
2038f902bd3aSMisono Tomohiro 
2039f902bd3aSMisono Tomohiro out_remove_group:
2040f902bd3aSMisono Tomohiro 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
2041001a648dSFilipe Manana out2:
2042001a648dSFilipe Manana 	kset_unregister(btrfs_kset);
20431bae3098SDavid Sterba 
20441bae3098SDavid Sterba 	return ret;
204558176a96SJosef Bacik }
204658176a96SJosef Bacik 
2047e67c718bSDavid Sterba void __cold btrfs_exit_sysfs(void)
204858176a96SJosef Bacik {
2049f902bd3aSMisono Tomohiro 	sysfs_unmerge_group(&btrfs_kset->kobj,
2050f902bd3aSMisono Tomohiro 			    &btrfs_static_feature_attr_group);
2051079b72bcSJeff Mahoney 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
205271e8978eSDennis Zhou #ifdef CONFIG_BTRFS_DEBUG
205371e8978eSDennis Zhou 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group);
205471e8978eSDennis Zhou #endif
2055e3fe4e71SGreg KH 	kset_unregister(btrfs_kset);
205658176a96SJosef Bacik }
205755d47414SChris Mason 
2058