| 
									
										
										
										
											2007-06-12 09:07:21 -04:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 2007 Oracle.  All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public | 
					
						
							|  |  |  |  * License v2 as published by the Free Software Foundation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public | 
					
						
							|  |  |  |  * License along with this program; if not, write to the | 
					
						
							|  |  |  |  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 
					
						
							|  |  |  |  * Boston, MA 021110-1307, USA. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-08-29 15:47:34 -04:00
										 |  |  | #include <linux/sched.h>
 | 
					
						
							|  |  |  | #include <linux/slab.h>
 | 
					
						
							|  |  |  | #include <linux/spinlock.h>
 | 
					
						
							|  |  |  | #include <linux/completion.h>
 | 
					
						
							|  |  |  | #include <linux/buffer_head.h>
 | 
					
						
							|  |  |  | #include <linux/kobject.h>
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:00 -04:00
										 |  |  | #include <linux/bug.h>
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:05 -04:00
										 |  |  | #include <linux/genhd.h>
 | 
					
						
							| 
									
										
										
										
											2014-02-05 15:36:18 +01:00
										 |  |  | #include <linux/debugfs.h>
 | 
					
						
							| 
									
										
										
										
											2007-08-29 15:47:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-04 21:22:22 -04:00
										 |  |  | #include "ctree.h"
 | 
					
						
							|  |  |  | #include "disk-io.h"
 | 
					
						
							|  |  |  | #include "transaction.h"
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:57 -04:00
										 |  |  | #include "sysfs.h"
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:05 -04:00
										 |  |  | #include "volumes.h"
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:57 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:58 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | static u64 get_features(struct btrfs_fs_info *fs_info, | 
					
						
							|  |  |  | 			enum btrfs_feature_set set) | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:58 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | 	struct btrfs_super_block *disk_super = fs_info->super_copy; | 
					
						
							|  |  |  | 	if (set == FEAT_COMPAT) | 
					
						
							|  |  |  | 		return btrfs_super_compat_flags(disk_super); | 
					
						
							|  |  |  | 	else if (set == FEAT_COMPAT_RO) | 
					
						
							|  |  |  | 		return btrfs_super_compat_ro_flags(disk_super); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		return btrfs_super_incompat_flags(disk_super); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:58 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:01 -04:00
										 |  |  | static void set_features(struct btrfs_fs_info *fs_info, | 
					
						
							|  |  |  | 			 enum btrfs_feature_set set, u64 features) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_super_block *disk_super = fs_info->super_copy; | 
					
						
							|  |  |  | 	if (set == FEAT_COMPAT) | 
					
						
							|  |  |  | 		btrfs_set_super_compat_flags(disk_super, features); | 
					
						
							|  |  |  | 	else if (set == FEAT_COMPAT_RO) | 
					
						
							|  |  |  | 		btrfs_set_super_compat_ro_flags(disk_super, features); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		btrfs_set_super_incompat_flags(disk_super, features); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int can_modify_feature(struct btrfs_feature_attr *fa) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int val = 0; | 
					
						
							|  |  |  | 	u64 set, clear; | 
					
						
							|  |  |  | 	switch (fa->feature_set) { | 
					
						
							|  |  |  | 	case FEAT_COMPAT: | 
					
						
							|  |  |  | 		set = BTRFS_FEATURE_COMPAT_SAFE_SET; | 
					
						
							|  |  |  | 		clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FEAT_COMPAT_RO: | 
					
						
							|  |  |  | 		set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; | 
					
						
							|  |  |  | 		clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case FEAT_INCOMPAT: | 
					
						
							|  |  |  | 		set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; | 
					
						
							|  |  |  | 		clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2013-11-19 13:36:21 +01:00
										 |  |  | 		printk(KERN_WARNING "btrfs: sysfs: unknown feature set %d\n", | 
					
						
							|  |  |  | 				fa->feature_set); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:01 -04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (set & fa->feature_bit) | 
					
						
							|  |  |  | 		val |= 1; | 
					
						
							|  |  |  | 	if (clear & fa->feature_bit) | 
					
						
							|  |  |  | 		val |= 2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return val; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | static ssize_t btrfs_feature_attr_show(struct kobject *kobj, | 
					
						
							|  |  |  | 				       struct kobj_attribute *a, char *buf) | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:58 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | 	int val = 0; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:58 -04:00
										 |  |  | 	struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:01 -04:00
										 |  |  | 	struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | 	if (fs_info) { | 
					
						
							|  |  |  | 		u64 features = get_features(fs_info, fa->feature_set); | 
					
						
							|  |  |  | 		if (features & fa->feature_bit) | 
					
						
							|  |  |  | 			val = 1; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:01 -04:00
										 |  |  | 	} else | 
					
						
							|  |  |  | 		val = can_modify_feature(fa); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return snprintf(buf, PAGE_SIZE, "%d\n", val); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:58 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:01 -04:00
										 |  |  | static ssize_t btrfs_feature_attr_store(struct kobject *kobj, | 
					
						
							|  |  |  | 					struct kobj_attribute *a, | 
					
						
							|  |  |  | 					const char *buf, size_t count) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_fs_info *fs_info; | 
					
						
							|  |  |  | 	struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); | 
					
						
							|  |  |  | 	u64 features, set, clear; | 
					
						
							|  |  |  | 	unsigned long val; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fs_info = to_fs_info(kobj); | 
					
						
							|  |  |  | 	if (!fs_info) | 
					
						
							|  |  |  | 		return -EPERM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = kstrtoul(skip_spaces(buf), 0, &val); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (fa->feature_set == FEAT_COMPAT) { | 
					
						
							|  |  |  | 		set = BTRFS_FEATURE_COMPAT_SAFE_SET; | 
					
						
							|  |  |  | 		clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; | 
					
						
							|  |  |  | 	} else if (fa->feature_set == FEAT_COMPAT_RO) { | 
					
						
							|  |  |  | 		set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; | 
					
						
							|  |  |  | 		clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; | 
					
						
							|  |  |  | 		clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	features = get_features(fs_info, fa->feature_set); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Nothing to do */ | 
					
						
							|  |  |  | 	if ((val && (features & fa->feature_bit)) || | 
					
						
							|  |  |  | 	    (!val && !(features & fa->feature_bit))) | 
					
						
							|  |  |  | 		return count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((val && !(set & fa->feature_bit)) || | 
					
						
							|  |  |  | 	    (!val && !(clear & fa->feature_bit))) { | 
					
						
							|  |  |  | 		btrfs_info(fs_info, | 
					
						
							|  |  |  | 			"%sabling feature %s on mounted fs is not supported.", | 
					
						
							|  |  |  | 			val ? "En" : "Dis", fa->kobj_attr.attr.name); | 
					
						
							|  |  |  | 		return -EPERM; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	btrfs_info(fs_info, "%s %s feature flag", | 
					
						
							|  |  |  | 		   val ? "Setting" : "Clearing", fa->kobj_attr.attr.name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock(&fs_info->super_lock); | 
					
						
							|  |  |  | 	features = get_features(fs_info, fa->feature_set); | 
					
						
							|  |  |  | 	if (val) | 
					
						
							|  |  |  | 		features |= fa->feature_bit; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		features &= ~fa->feature_bit; | 
					
						
							|  |  |  | 	set_features(fs_info, fa->feature_set, features); | 
					
						
							|  |  |  | 	spin_unlock(&fs_info->super_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-12 14:22:21 +01:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * We don't want to do full transaction commit from inside sysfs | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	btrfs_set_pending(fs_info, COMMIT); | 
					
						
							|  |  |  | 	wake_up_process(fs_info->transaction_kthread); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:01 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return count; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | static umode_t btrfs_feature_visible(struct kobject *kobj, | 
					
						
							|  |  |  | 				     struct attribute *attr, int unused) | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:57 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | 	struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
					
						
							|  |  |  | 	umode_t mode = attr->mode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (fs_info) { | 
					
						
							|  |  |  | 		struct btrfs_feature_attr *fa; | 
					
						
							|  |  |  | 		u64 features; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		fa = attr_to_btrfs_feature_attr(attr); | 
					
						
							|  |  |  | 		features = get_features(fs_info, fa->feature_set); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:01 -04:00
										 |  |  | 		if (can_modify_feature(fa)) | 
					
						
							|  |  |  | 			mode |= S_IWUSR; | 
					
						
							|  |  |  | 		else if (!(features & fa->feature_bit)) | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | 			mode = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return mode; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:57 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF); | 
					
						
							|  |  |  | BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL); | 
					
						
							|  |  |  | BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS); | 
					
						
							|  |  |  | BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO); | 
					
						
							|  |  |  | BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA); | 
					
						
							|  |  |  | BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF); | 
					
						
							|  |  |  | BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56); | 
					
						
							|  |  |  | BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA); | 
					
						
							| 
									
										
										
										
											2014-01-21 18:56:09 +01:00
										 |  |  | BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:57 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | static struct attribute *btrfs_supported_feature_attrs[] = { | 
					
						
							|  |  |  | 	BTRFS_FEAT_ATTR_PTR(mixed_backref), | 
					
						
							|  |  |  | 	BTRFS_FEAT_ATTR_PTR(default_subvol), | 
					
						
							|  |  |  | 	BTRFS_FEAT_ATTR_PTR(mixed_groups), | 
					
						
							|  |  |  | 	BTRFS_FEAT_ATTR_PTR(compress_lzo), | 
					
						
							|  |  |  | 	BTRFS_FEAT_ATTR_PTR(big_metadata), | 
					
						
							|  |  |  | 	BTRFS_FEAT_ATTR_PTR(extended_iref), | 
					
						
							|  |  |  | 	BTRFS_FEAT_ATTR_PTR(raid56), | 
					
						
							|  |  |  | 	BTRFS_FEAT_ATTR_PTR(skinny_metadata), | 
					
						
							| 
									
										
										
										
											2014-01-21 18:56:09 +01:00
										 |  |  | 	BTRFS_FEAT_ATTR_PTR(no_holes), | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:57 -04:00
										 |  |  | 	NULL | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct attribute_group btrfs_feature_attr_group = { | 
					
						
							|  |  |  | 	.name = "features", | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | 	.is_visible = btrfs_feature_visible, | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:57 -04:00
										 |  |  | 	.attrs = btrfs_supported_feature_attrs, | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2007-08-29 15:47:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:04 -04:00
										 |  |  | static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u64 val; | 
					
						
							|  |  |  | 	if (lock) | 
					
						
							|  |  |  | 		spin_lock(lock); | 
					
						
							|  |  |  | 	val = *value_ptr; | 
					
						
							|  |  |  | 	if (lock) | 
					
						
							|  |  |  | 		spin_unlock(lock); | 
					
						
							|  |  |  | 	return snprintf(buf, PAGE_SIZE, "%llu\n", val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t global_rsv_size_show(struct kobject *kobj, | 
					
						
							|  |  |  | 				    struct kobj_attribute *ka, char *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); | 
					
						
							|  |  |  | 	struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; | 
					
						
							|  |  |  | 	return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-07-30 20:04:08 +08:00
										 |  |  | BTRFS_ATTR(global_rsv_size, global_rsv_size_show); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:04 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | static ssize_t global_rsv_reserved_show(struct kobject *kobj, | 
					
						
							|  |  |  | 					struct kobj_attribute *a, char *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); | 
					
						
							|  |  |  | 	struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; | 
					
						
							|  |  |  | 	return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-07-30 20:04:08 +08:00
										 |  |  | BTRFS_ATTR(global_rsv_reserved, global_rsv_reserved_show); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:04 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj)
 | 
					
						
							| 
									
										
										
										
											2014-05-27 12:59:57 -04:00
										 |  |  | #define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj)
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:04 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | static ssize_t raid_bytes_show(struct kobject *kobj, | 
					
						
							|  |  |  | 			       struct kobj_attribute *attr, char *buf); | 
					
						
							|  |  |  | BTRFS_RAID_ATTR(total_bytes, raid_bytes_show); | 
					
						
							|  |  |  | BTRFS_RAID_ATTR(used_bytes, raid_bytes_show); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t raid_bytes_show(struct kobject *kobj, | 
					
						
							|  |  |  | 			       struct kobj_attribute *attr, char *buf) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_space_info *sinfo = to_space_info(kobj->parent); | 
					
						
							|  |  |  | 	struct btrfs_block_group_cache *block_group; | 
					
						
							| 
									
										
										
										
											2014-05-27 12:59:57 -04:00
										 |  |  | 	int index = to_raid_kobj(kobj)->raid_type; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:04 -04:00
										 |  |  | 	u64 val = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	down_read(&sinfo->groups_sem); | 
					
						
							|  |  |  | 	list_for_each_entry(block_group, &sinfo->block_groups[index], list) { | 
					
						
							|  |  |  | 		if (&attr->attr == BTRFS_RAID_ATTR_PTR(total_bytes)) | 
					
						
							|  |  |  | 			val += block_group->key.offset; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			val += btrfs_block_group_used(&block_group->item); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	up_read(&sinfo->groups_sem); | 
					
						
							|  |  |  | 	return snprintf(buf, PAGE_SIZE, "%llu\n", val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct attribute *raid_attributes[] = { | 
					
						
							|  |  |  | 	BTRFS_RAID_ATTR_PTR(total_bytes), | 
					
						
							|  |  |  | 	BTRFS_RAID_ATTR_PTR(used_bytes), | 
					
						
							|  |  |  | 	NULL | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void release_raid_kobj(struct kobject *kobj) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-05-27 12:59:57 -04:00
										 |  |  | 	kfree(to_raid_kobj(kobj)); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:04 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct kobj_type btrfs_raid_ktype = { | 
					
						
							|  |  |  | 	.sysfs_ops = &kobj_sysfs_ops, | 
					
						
							|  |  |  | 	.release = release_raid_kobj, | 
					
						
							|  |  |  | 	.default_attrs = raid_attributes, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SPACE_INFO_ATTR(field)						\
 | 
					
						
							|  |  |  | static ssize_t btrfs_space_info_show_##field(struct kobject *kobj,	\ | 
					
						
							|  |  |  | 					     struct kobj_attribute *a,	\ | 
					
						
							|  |  |  | 					     char *buf)			\ | 
					
						
							|  |  |  | {									\ | 
					
						
							|  |  |  | 	struct btrfs_space_info *sinfo = to_space_info(kobj);		\ | 
					
						
							|  |  |  | 	return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf);	\ | 
					
						
							|  |  |  | }									\ | 
					
						
							| 
									
										
										
										
											2014-07-30 20:04:08 +08:00
										 |  |  | BTRFS_ATTR(field, btrfs_space_info_show_##field) | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:04 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | static ssize_t btrfs_space_info_show_total_bytes_pinned(struct kobject *kobj, | 
					
						
							|  |  |  | 						       struct kobj_attribute *a, | 
					
						
							|  |  |  | 						       char *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_space_info *sinfo = to_space_info(kobj); | 
					
						
							|  |  |  | 	s64 val = percpu_counter_sum(&sinfo->total_bytes_pinned); | 
					
						
							|  |  |  | 	return snprintf(buf, PAGE_SIZE, "%lld\n", val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SPACE_INFO_ATTR(flags); | 
					
						
							|  |  |  | SPACE_INFO_ATTR(total_bytes); | 
					
						
							|  |  |  | SPACE_INFO_ATTR(bytes_used); | 
					
						
							|  |  |  | SPACE_INFO_ATTR(bytes_pinned); | 
					
						
							|  |  |  | SPACE_INFO_ATTR(bytes_reserved); | 
					
						
							|  |  |  | SPACE_INFO_ATTR(bytes_may_use); | 
					
						
							|  |  |  | SPACE_INFO_ATTR(disk_used); | 
					
						
							|  |  |  | SPACE_INFO_ATTR(disk_total); | 
					
						
							| 
									
										
										
										
											2014-07-30 20:04:08 +08:00
										 |  |  | BTRFS_ATTR(total_bytes_pinned, btrfs_space_info_show_total_bytes_pinned); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:04 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | static struct attribute *space_info_attrs[] = { | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(flags), | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(total_bytes), | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(bytes_used), | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(bytes_pinned), | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(bytes_reserved), | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(bytes_may_use), | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(disk_used), | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(disk_total), | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(total_bytes_pinned), | 
					
						
							|  |  |  | 	NULL, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void space_info_release(struct kobject *kobj) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_space_info *sinfo = to_space_info(kobj); | 
					
						
							|  |  |  | 	percpu_counter_destroy(&sinfo->total_bytes_pinned); | 
					
						
							|  |  |  | 	kfree(sinfo); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct kobj_type space_info_ktype = { | 
					
						
							|  |  |  | 	.sysfs_ops = &kobj_sysfs_ops, | 
					
						
							|  |  |  | 	.release = space_info_release, | 
					
						
							|  |  |  | 	.default_attrs = space_info_attrs, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct attribute *allocation_attrs[] = { | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(global_rsv_reserved), | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(global_rsv_size), | 
					
						
							|  |  |  | 	NULL, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:06 -04:00
										 |  |  | static ssize_t btrfs_label_show(struct kobject *kobj, | 
					
						
							|  |  |  | 				struct kobj_attribute *a, char *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
					
						
							| 
									
										
										
										
											2014-07-01 17:00:07 +09:00
										 |  |  | 	char *label = fs_info->super_copy->label; | 
					
						
							|  |  |  | 	return snprintf(buf, PAGE_SIZE, label[0] ? "%s\n" : "%s", label); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:06 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t btrfs_label_store(struct kobject *kobj, | 
					
						
							|  |  |  | 				 struct kobj_attribute *a, | 
					
						
							|  |  |  | 				 const char *buf, size_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
					
						
							| 
									
										
										
										
											2014-07-01 17:00:07 +09:00
										 |  |  | 	size_t p_len; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:06 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-30 20:04:10 +08:00
										 |  |  | 	if (fs_info->sb->s_flags & MS_RDONLY) | 
					
						
							|  |  |  | 		return -EROFS; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-01 17:00:07 +09:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * p_len is the len until the first occurrence of either | 
					
						
							|  |  |  | 	 * '\n' or '\0' | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	p_len = strcspn(buf, "\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (p_len >= BTRFS_LABEL_SIZE) | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:06 -04:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-30 19:29:05 +02:00
										 |  |  | 	spin_lock(&fs_info->super_lock); | 
					
						
							| 
									
										
										
										
											2014-07-01 17:00:07 +09:00
										 |  |  | 	memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE); | 
					
						
							|  |  |  | 	memcpy(fs_info->super_copy->label, buf, p_len); | 
					
						
							| 
									
										
										
										
											2014-05-30 19:29:05 +02:00
										 |  |  | 	spin_unlock(&fs_info->super_lock); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:06 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-30 19:29:05 +02:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * We don't want to do full transaction commit from inside sysfs | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	btrfs_set_pending(fs_info, COMMIT); | 
					
						
							|  |  |  | 	wake_up_process(fs_info->transaction_kthread); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:06 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-30 19:29:05 +02:00
										 |  |  | 	return len; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:06 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-07-30 20:04:09 +08:00
										 |  |  | BTRFS_ATTR_RW(label, btrfs_label_show, btrfs_label_store); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:06 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-07 18:17:16 +02:00
										 |  |  | static ssize_t btrfs_nodesize_show(struct kobject *kobj, | 
					
						
							|  |  |  | 				struct kobj_attribute *a, char *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->nodesize); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-30 20:04:08 +08:00
										 |  |  | BTRFS_ATTR(nodesize, btrfs_nodesize_show); | 
					
						
							| 
									
										
										
										
											2014-05-07 18:17:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static ssize_t btrfs_sectorsize_show(struct kobject *kobj, | 
					
						
							|  |  |  | 				struct kobj_attribute *a, char *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->sectorsize); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-30 20:04:08 +08:00
										 |  |  | BTRFS_ATTR(sectorsize, btrfs_sectorsize_show); | 
					
						
							| 
									
										
										
										
											2014-05-07 18:17:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | static ssize_t btrfs_clone_alignment_show(struct kobject *kobj, | 
					
						
							|  |  |  | 				struct kobj_attribute *a, char *buf) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->sectorsize); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-30 20:04:08 +08:00
										 |  |  | BTRFS_ATTR(clone_alignment, btrfs_clone_alignment_show); | 
					
						
							| 
									
										
										
										
											2014-05-07 18:17:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:06 -04:00
										 |  |  | static struct attribute *btrfs_attrs[] = { | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(label), | 
					
						
							| 
									
										
										
										
											2014-05-07 18:17:16 +02:00
										 |  |  | 	BTRFS_ATTR_PTR(nodesize), | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(sectorsize), | 
					
						
							|  |  |  | 	BTRFS_ATTR_PTR(clone_alignment), | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:06 -04:00
										 |  |  | 	NULL, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | static void btrfs_release_super_kobj(struct kobject *kobj) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
					
						
							|  |  |  | 	complete(&fs_info->kobj_unregister); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct kobj_type btrfs_ktype = { | 
					
						
							|  |  |  | 	.sysfs_ops	= &kobj_sysfs_ops, | 
					
						
							|  |  |  | 	.release	= btrfs_release_super_kobj, | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:06 -04:00
										 |  |  | 	.default_attrs	= btrfs_attrs, | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (kobj->ktype != &btrfs_ktype) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	return container_of(kobj, struct btrfs_fs_info, super_kobj); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2007-08-29 15:47:34 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-21 10:37:16 -05:00
										 |  |  | #define NUM_FEATURE_BITS 64
 | 
					
						
							|  |  |  | static char btrfs_unknown_feature_names[3][NUM_FEATURE_BITS][13]; | 
					
						
							|  |  |  | static struct btrfs_feature_attr btrfs_feature_attrs[3][NUM_FEATURE_BITS]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u64 supported_feature_masks[3] = { | 
					
						
							|  |  |  | 	[FEAT_COMPAT]    = BTRFS_FEATURE_COMPAT_SUPP, | 
					
						
							|  |  |  | 	[FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP, | 
					
						
							|  |  |  | 	[FEAT_INCOMPAT]  = BTRFS_FEATURE_INCOMPAT_SUPP, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int set; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (set = 0; set < FEAT_MAX; set++) { | 
					
						
							|  |  |  | 		int i; | 
					
						
							|  |  |  | 		struct attribute *attrs[2]; | 
					
						
							|  |  |  | 		struct attribute_group agroup = { | 
					
						
							|  |  |  | 			.name = "features", | 
					
						
							|  |  |  | 			.attrs = attrs, | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 		u64 features = get_features(fs_info, set); | 
					
						
							|  |  |  | 		features &= ~supported_feature_masks[set]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!features) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		attrs[1] = NULL; | 
					
						
							|  |  |  | 		for (i = 0; i < NUM_FEATURE_BITS; i++) { | 
					
						
							|  |  |  | 			struct btrfs_feature_attr *fa; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!(features & (1ULL << i))) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			fa = &btrfs_feature_attrs[set][i]; | 
					
						
							|  |  |  | 			attrs[0] = &fa->kobj_attr.attr; | 
					
						
							|  |  |  | 			if (add) { | 
					
						
							|  |  |  | 				int ret; | 
					
						
							|  |  |  | 				ret = sysfs_merge_group(&fs_info->super_kobj, | 
					
						
							|  |  |  | 							&agroup); | 
					
						
							|  |  |  | 				if (ret) | 
					
						
							|  |  |  | 					return ret; | 
					
						
							|  |  |  | 			} else | 
					
						
							|  |  |  | 				sysfs_unmerge_group(&fs_info->super_kobj, | 
					
						
							|  |  |  | 						    &agroup); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:58 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	kobject_del(&fs_info->super_kobj); | 
					
						
							|  |  |  | 	kobject_put(&fs_info->super_kobj); | 
					
						
							|  |  |  | 	wait_for_completion(&fs_info->kobj_unregister); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-21 10:37:16 -05:00
										 |  |  | void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (fs_info->space_info_kobj) { | 
					
						
							|  |  |  | 		sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs); | 
					
						
							|  |  |  | 		kobject_del(fs_info->space_info_kobj); | 
					
						
							|  |  |  | 		kobject_put(fs_info->space_info_kobj); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	kobject_del(fs_info->device_dir_kobj); | 
					
						
							|  |  |  | 	kobject_put(fs_info->device_dir_kobj); | 
					
						
							|  |  |  | 	addrm_unknown_feature_attrs(fs_info, false); | 
					
						
							|  |  |  | 	sysfs_remove_group(&fs_info->super_kobj, &btrfs_feature_attr_group); | 
					
						
							|  |  |  | 	__btrfs_sysfs_remove_one(fs_info); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:00 -04:00
										 |  |  | const char * const btrfs_feature_set_names[3] = { | 
					
						
							|  |  |  | 	[FEAT_COMPAT]	 = "compat", | 
					
						
							|  |  |  | 	[FEAT_COMPAT_RO] = "compat_ro", | 
					
						
							|  |  |  | 	[FEAT_INCOMPAT]	 = "incompat", | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:02 -04:00
										 |  |  | char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */ | 
					
						
							|  |  |  | 	int len = 0; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	char *str; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	str = kmalloc(bufsize, GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!str) | 
					
						
							|  |  |  | 		return str; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { | 
					
						
							|  |  |  | 		const char *name; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!(flags & (1ULL << i))) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		name = btrfs_feature_attrs[set][i].kobj_attr.attr.name; | 
					
						
							|  |  |  | 		len += snprintf(str + len, bufsize - len, "%s%s", | 
					
						
							|  |  |  | 				len ? "," : "", name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return str; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:00 -04:00
										 |  |  | static void init_feature_attrs(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct btrfs_feature_attr *fa; | 
					
						
							|  |  |  | 	int set, i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names) != | 
					
						
							|  |  |  | 		     ARRAY_SIZE(btrfs_feature_attrs)); | 
					
						
							|  |  |  | 	BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) != | 
					
						
							|  |  |  | 		     ARRAY_SIZE(btrfs_feature_attrs[0])); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:02 -04:00
										 |  |  | 	memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs)); | 
					
						
							|  |  |  | 	memset(btrfs_unknown_feature_names, 0, | 
					
						
							|  |  |  | 	       sizeof(btrfs_unknown_feature_names)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:00 -04:00
										 |  |  | 	for (i = 0; btrfs_supported_feature_attrs[i]; i++) { | 
					
						
							|  |  |  | 		struct btrfs_feature_attr *sfa; | 
					
						
							|  |  |  | 		struct attribute *a = btrfs_supported_feature_attrs[i]; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:02 -04:00
										 |  |  | 		int bit; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:00 -04:00
										 |  |  | 		sfa = attr_to_btrfs_feature_attr(a); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:02 -04:00
										 |  |  | 		bit = ilog2(sfa->feature_bit); | 
					
						
							|  |  |  | 		fa = &btrfs_feature_attrs[sfa->feature_set][bit]; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:00 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (set = 0; set < FEAT_MAX; set++) { | 
					
						
							|  |  |  | 		for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { | 
					
						
							|  |  |  | 			char *name = btrfs_unknown_feature_names[set][i]; | 
					
						
							|  |  |  | 			fa = &btrfs_feature_attrs[set][i]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (fa->kobj_attr.attr.name) | 
					
						
							|  |  |  | 				continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			snprintf(name, 13, "%s:%u", | 
					
						
							|  |  |  | 				 btrfs_feature_set_names[set], i); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			fa->kobj_attr.attr.name = name; | 
					
						
							|  |  |  | 			fa->kobj_attr.attr.mode = S_IRUGO; | 
					
						
							|  |  |  | 			fa->feature_set = set; | 
					
						
							|  |  |  | 			fa->feature_bit = 1ULL << i; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-03 11:36:00 +08:00
										 |  |  | int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info, | 
					
						
							|  |  |  | 		struct btrfs_device *one_device) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct hd_struct *disk; | 
					
						
							|  |  |  | 	struct kobject *disk_kobj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!fs_info->device_dir_kobj) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-29 19:09:39 +08:00
										 |  |  | 	if (one_device && one_device->bdev) { | 
					
						
							| 
									
										
										
										
											2014-06-03 11:36:00 +08:00
										 |  |  | 		disk = one_device->bdev->bd_part; | 
					
						
							|  |  |  | 		disk_kobj = &part_to_dev(disk)->kobj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sysfs_remove_link(fs_info->device_dir_kobj, | 
					
						
							|  |  |  | 						disk_kobj->name); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-03 11:36:01 +08:00
										 |  |  | int btrfs_kobj_add_device(struct btrfs_fs_info *fs_info, | 
					
						
							|  |  |  | 		struct btrfs_device *one_device) | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:05 -04:00
										 |  |  | { | 
					
						
							|  |  |  | 	int error = 0; | 
					
						
							|  |  |  | 	struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; | 
					
						
							|  |  |  | 	struct btrfs_device *dev; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-03 11:36:01 +08:00
										 |  |  | 	if (!fs_info->device_dir_kobj) | 
					
						
							|  |  |  | 		fs_info->device_dir_kobj = kobject_create_and_add("devices", | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:05 -04:00
										 |  |  | 						&fs_info->super_kobj); | 
					
						
							| 
									
										
										
										
											2014-06-03 11:36:01 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:05 -04:00
										 |  |  | 	if (!fs_info->device_dir_kobj) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	list_for_each_entry(dev, &fs_devices->devices, dev_list) { | 
					
						
							| 
									
										
										
										
											2014-01-15 17:22:28 +08:00
										 |  |  | 		struct hd_struct *disk; | 
					
						
							|  |  |  | 		struct kobject *disk_kobj; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!dev->bdev) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-03 11:36:01 +08:00
										 |  |  | 		if (one_device && one_device != dev) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-15 17:22:28 +08:00
										 |  |  | 		disk = dev->bdev->bd_part; | 
					
						
							|  |  |  | 		disk_kobj = &part_to_dev(disk)->kobj; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:05 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		error = sysfs_create_link(fs_info->device_dir_kobj, | 
					
						
							|  |  |  | 					  disk_kobj, disk_kobj->name); | 
					
						
							|  |  |  | 		if (error) | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return error; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | /* /sys/fs/btrfs/ entry */ | 
					
						
							|  |  |  | static struct kset *btrfs_kset; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 15:36:18 +01:00
										 |  |  | /* /sys/kernel/debug/btrfs */ | 
					
						
							|  |  |  | static struct dentry *btrfs_debugfs_root_dentry; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Debugging tunables and exported data */ | 
					
						
							|  |  |  | u64 btrfs_debugfs_test; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:58 -04:00
										 |  |  | int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	init_completion(&fs_info->kobj_unregister); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | 	fs_info->super_kobj.kset = btrfs_kset; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:58 -04:00
										 |  |  | 	error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL, | 
					
						
							|  |  |  | 				     "%pU", fs_info->fsid); | 
					
						
							| 
									
										
										
										
											2013-11-21 10:37:16 -05:00
										 |  |  | 	if (error) | 
					
						
							|  |  |  | 		return error; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:59 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	error = sysfs_create_group(&fs_info->super_kobj, | 
					
						
							|  |  |  | 				   &btrfs_feature_attr_group); | 
					
						
							| 
									
										
										
										
											2013-11-21 10:37:16 -05:00
										 |  |  | 	if (error) { | 
					
						
							|  |  |  | 		__btrfs_sysfs_remove_one(fs_info); | 
					
						
							|  |  |  | 		return error; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-21 10:37:16 -05:00
										 |  |  | 	error = addrm_unknown_feature_attrs(fs_info, true); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:00 -04:00
										 |  |  | 	if (error) | 
					
						
							|  |  |  | 		goto failure; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-03 11:36:01 +08:00
										 |  |  | 	error = btrfs_kobj_add_device(fs_info, NULL); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:05 -04:00
										 |  |  | 	if (error) | 
					
						
							|  |  |  | 		goto failure; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:04 -04:00
										 |  |  | 	fs_info->space_info_kobj = kobject_create_and_add("allocation", | 
					
						
							|  |  |  | 						  &fs_info->super_kobj); | 
					
						
							|  |  |  | 	if (!fs_info->space_info_kobj) { | 
					
						
							|  |  |  | 		error = -ENOMEM; | 
					
						
							|  |  |  | 		goto failure; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs); | 
					
						
							|  |  |  | 	if (error) | 
					
						
							|  |  |  | 		goto failure; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:00 -04:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | failure: | 
					
						
							|  |  |  | 	btrfs_sysfs_remove_one(fs_info); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:58 -04:00
										 |  |  | 	return error; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 15:36:18 +01:00
										 |  |  | static int btrfs_init_debugfs(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef CONFIG_DEBUG_FS
 | 
					
						
							|  |  |  | 	btrfs_debugfs_root_dentry = debugfs_create_dir("btrfs", NULL); | 
					
						
							|  |  |  | 	if (!btrfs_debugfs_root_dentry) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	debugfs_create_u64("test", S_IRUGO | S_IWUGO, btrfs_debugfs_root_dentry, | 
					
						
							|  |  |  | 			&btrfs_debugfs_test); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-05 16:43:31 -04:00
										 |  |  | int btrfs_init_sysfs(void) | 
					
						
							| 
									
										
										
										
											2007-08-29 15:47:34 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:57 -04:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2014-02-05 15:36:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-20 14:14:16 -05:00
										 |  |  | 	btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); | 
					
						
							|  |  |  | 	if (!btrfs_kset) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:57 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 15:36:18 +01:00
										 |  |  | 	ret = btrfs_init_debugfs(); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							| 
									
										
										
										
											2013-11-01 13:07:00 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 15:36:18 +01:00
										 |  |  | 	init_feature_attrs(); | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:57 -04:00
										 |  |  | 	ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-05 15:36:18 +01:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2007-08-29 15:47:34 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-05 16:43:31 -04:00
										 |  |  | void btrfs_exit_sysfs(void) | 
					
						
							| 
									
										
										
										
											2007-08-29 15:47:34 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-01 13:06:57 -04:00
										 |  |  | 	sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); | 
					
						
							| 
									
										
										
										
											2008-02-20 14:14:16 -05:00
										 |  |  | 	kset_unregister(btrfs_kset); | 
					
						
							| 
									
										
										
										
											2014-02-05 15:36:18 +01:00
										 |  |  | 	debugfs_remove_recursive(btrfs_debugfs_root_dentry); | 
					
						
							| 
									
										
										
										
											2007-08-29 15:47:34 -04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2008-02-20 16:02:51 -05:00
										 |  |  | 
 |