xref: /openbmc/linux/fs/btrfs/sysfs.c (revision 19fc516a)
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"
24*19fc516aSStefan Roesch #include "misc.h"
25079b72bcSJeff Mahoney 
26e7849e33SAnand Jain /*
27e7849e33SAnand Jain  * Structure name                       Path
28e7849e33SAnand Jain  * --------------------------------------------------------------------------
29e7849e33SAnand Jain  * btrfs_supported_static_feature_attrs /sys/fs/btrfs/features
30e7849e33SAnand Jain  * btrfs_supported_feature_attrs	/sys/fs/btrfs/features and
31e7849e33SAnand Jain  *					/sys/fs/btrfs/<uuid>/features
32e7849e33SAnand Jain  * btrfs_attrs				/sys/fs/btrfs/<uuid>
33e7849e33SAnand Jain  * devid_attrs				/sys/fs/btrfs/<uuid>/devinfo/<devid>
34e7849e33SAnand Jain  * allocation_attrs			/sys/fs/btrfs/<uuid>/allocation
35e7849e33SAnand Jain  * qgroup_attrs				/sys/fs/btrfs/<uuid>/qgroups/<level>_<qgroupid>
36e7849e33SAnand Jain  * space_info_attrs			/sys/fs/btrfs/<uuid>/allocation/<bg-type>
37e7849e33SAnand Jain  * raid_attrs				/sys/fs/btrfs/<uuid>/allocation/<bg-type>/<bg-profile>
38e7849e33SAnand Jain  *
39e7849e33SAnand Jain  * When built with BTRFS_CONFIG_DEBUG:
40e7849e33SAnand Jain  *
41e7849e33SAnand Jain  * btrfs_debug_feature_attrs		/sys/fs/btrfs/debug
42e7849e33SAnand Jain  * btrfs_debug_mount_attrs		/sys/fs/btrfs/<uuid>/debug
43e7849e33SAnand Jain  * discard_debug_attrs			/sys/fs/btrfs/<uuid>/debug/discard
44e7849e33SAnand Jain  */
45e7849e33SAnand Jain 
469188db61SDavid Sterba struct btrfs_feature_attr {
479188db61SDavid Sterba 	struct kobj_attribute kobj_attr;
489188db61SDavid Sterba 	enum btrfs_feature_set feature_set;
499188db61SDavid Sterba 	u64 feature_bit;
509188db61SDavid Sterba };
519188db61SDavid Sterba 
529188db61SDavid Sterba /* For raid type sysfs entries */
539188db61SDavid Sterba struct raid_kobject {
549188db61SDavid Sterba 	u64 flags;
559188db61SDavid Sterba 	struct kobject kobj;
569188db61SDavid Sterba };
579188db61SDavid Sterba 
589188db61SDavid Sterba #define __INIT_KOBJ_ATTR(_name, _mode, _show, _store)			\
599188db61SDavid Sterba {									\
609188db61SDavid Sterba 	.attr	= { .name = __stringify(_name), .mode = _mode },	\
619188db61SDavid Sterba 	.show	= _show,						\
629188db61SDavid Sterba 	.store	= _store,						\
639188db61SDavid Sterba }
649188db61SDavid Sterba 
659188db61SDavid Sterba #define BTRFS_ATTR_RW(_prefix, _name, _show, _store)			\
669188db61SDavid Sterba 	static struct kobj_attribute btrfs_attr_##_prefix##_##_name =	\
679188db61SDavid Sterba 			__INIT_KOBJ_ATTR(_name, 0644, _show, _store)
689188db61SDavid Sterba 
699188db61SDavid Sterba #define BTRFS_ATTR(_prefix, _name, _show)				\
709188db61SDavid Sterba 	static struct kobj_attribute btrfs_attr_##_prefix##_##_name =	\
719188db61SDavid Sterba 			__INIT_KOBJ_ATTR(_name, 0444, _show, NULL)
729188db61SDavid Sterba 
739188db61SDavid Sterba #define BTRFS_ATTR_PTR(_prefix, _name)					\
749188db61SDavid Sterba 	(&btrfs_attr_##_prefix##_##_name.attr)
759188db61SDavid Sterba 
769188db61SDavid Sterba #define BTRFS_FEAT_ATTR(_name, _feature_set, _feature_prefix, _feature_bit)  \
779188db61SDavid Sterba static struct btrfs_feature_attr btrfs_attr_features_##_name = {	     \
789188db61SDavid Sterba 	.kobj_attr = __INIT_KOBJ_ATTR(_name, S_IRUGO,			     \
799188db61SDavid Sterba 				      btrfs_feature_attr_show,		     \
809188db61SDavid Sterba 				      btrfs_feature_attr_store),	     \
819188db61SDavid Sterba 	.feature_set	= _feature_set,					     \
829188db61SDavid Sterba 	.feature_bit	= _feature_prefix ##_## _feature_bit,		     \
839188db61SDavid Sterba }
849188db61SDavid Sterba #define BTRFS_FEAT_ATTR_PTR(_name)					     \
859188db61SDavid Sterba 	(&btrfs_attr_features_##_name.kobj_attr.attr)
869188db61SDavid Sterba 
879188db61SDavid Sterba #define BTRFS_FEAT_ATTR_COMPAT(name, feature) \
889188db61SDavid Sterba 	BTRFS_FEAT_ATTR(name, FEAT_COMPAT, BTRFS_FEATURE_COMPAT, feature)
899188db61SDavid Sterba #define BTRFS_FEAT_ATTR_COMPAT_RO(name, feature) \
909188db61SDavid Sterba 	BTRFS_FEAT_ATTR(name, FEAT_COMPAT_RO, BTRFS_FEATURE_COMPAT_RO, feature)
919188db61SDavid Sterba #define BTRFS_FEAT_ATTR_INCOMPAT(name, feature) \
929188db61SDavid Sterba 	BTRFS_FEAT_ATTR(name, FEAT_INCOMPAT, BTRFS_FEATURE_INCOMPAT, feature)
939188db61SDavid Sterba 
94510d7360SJeff Mahoney static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj);
952e7910d6SAnand Jain static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj);
96*19fc516aSStefan Roesch static struct kobject *get_btrfs_kobj(struct kobject *kobj);
975ac1d209SJeff Mahoney 
988f52316cSDavid Sterba static struct btrfs_feature_attr *to_btrfs_feature_attr(struct kobj_attribute *a)
998f52316cSDavid Sterba {
1008f52316cSDavid Sterba 	return container_of(a, struct btrfs_feature_attr, kobj_attr);
1018f52316cSDavid Sterba }
1028f52316cSDavid Sterba 
1038f52316cSDavid Sterba static struct kobj_attribute *attr_to_btrfs_attr(struct attribute *attr)
1048f52316cSDavid Sterba {
1058f52316cSDavid Sterba 	return container_of(attr, struct kobj_attribute, attr);
1068f52316cSDavid Sterba }
1078f52316cSDavid Sterba 
1088f52316cSDavid Sterba static struct btrfs_feature_attr *attr_to_btrfs_feature_attr(
1098f52316cSDavid Sterba 		struct attribute *attr)
1108f52316cSDavid Sterba {
1118f52316cSDavid Sterba 	return to_btrfs_feature_attr(attr_to_btrfs_attr(attr));
1128f52316cSDavid Sterba }
1138f52316cSDavid Sterba 
114510d7360SJeff Mahoney static u64 get_features(struct btrfs_fs_info *fs_info,
115510d7360SJeff Mahoney 			enum btrfs_feature_set set)
1165ac1d209SJeff Mahoney {
117510d7360SJeff Mahoney 	struct btrfs_super_block *disk_super = fs_info->super_copy;
118510d7360SJeff Mahoney 	if (set == FEAT_COMPAT)
119510d7360SJeff Mahoney 		return btrfs_super_compat_flags(disk_super);
120510d7360SJeff Mahoney 	else if (set == FEAT_COMPAT_RO)
121510d7360SJeff Mahoney 		return btrfs_super_compat_ro_flags(disk_super);
122510d7360SJeff Mahoney 	else
123510d7360SJeff Mahoney 		return btrfs_super_incompat_flags(disk_super);
1245ac1d209SJeff Mahoney }
1255ac1d209SJeff Mahoney 
126ba631941SJeff Mahoney static void set_features(struct btrfs_fs_info *fs_info,
127ba631941SJeff Mahoney 			 enum btrfs_feature_set set, u64 features)
128ba631941SJeff Mahoney {
129ba631941SJeff Mahoney 	struct btrfs_super_block *disk_super = fs_info->super_copy;
130ba631941SJeff Mahoney 	if (set == FEAT_COMPAT)
131ba631941SJeff Mahoney 		btrfs_set_super_compat_flags(disk_super, features);
132ba631941SJeff Mahoney 	else if (set == FEAT_COMPAT_RO)
133ba631941SJeff Mahoney 		btrfs_set_super_compat_ro_flags(disk_super, features);
134ba631941SJeff Mahoney 	else
135ba631941SJeff Mahoney 		btrfs_set_super_incompat_flags(disk_super, features);
136ba631941SJeff Mahoney }
137ba631941SJeff Mahoney 
138ba631941SJeff Mahoney static int can_modify_feature(struct btrfs_feature_attr *fa)
139ba631941SJeff Mahoney {
140ba631941SJeff Mahoney 	int val = 0;
141ba631941SJeff Mahoney 	u64 set, clear;
142ba631941SJeff Mahoney 	switch (fa->feature_set) {
143ba631941SJeff Mahoney 	case FEAT_COMPAT:
144ba631941SJeff Mahoney 		set = BTRFS_FEATURE_COMPAT_SAFE_SET;
145ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR;
146ba631941SJeff Mahoney 		break;
147ba631941SJeff Mahoney 	case FEAT_COMPAT_RO:
148ba631941SJeff Mahoney 		set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET;
149ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR;
150ba631941SJeff Mahoney 		break;
151ba631941SJeff Mahoney 	case FEAT_INCOMPAT:
152ba631941SJeff Mahoney 		set = BTRFS_FEATURE_INCOMPAT_SAFE_SET;
153ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR;
154ba631941SJeff Mahoney 		break;
155ba631941SJeff Mahoney 	default:
15662e85577SJeff Mahoney 		pr_warn("btrfs: sysfs: unknown feature set %d\n",
157cc37bb04SDavid Sterba 				fa->feature_set);
158cc37bb04SDavid Sterba 		return 0;
159ba631941SJeff Mahoney 	}
160ba631941SJeff Mahoney 
161ba631941SJeff Mahoney 	if (set & fa->feature_bit)
162ba631941SJeff Mahoney 		val |= 1;
163ba631941SJeff Mahoney 	if (clear & fa->feature_bit)
164ba631941SJeff Mahoney 		val |= 2;
165ba631941SJeff Mahoney 
166ba631941SJeff Mahoney 	return val;
167ba631941SJeff Mahoney }
168ba631941SJeff Mahoney 
169079b72bcSJeff Mahoney static ssize_t btrfs_feature_attr_show(struct kobject *kobj,
170079b72bcSJeff Mahoney 				       struct kobj_attribute *a, char *buf)
171079b72bcSJeff Mahoney {
172510d7360SJeff Mahoney 	int val = 0;
173510d7360SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
174510d7360SJeff Mahoney 	struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a);
175ba631941SJeff Mahoney 	if (fs_info) {
176510d7360SJeff Mahoney 		u64 features = get_features(fs_info, fa->feature_set);
177510d7360SJeff Mahoney 		if (features & fa->feature_bit)
178510d7360SJeff Mahoney 			val = 1;
179ba631941SJeff Mahoney 	} else
180ba631941SJeff Mahoney 		val = can_modify_feature(fa);
181510d7360SJeff Mahoney 
182020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
183510d7360SJeff Mahoney }
184510d7360SJeff Mahoney 
185ba631941SJeff Mahoney static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
186ba631941SJeff Mahoney 					struct kobj_attribute *a,
187ba631941SJeff Mahoney 					const char *buf, size_t count)
188ba631941SJeff Mahoney {
189ba631941SJeff Mahoney 	struct btrfs_fs_info *fs_info;
190ba631941SJeff Mahoney 	struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a);
191ba631941SJeff Mahoney 	u64 features, set, clear;
192ba631941SJeff Mahoney 	unsigned long val;
193ba631941SJeff Mahoney 	int ret;
194ba631941SJeff Mahoney 
195ba631941SJeff Mahoney 	fs_info = to_fs_info(kobj);
196ba631941SJeff Mahoney 	if (!fs_info)
197ba631941SJeff Mahoney 		return -EPERM;
198ba631941SJeff Mahoney 
199bc98a42cSDavid Howells 	if (sb_rdonly(fs_info->sb))
200ee611138SDavid Sterba 		return -EROFS;
201ee611138SDavid Sterba 
202ba631941SJeff Mahoney 	ret = kstrtoul(skip_spaces(buf), 0, &val);
203ba631941SJeff Mahoney 	if (ret)
204ba631941SJeff Mahoney 		return ret;
205ba631941SJeff Mahoney 
206ba631941SJeff Mahoney 	if (fa->feature_set == FEAT_COMPAT) {
207ba631941SJeff Mahoney 		set = BTRFS_FEATURE_COMPAT_SAFE_SET;
208ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR;
209ba631941SJeff Mahoney 	} else if (fa->feature_set == FEAT_COMPAT_RO) {
210ba631941SJeff Mahoney 		set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET;
211ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR;
212ba631941SJeff Mahoney 	} else {
213ba631941SJeff Mahoney 		set = BTRFS_FEATURE_INCOMPAT_SAFE_SET;
214ba631941SJeff Mahoney 		clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR;
215ba631941SJeff Mahoney 	}
216ba631941SJeff Mahoney 
217ba631941SJeff Mahoney 	features = get_features(fs_info, fa->feature_set);
218ba631941SJeff Mahoney 
219ba631941SJeff Mahoney 	/* Nothing to do */
220ba631941SJeff Mahoney 	if ((val && (features & fa->feature_bit)) ||
221ba631941SJeff Mahoney 	    (!val && !(features & fa->feature_bit)))
222ba631941SJeff Mahoney 		return count;
223ba631941SJeff Mahoney 
224ba631941SJeff Mahoney 	if ((val && !(set & fa->feature_bit)) ||
225ba631941SJeff Mahoney 	    (!val && !(clear & fa->feature_bit))) {
226ba631941SJeff Mahoney 		btrfs_info(fs_info,
227ba631941SJeff Mahoney 			"%sabling feature %s on mounted fs is not supported.",
228ba631941SJeff Mahoney 			val ? "En" : "Dis", fa->kobj_attr.attr.name);
229ba631941SJeff Mahoney 		return -EPERM;
230ba631941SJeff Mahoney 	}
231ba631941SJeff Mahoney 
232ba631941SJeff Mahoney 	btrfs_info(fs_info, "%s %s feature flag",
233ba631941SJeff Mahoney 		   val ? "Setting" : "Clearing", fa->kobj_attr.attr.name);
234ba631941SJeff Mahoney 
235ba631941SJeff Mahoney 	spin_lock(&fs_info->super_lock);
236ba631941SJeff Mahoney 	features = get_features(fs_info, fa->feature_set);
237ba631941SJeff Mahoney 	if (val)
238ba631941SJeff Mahoney 		features |= fa->feature_bit;
239ba631941SJeff Mahoney 	else
240ba631941SJeff Mahoney 		features &= ~fa->feature_bit;
241ba631941SJeff Mahoney 	set_features(fs_info, fa->feature_set, features);
242ba631941SJeff Mahoney 	spin_unlock(&fs_info->super_lock);
243ba631941SJeff Mahoney 
2440eae2747SDavid Sterba 	/*
2450eae2747SDavid Sterba 	 * We don't want to do full transaction commit from inside sysfs
2460eae2747SDavid Sterba 	 */
2470eae2747SDavid Sterba 	btrfs_set_pending(fs_info, COMMIT);
2480eae2747SDavid Sterba 	wake_up_process(fs_info->transaction_kthread);
249ba631941SJeff Mahoney 
250ba631941SJeff Mahoney 	return count;
251ba631941SJeff Mahoney }
252ba631941SJeff Mahoney 
253510d7360SJeff Mahoney static umode_t btrfs_feature_visible(struct kobject *kobj,
254510d7360SJeff Mahoney 				     struct attribute *attr, int unused)
255510d7360SJeff Mahoney {
256510d7360SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
257510d7360SJeff Mahoney 	umode_t mode = attr->mode;
258510d7360SJeff Mahoney 
259510d7360SJeff Mahoney 	if (fs_info) {
260510d7360SJeff Mahoney 		struct btrfs_feature_attr *fa;
261510d7360SJeff Mahoney 		u64 features;
262510d7360SJeff Mahoney 
263510d7360SJeff Mahoney 		fa = attr_to_btrfs_feature_attr(attr);
264510d7360SJeff Mahoney 		features = get_features(fs_info, fa->feature_set);
265510d7360SJeff Mahoney 
266ba631941SJeff Mahoney 		if (can_modify_feature(fa))
267ba631941SJeff Mahoney 			mode |= S_IWUSR;
268ba631941SJeff Mahoney 		else if (!(features & fa->feature_bit))
269510d7360SJeff Mahoney 			mode = 0;
270510d7360SJeff Mahoney 	}
271510d7360SJeff Mahoney 
272510d7360SJeff Mahoney 	return mode;
273079b72bcSJeff Mahoney }
274079b72bcSJeff Mahoney 
275079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF);
276079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL);
277079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS);
278079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO);
2795c1aab1dSNick Terrell BTRFS_FEAT_ATTR_INCOMPAT(compress_zstd, COMPRESS_ZSTD);
280079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA);
281079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF);
282079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56);
283079b72bcSJeff Mahoney BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA);
284c736c095SDavid Sterba BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES);
28556f20f40SNikolay Borisov BTRFS_FEAT_ATTR_INCOMPAT(metadata_uuid, METADATA_UUID);
2863b5bb73bSDavid Sterba BTRFS_FEAT_ATTR_COMPAT_RO(free_space_tree, FREE_SPACE_TREE);
287cfbb825cSDavid Sterba BTRFS_FEAT_ATTR_INCOMPAT(raid1c34, RAID1C34);
2887b3d5a90SNaohiro Aota #ifdef CONFIG_BTRFS_DEBUG
2892c7d2a23SJosef Bacik /* Remove once support for zoned allocation is feature complete */
2907b3d5a90SNaohiro Aota BTRFS_FEAT_ATTR_INCOMPAT(zoned, ZONED);
2912c7d2a23SJosef Bacik /* Remove once support for extent tree v2 is feature complete */
2922c7d2a23SJosef Bacik BTRFS_FEAT_ATTR_INCOMPAT(extent_tree_v2, EXTENT_TREE_V2);
2937b3d5a90SNaohiro Aota #endif
29414605409SBoris Burkov #ifdef CONFIG_FS_VERITY
29514605409SBoris Burkov BTRFS_FEAT_ATTR_COMPAT_RO(verity, VERITY);
29614605409SBoris Burkov #endif
297079b72bcSJeff Mahoney 
298e7849e33SAnand Jain /*
299e7849e33SAnand Jain  * Features which depend on feature bits and may differ between each fs.
300e7849e33SAnand Jain  *
301143823cfSDavid Sterba  * /sys/fs/btrfs/features      - all available features implemented by this version
302e7849e33SAnand Jain  * /sys/fs/btrfs/UUID/features - features of the fs which are enabled or
303e7849e33SAnand Jain  *                               can be changed on a mounted filesystem.
304e7849e33SAnand Jain  */
305079b72bcSJeff Mahoney static struct attribute *btrfs_supported_feature_attrs[] = {
306079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(mixed_backref),
307079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(default_subvol),
308079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(mixed_groups),
309079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(compress_lzo),
3105c1aab1dSNick Terrell 	BTRFS_FEAT_ATTR_PTR(compress_zstd),
311079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(big_metadata),
312079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(extended_iref),
313079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(raid56),
314079b72bcSJeff Mahoney 	BTRFS_FEAT_ATTR_PTR(skinny_metadata),
315c736c095SDavid Sterba 	BTRFS_FEAT_ATTR_PTR(no_holes),
31656f20f40SNikolay Borisov 	BTRFS_FEAT_ATTR_PTR(metadata_uuid),
3173b5bb73bSDavid Sterba 	BTRFS_FEAT_ATTR_PTR(free_space_tree),
318cfbb825cSDavid Sterba 	BTRFS_FEAT_ATTR_PTR(raid1c34),
3197b3d5a90SNaohiro Aota #ifdef CONFIG_BTRFS_DEBUG
3207b3d5a90SNaohiro Aota 	BTRFS_FEAT_ATTR_PTR(zoned),
3212c7d2a23SJosef Bacik 	BTRFS_FEAT_ATTR_PTR(extent_tree_v2),
3227b3d5a90SNaohiro Aota #endif
32314605409SBoris Burkov #ifdef CONFIG_FS_VERITY
32414605409SBoris Burkov 	BTRFS_FEAT_ATTR_PTR(verity),
32514605409SBoris Burkov #endif
326079b72bcSJeff Mahoney 	NULL
327079b72bcSJeff Mahoney };
328079b72bcSJeff Mahoney 
329079b72bcSJeff Mahoney static const struct attribute_group btrfs_feature_attr_group = {
330079b72bcSJeff Mahoney 	.name = "features",
331510d7360SJeff Mahoney 	.is_visible = btrfs_feature_visible,
332079b72bcSJeff Mahoney 	.attrs = btrfs_supported_feature_attrs,
333079b72bcSJeff Mahoney };
33458176a96SJosef Bacik 
335f902bd3aSMisono Tomohiro static ssize_t rmdir_subvol_show(struct kobject *kobj,
336f902bd3aSMisono Tomohiro 				 struct kobj_attribute *ka, char *buf)
337f902bd3aSMisono Tomohiro {
338020e5277SAnand Jain 	return sysfs_emit(buf, "0\n");
339f902bd3aSMisono Tomohiro }
340f902bd3aSMisono Tomohiro BTRFS_ATTR(static_feature, rmdir_subvol, rmdir_subvol_show);
341f902bd3aSMisono Tomohiro 
342f7cea56cSDavid Sterba static ssize_t supported_checksums_show(struct kobject *kobj,
343f7cea56cSDavid Sterba 					struct kobj_attribute *a, char *buf)
344f7cea56cSDavid Sterba {
345f7cea56cSDavid Sterba 	ssize_t ret = 0;
346f7cea56cSDavid Sterba 	int i;
347f7cea56cSDavid Sterba 
348f7cea56cSDavid Sterba 	for (i = 0; i < btrfs_get_num_csums(); i++) {
349f7cea56cSDavid Sterba 		/*
350f7cea56cSDavid Sterba 		 * This "trick" only works as long as 'enum btrfs_csum_type' has
351f7cea56cSDavid Sterba 		 * no holes in it
352f7cea56cSDavid Sterba 		 */
353020e5277SAnand Jain 		ret += sysfs_emit_at(buf, ret, "%s%s", (i == 0 ? "" : " "),
354020e5277SAnand Jain 				     btrfs_super_csum_name(i));
355f7cea56cSDavid Sterba 
356f7cea56cSDavid Sterba 	}
357f7cea56cSDavid Sterba 
358020e5277SAnand Jain 	ret += sysfs_emit_at(buf, ret, "\n");
359f7cea56cSDavid Sterba 	return ret;
360f7cea56cSDavid Sterba }
361f7cea56cSDavid Sterba BTRFS_ATTR(static_feature, supported_checksums, supported_checksums_show);
362f7cea56cSDavid Sterba 
3637573df55SOmar Sandoval static ssize_t send_stream_version_show(struct kobject *kobj,
3647573df55SOmar Sandoval 					struct kobj_attribute *ka, char *buf)
3657573df55SOmar Sandoval {
366020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", BTRFS_SEND_STREAM_VERSION);
3677573df55SOmar Sandoval }
3687573df55SOmar Sandoval BTRFS_ATTR(static_feature, send_stream_version, send_stream_version_show);
3697573df55SOmar Sandoval 
370ceafe3ccSJosef Bacik static const char *rescue_opts[] = {
371ceafe3ccSJosef Bacik 	"usebackuproot",
372ceafe3ccSJosef Bacik 	"nologreplay",
37342437a63SJosef Bacik 	"ignorebadroots",
374882dbe0cSJosef Bacik 	"ignoredatacsums",
3759037d3cbSJosef Bacik 	"all",
376ceafe3ccSJosef Bacik };
377ceafe3ccSJosef Bacik 
378ceafe3ccSJosef Bacik static ssize_t supported_rescue_options_show(struct kobject *kobj,
379ceafe3ccSJosef Bacik 					     struct kobj_attribute *a,
380ceafe3ccSJosef Bacik 					     char *buf)
381ceafe3ccSJosef Bacik {
382ceafe3ccSJosef Bacik 	ssize_t ret = 0;
383ceafe3ccSJosef Bacik 	int i;
384ceafe3ccSJosef Bacik 
385ceafe3ccSJosef Bacik 	for (i = 0; i < ARRAY_SIZE(rescue_opts); i++)
386020e5277SAnand Jain 		ret += sysfs_emit_at(buf, ret, "%s%s", (i ? " " : ""), rescue_opts[i]);
387020e5277SAnand Jain 	ret += sysfs_emit_at(buf, ret, "\n");
388ceafe3ccSJosef Bacik 	return ret;
389ceafe3ccSJosef Bacik }
390ceafe3ccSJosef Bacik BTRFS_ATTR(static_feature, supported_rescue_options,
391ceafe3ccSJosef Bacik 	   supported_rescue_options_show);
392ceafe3ccSJosef Bacik 
393fc57ad8dSQu Wenruo static ssize_t supported_sectorsizes_show(struct kobject *kobj,
394fc57ad8dSQu Wenruo 					  struct kobj_attribute *a,
395fc57ad8dSQu Wenruo 					  char *buf)
396fc57ad8dSQu Wenruo {
397fc57ad8dSQu Wenruo 	ssize_t ret = 0;
398fc57ad8dSQu Wenruo 
3991a42daabSQu Wenruo 	/* An artificial limit to only support 4K and PAGE_SIZE */
4001a42daabSQu Wenruo 	if (PAGE_SIZE > SZ_4K)
401020e5277SAnand Jain 		ret += sysfs_emit_at(buf, ret, "%u ", SZ_4K);
402020e5277SAnand Jain 	ret += sysfs_emit_at(buf, ret, "%lu\n", PAGE_SIZE);
403fc57ad8dSQu Wenruo 
404fc57ad8dSQu Wenruo 	return ret;
405fc57ad8dSQu Wenruo }
406fc57ad8dSQu Wenruo BTRFS_ATTR(static_feature, supported_sectorsizes,
407fc57ad8dSQu Wenruo 	   supported_sectorsizes_show);
408fc57ad8dSQu Wenruo 
409e7849e33SAnand Jain /*
410e7849e33SAnand Jain  * Features which only depend on kernel version.
411e7849e33SAnand Jain  *
412e7849e33SAnand Jain  * These are listed in /sys/fs/btrfs/features along with
413e7849e33SAnand Jain  * btrfs_supported_feature_attrs.
414e7849e33SAnand Jain  */
415f902bd3aSMisono Tomohiro static struct attribute *btrfs_supported_static_feature_attrs[] = {
416f902bd3aSMisono Tomohiro 	BTRFS_ATTR_PTR(static_feature, rmdir_subvol),
417f7cea56cSDavid Sterba 	BTRFS_ATTR_PTR(static_feature, supported_checksums),
4187573df55SOmar Sandoval 	BTRFS_ATTR_PTR(static_feature, send_stream_version),
419ceafe3ccSJosef Bacik 	BTRFS_ATTR_PTR(static_feature, supported_rescue_options),
420fc57ad8dSQu Wenruo 	BTRFS_ATTR_PTR(static_feature, supported_sectorsizes),
421f902bd3aSMisono Tomohiro 	NULL
422f902bd3aSMisono Tomohiro };
423f902bd3aSMisono Tomohiro 
424f902bd3aSMisono Tomohiro static const struct attribute_group btrfs_static_feature_attr_group = {
425f902bd3aSMisono Tomohiro 	.name = "features",
426f902bd3aSMisono Tomohiro 	.attrs = btrfs_supported_static_feature_attrs,
427f902bd3aSMisono Tomohiro };
428f902bd3aSMisono Tomohiro 
4296e369febSDavid Sterba #ifdef CONFIG_BTRFS_DEBUG
4306e369febSDavid Sterba 
4316e369febSDavid Sterba /*
432e4faab84SDennis Zhou  * Discard statistics and tunables
433e4faab84SDennis Zhou  */
434dfb79ddbSDennis Zhou #define discard_to_fs_info(_kobj)	to_fs_info((_kobj)->parent->parent)
435dfb79ddbSDennis Zhou 
4365dc7c10bSDennis Zhou static ssize_t btrfs_discardable_bytes_show(struct kobject *kobj,
4375dc7c10bSDennis Zhou 					    struct kobj_attribute *a,
4385dc7c10bSDennis Zhou 					    char *buf)
4395dc7c10bSDennis Zhou {
4405dc7c10bSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4415dc7c10bSDennis Zhou 
442020e5277SAnand Jain 	return sysfs_emit(buf, "%lld\n",
4435dc7c10bSDennis Zhou 			atomic64_read(&fs_info->discard_ctl.discardable_bytes));
4445dc7c10bSDennis Zhou }
4455dc7c10bSDennis Zhou BTRFS_ATTR(discard, discardable_bytes, btrfs_discardable_bytes_show);
4465dc7c10bSDennis Zhou 
447dfb79ddbSDennis Zhou static ssize_t btrfs_discardable_extents_show(struct kobject *kobj,
448dfb79ddbSDennis Zhou 					      struct kobj_attribute *a,
449dfb79ddbSDennis Zhou 					      char *buf)
450dfb79ddbSDennis Zhou {
451dfb79ddbSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
452dfb79ddbSDennis Zhou 
453020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n",
454dfb79ddbSDennis Zhou 			atomic_read(&fs_info->discard_ctl.discardable_extents));
455dfb79ddbSDennis Zhou }
456dfb79ddbSDennis Zhou BTRFS_ATTR(discard, discardable_extents, btrfs_discardable_extents_show);
457dfb79ddbSDennis Zhou 
4589ddf648fSDennis Zhou static ssize_t btrfs_discard_bitmap_bytes_show(struct kobject *kobj,
4599ddf648fSDennis Zhou 					       struct kobj_attribute *a,
4609ddf648fSDennis Zhou 					       char *buf)
4619ddf648fSDennis Zhou {
4629ddf648fSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4639ddf648fSDennis Zhou 
464020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n",
4659ddf648fSDennis Zhou 			  fs_info->discard_ctl.discard_bitmap_bytes);
4669ddf648fSDennis Zhou }
4679ddf648fSDennis Zhou BTRFS_ATTR(discard, discard_bitmap_bytes, btrfs_discard_bitmap_bytes_show);
4689ddf648fSDennis Zhou 
4699ddf648fSDennis Zhou static ssize_t btrfs_discard_bytes_saved_show(struct kobject *kobj,
4709ddf648fSDennis Zhou 					      struct kobj_attribute *a,
4719ddf648fSDennis Zhou 					      char *buf)
4729ddf648fSDennis Zhou {
4739ddf648fSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4749ddf648fSDennis Zhou 
475020e5277SAnand Jain 	return sysfs_emit(buf, "%lld\n",
4769ddf648fSDennis Zhou 		atomic64_read(&fs_info->discard_ctl.discard_bytes_saved));
4779ddf648fSDennis Zhou }
4789ddf648fSDennis Zhou BTRFS_ATTR(discard, discard_bytes_saved, btrfs_discard_bytes_saved_show);
4799ddf648fSDennis Zhou 
4809ddf648fSDennis Zhou static ssize_t btrfs_discard_extent_bytes_show(struct kobject *kobj,
4819ddf648fSDennis Zhou 					       struct kobj_attribute *a,
4829ddf648fSDennis Zhou 					       char *buf)
4839ddf648fSDennis Zhou {
4849ddf648fSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
4859ddf648fSDennis Zhou 
486020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n",
4879ddf648fSDennis Zhou 			  fs_info->discard_ctl.discard_extent_bytes);
4889ddf648fSDennis Zhou }
4899ddf648fSDennis Zhou BTRFS_ATTR(discard, discard_extent_bytes, btrfs_discard_extent_bytes_show);
4909ddf648fSDennis Zhou 
491a2309300SDennis Zhou static ssize_t btrfs_discard_iops_limit_show(struct kobject *kobj,
492a2309300SDennis Zhou 					     struct kobj_attribute *a,
493a2309300SDennis Zhou 					     char *buf)
494a2309300SDennis Zhou {
495a2309300SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
496a2309300SDennis Zhou 
497020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n",
498a2309300SDennis Zhou 			  READ_ONCE(fs_info->discard_ctl.iops_limit));
499a2309300SDennis Zhou }
500a2309300SDennis Zhou 
501a2309300SDennis Zhou static ssize_t btrfs_discard_iops_limit_store(struct kobject *kobj,
502a2309300SDennis Zhou 					      struct kobj_attribute *a,
503a2309300SDennis Zhou 					      const char *buf, size_t len)
504a2309300SDennis Zhou {
505a2309300SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
506a2309300SDennis Zhou 	struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl;
507a2309300SDennis Zhou 	u32 iops_limit;
508a2309300SDennis Zhou 	int ret;
509a2309300SDennis Zhou 
510a2309300SDennis Zhou 	ret = kstrtou32(buf, 10, &iops_limit);
511a2309300SDennis Zhou 	if (ret)
512a2309300SDennis Zhou 		return -EINVAL;
513a2309300SDennis Zhou 
514a2309300SDennis Zhou 	WRITE_ONCE(discard_ctl->iops_limit, iops_limit);
5153e48d8d2SPavel Begunkov 	btrfs_discard_calc_delay(discard_ctl);
5163e48d8d2SPavel Begunkov 	btrfs_discard_schedule_work(discard_ctl, true);
517a2309300SDennis Zhou 	return len;
518a2309300SDennis Zhou }
519a2309300SDennis Zhou BTRFS_ATTR_RW(discard, iops_limit, btrfs_discard_iops_limit_show,
520a2309300SDennis Zhou 	      btrfs_discard_iops_limit_store);
521a2309300SDennis Zhou 
522e93591bbSDennis Zhou static ssize_t btrfs_discard_kbps_limit_show(struct kobject *kobj,
523e93591bbSDennis Zhou 					     struct kobj_attribute *a,
524e93591bbSDennis Zhou 					     char *buf)
525e93591bbSDennis Zhou {
526e93591bbSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
527e93591bbSDennis Zhou 
528020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n",
529e93591bbSDennis Zhou 			  READ_ONCE(fs_info->discard_ctl.kbps_limit));
530e93591bbSDennis Zhou }
531e93591bbSDennis Zhou 
532e93591bbSDennis Zhou static ssize_t btrfs_discard_kbps_limit_store(struct kobject *kobj,
533e93591bbSDennis Zhou 					      struct kobj_attribute *a,
534e93591bbSDennis Zhou 					      const char *buf, size_t len)
535e93591bbSDennis Zhou {
536e93591bbSDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
537e93591bbSDennis Zhou 	struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl;
538e93591bbSDennis Zhou 	u32 kbps_limit;
539e93591bbSDennis Zhou 	int ret;
540e93591bbSDennis Zhou 
541e93591bbSDennis Zhou 	ret = kstrtou32(buf, 10, &kbps_limit);
542e93591bbSDennis Zhou 	if (ret)
543e93591bbSDennis Zhou 		return -EINVAL;
544e93591bbSDennis Zhou 
545e93591bbSDennis Zhou 	WRITE_ONCE(discard_ctl->kbps_limit, kbps_limit);
5463e48d8d2SPavel Begunkov 	btrfs_discard_schedule_work(discard_ctl, true);
547e93591bbSDennis Zhou 	return len;
548e93591bbSDennis Zhou }
549e93591bbSDennis Zhou BTRFS_ATTR_RW(discard, kbps_limit, btrfs_discard_kbps_limit_show,
550e93591bbSDennis Zhou 	      btrfs_discard_kbps_limit_store);
551e93591bbSDennis Zhou 
55219b2a2c7SDennis Zhou static ssize_t btrfs_discard_max_discard_size_show(struct kobject *kobj,
55319b2a2c7SDennis Zhou 						   struct kobj_attribute *a,
55419b2a2c7SDennis Zhou 						   char *buf)
55519b2a2c7SDennis Zhou {
55619b2a2c7SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
55719b2a2c7SDennis Zhou 
558020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n",
55919b2a2c7SDennis Zhou 			  READ_ONCE(fs_info->discard_ctl.max_discard_size));
56019b2a2c7SDennis Zhou }
56119b2a2c7SDennis Zhou 
56219b2a2c7SDennis Zhou static ssize_t btrfs_discard_max_discard_size_store(struct kobject *kobj,
56319b2a2c7SDennis Zhou 						    struct kobj_attribute *a,
56419b2a2c7SDennis Zhou 						    const char *buf, size_t len)
56519b2a2c7SDennis Zhou {
56619b2a2c7SDennis Zhou 	struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
56719b2a2c7SDennis Zhou 	struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl;
56819b2a2c7SDennis Zhou 	u64 max_discard_size;
56919b2a2c7SDennis Zhou 	int ret;
57019b2a2c7SDennis Zhou 
57119b2a2c7SDennis Zhou 	ret = kstrtou64(buf, 10, &max_discard_size);
57219b2a2c7SDennis Zhou 	if (ret)
57319b2a2c7SDennis Zhou 		return -EINVAL;
57419b2a2c7SDennis Zhou 
57519b2a2c7SDennis Zhou 	WRITE_ONCE(discard_ctl->max_discard_size, max_discard_size);
57619b2a2c7SDennis Zhou 
57719b2a2c7SDennis Zhou 	return len;
57819b2a2c7SDennis Zhou }
57919b2a2c7SDennis Zhou BTRFS_ATTR_RW(discard, max_discard_size, btrfs_discard_max_discard_size_show,
58019b2a2c7SDennis Zhou 	      btrfs_discard_max_discard_size_store);
58119b2a2c7SDennis Zhou 
582e7849e33SAnand Jain /*
583e7849e33SAnand Jain  * Per-filesystem debugging of discard (when mounted with discard=async).
584e7849e33SAnand Jain  *
585e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/debug/discard/
586e7849e33SAnand Jain  */
587e4faab84SDennis Zhou static const struct attribute *discard_debug_attrs[] = {
5885dc7c10bSDennis Zhou 	BTRFS_ATTR_PTR(discard, discardable_bytes),
589dfb79ddbSDennis Zhou 	BTRFS_ATTR_PTR(discard, discardable_extents),
5909ddf648fSDennis Zhou 	BTRFS_ATTR_PTR(discard, discard_bitmap_bytes),
5919ddf648fSDennis Zhou 	BTRFS_ATTR_PTR(discard, discard_bytes_saved),
5929ddf648fSDennis Zhou 	BTRFS_ATTR_PTR(discard, discard_extent_bytes),
593a2309300SDennis Zhou 	BTRFS_ATTR_PTR(discard, iops_limit),
594e93591bbSDennis Zhou 	BTRFS_ATTR_PTR(discard, kbps_limit),
59519b2a2c7SDennis Zhou 	BTRFS_ATTR_PTR(discard, max_discard_size),
596e4faab84SDennis Zhou 	NULL,
597e4faab84SDennis Zhou };
598e4faab84SDennis Zhou 
599e4faab84SDennis Zhou /*
600e7849e33SAnand Jain  * Per-filesystem runtime debugging exported via sysfs.
6016e369febSDavid Sterba  *
602e7849e33SAnand Jain  * Path: /sys/fs/btrfs/UUID/debug/
6036e369febSDavid Sterba  */
60493945cb4SDennis Zhou static const struct attribute *btrfs_debug_mount_attrs[] = {
60593945cb4SDennis Zhou 	NULL,
60693945cb4SDennis Zhou };
60793945cb4SDennis Zhou 
608e7849e33SAnand Jain /*
609e7849e33SAnand Jain  * Runtime debugging exported via sysfs, applies to all mounted filesystems.
610e7849e33SAnand Jain  *
611e7849e33SAnand Jain  * Path: /sys/fs/btrfs/debug
612e7849e33SAnand Jain  */
6136e369febSDavid Sterba static struct attribute *btrfs_debug_feature_attrs[] = {
6146e369febSDavid Sterba 	NULL
6156e369febSDavid Sterba };
6166e369febSDavid Sterba 
6176e369febSDavid Sterba static const struct attribute_group btrfs_debug_feature_attr_group = {
6186e369febSDavid Sterba 	.name = "debug",
6196e369febSDavid Sterba 	.attrs = btrfs_debug_feature_attrs,
6206e369febSDavid Sterba };
6216e369febSDavid Sterba 
6226e369febSDavid Sterba #endif
6236e369febSDavid Sterba 
6246ab0a202SJeff Mahoney static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf)
6256ab0a202SJeff Mahoney {
6266ab0a202SJeff Mahoney 	u64 val;
6276ab0a202SJeff Mahoney 	if (lock)
6286ab0a202SJeff Mahoney 		spin_lock(lock);
6296ab0a202SJeff Mahoney 	val = *value_ptr;
6306ab0a202SJeff Mahoney 	if (lock)
6316ab0a202SJeff Mahoney 		spin_unlock(lock);
632020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", val);
6336ab0a202SJeff Mahoney }
6346ab0a202SJeff Mahoney 
6356ab0a202SJeff Mahoney static ssize_t global_rsv_size_show(struct kobject *kobj,
6366ab0a202SJeff Mahoney 				    struct kobj_attribute *ka, char *buf)
6376ab0a202SJeff Mahoney {
6386ab0a202SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
6396ab0a202SJeff Mahoney 	struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
6406ab0a202SJeff Mahoney 	return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf);
6416ab0a202SJeff Mahoney }
642a969f4ccSHans van Kranenburg BTRFS_ATTR(allocation, global_rsv_size, global_rsv_size_show);
6436ab0a202SJeff Mahoney 
6446ab0a202SJeff Mahoney static ssize_t global_rsv_reserved_show(struct kobject *kobj,
6456ab0a202SJeff Mahoney 					struct kobj_attribute *a, char *buf)
6466ab0a202SJeff Mahoney {
6476ab0a202SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
6486ab0a202SJeff Mahoney 	struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
6496ab0a202SJeff Mahoney 	return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf);
6506ab0a202SJeff Mahoney }
651a969f4ccSHans van Kranenburg BTRFS_ATTR(allocation, global_rsv_reserved, global_rsv_reserved_show);
6526ab0a202SJeff Mahoney 
6536ab0a202SJeff Mahoney #define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj)
654c1895442SJeff Mahoney #define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj)
6556ab0a202SJeff Mahoney 
6566ab0a202SJeff Mahoney static ssize_t raid_bytes_show(struct kobject *kobj,
6576ab0a202SJeff Mahoney 			       struct kobj_attribute *attr, char *buf);
658a969f4ccSHans van Kranenburg BTRFS_ATTR(raid, total_bytes, raid_bytes_show);
659a969f4ccSHans van Kranenburg BTRFS_ATTR(raid, used_bytes, raid_bytes_show);
6606ab0a202SJeff Mahoney 
6616ab0a202SJeff Mahoney static ssize_t raid_bytes_show(struct kobject *kobj,
6626ab0a202SJeff Mahoney 			       struct kobj_attribute *attr, char *buf)
6636ab0a202SJeff Mahoney 
6646ab0a202SJeff Mahoney {
6656ab0a202SJeff Mahoney 	struct btrfs_space_info *sinfo = to_space_info(kobj->parent);
66632da5386SDavid Sterba 	struct btrfs_block_group *block_group;
66775cb379dSJeff Mahoney 	int index = btrfs_bg_flags_to_raid_index(to_raid_kobj(kobj)->flags);
6686ab0a202SJeff Mahoney 	u64 val = 0;
6696ab0a202SJeff Mahoney 
6706ab0a202SJeff Mahoney 	down_read(&sinfo->groups_sem);
6716ab0a202SJeff Mahoney 	list_for_each_entry(block_group, &sinfo->block_groups[index], list) {
672a969f4ccSHans van Kranenburg 		if (&attr->attr == BTRFS_ATTR_PTR(raid, total_bytes))
673b3470b5dSDavid Sterba 			val += block_group->length;
6746ab0a202SJeff Mahoney 		else
675bf38be65SDavid Sterba 			val += block_group->used;
6766ab0a202SJeff Mahoney 	}
6776ab0a202SJeff Mahoney 	up_read(&sinfo->groups_sem);
678020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", val);
6796ab0a202SJeff Mahoney }
6806ab0a202SJeff Mahoney 
681e7849e33SAnand Jain /*
682e7849e33SAnand Jain  * Allocation information about block group profiles.
683e7849e33SAnand Jain  *
684e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/allocation/<bg-type>/<bg-profile>/
685e7849e33SAnand Jain  */
6867c7e3014SKimberly Brown static struct attribute *raid_attrs[] = {
687a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(raid, total_bytes),
688a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(raid, used_bytes),
6896ab0a202SJeff Mahoney 	NULL
6906ab0a202SJeff Mahoney };
6917c7e3014SKimberly Brown ATTRIBUTE_GROUPS(raid);
6926ab0a202SJeff Mahoney 
6936ab0a202SJeff Mahoney static void release_raid_kobj(struct kobject *kobj)
6946ab0a202SJeff Mahoney {
695c1895442SJeff Mahoney 	kfree(to_raid_kobj(kobj));
6966ab0a202SJeff Mahoney }
6976ab0a202SJeff Mahoney 
698536ea45cSDavid Sterba static struct kobj_type btrfs_raid_ktype = {
6996ab0a202SJeff Mahoney 	.sysfs_ops = &kobj_sysfs_ops,
7006ab0a202SJeff Mahoney 	.release = release_raid_kobj,
7017c7e3014SKimberly Brown 	.default_groups = raid_groups,
7026ab0a202SJeff Mahoney };
7036ab0a202SJeff Mahoney 
7046ab0a202SJeff Mahoney #define SPACE_INFO_ATTR(field)						\
7056ab0a202SJeff Mahoney static ssize_t btrfs_space_info_show_##field(struct kobject *kobj,	\
7066ab0a202SJeff Mahoney 					     struct kobj_attribute *a,	\
7076ab0a202SJeff Mahoney 					     char *buf)			\
7086ab0a202SJeff Mahoney {									\
7096ab0a202SJeff Mahoney 	struct btrfs_space_info *sinfo = to_space_info(kobj);		\
7106ab0a202SJeff Mahoney 	return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf);	\
7116ab0a202SJeff Mahoney }									\
712a969f4ccSHans van Kranenburg BTRFS_ATTR(space_info, field, btrfs_space_info_show_##field)
7136ab0a202SJeff Mahoney 
714*19fc516aSStefan Roesch static ssize_t btrfs_chunk_size_show(struct kobject *kobj,
715*19fc516aSStefan Roesch 				     struct kobj_attribute *a, char *buf)
716*19fc516aSStefan Roesch {
717*19fc516aSStefan Roesch 	struct btrfs_space_info *sinfo = to_space_info(kobj);
718*19fc516aSStefan Roesch 
719*19fc516aSStefan Roesch 	return sysfs_emit(buf, "%llu\n", READ_ONCE(sinfo->chunk_size));
720*19fc516aSStefan Roesch }
721*19fc516aSStefan Roesch 
722*19fc516aSStefan Roesch /*
723*19fc516aSStefan Roesch  * Store new chunk size in space info. Can be called on a read-only filesystem.
724*19fc516aSStefan Roesch  *
725*19fc516aSStefan Roesch  * If the new chunk size value is larger than 10% of free space it is reduced
726*19fc516aSStefan Roesch  * to match that limit. Alignment must be to 256M and the system chunk size
727*19fc516aSStefan Roesch  * cannot be set.
728*19fc516aSStefan Roesch  */
729*19fc516aSStefan Roesch static ssize_t btrfs_chunk_size_store(struct kobject *kobj,
730*19fc516aSStefan Roesch 				      struct kobj_attribute *a,
731*19fc516aSStefan Roesch 				      const char *buf, size_t len)
732*19fc516aSStefan Roesch {
733*19fc516aSStefan Roesch 	struct btrfs_space_info *space_info = to_space_info(kobj);
734*19fc516aSStefan Roesch 	struct btrfs_fs_info *fs_info = to_fs_info(get_btrfs_kobj(kobj));
735*19fc516aSStefan Roesch 	char *retptr;
736*19fc516aSStefan Roesch 	u64 val;
737*19fc516aSStefan Roesch 
738*19fc516aSStefan Roesch 	if (!capable(CAP_SYS_ADMIN))
739*19fc516aSStefan Roesch 		return -EPERM;
740*19fc516aSStefan Roesch 
741*19fc516aSStefan Roesch 	if (!fs_info->fs_devices)
742*19fc516aSStefan Roesch 		return -EINVAL;
743*19fc516aSStefan Roesch 
744*19fc516aSStefan Roesch 	if (btrfs_is_zoned(fs_info))
745*19fc516aSStefan Roesch 		return -EINVAL;
746*19fc516aSStefan Roesch 
747*19fc516aSStefan Roesch 	/* System block type must not be changed. */
748*19fc516aSStefan Roesch 	if (space_info->flags & BTRFS_BLOCK_GROUP_SYSTEM)
749*19fc516aSStefan Roesch 		return -EPERM;
750*19fc516aSStefan Roesch 
751*19fc516aSStefan Roesch 	val = memparse(buf, &retptr);
752*19fc516aSStefan Roesch 	/* There could be trailing '\n', also catch any typos after the value */
753*19fc516aSStefan Roesch 	retptr = skip_spaces(retptr);
754*19fc516aSStefan Roesch 	if (*retptr != 0 || val == 0)
755*19fc516aSStefan Roesch 		return -EINVAL;
756*19fc516aSStefan Roesch 
757*19fc516aSStefan Roesch 	val = min(val, BTRFS_MAX_DATA_CHUNK_SIZE);
758*19fc516aSStefan Roesch 
759*19fc516aSStefan Roesch 	/* Limit stripe size to 10% of available space. */
760*19fc516aSStefan Roesch 	val = min(div_factor(fs_info->fs_devices->total_rw_bytes, 1), val);
761*19fc516aSStefan Roesch 
762*19fc516aSStefan Roesch 	/* Must be multiple of 256M. */
763*19fc516aSStefan Roesch 	val &= ~((u64)SZ_256M - 1);
764*19fc516aSStefan Roesch 
765*19fc516aSStefan Roesch 	/* Must be at least 256M. */
766*19fc516aSStefan Roesch 	if (val < SZ_256M)
767*19fc516aSStefan Roesch 		return -EINVAL;
768*19fc516aSStefan Roesch 
769*19fc516aSStefan Roesch 	btrfs_update_space_info_chunk_size(space_info, val);
770*19fc516aSStefan Roesch 
771*19fc516aSStefan Roesch 	return len;
772*19fc516aSStefan Roesch }
773*19fc516aSStefan Roesch 
7746ab0a202SJeff Mahoney SPACE_INFO_ATTR(flags);
7756ab0a202SJeff Mahoney SPACE_INFO_ATTR(total_bytes);
7766ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_used);
7776ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_pinned);
7786ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_reserved);
7796ab0a202SJeff Mahoney SPACE_INFO_ATTR(bytes_may_use);
780c1fd5c30SWang Xiaoguang SPACE_INFO_ATTR(bytes_readonly);
781169e0da9SNaohiro Aota SPACE_INFO_ATTR(bytes_zone_unusable);
7826ab0a202SJeff Mahoney SPACE_INFO_ATTR(disk_used);
7836ab0a202SJeff Mahoney SPACE_INFO_ATTR(disk_total);
784*19fc516aSStefan Roesch BTRFS_ATTR_RW(space_info, chunk_size, btrfs_chunk_size_show, btrfs_chunk_size_store);
7856ab0a202SJeff Mahoney 
786bb5a098dSJosef Bacik static ssize_t btrfs_sinfo_bg_reclaim_threshold_show(struct kobject *kobj,
787bb5a098dSJosef Bacik 						     struct kobj_attribute *a,
788bb5a098dSJosef Bacik 						     char *buf)
789bb5a098dSJosef Bacik {
790bb5a098dSJosef Bacik 	struct btrfs_space_info *space_info = to_space_info(kobj);
791bb5a098dSJosef Bacik 	ssize_t ret;
792bb5a098dSJosef Bacik 
793bb5a098dSJosef Bacik 	ret = sysfs_emit(buf, "%d\n", READ_ONCE(space_info->bg_reclaim_threshold));
794bb5a098dSJosef Bacik 
795bb5a098dSJosef Bacik 	return ret;
796bb5a098dSJosef Bacik }
797bb5a098dSJosef Bacik 
798bb5a098dSJosef Bacik static ssize_t btrfs_sinfo_bg_reclaim_threshold_store(struct kobject *kobj,
799bb5a098dSJosef Bacik 						      struct kobj_attribute *a,
800bb5a098dSJosef Bacik 						      const char *buf, size_t len)
801bb5a098dSJosef Bacik {
802bb5a098dSJosef Bacik 	struct btrfs_space_info *space_info = to_space_info(kobj);
803bb5a098dSJosef Bacik 	int thresh;
804bb5a098dSJosef Bacik 	int ret;
805bb5a098dSJosef Bacik 
806bb5a098dSJosef Bacik 	ret = kstrtoint(buf, 10, &thresh);
807bb5a098dSJosef Bacik 	if (ret)
808bb5a098dSJosef Bacik 		return ret;
809bb5a098dSJosef Bacik 
810ef972e7bSJosef Bacik 	if (thresh < 0 || thresh > 100)
811bb5a098dSJosef Bacik 		return -EINVAL;
812bb5a098dSJosef Bacik 
813bb5a098dSJosef Bacik 	WRITE_ONCE(space_info->bg_reclaim_threshold, thresh);
814bb5a098dSJosef Bacik 
815bb5a098dSJosef Bacik 	return len;
816bb5a098dSJosef Bacik }
817bb5a098dSJosef Bacik 
818bb5a098dSJosef Bacik BTRFS_ATTR_RW(space_info, bg_reclaim_threshold,
819bb5a098dSJosef Bacik 	      btrfs_sinfo_bg_reclaim_threshold_show,
820bb5a098dSJosef Bacik 	      btrfs_sinfo_bg_reclaim_threshold_store);
821bb5a098dSJosef Bacik 
822e7849e33SAnand Jain /*
823e7849e33SAnand Jain  * Allocation information about block group types.
824e7849e33SAnand Jain  *
825e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/allocation/<bg-type>/
826e7849e33SAnand Jain  */
8276ab0a202SJeff Mahoney static struct attribute *space_info_attrs[] = {
828a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, flags),
829a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, total_bytes),
830a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_used),
831a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_pinned),
832a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_reserved),
833a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_may_use),
834a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, bytes_readonly),
835169e0da9SNaohiro Aota 	BTRFS_ATTR_PTR(space_info, bytes_zone_unusable),
836a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, disk_used),
837a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(space_info, disk_total),
838bb5a098dSJosef Bacik 	BTRFS_ATTR_PTR(space_info, bg_reclaim_threshold),
839*19fc516aSStefan Roesch 	BTRFS_ATTR_PTR(space_info, chunk_size),
8406ab0a202SJeff Mahoney 	NULL,
8416ab0a202SJeff Mahoney };
8427c7e3014SKimberly Brown ATTRIBUTE_GROUPS(space_info);
8436ab0a202SJeff Mahoney 
8446ab0a202SJeff Mahoney static void space_info_release(struct kobject *kobj)
8456ab0a202SJeff Mahoney {
8466ab0a202SJeff Mahoney 	struct btrfs_space_info *sinfo = to_space_info(kobj);
8476ab0a202SJeff Mahoney 	kfree(sinfo);
8486ab0a202SJeff Mahoney }
8496ab0a202SJeff Mahoney 
85027992d01SDavid Sterba static struct kobj_type space_info_ktype = {
8516ab0a202SJeff Mahoney 	.sysfs_ops = &kobj_sysfs_ops,
8526ab0a202SJeff Mahoney 	.release = space_info_release,
8537c7e3014SKimberly Brown 	.default_groups = space_info_groups,
8546ab0a202SJeff Mahoney };
8556ab0a202SJeff Mahoney 
856e7849e33SAnand Jain /*
857e7849e33SAnand Jain  * Allocation information about block groups.
858e7849e33SAnand Jain  *
859e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/allocation/
860e7849e33SAnand Jain  */
8616ab0a202SJeff Mahoney static const struct attribute *allocation_attrs[] = {
862a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(allocation, global_rsv_reserved),
863a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(allocation, global_rsv_size),
8646ab0a202SJeff Mahoney 	NULL,
8656ab0a202SJeff Mahoney };
8666ab0a202SJeff Mahoney 
867f8ba9c11SJeff Mahoney static ssize_t btrfs_label_show(struct kobject *kobj,
868f8ba9c11SJeff Mahoney 				struct kobj_attribute *a, char *buf)
869f8ba9c11SJeff Mahoney {
870f8ba9c11SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
87148fcc3ffSSatoru Takeuchi 	char *label = fs_info->super_copy->label;
872ee17fc80SDavid Sterba 	ssize_t ret;
873ee17fc80SDavid Sterba 
874ee17fc80SDavid Sterba 	spin_lock(&fs_info->super_lock);
875020e5277SAnand Jain 	ret = sysfs_emit(buf, label[0] ? "%s\n" : "%s", label);
876ee17fc80SDavid Sterba 	spin_unlock(&fs_info->super_lock);
877ee17fc80SDavid Sterba 
878ee17fc80SDavid Sterba 	return ret;
879f8ba9c11SJeff Mahoney }
880f8ba9c11SJeff Mahoney 
881f8ba9c11SJeff Mahoney static ssize_t btrfs_label_store(struct kobject *kobj,
882f8ba9c11SJeff Mahoney 				 struct kobj_attribute *a,
883f8ba9c11SJeff Mahoney 				 const char *buf, size_t len)
884f8ba9c11SJeff Mahoney {
885f8ba9c11SJeff Mahoney 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
88648fcc3ffSSatoru Takeuchi 	size_t p_len;
887f8ba9c11SJeff Mahoney 
88866ac9fe7SDavid Sterba 	if (!fs_info)
88966ac9fe7SDavid Sterba 		return -EPERM;
89066ac9fe7SDavid Sterba 
891bc98a42cSDavid Howells 	if (sb_rdonly(fs_info->sb))
89279aec2b8SAnand Jain 		return -EROFS;
89379aec2b8SAnand Jain 
89448fcc3ffSSatoru Takeuchi 	/*
89548fcc3ffSSatoru Takeuchi 	 * p_len is the len until the first occurrence of either
89648fcc3ffSSatoru Takeuchi 	 * '\n' or '\0'
89748fcc3ffSSatoru Takeuchi 	 */
89848fcc3ffSSatoru Takeuchi 	p_len = strcspn(buf, "\n");
89948fcc3ffSSatoru Takeuchi 
90048fcc3ffSSatoru Takeuchi 	if (p_len >= BTRFS_LABEL_SIZE)
901f8ba9c11SJeff Mahoney 		return -EINVAL;
902f8ba9c11SJeff Mahoney 
903a6f69dc8SDavid Sterba 	spin_lock(&fs_info->super_lock);
90448fcc3ffSSatoru Takeuchi 	memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE);
90548fcc3ffSSatoru Takeuchi 	memcpy(fs_info->super_copy->label, buf, p_len);
906a6f69dc8SDavid Sterba 	spin_unlock(&fs_info->super_lock);
907f8ba9c11SJeff Mahoney 
908a6f69dc8SDavid Sterba 	/*
909a6f69dc8SDavid Sterba 	 * We don't want to do full transaction commit from inside sysfs
910a6f69dc8SDavid Sterba 	 */
911a6f69dc8SDavid Sterba 	btrfs_set_pending(fs_info, COMMIT);
912a6f69dc8SDavid Sterba 	wake_up_process(fs_info->transaction_kthread);
913a6f69dc8SDavid Sterba 
914f8ba9c11SJeff Mahoney 	return len;
915f8ba9c11SJeff Mahoney }
916a969f4ccSHans van Kranenburg BTRFS_ATTR_RW(, label, btrfs_label_show, btrfs_label_store);
917f8ba9c11SJeff Mahoney 
918df93589aSDavid Sterba static ssize_t btrfs_nodesize_show(struct kobject *kobj,
919df93589aSDavid Sterba 				struct kobj_attribute *a, char *buf)
920df93589aSDavid Sterba {
921df93589aSDavid Sterba 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
922df93589aSDavid Sterba 
923020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n", fs_info->super_copy->nodesize);
924df93589aSDavid Sterba }
925df93589aSDavid Sterba 
926a969f4ccSHans van Kranenburg BTRFS_ATTR(, nodesize, btrfs_nodesize_show);
927df93589aSDavid Sterba 
928df93589aSDavid Sterba static ssize_t btrfs_sectorsize_show(struct kobject *kobj,
929df93589aSDavid Sterba 				struct kobj_attribute *a, char *buf)
930df93589aSDavid Sterba {
931df93589aSDavid Sterba 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
932df93589aSDavid Sterba 
933020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n", fs_info->super_copy->sectorsize);
934df93589aSDavid Sterba }
935df93589aSDavid Sterba 
936a969f4ccSHans van Kranenburg BTRFS_ATTR(, sectorsize, btrfs_sectorsize_show);
937df93589aSDavid Sterba 
938df93589aSDavid Sterba static ssize_t btrfs_clone_alignment_show(struct kobject *kobj,
939df93589aSDavid Sterba 				struct kobj_attribute *a, char *buf)
940df93589aSDavid Sterba {
941df93589aSDavid Sterba 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
942df93589aSDavid Sterba 
943020e5277SAnand Jain 	return sysfs_emit(buf, "%u\n", fs_info->super_copy->sectorsize);
944df93589aSDavid Sterba }
945df93589aSDavid Sterba 
946a969f4ccSHans van Kranenburg BTRFS_ATTR(, clone_alignment, btrfs_clone_alignment_show);
947df93589aSDavid Sterba 
9482723480aSSargun Dhillon static ssize_t quota_override_show(struct kobject *kobj,
9492723480aSSargun Dhillon 				   struct kobj_attribute *a, char *buf)
9502723480aSSargun Dhillon {
9512723480aSSargun Dhillon 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
9522723480aSSargun Dhillon 	int quota_override;
9532723480aSSargun Dhillon 
9542723480aSSargun Dhillon 	quota_override = test_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags);
955020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", quota_override);
9562723480aSSargun Dhillon }
9572723480aSSargun Dhillon 
9582723480aSSargun Dhillon static ssize_t quota_override_store(struct kobject *kobj,
9592723480aSSargun Dhillon 				    struct kobj_attribute *a,
9602723480aSSargun Dhillon 				    const char *buf, size_t len)
9612723480aSSargun Dhillon {
9622723480aSSargun Dhillon 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
9632723480aSSargun Dhillon 	unsigned long knob;
9642723480aSSargun Dhillon 	int err;
9652723480aSSargun Dhillon 
9662723480aSSargun Dhillon 	if (!fs_info)
9672723480aSSargun Dhillon 		return -EPERM;
9682723480aSSargun Dhillon 
9692723480aSSargun Dhillon 	if (!capable(CAP_SYS_RESOURCE))
9702723480aSSargun Dhillon 		return -EPERM;
9712723480aSSargun Dhillon 
9722723480aSSargun Dhillon 	err = kstrtoul(buf, 10, &knob);
9732723480aSSargun Dhillon 	if (err)
9742723480aSSargun Dhillon 		return err;
9752723480aSSargun Dhillon 	if (knob > 1)
9762723480aSSargun Dhillon 		return -EINVAL;
9772723480aSSargun Dhillon 
9782723480aSSargun Dhillon 	if (knob)
9792723480aSSargun Dhillon 		set_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags);
9802723480aSSargun Dhillon 	else
9812723480aSSargun Dhillon 		clear_bit(BTRFS_FS_QUOTA_OVERRIDE, &fs_info->flags);
9822723480aSSargun Dhillon 
9832723480aSSargun Dhillon 	return len;
9842723480aSSargun Dhillon }
9852723480aSSargun Dhillon 
986a969f4ccSHans van Kranenburg BTRFS_ATTR_RW(, quota_override, quota_override_show, quota_override_store);
9872723480aSSargun Dhillon 
98856f20f40SNikolay Borisov static ssize_t btrfs_metadata_uuid_show(struct kobject *kobj,
98956f20f40SNikolay Borisov 				struct kobj_attribute *a, char *buf)
99056f20f40SNikolay Borisov {
99156f20f40SNikolay Borisov 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
99256f20f40SNikolay Borisov 
993020e5277SAnand Jain 	return sysfs_emit(buf, "%pU\n", fs_info->fs_devices->metadata_uuid);
99456f20f40SNikolay Borisov }
99556f20f40SNikolay Borisov 
99656f20f40SNikolay Borisov BTRFS_ATTR(, metadata_uuid, btrfs_metadata_uuid_show);
99756f20f40SNikolay Borisov 
99841e6d2a8SJohannes Thumshirn static ssize_t btrfs_checksum_show(struct kobject *kobj,
99941e6d2a8SJohannes Thumshirn 				   struct kobj_attribute *a, char *buf)
100041e6d2a8SJohannes Thumshirn {
100141e6d2a8SJohannes Thumshirn 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
100241e6d2a8SJohannes Thumshirn 	u16 csum_type = btrfs_super_csum_type(fs_info->super_copy);
100341e6d2a8SJohannes Thumshirn 
1004020e5277SAnand Jain 	return sysfs_emit(buf, "%s (%s)\n",
100541e6d2a8SJohannes Thumshirn 			  btrfs_super_csum_name(csum_type),
100641e6d2a8SJohannes Thumshirn 			  crypto_shash_driver_name(fs_info->csum_shash));
100741e6d2a8SJohannes Thumshirn }
100841e6d2a8SJohannes Thumshirn 
100941e6d2a8SJohannes Thumshirn BTRFS_ATTR(, checksum, btrfs_checksum_show);
101041e6d2a8SJohannes Thumshirn 
101166a2823cSGoldwyn Rodrigues static ssize_t btrfs_exclusive_operation_show(struct kobject *kobj,
101266a2823cSGoldwyn Rodrigues 		struct kobj_attribute *a, char *buf)
101366a2823cSGoldwyn Rodrigues {
101466a2823cSGoldwyn Rodrigues 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
101566a2823cSGoldwyn Rodrigues 	const char *str;
101666a2823cSGoldwyn Rodrigues 
101766a2823cSGoldwyn Rodrigues 	switch (READ_ONCE(fs_info->exclusive_operation)) {
101866a2823cSGoldwyn Rodrigues 		case  BTRFS_EXCLOP_NONE:
101966a2823cSGoldwyn Rodrigues 			str = "none\n";
102066a2823cSGoldwyn Rodrigues 			break;
102166a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_BALANCE:
102266a2823cSGoldwyn Rodrigues 			str = "balance\n";
102366a2823cSGoldwyn Rodrigues 			break;
10243e1ad196SDavid Sterba 		case BTRFS_EXCLOP_BALANCE_PAUSED:
10253e1ad196SDavid Sterba 			str = "balance paused\n";
10263e1ad196SDavid Sterba 			break;
102766a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_ADD:
102866a2823cSGoldwyn Rodrigues 			str = "device add\n";
102966a2823cSGoldwyn Rodrigues 			break;
103066a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_REMOVE:
103166a2823cSGoldwyn Rodrigues 			str = "device remove\n";
103266a2823cSGoldwyn Rodrigues 			break;
103366a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_DEV_REPLACE:
103466a2823cSGoldwyn Rodrigues 			str = "device replace\n";
103566a2823cSGoldwyn Rodrigues 			break;
103666a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_RESIZE:
103766a2823cSGoldwyn Rodrigues 			str = "resize\n";
103866a2823cSGoldwyn Rodrigues 			break;
103966a2823cSGoldwyn Rodrigues 		case BTRFS_EXCLOP_SWAP_ACTIVATE:
104066a2823cSGoldwyn Rodrigues 			str = "swap activate\n";
104166a2823cSGoldwyn Rodrigues 			break;
104266a2823cSGoldwyn Rodrigues 		default:
104366a2823cSGoldwyn Rodrigues 			str = "UNKNOWN\n";
104466a2823cSGoldwyn Rodrigues 			break;
104566a2823cSGoldwyn Rodrigues 	}
1046020e5277SAnand Jain 	return sysfs_emit(buf, "%s", str);
104766a2823cSGoldwyn Rodrigues }
104866a2823cSGoldwyn Rodrigues BTRFS_ATTR(, exclusive_operation, btrfs_exclusive_operation_show);
104966a2823cSGoldwyn Rodrigues 
1050089c8b05SAnand Jain static ssize_t btrfs_generation_show(struct kobject *kobj,
1051089c8b05SAnand Jain 				     struct kobj_attribute *a, char *buf)
1052089c8b05SAnand Jain {
1053089c8b05SAnand Jain 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
1054089c8b05SAnand Jain 
1055020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", fs_info->generation);
1056089c8b05SAnand Jain }
1057089c8b05SAnand Jain BTRFS_ATTR(, generation, btrfs_generation_show);
1058089c8b05SAnand Jain 
1059aaefed20SAnand Jain /*
1060aaefed20SAnand Jain  * Look for an exact string @string in @buffer with possible leading or
1061aaefed20SAnand Jain  * trailing whitespace
1062aaefed20SAnand Jain  */
1063aaefed20SAnand Jain static bool strmatch(const char *buffer, const char *string)
1064aaefed20SAnand Jain {
1065aaefed20SAnand Jain 	const size_t len = strlen(string);
1066aaefed20SAnand Jain 
1067aaefed20SAnand Jain 	/* Skip leading whitespace */
1068aaefed20SAnand Jain 	buffer = skip_spaces(buffer);
1069aaefed20SAnand Jain 
1070aaefed20SAnand Jain 	/* Match entire string, check if the rest is whitespace or empty */
1071aaefed20SAnand Jain 	if (strncmp(string, buffer, len) == 0 &&
1072aaefed20SAnand Jain 	    strlen(skip_spaces(buffer + len)) == 0)
1073aaefed20SAnand Jain 		return true;
1074aaefed20SAnand Jain 
1075aaefed20SAnand Jain 	return false;
1076aaefed20SAnand Jain }
1077aaefed20SAnand Jain 
10783d8cc17aSAnand Jain static const char * const btrfs_read_policy_name[] = { "pid" };
10793d8cc17aSAnand Jain 
10803d8cc17aSAnand Jain static ssize_t btrfs_read_policy_show(struct kobject *kobj,
10813d8cc17aSAnand Jain 				      struct kobj_attribute *a, char *buf)
10823d8cc17aSAnand Jain {
10833d8cc17aSAnand Jain 	struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
10843d8cc17aSAnand Jain 	ssize_t ret = 0;
10853d8cc17aSAnand Jain 	int i;
10863d8cc17aSAnand Jain 
10873d8cc17aSAnand Jain 	for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
10883d8cc17aSAnand Jain 		if (fs_devices->read_policy == i)
10893d8cc17aSAnand Jain 			ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s[%s]",
10903d8cc17aSAnand Jain 					 (ret == 0 ? "" : " "),
10913d8cc17aSAnand Jain 					 btrfs_read_policy_name[i]);
10923d8cc17aSAnand Jain 		else
10933d8cc17aSAnand Jain 			ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s%s",
10943d8cc17aSAnand Jain 					 (ret == 0 ? "" : " "),
10953d8cc17aSAnand Jain 					 btrfs_read_policy_name[i]);
10963d8cc17aSAnand Jain 	}
10973d8cc17aSAnand Jain 
10983d8cc17aSAnand Jain 	ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
10993d8cc17aSAnand Jain 
11003d8cc17aSAnand Jain 	return ret;
11013d8cc17aSAnand Jain }
11023d8cc17aSAnand Jain 
11033d8cc17aSAnand Jain static ssize_t btrfs_read_policy_store(struct kobject *kobj,
11043d8cc17aSAnand Jain 				       struct kobj_attribute *a,
11053d8cc17aSAnand Jain 				       const char *buf, size_t len)
11063d8cc17aSAnand Jain {
11073d8cc17aSAnand Jain 	struct btrfs_fs_devices *fs_devices = to_fs_devs(kobj);
11083d8cc17aSAnand Jain 	int i;
11093d8cc17aSAnand Jain 
11103d8cc17aSAnand Jain 	for (i = 0; i < BTRFS_NR_READ_POLICY; i++) {
11113d8cc17aSAnand Jain 		if (strmatch(buf, btrfs_read_policy_name[i])) {
11123d8cc17aSAnand Jain 			if (i != fs_devices->read_policy) {
11133d8cc17aSAnand Jain 				fs_devices->read_policy = i;
11143d8cc17aSAnand Jain 				btrfs_info(fs_devices->fs_info,
11153d8cc17aSAnand Jain 					   "read policy set to '%s'",
11163d8cc17aSAnand Jain 					   btrfs_read_policy_name[i]);
11173d8cc17aSAnand Jain 			}
11183d8cc17aSAnand Jain 			return len;
11193d8cc17aSAnand Jain 		}
11203d8cc17aSAnand Jain 	}
11213d8cc17aSAnand Jain 
11223d8cc17aSAnand Jain 	return -EINVAL;
11233d8cc17aSAnand Jain }
11243d8cc17aSAnand Jain BTRFS_ATTR_RW(, read_policy, btrfs_read_policy_show, btrfs_read_policy_store);
11253d8cc17aSAnand Jain 
112618bb8bbfSJohannes Thumshirn static ssize_t btrfs_bg_reclaim_threshold_show(struct kobject *kobj,
112718bb8bbfSJohannes Thumshirn 					       struct kobj_attribute *a,
112818bb8bbfSJohannes Thumshirn 					       char *buf)
112918bb8bbfSJohannes Thumshirn {
113018bb8bbfSJohannes Thumshirn 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
113118bb8bbfSJohannes Thumshirn 	ssize_t ret;
113218bb8bbfSJohannes Thumshirn 
1133020e5277SAnand Jain 	ret = sysfs_emit(buf, "%d\n", READ_ONCE(fs_info->bg_reclaim_threshold));
113418bb8bbfSJohannes Thumshirn 
113518bb8bbfSJohannes Thumshirn 	return ret;
113618bb8bbfSJohannes Thumshirn }
113718bb8bbfSJohannes Thumshirn 
113818bb8bbfSJohannes Thumshirn static ssize_t btrfs_bg_reclaim_threshold_store(struct kobject *kobj,
113918bb8bbfSJohannes Thumshirn 						struct kobj_attribute *a,
114018bb8bbfSJohannes Thumshirn 						const char *buf, size_t len)
114118bb8bbfSJohannes Thumshirn {
114218bb8bbfSJohannes Thumshirn 	struct btrfs_fs_info *fs_info = to_fs_info(kobj);
114318bb8bbfSJohannes Thumshirn 	int thresh;
114418bb8bbfSJohannes Thumshirn 	int ret;
114518bb8bbfSJohannes Thumshirn 
114618bb8bbfSJohannes Thumshirn 	ret = kstrtoint(buf, 10, &thresh);
114718bb8bbfSJohannes Thumshirn 	if (ret)
114818bb8bbfSJohannes Thumshirn 		return ret;
114918bb8bbfSJohannes Thumshirn 
115077233c2dSJohannes Thumshirn 	if (thresh != 0 && (thresh <= 50 || thresh > 100))
115118bb8bbfSJohannes Thumshirn 		return -EINVAL;
115218bb8bbfSJohannes Thumshirn 
115377233c2dSJohannes Thumshirn 	WRITE_ONCE(fs_info->bg_reclaim_threshold, thresh);
115418bb8bbfSJohannes Thumshirn 
115518bb8bbfSJohannes Thumshirn 	return len;
115618bb8bbfSJohannes Thumshirn }
115718bb8bbfSJohannes Thumshirn BTRFS_ATTR_RW(, bg_reclaim_threshold, btrfs_bg_reclaim_threshold_show,
115818bb8bbfSJohannes Thumshirn 	      btrfs_bg_reclaim_threshold_store);
115918bb8bbfSJohannes Thumshirn 
1160e7849e33SAnand Jain /*
1161e7849e33SAnand Jain  * Per-filesystem information and stats.
1162e7849e33SAnand Jain  *
1163e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/
1164e7849e33SAnand Jain  */
11650dd2906fSAnand Jain static const struct attribute *btrfs_attrs[] = {
1166a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, label),
1167a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, nodesize),
1168a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, sectorsize),
1169a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, clone_alignment),
1170a969f4ccSHans van Kranenburg 	BTRFS_ATTR_PTR(, quota_override),
117156f20f40SNikolay Borisov 	BTRFS_ATTR_PTR(, metadata_uuid),
117241e6d2a8SJohannes Thumshirn 	BTRFS_ATTR_PTR(, checksum),
117366a2823cSGoldwyn Rodrigues 	BTRFS_ATTR_PTR(, exclusive_operation),
1174089c8b05SAnand Jain 	BTRFS_ATTR_PTR(, generation),
11753d8cc17aSAnand Jain 	BTRFS_ATTR_PTR(, read_policy),
117618bb8bbfSJohannes Thumshirn 	BTRFS_ATTR_PTR(, bg_reclaim_threshold),
1177f8ba9c11SJeff Mahoney 	NULL,
1178f8ba9c11SJeff Mahoney };
1179f8ba9c11SJeff Mahoney 
1180c1b7e474SAnand Jain static void btrfs_release_fsid_kobj(struct kobject *kobj)
1181510d7360SJeff Mahoney {
11822e7910d6SAnand Jain 	struct btrfs_fs_devices *fs_devs = to_fs_devs(kobj);
1183248d200dSAnand Jain 
1184c1b7e474SAnand Jain 	memset(&fs_devs->fsid_kobj, 0, sizeof(struct kobject));
11852e7910d6SAnand Jain 	complete(&fs_devs->kobj_unregister);
1186510d7360SJeff Mahoney }
1187510d7360SJeff Mahoney 
1188510d7360SJeff Mahoney static struct kobj_type btrfs_ktype = {
1189510d7360SJeff Mahoney 	.sysfs_ops	= &kobj_sysfs_ops,
1190c1b7e474SAnand Jain 	.release	= btrfs_release_fsid_kobj,
1191510d7360SJeff Mahoney };
1192510d7360SJeff Mahoney 
11932e7910d6SAnand Jain static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj)
11942e7910d6SAnand Jain {
11952e7910d6SAnand Jain 	if (kobj->ktype != &btrfs_ktype)
11962e7910d6SAnand Jain 		return NULL;
1197c1b7e474SAnand Jain 	return container_of(kobj, struct btrfs_fs_devices, fsid_kobj);
11982e7910d6SAnand Jain }
11992e7910d6SAnand Jain 
1200510d7360SJeff Mahoney static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj)
1201510d7360SJeff Mahoney {
1202510d7360SJeff Mahoney 	if (kobj->ktype != &btrfs_ktype)
1203510d7360SJeff Mahoney 		return NULL;
12042e7910d6SAnand Jain 	return to_fs_devs(kobj)->fs_info;
1205510d7360SJeff Mahoney }
120658176a96SJosef Bacik 
1207*19fc516aSStefan Roesch static struct kobject *get_btrfs_kobj(struct kobject *kobj)
1208*19fc516aSStefan Roesch {
1209*19fc516aSStefan Roesch 	while (kobj) {
1210*19fc516aSStefan Roesch 		if (kobj->ktype == &btrfs_ktype)
1211*19fc516aSStefan Roesch 			return kobj;
1212*19fc516aSStefan Roesch 		kobj = kobj->parent;
1213*19fc516aSStefan Roesch 	}
1214*19fc516aSStefan Roesch 	return NULL;
1215*19fc516aSStefan Roesch }
1216*19fc516aSStefan Roesch 
1217e453d989SJeff Mahoney #define NUM_FEATURE_BITS 64
12186c52157fSTomohiro Misono #define BTRFS_FEATURE_NAME_MAX 13
12196c52157fSTomohiro Misono static char btrfs_unknown_feature_names[FEAT_MAX][NUM_FEATURE_BITS][BTRFS_FEATURE_NAME_MAX];
12206c52157fSTomohiro Misono static struct btrfs_feature_attr btrfs_feature_attrs[FEAT_MAX][NUM_FEATURE_BITS];
1221e453d989SJeff Mahoney 
1222a55e65b8SDavid Sterba static_assert(ARRAY_SIZE(btrfs_unknown_feature_names) ==
1223a55e65b8SDavid Sterba 	      ARRAY_SIZE(btrfs_feature_attrs));
1224a55e65b8SDavid Sterba static_assert(ARRAY_SIZE(btrfs_unknown_feature_names[0]) ==
1225a55e65b8SDavid Sterba 	      ARRAY_SIZE(btrfs_feature_attrs[0]));
1226a55e65b8SDavid Sterba 
12276c52157fSTomohiro Misono static const u64 supported_feature_masks[FEAT_MAX] = {
1228e453d989SJeff Mahoney 	[FEAT_COMPAT]    = BTRFS_FEATURE_COMPAT_SUPP,
1229e453d989SJeff Mahoney 	[FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP,
1230e453d989SJeff Mahoney 	[FEAT_INCOMPAT]  = BTRFS_FEATURE_INCOMPAT_SUPP,
1231e453d989SJeff Mahoney };
1232e453d989SJeff Mahoney 
1233e453d989SJeff Mahoney static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add)
12345ac1d209SJeff Mahoney {
1235e453d989SJeff Mahoney 	int set;
1236e453d989SJeff Mahoney 
1237e453d989SJeff Mahoney 	for (set = 0; set < FEAT_MAX; set++) {
1238e453d989SJeff Mahoney 		int i;
1239e453d989SJeff Mahoney 		struct attribute *attrs[2];
1240e453d989SJeff Mahoney 		struct attribute_group agroup = {
1241e453d989SJeff Mahoney 			.name = "features",
1242e453d989SJeff Mahoney 			.attrs = attrs,
1243e453d989SJeff Mahoney 		};
1244e453d989SJeff Mahoney 		u64 features = get_features(fs_info, set);
1245e453d989SJeff Mahoney 		features &= ~supported_feature_masks[set];
1246e453d989SJeff Mahoney 
1247e453d989SJeff Mahoney 		if (!features)
1248e453d989SJeff Mahoney 			continue;
1249e453d989SJeff Mahoney 
1250e453d989SJeff Mahoney 		attrs[1] = NULL;
1251e453d989SJeff Mahoney 		for (i = 0; i < NUM_FEATURE_BITS; i++) {
1252e453d989SJeff Mahoney 			struct btrfs_feature_attr *fa;
1253e453d989SJeff Mahoney 
1254e453d989SJeff Mahoney 			if (!(features & (1ULL << i)))
1255e453d989SJeff Mahoney 				continue;
1256e453d989SJeff Mahoney 
1257e453d989SJeff Mahoney 			fa = &btrfs_feature_attrs[set][i];
1258e453d989SJeff Mahoney 			attrs[0] = &fa->kobj_attr.attr;
1259e453d989SJeff Mahoney 			if (add) {
1260e453d989SJeff Mahoney 				int ret;
1261c1b7e474SAnand Jain 				ret = sysfs_merge_group(&fs_info->fs_devices->fsid_kobj,
1262e453d989SJeff Mahoney 							&agroup);
1263e453d989SJeff Mahoney 				if (ret)
1264e453d989SJeff Mahoney 					return ret;
1265e453d989SJeff Mahoney 			} else
1266c1b7e474SAnand Jain 				sysfs_unmerge_group(&fs_info->fs_devices->fsid_kobj,
1267e453d989SJeff Mahoney 						    &agroup);
1268e453d989SJeff Mahoney 		}
1269e453d989SJeff Mahoney 
1270e453d989SJeff Mahoney 	}
1271e453d989SJeff Mahoney 	return 0;
1272e453d989SJeff Mahoney }
1273e453d989SJeff Mahoney 
12742e3e1281SAnand Jain static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs)
1275e453d989SJeff Mahoney {
1276a013d141SAnand Jain 	if (fs_devs->devinfo_kobj) {
1277a013d141SAnand Jain 		kobject_del(fs_devs->devinfo_kobj);
1278a013d141SAnand Jain 		kobject_put(fs_devs->devinfo_kobj);
1279a013d141SAnand Jain 		fs_devs->devinfo_kobj = NULL;
1280a013d141SAnand Jain 	}
1281a013d141SAnand Jain 
1282b5501504SAnand Jain 	if (fs_devs->devices_kobj) {
1283b5501504SAnand Jain 		kobject_del(fs_devs->devices_kobj);
1284b5501504SAnand Jain 		kobject_put(fs_devs->devices_kobj);
1285b5501504SAnand Jain 		fs_devs->devices_kobj = NULL;
1286aaf13305SAnand Jain 	}
1287aaf13305SAnand Jain 
1288c1b7e474SAnand Jain 	if (fs_devs->fsid_kobj.state_initialized) {
1289c1b7e474SAnand Jain 		kobject_del(&fs_devs->fsid_kobj);
1290c1b7e474SAnand Jain 		kobject_put(&fs_devs->fsid_kobj);
12912e7910d6SAnand Jain 		wait_for_completion(&fs_devs->kobj_unregister);
12925ac1d209SJeff Mahoney 	}
1293f90fc547SAnand Jain }
12945ac1d209SJeff Mahoney 
12952e3e1281SAnand Jain /* when fs_devs is NULL it will remove all fsid kobject */
12961d1c1be3SAnand Jain void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs)
12972e3e1281SAnand Jain {
12982e3e1281SAnand Jain 	struct list_head *fs_uuids = btrfs_get_fs_uuids();
12992e3e1281SAnand Jain 
13002e3e1281SAnand Jain 	if (fs_devs) {
13012e3e1281SAnand Jain 		__btrfs_sysfs_remove_fsid(fs_devs);
13022e3e1281SAnand Jain 		return;
13032e3e1281SAnand Jain 	}
13042e3e1281SAnand Jain 
1305c4babc5eSAnand Jain 	list_for_each_entry(fs_devs, fs_uuids, fs_list) {
13062e3e1281SAnand Jain 		__btrfs_sysfs_remove_fsid(fs_devs);
13072e3e1281SAnand Jain 	}
13082e3e1281SAnand Jain }
13092e3e1281SAnand Jain 
131053f8a74cSAnand Jain static void btrfs_sysfs_remove_fs_devices(struct btrfs_fs_devices *fs_devices)
131153f8a74cSAnand Jain {
131253f8a74cSAnand Jain 	struct btrfs_device *device;
131330b0e4e0SAnand Jain 	struct btrfs_fs_devices *seed;
131453f8a74cSAnand Jain 
131553f8a74cSAnand Jain 	list_for_each_entry(device, &fs_devices->devices, dev_list)
131653f8a74cSAnand Jain 		btrfs_sysfs_remove_device(device);
131730b0e4e0SAnand Jain 
131830b0e4e0SAnand Jain 	list_for_each_entry(seed, &fs_devices->seed_list, seed_list) {
131930b0e4e0SAnand Jain 		list_for_each_entry(device, &seed->devices, dev_list)
132030b0e4e0SAnand Jain 			btrfs_sysfs_remove_device(device);
132130b0e4e0SAnand Jain 	}
132253f8a74cSAnand Jain }
132353f8a74cSAnand Jain 
13246618a59bSAnand Jain void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info)
1325e453d989SJeff Mahoney {
13263092c68fSNikolay Borisov 	struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj;
13273092c68fSNikolay Borisov 
13283092c68fSNikolay Borisov 	sysfs_remove_link(fsid_kobj, "bdi");
13293092c68fSNikolay Borisov 
1330e453d989SJeff Mahoney 	if (fs_info->space_info_kobj) {
1331e453d989SJeff Mahoney 		sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs);
1332e453d989SJeff Mahoney 		kobject_del(fs_info->space_info_kobj);
1333e453d989SJeff Mahoney 		kobject_put(fs_info->space_info_kobj);
1334e453d989SJeff Mahoney 	}
133571e8978eSDennis Zhou #ifdef CONFIG_BTRFS_DEBUG
1336e4faab84SDennis Zhou 	if (fs_info->discard_debug_kobj) {
1337e4faab84SDennis Zhou 		sysfs_remove_files(fs_info->discard_debug_kobj,
1338e4faab84SDennis Zhou 				   discard_debug_attrs);
1339e4faab84SDennis Zhou 		kobject_del(fs_info->discard_debug_kobj);
1340e4faab84SDennis Zhou 		kobject_put(fs_info->discard_debug_kobj);
1341e4faab84SDennis Zhou 	}
134293945cb4SDennis Zhou 	if (fs_info->debug_kobj) {
134393945cb4SDennis Zhou 		sysfs_remove_files(fs_info->debug_kobj, btrfs_debug_mount_attrs);
134493945cb4SDennis Zhou 		kobject_del(fs_info->debug_kobj);
134593945cb4SDennis Zhou 		kobject_put(fs_info->debug_kobj);
134693945cb4SDennis Zhou 	}
134771e8978eSDennis Zhou #endif
1348e453d989SJeff Mahoney 	addrm_unknown_feature_attrs(fs_info, false);
13493092c68fSNikolay Borisov 	sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group);
13503092c68fSNikolay Borisov 	sysfs_remove_files(fsid_kobj, btrfs_attrs);
135153f8a74cSAnand Jain 	btrfs_sysfs_remove_fs_devices(fs_info->fs_devices);
1352e453d989SJeff Mahoney }
1353e453d989SJeff Mahoney 
1354f10152bcSDavid Sterba static const char * const btrfs_feature_set_names[FEAT_MAX] = {
135579da4fa4SJeff Mahoney 	[FEAT_COMPAT]	 = "compat",
135679da4fa4SJeff Mahoney 	[FEAT_COMPAT_RO] = "compat_ro",
135779da4fa4SJeff Mahoney 	[FEAT_INCOMPAT]	 = "incompat",
135879da4fa4SJeff Mahoney };
135979da4fa4SJeff Mahoney 
13609e6df7ceSDavid Sterba const char *btrfs_feature_set_name(enum btrfs_feature_set set)
1361f10152bcSDavid Sterba {
1362f10152bcSDavid Sterba 	return btrfs_feature_set_names[set];
1363f10152bcSDavid Sterba }
1364f10152bcSDavid Sterba 
13653b02a68aSJeff Mahoney char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags)
13663b02a68aSJeff Mahoney {
13673b02a68aSJeff Mahoney 	size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */
13683b02a68aSJeff Mahoney 	int len = 0;
13693b02a68aSJeff Mahoney 	int i;
13703b02a68aSJeff Mahoney 	char *str;
13713b02a68aSJeff Mahoney 
13723b02a68aSJeff Mahoney 	str = kmalloc(bufsize, GFP_KERNEL);
13733b02a68aSJeff Mahoney 	if (!str)
13743b02a68aSJeff Mahoney 		return str;
13753b02a68aSJeff Mahoney 
13763b02a68aSJeff Mahoney 	for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
13773b02a68aSJeff Mahoney 		const char *name;
13783b02a68aSJeff Mahoney 
13793b02a68aSJeff Mahoney 		if (!(flags & (1ULL << i)))
13803b02a68aSJeff Mahoney 			continue;
13813b02a68aSJeff Mahoney 
13823b02a68aSJeff Mahoney 		name = btrfs_feature_attrs[set][i].kobj_attr.attr.name;
1383abdd9febSTakashi Iwai 		len += scnprintf(str + len, bufsize - len, "%s%s",
13843b02a68aSJeff Mahoney 				len ? "," : "", name);
13853b02a68aSJeff Mahoney 	}
13863b02a68aSJeff Mahoney 
13873b02a68aSJeff Mahoney 	return str;
13883b02a68aSJeff Mahoney }
13893b02a68aSJeff Mahoney 
139079da4fa4SJeff Mahoney static void init_feature_attrs(void)
139179da4fa4SJeff Mahoney {
139279da4fa4SJeff Mahoney 	struct btrfs_feature_attr *fa;
139379da4fa4SJeff Mahoney 	int set, i;
139479da4fa4SJeff Mahoney 
13953b02a68aSJeff Mahoney 	memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs));
13963b02a68aSJeff Mahoney 	memset(btrfs_unknown_feature_names, 0,
13973b02a68aSJeff Mahoney 	       sizeof(btrfs_unknown_feature_names));
13983b02a68aSJeff Mahoney 
139979da4fa4SJeff Mahoney 	for (i = 0; btrfs_supported_feature_attrs[i]; i++) {
140079da4fa4SJeff Mahoney 		struct btrfs_feature_attr *sfa;
140179da4fa4SJeff Mahoney 		struct attribute *a = btrfs_supported_feature_attrs[i];
14023b02a68aSJeff Mahoney 		int bit;
140379da4fa4SJeff Mahoney 		sfa = attr_to_btrfs_feature_attr(a);
14043b02a68aSJeff Mahoney 		bit = ilog2(sfa->feature_bit);
14053b02a68aSJeff Mahoney 		fa = &btrfs_feature_attrs[sfa->feature_set][bit];
140679da4fa4SJeff Mahoney 
140779da4fa4SJeff Mahoney 		fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name;
140879da4fa4SJeff Mahoney 	}
140979da4fa4SJeff Mahoney 
141079da4fa4SJeff Mahoney 	for (set = 0; set < FEAT_MAX; set++) {
141179da4fa4SJeff Mahoney 		for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
141279da4fa4SJeff Mahoney 			char *name = btrfs_unknown_feature_names[set][i];
141379da4fa4SJeff Mahoney 			fa = &btrfs_feature_attrs[set][i];
141479da4fa4SJeff Mahoney 
141579da4fa4SJeff Mahoney 			if (fa->kobj_attr.attr.name)
141679da4fa4SJeff Mahoney 				continue;
141779da4fa4SJeff Mahoney 
14186c52157fSTomohiro Misono 			snprintf(name, BTRFS_FEATURE_NAME_MAX, "%s:%u",
141979da4fa4SJeff Mahoney 				 btrfs_feature_set_names[set], i);
142079da4fa4SJeff Mahoney 
142179da4fa4SJeff Mahoney 			fa->kobj_attr.attr.name = name;
142279da4fa4SJeff Mahoney 			fa->kobj_attr.attr.mode = S_IRUGO;
142379da4fa4SJeff Mahoney 			fa->feature_set = set;
142479da4fa4SJeff Mahoney 			fa->feature_bit = 1ULL << i;
142579da4fa4SJeff Mahoney 		}
142679da4fa4SJeff Mahoney 	}
142779da4fa4SJeff Mahoney }
142879da4fa4SJeff Mahoney 
142932a9991fSDavid Sterba /*
143032a9991fSDavid Sterba  * Create a sysfs entry for a given block group type at path
143132a9991fSDavid Sterba  * /sys/fs/btrfs/UUID/allocation/data/TYPE
143232a9991fSDavid Sterba  */
143332da5386SDavid Sterba void btrfs_sysfs_add_block_group_type(struct btrfs_block_group *cache)
143432a9991fSDavid Sterba {
143532a9991fSDavid Sterba 	struct btrfs_fs_info *fs_info = cache->fs_info;
143632a9991fSDavid Sterba 	struct btrfs_space_info *space_info = cache->space_info;
143732a9991fSDavid Sterba 	struct raid_kobject *rkobj;
143832a9991fSDavid Sterba 	const int index = btrfs_bg_flags_to_raid_index(cache->flags);
143932a9991fSDavid Sterba 	unsigned int nofs_flag;
144032a9991fSDavid Sterba 	int ret;
144132a9991fSDavid Sterba 
144232a9991fSDavid Sterba 	/*
144332a9991fSDavid Sterba 	 * Setup a NOFS context because kobject_add(), deep in its call chain,
144432a9991fSDavid Sterba 	 * does GFP_KERNEL allocations, and we are often called in a context
144532a9991fSDavid Sterba 	 * where if reclaim is triggered we can deadlock (we are either holding
144632a9991fSDavid Sterba 	 * a transaction handle or some lock required for a transaction
144732a9991fSDavid Sterba 	 * commit).
144832a9991fSDavid Sterba 	 */
144932a9991fSDavid Sterba 	nofs_flag = memalloc_nofs_save();
145032a9991fSDavid Sterba 
145132a9991fSDavid Sterba 	rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS);
145232a9991fSDavid Sterba 	if (!rkobj) {
145332a9991fSDavid Sterba 		memalloc_nofs_restore(nofs_flag);
145432a9991fSDavid Sterba 		btrfs_warn(cache->fs_info,
145532a9991fSDavid Sterba 				"couldn't alloc memory for raid level kobject");
145632a9991fSDavid Sterba 		return;
145732a9991fSDavid Sterba 	}
145832a9991fSDavid Sterba 
145932a9991fSDavid Sterba 	rkobj->flags = cache->flags;
146032a9991fSDavid Sterba 	kobject_init(&rkobj->kobj, &btrfs_raid_ktype);
146149ea112dSJosef Bacik 
146249ea112dSJosef Bacik 	/*
146349ea112dSJosef Bacik 	 * We call this either on mount, or if we've created a block group for a
146449ea112dSJosef Bacik 	 * new index type while running (i.e. when restriping).  The running
146549ea112dSJosef Bacik 	 * case is tricky because we could race with other threads, so we need
146649ea112dSJosef Bacik 	 * to have this check to make sure we didn't already init the kobject.
146749ea112dSJosef Bacik 	 *
146849ea112dSJosef Bacik 	 * We don't have to protect on the free side because it only happens on
146949ea112dSJosef Bacik 	 * unmount.
147049ea112dSJosef Bacik 	 */
147149ea112dSJosef Bacik 	spin_lock(&space_info->lock);
147249ea112dSJosef Bacik 	if (space_info->block_group_kobjs[index]) {
147349ea112dSJosef Bacik 		spin_unlock(&space_info->lock);
147449ea112dSJosef Bacik 		kobject_put(&rkobj->kobj);
147549ea112dSJosef Bacik 		return;
147649ea112dSJosef Bacik 	} else {
147749ea112dSJosef Bacik 		space_info->block_group_kobjs[index] = &rkobj->kobj;
147849ea112dSJosef Bacik 	}
147949ea112dSJosef Bacik 	spin_unlock(&space_info->lock);
148049ea112dSJosef Bacik 
148132a9991fSDavid Sterba 	ret = kobject_add(&rkobj->kobj, &space_info->kobj, "%s",
148232a9991fSDavid Sterba 			  btrfs_bg_type_to_raid_name(rkobj->flags));
148332a9991fSDavid Sterba 	memalloc_nofs_restore(nofs_flag);
148432a9991fSDavid Sterba 	if (ret) {
148549ea112dSJosef Bacik 		spin_lock(&space_info->lock);
148649ea112dSJosef Bacik 		space_info->block_group_kobjs[index] = NULL;
148749ea112dSJosef Bacik 		spin_unlock(&space_info->lock);
148832a9991fSDavid Sterba 		kobject_put(&rkobj->kobj);
148932a9991fSDavid Sterba 		btrfs_warn(fs_info,
149032a9991fSDavid Sterba 			"failed to add kobject for block cache, ignoring");
149132a9991fSDavid Sterba 		return;
149232a9991fSDavid Sterba 	}
149332a9991fSDavid Sterba }
149432a9991fSDavid Sterba 
1495b5865babSDavid Sterba /*
1496b5865babSDavid Sterba  * Remove sysfs directories for all block group types of a given space info and
1497b5865babSDavid Sterba  * the space info as well
1498b5865babSDavid Sterba  */
1499b5865babSDavid Sterba void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info)
1500b5865babSDavid Sterba {
1501b5865babSDavid Sterba 	int i;
1502b5865babSDavid Sterba 
1503b5865babSDavid Sterba 	for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
1504b5865babSDavid Sterba 		struct kobject *kobj;
1505b5865babSDavid Sterba 
1506b5865babSDavid Sterba 		kobj = space_info->block_group_kobjs[i];
1507b5865babSDavid Sterba 		space_info->block_group_kobjs[i] = NULL;
1508b5865babSDavid Sterba 		if (kobj) {
1509b5865babSDavid Sterba 			kobject_del(kobj);
1510b5865babSDavid Sterba 			kobject_put(kobj);
1511b5865babSDavid Sterba 		}
1512b5865babSDavid Sterba 	}
1513b5865babSDavid Sterba 	kobject_del(&space_info->kobj);
1514b5865babSDavid Sterba 	kobject_put(&space_info->kobj);
1515b5865babSDavid Sterba }
1516b5865babSDavid Sterba 
1517b882327aSDavid Sterba static const char *alloc_name(u64 flags)
1518b882327aSDavid Sterba {
1519b882327aSDavid Sterba 	switch (flags) {
1520b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA:
1521b882327aSDavid Sterba 		return "mixed";
1522b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_METADATA:
1523b882327aSDavid Sterba 		return "metadata";
1524b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_DATA:
1525b882327aSDavid Sterba 		return "data";
1526b882327aSDavid Sterba 	case BTRFS_BLOCK_GROUP_SYSTEM:
1527b882327aSDavid Sterba 		return "system";
1528b882327aSDavid Sterba 	default:
1529b882327aSDavid Sterba 		WARN_ON(1);
1530b882327aSDavid Sterba 		return "invalid-combination";
1531445d8ab5STom Rix 	}
1532b882327aSDavid Sterba }
1533b882327aSDavid Sterba 
1534b882327aSDavid Sterba /*
1535b882327aSDavid Sterba  * Create a sysfs entry for a space info type at path
1536b882327aSDavid Sterba  * /sys/fs/btrfs/UUID/allocation/TYPE
1537b882327aSDavid Sterba  */
1538b882327aSDavid Sterba int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info,
1539b882327aSDavid Sterba 				    struct btrfs_space_info *space_info)
1540b882327aSDavid Sterba {
1541b882327aSDavid Sterba 	int ret;
1542b882327aSDavid Sterba 
1543b882327aSDavid Sterba 	ret = kobject_init_and_add(&space_info->kobj, &space_info_ktype,
1544b882327aSDavid Sterba 				   fs_info->space_info_kobj, "%s",
1545b882327aSDavid Sterba 				   alloc_name(space_info->flags));
1546b882327aSDavid Sterba 	if (ret) {
1547b882327aSDavid Sterba 		kobject_put(&space_info->kobj);
1548b882327aSDavid Sterba 		return ret;
1549b882327aSDavid Sterba 	}
1550b882327aSDavid Sterba 
1551b882327aSDavid Sterba 	return 0;
1552b882327aSDavid Sterba }
1553b882327aSDavid Sterba 
155453f8a74cSAnand Jain void btrfs_sysfs_remove_device(struct btrfs_device *device)
155599994cdeSAnand Jain {
1556985e233eSAnand Jain 	struct kobject *devices_kobj;
155799994cdeSAnand Jain 
1558985e233eSAnand Jain 	/*
1559985e233eSAnand Jain 	 * Seed fs_devices devices_kobj aren't used, fetch kobject from the
1560985e233eSAnand Jain 	 * fs_info::fs_devices.
1561985e233eSAnand Jain 	 */
1562985e233eSAnand Jain 	devices_kobj = device->fs_info->fs_devices->devices_kobj;
1563985e233eSAnand Jain 	ASSERT(devices_kobj);
156499994cdeSAnand Jain 
15658d65269fSChristoph Hellwig 	if (device->bdev)
15668d65269fSChristoph Hellwig 		sysfs_remove_link(devices_kobj, bdev_kobj(device->bdev)->name);
156799994cdeSAnand Jain 
1568985e233eSAnand Jain 	if (device->devid_kobj.state_initialized) {
1569985e233eSAnand Jain 		kobject_del(&device->devid_kobj);
1570985e233eSAnand Jain 		kobject_put(&device->devid_kobj);
1571985e233eSAnand Jain 		wait_for_completion(&device->kobj_unregister);
1572985e233eSAnand Jain 	}
1573b5ddcffaSAnand Jain }
1574668e48afSAnand Jain 
1575668e48afSAnand Jain static ssize_t btrfs_devinfo_in_fs_metadata_show(struct kobject *kobj,
1576668e48afSAnand Jain 					         struct kobj_attribute *a,
1577668e48afSAnand Jain 					         char *buf)
1578668e48afSAnand Jain {
1579668e48afSAnand Jain 	int val;
1580668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1581668e48afSAnand Jain 						   devid_kobj);
1582668e48afSAnand Jain 
1583668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_IN_FS_METADATA, &device->dev_state);
1584668e48afSAnand Jain 
1585020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1586668e48afSAnand Jain }
1587668e48afSAnand Jain BTRFS_ATTR(devid, in_fs_metadata, btrfs_devinfo_in_fs_metadata_show);
1588668e48afSAnand Jain 
158925864778SAnand Jain static ssize_t btrfs_devinfo_missing_show(struct kobject *kobj,
1590668e48afSAnand Jain 					struct kobj_attribute *a, char *buf)
1591668e48afSAnand Jain {
1592668e48afSAnand Jain 	int val;
1593668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1594668e48afSAnand Jain 						   devid_kobj);
1595668e48afSAnand Jain 
1596668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_MISSING, &device->dev_state);
1597668e48afSAnand Jain 
1598020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1599668e48afSAnand Jain }
160025864778SAnand Jain BTRFS_ATTR(devid, missing, btrfs_devinfo_missing_show);
1601668e48afSAnand Jain 
1602668e48afSAnand Jain static ssize_t btrfs_devinfo_replace_target_show(struct kobject *kobj,
1603668e48afSAnand Jain 					         struct kobj_attribute *a,
1604668e48afSAnand Jain 					         char *buf)
1605668e48afSAnand Jain {
1606668e48afSAnand Jain 	int val;
1607668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1608668e48afSAnand Jain 						   devid_kobj);
1609668e48afSAnand Jain 
1610668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_REPLACE_TGT, &device->dev_state);
1611668e48afSAnand Jain 
1612020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1613668e48afSAnand Jain }
1614668e48afSAnand Jain BTRFS_ATTR(devid, replace_target, btrfs_devinfo_replace_target_show);
1615668e48afSAnand Jain 
1616eb3b5053SDavid Sterba static ssize_t btrfs_devinfo_scrub_speed_max_show(struct kobject *kobj,
1617eb3b5053SDavid Sterba 					     struct kobj_attribute *a,
1618eb3b5053SDavid Sterba 					     char *buf)
1619eb3b5053SDavid Sterba {
1620eb3b5053SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1621eb3b5053SDavid Sterba 						   devid_kobj);
1622eb3b5053SDavid Sterba 
1623020e5277SAnand Jain 	return sysfs_emit(buf, "%llu\n", READ_ONCE(device->scrub_speed_max));
1624eb3b5053SDavid Sterba }
1625eb3b5053SDavid Sterba 
1626eb3b5053SDavid Sterba static ssize_t btrfs_devinfo_scrub_speed_max_store(struct kobject *kobj,
1627eb3b5053SDavid Sterba 					      struct kobj_attribute *a,
1628eb3b5053SDavid Sterba 					      const char *buf, size_t len)
1629eb3b5053SDavid Sterba {
1630eb3b5053SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1631eb3b5053SDavid Sterba 						   devid_kobj);
1632eb3b5053SDavid Sterba 	char *endptr;
1633eb3b5053SDavid Sterba 	unsigned long long limit;
1634eb3b5053SDavid Sterba 
1635eb3b5053SDavid Sterba 	limit = memparse(buf, &endptr);
1636eb3b5053SDavid Sterba 	WRITE_ONCE(device->scrub_speed_max, limit);
1637eb3b5053SDavid Sterba 	return len;
1638eb3b5053SDavid Sterba }
1639eb3b5053SDavid Sterba BTRFS_ATTR_RW(devid, scrub_speed_max, btrfs_devinfo_scrub_speed_max_show,
1640eb3b5053SDavid Sterba 	      btrfs_devinfo_scrub_speed_max_store);
1641eb3b5053SDavid Sterba 
1642668e48afSAnand Jain static ssize_t btrfs_devinfo_writeable_show(struct kobject *kobj,
1643668e48afSAnand Jain 					    struct kobj_attribute *a, char *buf)
1644668e48afSAnand Jain {
1645668e48afSAnand Jain 	int val;
1646668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1647668e48afSAnand Jain 						   devid_kobj);
1648668e48afSAnand Jain 
1649668e48afSAnand Jain 	val = !!test_bit(BTRFS_DEV_STATE_WRITEABLE, &device->dev_state);
1650668e48afSAnand Jain 
1651020e5277SAnand Jain 	return sysfs_emit(buf, "%d\n", val);
1652668e48afSAnand Jain }
1653668e48afSAnand Jain BTRFS_ATTR(devid, writeable, btrfs_devinfo_writeable_show);
1654668e48afSAnand Jain 
1655a26d60deSAnand Jain static ssize_t btrfs_devinfo_fsid_show(struct kobject *kobj,
1656a26d60deSAnand Jain 				       struct kobj_attribute *a, char *buf)
1657a26d60deSAnand Jain {
1658a26d60deSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1659a26d60deSAnand Jain 						   devid_kobj);
1660a26d60deSAnand Jain 
1661a26d60deSAnand Jain 	return sysfs_emit(buf, "%pU\n", device->fs_devices->fsid);
1662a26d60deSAnand Jain }
1663a26d60deSAnand Jain BTRFS_ATTR(devid, fsid, btrfs_devinfo_fsid_show);
1664a26d60deSAnand Jain 
1665da658b57SDavid Sterba static ssize_t btrfs_devinfo_error_stats_show(struct kobject *kobj,
1666da658b57SDavid Sterba 		struct kobj_attribute *a, char *buf)
1667da658b57SDavid Sterba {
1668da658b57SDavid Sterba 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1669da658b57SDavid Sterba 						   devid_kobj);
1670da658b57SDavid Sterba 
1671da658b57SDavid Sterba 	if (!device->dev_stats_valid)
1672020e5277SAnand Jain 		return sysfs_emit(buf, "invalid\n");
1673da658b57SDavid Sterba 
1674da658b57SDavid Sterba 	/*
1675da658b57SDavid Sterba 	 * Print all at once so we get a snapshot of all values from the same
1676da658b57SDavid Sterba 	 * time. Keep them in sync and in order of definition of
1677da658b57SDavid Sterba 	 * btrfs_dev_stat_values.
1678da658b57SDavid Sterba 	 */
1679020e5277SAnand Jain 	return sysfs_emit(buf,
1680da658b57SDavid Sterba 		"write_errs %d\n"
1681da658b57SDavid Sterba 		"read_errs %d\n"
1682da658b57SDavid Sterba 		"flush_errs %d\n"
1683da658b57SDavid Sterba 		"corruption_errs %d\n"
1684da658b57SDavid Sterba 		"generation_errs %d\n",
1685da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_WRITE_ERRS),
1686da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_READ_ERRS),
1687da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_FLUSH_ERRS),
1688da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_CORRUPTION_ERRS),
1689da658b57SDavid Sterba 		btrfs_dev_stat_read(device, BTRFS_DEV_STAT_GENERATION_ERRS));
1690da658b57SDavid Sterba }
1691da658b57SDavid Sterba BTRFS_ATTR(devid, error_stats, btrfs_devinfo_error_stats_show);
1692da658b57SDavid Sterba 
1693e7849e33SAnand Jain /*
1694e7849e33SAnand Jain  * Information about one device.
1695e7849e33SAnand Jain  *
1696e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/devinfo/<devid>/
1697e7849e33SAnand Jain  */
1698668e48afSAnand Jain static struct attribute *devid_attrs[] = {
1699da658b57SDavid Sterba 	BTRFS_ATTR_PTR(devid, error_stats),
1700a26d60deSAnand Jain 	BTRFS_ATTR_PTR(devid, fsid),
1701668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, in_fs_metadata),
1702668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, missing),
1703668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, replace_target),
1704eb3b5053SDavid Sterba 	BTRFS_ATTR_PTR(devid, scrub_speed_max),
1705668e48afSAnand Jain 	BTRFS_ATTR_PTR(devid, writeable),
1706668e48afSAnand Jain 	NULL
1707668e48afSAnand Jain };
1708668e48afSAnand Jain ATTRIBUTE_GROUPS(devid);
1709668e48afSAnand Jain 
1710668e48afSAnand Jain static void btrfs_release_devid_kobj(struct kobject *kobj)
1711668e48afSAnand Jain {
1712668e48afSAnand Jain 	struct btrfs_device *device = container_of(kobj, struct btrfs_device,
1713668e48afSAnand Jain 						   devid_kobj);
1714668e48afSAnand Jain 
1715668e48afSAnand Jain 	memset(&device->devid_kobj, 0, sizeof(struct kobject));
1716668e48afSAnand Jain 	complete(&device->kobj_unregister);
1717668e48afSAnand Jain }
1718668e48afSAnand Jain 
1719668e48afSAnand Jain static struct kobj_type devid_ktype = {
1720668e48afSAnand Jain 	.sysfs_ops	= &kobj_sysfs_ops,
1721668e48afSAnand Jain 	.default_groups = devid_groups,
1722668e48afSAnand Jain 	.release	= btrfs_release_devid_kobj,
1723668e48afSAnand Jain };
1724668e48afSAnand Jain 
1725cd36da2eSAnand Jain int btrfs_sysfs_add_device(struct btrfs_device *device)
172629e5be24SJeff Mahoney {
1727178a16c9SAnand Jain 	int ret;
1728a47bd78dSJosef Bacik 	unsigned int nofs_flag;
1729178a16c9SAnand Jain 	struct kobject *devices_kobj;
1730178a16c9SAnand Jain 	struct kobject *devinfo_kobj;
1731178a16c9SAnand Jain 
1732178a16c9SAnand Jain 	/*
1733178a16c9SAnand Jain 	 * Make sure we use the fs_info::fs_devices to fetch the kobjects even
1734178a16c9SAnand Jain 	 * for the seed fs_devices
1735178a16c9SAnand Jain 	 */
1736178a16c9SAnand Jain 	devices_kobj = device->fs_info->fs_devices->devices_kobj;
1737178a16c9SAnand Jain 	devinfo_kobj = device->fs_info->fs_devices->devinfo_kobj;
1738178a16c9SAnand Jain 	ASSERT(devices_kobj);
1739178a16c9SAnand Jain 	ASSERT(devinfo_kobj);
174029e5be24SJeff Mahoney 
1741a47bd78dSJosef Bacik 	nofs_flag = memalloc_nofs_save();
1742f085381eSAnand Jain 
1743178a16c9SAnand Jain 	if (device->bdev) {
17448d65269fSChristoph Hellwig 		struct kobject *disk_kobj = bdev_kobj(device->bdev);
174529e5be24SJeff Mahoney 
1746178a16c9SAnand Jain 		ret = sysfs_create_link(devices_kobj, disk_kobj, disk_kobj->name);
1747178a16c9SAnand Jain 		if (ret) {
1748178a16c9SAnand Jain 			btrfs_warn(device->fs_info,
1749178a16c9SAnand Jain 				"creating sysfs device link for devid %llu failed: %d",
1750178a16c9SAnand Jain 				device->devid, ret);
1751178a16c9SAnand Jain 			goto out;
1752178a16c9SAnand Jain 		}
175329e5be24SJeff Mahoney 	}
175429e5be24SJeff Mahoney 
1755178a16c9SAnand Jain 	init_completion(&device->kobj_unregister);
1756178a16c9SAnand Jain 	ret = kobject_init_and_add(&device->devid_kobj, &devid_ktype,
1757178a16c9SAnand Jain 				   devinfo_kobj, "%llu", device->devid);
1758178a16c9SAnand Jain 	if (ret) {
1759178a16c9SAnand Jain 		kobject_put(&device->devid_kobj);
1760178a16c9SAnand Jain 		btrfs_warn(device->fs_info,
1761178a16c9SAnand Jain 			   "devinfo init for devid %llu failed: %d",
1762178a16c9SAnand Jain 			   device->devid, ret);
1763668e48afSAnand Jain 	}
1764178a16c9SAnand Jain 
1765178a16c9SAnand Jain out:
1766a47bd78dSJosef Bacik 	memalloc_nofs_restore(nofs_flag);
1767178a16c9SAnand Jain 	return ret;
1768178a16c9SAnand Jain }
1769668e48afSAnand Jain 
1770cd36da2eSAnand Jain static int btrfs_sysfs_add_fs_devices(struct btrfs_fs_devices *fs_devices)
1771178a16c9SAnand Jain {
1772178a16c9SAnand Jain 	int ret;
1773cd36da2eSAnand Jain 	struct btrfs_device *device;
177430b0e4e0SAnand Jain 	struct btrfs_fs_devices *seed;
1775178a16c9SAnand Jain 
1776178a16c9SAnand Jain 	list_for_each_entry(device, &fs_devices->devices, dev_list) {
1777178a16c9SAnand Jain 		ret = btrfs_sysfs_add_device(device);
1778178a16c9SAnand Jain 		if (ret)
17797ad3912aSAnand Jain 			goto fail;
1780178a16c9SAnand Jain 	}
1781178a16c9SAnand Jain 
178230b0e4e0SAnand Jain 	list_for_each_entry(seed, &fs_devices->seed_list, seed_list) {
178330b0e4e0SAnand Jain 		list_for_each_entry(device, &seed->devices, dev_list) {
178430b0e4e0SAnand Jain 			ret = btrfs_sysfs_add_device(device);
178530b0e4e0SAnand Jain 			if (ret)
17867ad3912aSAnand Jain 				goto fail;
178730b0e4e0SAnand Jain 		}
178830b0e4e0SAnand Jain 	}
178930b0e4e0SAnand Jain 
1790178a16c9SAnand Jain 	return 0;
17917ad3912aSAnand Jain 
17927ad3912aSAnand Jain fail:
17937ad3912aSAnand Jain 	btrfs_sysfs_remove_fs_devices(fs_devices);
17947ad3912aSAnand Jain 	return ret;
179529e5be24SJeff Mahoney }
179629e5be24SJeff Mahoney 
17975b28692eSDavid Sterba void btrfs_kobject_uevent(struct block_device *bdev, enum kobject_action action)
17985b28692eSDavid Sterba {
17995b28692eSDavid Sterba 	int ret;
18005b28692eSDavid Sterba 
18015b28692eSDavid Sterba 	ret = kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, action);
18025b28692eSDavid Sterba 	if (ret)
18035b28692eSDavid Sterba 		pr_warn("BTRFS: Sending event '%d' to kobject: '%s' (%p): failed\n",
18045b28692eSDavid Sterba 			action, kobject_name(&disk_to_dev(bdev->bd_disk)->kobj),
18055b28692eSDavid Sterba 			&disk_to_dev(bdev->bd_disk)->kobj);
18065b28692eSDavid Sterba }
18075b28692eSDavid Sterba 
18088e560081SNikolay Borisov void btrfs_sysfs_update_sprout_fsid(struct btrfs_fs_devices *fs_devices)
18098e560081SNikolay Borisov 
1810f93c3997SDavid Sterba {
1811f93c3997SDavid Sterba 	char fsid_buf[BTRFS_UUID_UNPARSED_SIZE];
1812f93c3997SDavid Sterba 
1813f93c3997SDavid Sterba 	/*
1814f93c3997SDavid Sterba 	 * Sprouting changes fsid of the mounted filesystem, rename the fsid
1815f93c3997SDavid Sterba 	 * directory
1816f93c3997SDavid Sterba 	 */
18178e560081SNikolay Borisov 	snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU", fs_devices->fsid);
1818f93c3997SDavid Sterba 	if (kobject_rename(&fs_devices->fsid_kobj, fsid_buf))
1819f93c3997SDavid Sterba 		btrfs_warn(fs_devices->fs_info,
1820f93c3997SDavid Sterba 				"sysfs: failed to create fsid for sprout");
1821f93c3997SDavid Sterba }
1822f93c3997SDavid Sterba 
1823668e48afSAnand Jain void btrfs_sysfs_update_devid(struct btrfs_device *device)
1824668e48afSAnand Jain {
1825668e48afSAnand Jain 	char tmp[24];
1826668e48afSAnand Jain 
1827668e48afSAnand Jain 	snprintf(tmp, sizeof(tmp), "%llu", device->devid);
1828668e48afSAnand Jain 
1829668e48afSAnand Jain 	if (kobject_rename(&device->devid_kobj, tmp))
1830668e48afSAnand Jain 		btrfs_warn(device->fs_devices->fs_info,
1831668e48afSAnand Jain 			   "sysfs: failed to update devid for %llu",
1832668e48afSAnand Jain 			   device->devid);
1833668e48afSAnand Jain }
1834668e48afSAnand Jain 
1835510d7360SJeff Mahoney /* /sys/fs/btrfs/ entry */
1836510d7360SJeff Mahoney static struct kset *btrfs_kset;
1837510d7360SJeff Mahoney 
183872059215SAnand Jain /*
1839c6761a9eSAnand Jain  * Creates:
1840c6761a9eSAnand Jain  *		/sys/fs/btrfs/UUID
1841c6761a9eSAnand Jain  *
184272059215SAnand Jain  * Can be called by the device discovery thread.
184372059215SAnand Jain  */
1844c6761a9eSAnand Jain int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs)
18455ac1d209SJeff Mahoney {
18465ac1d209SJeff Mahoney 	int error;
18475ac1d209SJeff Mahoney 
18482e7910d6SAnand Jain 	init_completion(&fs_devs->kobj_unregister);
1849c1b7e474SAnand Jain 	fs_devs->fsid_kobj.kset = btrfs_kset;
1850c6761a9eSAnand Jain 	error = kobject_init_and_add(&fs_devs->fsid_kobj, &btrfs_ktype, NULL,
1851c6761a9eSAnand Jain 				     "%pU", fs_devs->fsid);
1852e3277335STobin C. Harding 	if (error) {
1853e3277335STobin C. Harding 		kobject_put(&fs_devs->fsid_kobj);
185472059215SAnand Jain 		return error;
185572059215SAnand Jain 	}
185672059215SAnand Jain 
1857bc036bb3SAnand Jain 	fs_devs->devices_kobj = kobject_create_and_add("devices",
1858bc036bb3SAnand Jain 						       &fs_devs->fsid_kobj);
1859bc036bb3SAnand Jain 	if (!fs_devs->devices_kobj) {
1860bc036bb3SAnand Jain 		btrfs_err(fs_devs->fs_info,
1861bc036bb3SAnand Jain 			  "failed to init sysfs device interface");
18621f6087e6SAnand Jain 		btrfs_sysfs_remove_fsid(fs_devs);
1863bc036bb3SAnand Jain 		return -ENOMEM;
1864bc036bb3SAnand Jain 	}
1865bc036bb3SAnand Jain 
1866a013d141SAnand Jain 	fs_devs->devinfo_kobj = kobject_create_and_add("devinfo",
1867a013d141SAnand Jain 						       &fs_devs->fsid_kobj);
1868a013d141SAnand Jain 	if (!fs_devs->devinfo_kobj) {
1869a013d141SAnand Jain 		btrfs_err(fs_devs->fs_info,
1870a013d141SAnand Jain 			  "failed to init sysfs devinfo kobject");
1871a013d141SAnand Jain 		btrfs_sysfs_remove_fsid(fs_devs);
1872a013d141SAnand Jain 		return -ENOMEM;
1873a013d141SAnand Jain 	}
1874a013d141SAnand Jain 
1875e3277335STobin C. Harding 	return 0;
1876e3277335STobin C. Harding }
1877e3277335STobin C. Harding 
187896f3136eSAnand Jain int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info)
187972059215SAnand Jain {
188072059215SAnand Jain 	int error;
18812e7910d6SAnand Jain 	struct btrfs_fs_devices *fs_devs = fs_info->fs_devices;
1882c1b7e474SAnand Jain 	struct kobject *fsid_kobj = &fs_devs->fsid_kobj;
188372059215SAnand Jain 
1884cd36da2eSAnand Jain 	error = btrfs_sysfs_add_fs_devices(fs_devs);
1885e453d989SJeff Mahoney 	if (error)
1886e453d989SJeff Mahoney 		return error;
1887510d7360SJeff Mahoney 
1888c1b7e474SAnand Jain 	error = sysfs_create_files(fsid_kobj, btrfs_attrs);
1889e453d989SJeff Mahoney 	if (error) {
189053f8a74cSAnand Jain 		btrfs_sysfs_remove_fs_devices(fs_devs);
1891e453d989SJeff Mahoney 		return error;
1892e453d989SJeff Mahoney 	}
189379da4fa4SJeff Mahoney 
1894c1b7e474SAnand Jain 	error = sysfs_create_group(fsid_kobj,
18950dd2906fSAnand Jain 				   &btrfs_feature_attr_group);
18960dd2906fSAnand Jain 	if (error)
18970dd2906fSAnand Jain 		goto failure;
18980dd2906fSAnand Jain 
18996e369febSDavid Sterba #ifdef CONFIG_BTRFS_DEBUG
190093945cb4SDennis Zhou 	fs_info->debug_kobj = kobject_create_and_add("debug", fsid_kobj);
190193945cb4SDennis Zhou 	if (!fs_info->debug_kobj) {
190293945cb4SDennis Zhou 		error = -ENOMEM;
190393945cb4SDennis Zhou 		goto failure;
190493945cb4SDennis Zhou 	}
190593945cb4SDennis Zhou 
190693945cb4SDennis Zhou 	error = sysfs_create_files(fs_info->debug_kobj, btrfs_debug_mount_attrs);
19076e369febSDavid Sterba 	if (error)
19086e369febSDavid Sterba 		goto failure;
1909e4faab84SDennis Zhou 
1910e4faab84SDennis Zhou 	/* Discard directory */
1911e4faab84SDennis Zhou 	fs_info->discard_debug_kobj = kobject_create_and_add("discard",
1912e4faab84SDennis Zhou 						     fs_info->debug_kobj);
1913e4faab84SDennis Zhou 	if (!fs_info->discard_debug_kobj) {
1914e4faab84SDennis Zhou 		error = -ENOMEM;
1915e4faab84SDennis Zhou 		goto failure;
1916e4faab84SDennis Zhou 	}
1917e4faab84SDennis Zhou 
1918e4faab84SDennis Zhou 	error = sysfs_create_files(fs_info->discard_debug_kobj,
1919e4faab84SDennis Zhou 				   discard_debug_attrs);
1920e4faab84SDennis Zhou 	if (error)
1921e4faab84SDennis Zhou 		goto failure;
19226e369febSDavid Sterba #endif
19236e369febSDavid Sterba 
1924e453d989SJeff Mahoney 	error = addrm_unknown_feature_attrs(fs_info, true);
192579da4fa4SJeff Mahoney 	if (error)
192679da4fa4SJeff Mahoney 		goto failure;
192779da4fa4SJeff Mahoney 
19283092c68fSNikolay Borisov 	error = sysfs_create_link(fsid_kobj, &fs_info->sb->s_bdi->dev->kobj, "bdi");
19293092c68fSNikolay Borisov 	if (error)
19303092c68fSNikolay Borisov 		goto failure;
19313092c68fSNikolay Borisov 
19326ab0a202SJeff Mahoney 	fs_info->space_info_kobj = kobject_create_and_add("allocation",
1933c1b7e474SAnand Jain 						  fsid_kobj);
19346ab0a202SJeff Mahoney 	if (!fs_info->space_info_kobj) {
19356ab0a202SJeff Mahoney 		error = -ENOMEM;
19366ab0a202SJeff Mahoney 		goto failure;
19376ab0a202SJeff Mahoney 	}
19386ab0a202SJeff Mahoney 
19396ab0a202SJeff Mahoney 	error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs);
19406ab0a202SJeff Mahoney 	if (error)
19416ab0a202SJeff Mahoney 		goto failure;
19426ab0a202SJeff Mahoney 
194379da4fa4SJeff Mahoney 	return 0;
194479da4fa4SJeff Mahoney failure:
19456618a59bSAnand Jain 	btrfs_sysfs_remove_mounted(fs_info);
19465ac1d209SJeff Mahoney 	return error;
19475ac1d209SJeff Mahoney }
19485ac1d209SJeff Mahoney 
194949e5fb46SQu Wenruo static inline struct btrfs_fs_info *qgroup_kobj_to_fs_info(struct kobject *kobj)
195049e5fb46SQu Wenruo {
195149e5fb46SQu Wenruo 	return to_fs_info(kobj->parent->parent);
195249e5fb46SQu Wenruo }
195349e5fb46SQu Wenruo 
195449e5fb46SQu Wenruo #define QGROUP_ATTR(_member, _show_name)					\
195549e5fb46SQu Wenruo static ssize_t btrfs_qgroup_show_##_member(struct kobject *qgroup_kobj,		\
195649e5fb46SQu Wenruo 					   struct kobj_attribute *a,		\
195749e5fb46SQu Wenruo 					   char *buf)				\
195849e5fb46SQu Wenruo {										\
195949e5fb46SQu Wenruo 	struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj);	\
196049e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(qgroup_kobj,			\
196149e5fb46SQu Wenruo 			struct btrfs_qgroup, kobj);				\
196249e5fb46SQu Wenruo 	return btrfs_show_u64(&qgroup->_member, &fs_info->qgroup_lock, buf);	\
196349e5fb46SQu Wenruo }										\
196449e5fb46SQu Wenruo BTRFS_ATTR(qgroup, _show_name, btrfs_qgroup_show_##_member)
196549e5fb46SQu Wenruo 
196649e5fb46SQu Wenruo #define QGROUP_RSV_ATTR(_name, _type)						\
196749e5fb46SQu Wenruo static ssize_t btrfs_qgroup_rsv_show_##_name(struct kobject *qgroup_kobj,	\
196849e5fb46SQu Wenruo 					     struct kobj_attribute *a,		\
196949e5fb46SQu Wenruo 					     char *buf)				\
197049e5fb46SQu Wenruo {										\
197149e5fb46SQu Wenruo 	struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj);	\
197249e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(qgroup_kobj,			\
197349e5fb46SQu Wenruo 			struct btrfs_qgroup, kobj);				\
197449e5fb46SQu Wenruo 	return btrfs_show_u64(&qgroup->rsv.values[_type],			\
197549e5fb46SQu Wenruo 			&fs_info->qgroup_lock, buf);				\
197649e5fb46SQu Wenruo }										\
197749e5fb46SQu Wenruo BTRFS_ATTR(qgroup, rsv_##_name, btrfs_qgroup_rsv_show_##_name)
197849e5fb46SQu Wenruo 
197949e5fb46SQu Wenruo QGROUP_ATTR(rfer, referenced);
198049e5fb46SQu Wenruo QGROUP_ATTR(excl, exclusive);
198149e5fb46SQu Wenruo QGROUP_ATTR(max_rfer, max_referenced);
198249e5fb46SQu Wenruo QGROUP_ATTR(max_excl, max_exclusive);
198349e5fb46SQu Wenruo QGROUP_ATTR(lim_flags, limit_flags);
198449e5fb46SQu Wenruo QGROUP_RSV_ATTR(data, BTRFS_QGROUP_RSV_DATA);
198549e5fb46SQu Wenruo QGROUP_RSV_ATTR(meta_pertrans, BTRFS_QGROUP_RSV_META_PERTRANS);
198649e5fb46SQu Wenruo QGROUP_RSV_ATTR(meta_prealloc, BTRFS_QGROUP_RSV_META_PREALLOC);
198749e5fb46SQu Wenruo 
1988e7849e33SAnand Jain /*
1989e7849e33SAnand Jain  * Qgroup information.
1990e7849e33SAnand Jain  *
1991e7849e33SAnand Jain  * Path: /sys/fs/btrfs/<uuid>/qgroups/<level>_<qgroupid>/
1992e7849e33SAnand Jain  */
199349e5fb46SQu Wenruo static struct attribute *qgroup_attrs[] = {
199449e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, referenced),
199549e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, exclusive),
199649e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, max_referenced),
199749e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, max_exclusive),
199849e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, limit_flags),
199949e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_data),
200049e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_meta_pertrans),
200149e5fb46SQu Wenruo 	BTRFS_ATTR_PTR(qgroup, rsv_meta_prealloc),
200249e5fb46SQu Wenruo 	NULL
200349e5fb46SQu Wenruo };
200449e5fb46SQu Wenruo ATTRIBUTE_GROUPS(qgroup);
200549e5fb46SQu Wenruo 
200649e5fb46SQu Wenruo static void qgroup_release(struct kobject *kobj)
200749e5fb46SQu Wenruo {
200849e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup = container_of(kobj, struct btrfs_qgroup, kobj);
200949e5fb46SQu Wenruo 
201049e5fb46SQu Wenruo 	memset(&qgroup->kobj, 0, sizeof(*kobj));
201149e5fb46SQu Wenruo }
201249e5fb46SQu Wenruo 
201349e5fb46SQu Wenruo static struct kobj_type qgroup_ktype = {
201449e5fb46SQu Wenruo 	.sysfs_ops = &kobj_sysfs_ops,
201549e5fb46SQu Wenruo 	.release = qgroup_release,
201649e5fb46SQu Wenruo 	.default_groups = qgroup_groups,
201749e5fb46SQu Wenruo };
201849e5fb46SQu Wenruo 
201949e5fb46SQu Wenruo int btrfs_sysfs_add_one_qgroup(struct btrfs_fs_info *fs_info,
202049e5fb46SQu Wenruo 				struct btrfs_qgroup *qgroup)
202149e5fb46SQu Wenruo {
202249e5fb46SQu Wenruo 	struct kobject *qgroups_kobj = fs_info->qgroups_kobj;
202349e5fb46SQu Wenruo 	int ret;
202449e5fb46SQu Wenruo 
202549e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
202649e5fb46SQu Wenruo 		return 0;
202749e5fb46SQu Wenruo 	if (qgroup->kobj.state_initialized)
202849e5fb46SQu Wenruo 		return 0;
202949e5fb46SQu Wenruo 	if (!qgroups_kobj)
203049e5fb46SQu Wenruo 		return -EINVAL;
203149e5fb46SQu Wenruo 
203249e5fb46SQu Wenruo 	ret = kobject_init_and_add(&qgroup->kobj, &qgroup_ktype, qgroups_kobj,
203349e5fb46SQu Wenruo 			"%hu_%llu", btrfs_qgroup_level(qgroup->qgroupid),
203449e5fb46SQu Wenruo 			btrfs_qgroup_subvolid(qgroup->qgroupid));
203549e5fb46SQu Wenruo 	if (ret < 0)
203649e5fb46SQu Wenruo 		kobject_put(&qgroup->kobj);
203749e5fb46SQu Wenruo 
203849e5fb46SQu Wenruo 	return ret;
203949e5fb46SQu Wenruo }
204049e5fb46SQu Wenruo 
204149e5fb46SQu Wenruo void btrfs_sysfs_del_qgroups(struct btrfs_fs_info *fs_info)
204249e5fb46SQu Wenruo {
204349e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup;
204449e5fb46SQu Wenruo 	struct btrfs_qgroup *next;
204549e5fb46SQu Wenruo 
204649e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
204749e5fb46SQu Wenruo 		return;
204849e5fb46SQu Wenruo 
204949e5fb46SQu Wenruo 	rbtree_postorder_for_each_entry_safe(qgroup, next,
205049e5fb46SQu Wenruo 					     &fs_info->qgroup_tree, node)
205149e5fb46SQu Wenruo 		btrfs_sysfs_del_one_qgroup(fs_info, qgroup);
205262ab2cc0SQu Wenruo 	if (fs_info->qgroups_kobj) {
205349e5fb46SQu Wenruo 		kobject_del(fs_info->qgroups_kobj);
205449e5fb46SQu Wenruo 		kobject_put(fs_info->qgroups_kobj);
205549e5fb46SQu Wenruo 		fs_info->qgroups_kobj = NULL;
205649e5fb46SQu Wenruo 	}
205762ab2cc0SQu Wenruo }
205849e5fb46SQu Wenruo 
205949e5fb46SQu Wenruo /* Called when qgroups get initialized, thus there is no need for locking */
206049e5fb46SQu Wenruo int btrfs_sysfs_add_qgroups(struct btrfs_fs_info *fs_info)
206149e5fb46SQu Wenruo {
206249e5fb46SQu Wenruo 	struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj;
206349e5fb46SQu Wenruo 	struct btrfs_qgroup *qgroup;
206449e5fb46SQu Wenruo 	struct btrfs_qgroup *next;
206549e5fb46SQu Wenruo 	int ret = 0;
206649e5fb46SQu Wenruo 
206749e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
206849e5fb46SQu Wenruo 		return 0;
206949e5fb46SQu Wenruo 
207049e5fb46SQu Wenruo 	ASSERT(fsid_kobj);
207149e5fb46SQu Wenruo 	if (fs_info->qgroups_kobj)
207249e5fb46SQu Wenruo 		return 0;
207349e5fb46SQu Wenruo 
207449e5fb46SQu Wenruo 	fs_info->qgroups_kobj = kobject_create_and_add("qgroups", fsid_kobj);
207549e5fb46SQu Wenruo 	if (!fs_info->qgroups_kobj) {
207649e5fb46SQu Wenruo 		ret = -ENOMEM;
207749e5fb46SQu Wenruo 		goto out;
207849e5fb46SQu Wenruo 	}
207949e5fb46SQu Wenruo 	rbtree_postorder_for_each_entry_safe(qgroup, next,
208049e5fb46SQu Wenruo 					     &fs_info->qgroup_tree, node) {
208149e5fb46SQu Wenruo 		ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
208249e5fb46SQu Wenruo 		if (ret < 0)
208349e5fb46SQu Wenruo 			goto out;
208449e5fb46SQu Wenruo 	}
208549e5fb46SQu Wenruo 
208649e5fb46SQu Wenruo out:
208749e5fb46SQu Wenruo 	if (ret < 0)
208849e5fb46SQu Wenruo 		btrfs_sysfs_del_qgroups(fs_info);
208949e5fb46SQu Wenruo 	return ret;
209049e5fb46SQu Wenruo }
209149e5fb46SQu Wenruo 
209249e5fb46SQu Wenruo void btrfs_sysfs_del_one_qgroup(struct btrfs_fs_info *fs_info,
209349e5fb46SQu Wenruo 				struct btrfs_qgroup *qgroup)
209449e5fb46SQu Wenruo {
209549e5fb46SQu Wenruo 	if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
209649e5fb46SQu Wenruo 		return;
209749e5fb46SQu Wenruo 
209849e5fb46SQu Wenruo 	if (qgroup->kobj.state_initialized) {
209949e5fb46SQu Wenruo 		kobject_del(&qgroup->kobj);
210049e5fb46SQu Wenruo 		kobject_put(&qgroup->kobj);
210149e5fb46SQu Wenruo 	}
210249e5fb46SQu Wenruo }
2103444e7516SDavid Sterba 
2104444e7516SDavid Sterba /*
2105444e7516SDavid Sterba  * Change per-fs features in /sys/fs/btrfs/UUID/features to match current
2106444e7516SDavid Sterba  * values in superblock. Call after any changes to incompat/compat_ro flags
2107444e7516SDavid Sterba  */
2108444e7516SDavid Sterba void btrfs_sysfs_feature_update(struct btrfs_fs_info *fs_info,
2109444e7516SDavid Sterba 		u64 bit, enum btrfs_feature_set set)
2110444e7516SDavid Sterba {
2111444e7516SDavid Sterba 	struct btrfs_fs_devices *fs_devs;
2112444e7516SDavid Sterba 	struct kobject *fsid_kobj;
211324646481SLeon Romanovsky 	u64 __maybe_unused features;
211424646481SLeon Romanovsky 	int __maybe_unused ret;
2115444e7516SDavid Sterba 
2116444e7516SDavid Sterba 	if (!fs_info)
2117444e7516SDavid Sterba 		return;
2118444e7516SDavid Sterba 
211924646481SLeon Romanovsky 	/*
212024646481SLeon Romanovsky 	 * See 14e46e04958df74 and e410e34fad913dd, feature bit updates are not
212124646481SLeon Romanovsky 	 * safe when called from some contexts (eg. balance)
212224646481SLeon Romanovsky 	 */
2123444e7516SDavid Sterba 	features = get_features(fs_info, set);
2124444e7516SDavid Sterba 	ASSERT(bit & supported_feature_masks[set]);
2125444e7516SDavid Sterba 
2126444e7516SDavid Sterba 	fs_devs = fs_info->fs_devices;
2127444e7516SDavid Sterba 	fsid_kobj = &fs_devs->fsid_kobj;
2128444e7516SDavid Sterba 
2129bf609206SDavid Sterba 	if (!fsid_kobj->state_initialized)
2130bf609206SDavid Sterba 		return;
2131bf609206SDavid Sterba 
2132444e7516SDavid Sterba 	/*
2133444e7516SDavid Sterba 	 * FIXME: this is too heavy to update just one value, ideally we'd like
2134444e7516SDavid Sterba 	 * to use sysfs_update_group but some refactoring is needed first.
2135444e7516SDavid Sterba 	 */
2136444e7516SDavid Sterba 	sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group);
2137444e7516SDavid Sterba 	ret = sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group);
2138444e7516SDavid Sterba }
2139444e7516SDavid Sterba 
2140f5c29bd9SLiu Bo int __init btrfs_init_sysfs(void)
214158176a96SJosef Bacik {
2142079b72bcSJeff Mahoney 	int ret;
21431bae3098SDavid Sterba 
2144e3fe4e71SGreg KH 	btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
2145e3fe4e71SGreg KH 	if (!btrfs_kset)
2146e3fe4e71SGreg KH 		return -ENOMEM;
2147079b72bcSJeff Mahoney 
21481bae3098SDavid Sterba 	init_feature_attrs();
21491bae3098SDavid Sterba 	ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
2150001a648dSFilipe Manana 	if (ret)
2151001a648dSFilipe Manana 		goto out2;
2152f902bd3aSMisono Tomohiro 	ret = sysfs_merge_group(&btrfs_kset->kobj,
2153f902bd3aSMisono Tomohiro 				&btrfs_static_feature_attr_group);
2154f902bd3aSMisono Tomohiro 	if (ret)
2155f902bd3aSMisono Tomohiro 		goto out_remove_group;
2156001a648dSFilipe Manana 
21576e369febSDavid Sterba #ifdef CONFIG_BTRFS_DEBUG
21586e369febSDavid Sterba 	ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group);
21596e369febSDavid Sterba 	if (ret)
21606e369febSDavid Sterba 		goto out2;
21616e369febSDavid Sterba #endif
21626e369febSDavid Sterba 
2163001a648dSFilipe Manana 	return 0;
2164f902bd3aSMisono Tomohiro 
2165f902bd3aSMisono Tomohiro out_remove_group:
2166f902bd3aSMisono Tomohiro 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
2167001a648dSFilipe Manana out2:
2168001a648dSFilipe Manana 	kset_unregister(btrfs_kset);
21691bae3098SDavid Sterba 
21701bae3098SDavid Sterba 	return ret;
217158176a96SJosef Bacik }
217258176a96SJosef Bacik 
2173e67c718bSDavid Sterba void __cold btrfs_exit_sysfs(void)
217458176a96SJosef Bacik {
2175f902bd3aSMisono Tomohiro 	sysfs_unmerge_group(&btrfs_kset->kobj,
2176f902bd3aSMisono Tomohiro 			    &btrfs_static_feature_attr_group);
2177079b72bcSJeff Mahoney 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
217871e8978eSDennis Zhou #ifdef CONFIG_BTRFS_DEBUG
217971e8978eSDennis Zhou 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_debug_feature_attr_group);
218071e8978eSDennis Zhou #endif
2181e3fe4e71SGreg KH 	kset_unregister(btrfs_kset);
218258176a96SJosef Bacik }
218355d47414SChris Mason 
2184