| Chris Mason | 6cbd557 | 2007-06-12 09:07:21 -0400 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2007 Oracle.  All rights reserved. | 
|  | 3 | * | 
|  | 4 | * This program is free software; you can redistribute it and/or | 
|  | 5 | * modify it under the terms of the GNU General Public | 
|  | 6 | * License v2 as published by the Free Software Foundation. | 
|  | 7 | * | 
|  | 8 | * This program is distributed in the hope that it will be useful, | 
|  | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 11 | * General Public License for more details. | 
|  | 12 | * | 
|  | 13 | * You should have received a copy of the GNU General Public | 
|  | 14 | * License along with this program; if not, write to the | 
|  | 15 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 
|  | 16 | * Boston, MA 021110-1307, USA. | 
|  | 17 | */ | 
|  | 18 |  | 
| Josef Bacik | 58176a9 | 2007-08-29 15:47:34 -0400 | [diff] [blame] | 19 | #include <linux/sched.h> | 
|  | 20 | #include <linux/slab.h> | 
|  | 21 | #include <linux/spinlock.h> | 
|  | 22 | #include <linux/completion.h> | 
|  | 23 | #include <linux/buffer_head.h> | 
| Josef Bacik | 58176a9 | 2007-08-29 15:47:34 -0400 | [diff] [blame] | 24 | #include <linux/kobject.h> | 
| Jeff Mahoney | 79da4fa | 2013-11-01 13:07:00 -0400 | [diff] [blame] | 25 | #include <linux/bug.h> | 
| Jeff Mahoney | 29e5be2 | 2013-11-01 13:07:05 -0400 | [diff] [blame] | 26 | #include <linux/genhd.h> | 
| David Sterba | 1bae309 | 2014-02-05 15:36:18 +0100 | [diff] [blame] | 27 | #include <linux/debugfs.h> | 
| Josef Bacik | 58176a9 | 2007-08-29 15:47:34 -0400 | [diff] [blame] | 28 |  | 
| Chris Mason | bae45de | 2007-04-04 21:22:22 -0400 | [diff] [blame] | 29 | #include "ctree.h" | 
|  | 30 | #include "disk-io.h" | 
|  | 31 | #include "transaction.h" | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 32 | #include "sysfs.h" | 
| Jeff Mahoney | 29e5be2 | 2013-11-01 13:07:05 -0400 | [diff] [blame] | 33 | #include "volumes.h" | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 34 |  | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 35 | static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj); | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 36 | static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj); | 
| Jeff Mahoney | 5ac1d20 | 2013-11-01 13:06:58 -0400 | [diff] [blame] | 37 |  | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 38 | static u64 get_features(struct btrfs_fs_info *fs_info, | 
|  | 39 | enum btrfs_feature_set set) | 
| Jeff Mahoney | 5ac1d20 | 2013-11-01 13:06:58 -0400 | [diff] [blame] | 40 | { | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 41 | struct btrfs_super_block *disk_super = fs_info->super_copy; | 
|  | 42 | if (set == FEAT_COMPAT) | 
|  | 43 | return btrfs_super_compat_flags(disk_super); | 
|  | 44 | else if (set == FEAT_COMPAT_RO) | 
|  | 45 | return btrfs_super_compat_ro_flags(disk_super); | 
|  | 46 | else | 
|  | 47 | return btrfs_super_incompat_flags(disk_super); | 
| Jeff Mahoney | 5ac1d20 | 2013-11-01 13:06:58 -0400 | [diff] [blame] | 48 | } | 
|  | 49 |  | 
| Jeff Mahoney | ba63194 | 2013-11-01 13:07:01 -0400 | [diff] [blame] | 50 | static void set_features(struct btrfs_fs_info *fs_info, | 
|  | 51 | enum btrfs_feature_set set, u64 features) | 
|  | 52 | { | 
|  | 53 | struct btrfs_super_block *disk_super = fs_info->super_copy; | 
|  | 54 | if (set == FEAT_COMPAT) | 
|  | 55 | btrfs_set_super_compat_flags(disk_super, features); | 
|  | 56 | else if (set == FEAT_COMPAT_RO) | 
|  | 57 | btrfs_set_super_compat_ro_flags(disk_super, features); | 
|  | 58 | else | 
|  | 59 | btrfs_set_super_incompat_flags(disk_super, features); | 
|  | 60 | } | 
|  | 61 |  | 
|  | 62 | static int can_modify_feature(struct btrfs_feature_attr *fa) | 
|  | 63 | { | 
|  | 64 | int val = 0; | 
|  | 65 | u64 set, clear; | 
|  | 66 | switch (fa->feature_set) { | 
|  | 67 | case FEAT_COMPAT: | 
|  | 68 | set = BTRFS_FEATURE_COMPAT_SAFE_SET; | 
|  | 69 | clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; | 
|  | 70 | break; | 
|  | 71 | case FEAT_COMPAT_RO: | 
|  | 72 | set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; | 
|  | 73 | clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; | 
|  | 74 | break; | 
|  | 75 | case FEAT_INCOMPAT: | 
|  | 76 | set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; | 
|  | 77 | clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; | 
|  | 78 | break; | 
|  | 79 | default: | 
| David Sterba | cc37bb0 | 2013-11-19 13:36:21 +0100 | [diff] [blame] | 80 | printk(KERN_WARNING "btrfs: sysfs: unknown feature set %d\n", | 
|  | 81 | fa->feature_set); | 
|  | 82 | return 0; | 
| Jeff Mahoney | ba63194 | 2013-11-01 13:07:01 -0400 | [diff] [blame] | 83 | } | 
|  | 84 |  | 
|  | 85 | if (set & fa->feature_bit) | 
|  | 86 | val |= 1; | 
|  | 87 | if (clear & fa->feature_bit) | 
|  | 88 | val |= 2; | 
|  | 89 |  | 
|  | 90 | return val; | 
|  | 91 | } | 
|  | 92 |  | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 93 | static ssize_t btrfs_feature_attr_show(struct kobject *kobj, | 
|  | 94 | struct kobj_attribute *a, char *buf) | 
|  | 95 | { | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 96 | int val = 0; | 
|  | 97 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
| Jeff Mahoney | ba63194 | 2013-11-01 13:07:01 -0400 | [diff] [blame] | 98 | struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 99 | if (fs_info) { | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 100 | u64 features = get_features(fs_info, fa->feature_set); | 
|  | 101 | if (features & fa->feature_bit) | 
|  | 102 | val = 1; | 
| Jeff Mahoney | ba63194 | 2013-11-01 13:07:01 -0400 | [diff] [blame] | 103 | } else | 
|  | 104 | val = can_modify_feature(fa); | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 105 |  | 
|  | 106 | return snprintf(buf, PAGE_SIZE, "%d\n", val); | 
|  | 107 | } | 
|  | 108 |  | 
| Jeff Mahoney | ba63194 | 2013-11-01 13:07:01 -0400 | [diff] [blame] | 109 | static ssize_t btrfs_feature_attr_store(struct kobject *kobj, | 
|  | 110 | struct kobj_attribute *a, | 
|  | 111 | const char *buf, size_t count) | 
|  | 112 | { | 
|  | 113 | struct btrfs_fs_info *fs_info; | 
|  | 114 | struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); | 
| Jeff Mahoney | ba63194 | 2013-11-01 13:07:01 -0400 | [diff] [blame] | 115 | u64 features, set, clear; | 
|  | 116 | unsigned long val; | 
|  | 117 | int ret; | 
|  | 118 |  | 
|  | 119 | fs_info = to_fs_info(kobj); | 
|  | 120 | if (!fs_info) | 
|  | 121 | return -EPERM; | 
|  | 122 |  | 
|  | 123 | ret = kstrtoul(skip_spaces(buf), 0, &val); | 
|  | 124 | if (ret) | 
|  | 125 | return ret; | 
|  | 126 |  | 
|  | 127 | if (fa->feature_set == FEAT_COMPAT) { | 
|  | 128 | set = BTRFS_FEATURE_COMPAT_SAFE_SET; | 
|  | 129 | clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; | 
|  | 130 | } else if (fa->feature_set == FEAT_COMPAT_RO) { | 
|  | 131 | set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; | 
|  | 132 | clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; | 
|  | 133 | } else { | 
|  | 134 | set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; | 
|  | 135 | clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; | 
|  | 136 | } | 
|  | 137 |  | 
|  | 138 | features = get_features(fs_info, fa->feature_set); | 
|  | 139 |  | 
|  | 140 | /* Nothing to do */ | 
|  | 141 | if ((val && (features & fa->feature_bit)) || | 
|  | 142 | (!val && !(features & fa->feature_bit))) | 
|  | 143 | return count; | 
|  | 144 |  | 
|  | 145 | if ((val && !(set & fa->feature_bit)) || | 
|  | 146 | (!val && !(clear & fa->feature_bit))) { | 
|  | 147 | btrfs_info(fs_info, | 
|  | 148 | "%sabling feature %s on mounted fs is not supported.", | 
|  | 149 | val ? "En" : "Dis", fa->kobj_attr.attr.name); | 
|  | 150 | return -EPERM; | 
|  | 151 | } | 
|  | 152 |  | 
|  | 153 | btrfs_info(fs_info, "%s %s feature flag", | 
|  | 154 | val ? "Setting" : "Clearing", fa->kobj_attr.attr.name); | 
|  | 155 |  | 
| Jeff Mahoney | ba63194 | 2013-11-01 13:07:01 -0400 | [diff] [blame] | 156 | spin_lock(&fs_info->super_lock); | 
|  | 157 | features = get_features(fs_info, fa->feature_set); | 
|  | 158 | if (val) | 
|  | 159 | features |= fa->feature_bit; | 
|  | 160 | else | 
|  | 161 | features &= ~fa->feature_bit; | 
|  | 162 | set_features(fs_info, fa->feature_set, features); | 
|  | 163 | spin_unlock(&fs_info->super_lock); | 
|  | 164 |  | 
| David Sterba | 0eae274 | 2014-11-12 14:22:21 +0100 | [diff] [blame] | 165 | /* | 
|  | 166 | * We don't want to do full transaction commit from inside sysfs | 
|  | 167 | */ | 
|  | 168 | btrfs_set_pending(fs_info, COMMIT); | 
|  | 169 | wake_up_process(fs_info->transaction_kthread); | 
| Jeff Mahoney | ba63194 | 2013-11-01 13:07:01 -0400 | [diff] [blame] | 170 |  | 
|  | 171 | return count; | 
|  | 172 | } | 
|  | 173 |  | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 174 | static umode_t btrfs_feature_visible(struct kobject *kobj, | 
|  | 175 | struct attribute *attr, int unused) | 
|  | 176 | { | 
|  | 177 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
|  | 178 | umode_t mode = attr->mode; | 
|  | 179 |  | 
|  | 180 | if (fs_info) { | 
|  | 181 | struct btrfs_feature_attr *fa; | 
|  | 182 | u64 features; | 
|  | 183 |  | 
|  | 184 | fa = attr_to_btrfs_feature_attr(attr); | 
|  | 185 | features = get_features(fs_info, fa->feature_set); | 
|  | 186 |  | 
| Jeff Mahoney | ba63194 | 2013-11-01 13:07:01 -0400 | [diff] [blame] | 187 | if (can_modify_feature(fa)) | 
|  | 188 | mode |= S_IWUSR; | 
|  | 189 | else if (!(features & fa->feature_bit)) | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 190 | mode = 0; | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | return mode; | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 194 | } | 
|  | 195 |  | 
|  | 196 | BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF); | 
|  | 197 | BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL); | 
|  | 198 | BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS); | 
|  | 199 | BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO); | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 200 | BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA); | 
|  | 201 | BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF); | 
|  | 202 | BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56); | 
|  | 203 | BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA); | 
| David Sterba | c736c09 | 2014-01-21 18:56:09 +0100 | [diff] [blame] | 204 | BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES); | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 205 |  | 
|  | 206 | static struct attribute *btrfs_supported_feature_attrs[] = { | 
|  | 207 | BTRFS_FEAT_ATTR_PTR(mixed_backref), | 
|  | 208 | BTRFS_FEAT_ATTR_PTR(default_subvol), | 
|  | 209 | BTRFS_FEAT_ATTR_PTR(mixed_groups), | 
|  | 210 | BTRFS_FEAT_ATTR_PTR(compress_lzo), | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 211 | BTRFS_FEAT_ATTR_PTR(big_metadata), | 
|  | 212 | BTRFS_FEAT_ATTR_PTR(extended_iref), | 
|  | 213 | BTRFS_FEAT_ATTR_PTR(raid56), | 
|  | 214 | BTRFS_FEAT_ATTR_PTR(skinny_metadata), | 
| David Sterba | c736c09 | 2014-01-21 18:56:09 +0100 | [diff] [blame] | 215 | BTRFS_FEAT_ATTR_PTR(no_holes), | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 216 | NULL | 
|  | 217 | }; | 
|  | 218 |  | 
|  | 219 | static const struct attribute_group btrfs_feature_attr_group = { | 
|  | 220 | .name = "features", | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 221 | .is_visible = btrfs_feature_visible, | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 222 | .attrs = btrfs_supported_feature_attrs, | 
|  | 223 | }; | 
| Josef Bacik | 58176a9 | 2007-08-29 15:47:34 -0400 | [diff] [blame] | 224 |  | 
| Jeff Mahoney | 6ab0a20 | 2013-11-01 13:07:04 -0400 | [diff] [blame] | 225 | static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf) | 
|  | 226 | { | 
|  | 227 | u64 val; | 
|  | 228 | if (lock) | 
|  | 229 | spin_lock(lock); | 
|  | 230 | val = *value_ptr; | 
|  | 231 | if (lock) | 
|  | 232 | spin_unlock(lock); | 
|  | 233 | return snprintf(buf, PAGE_SIZE, "%llu\n", val); | 
|  | 234 | } | 
|  | 235 |  | 
|  | 236 | static ssize_t global_rsv_size_show(struct kobject *kobj, | 
|  | 237 | struct kobj_attribute *ka, char *buf) | 
|  | 238 | { | 
|  | 239 | struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); | 
|  | 240 | struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; | 
|  | 241 | return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf); | 
|  | 242 | } | 
| Anand Jain | 98b3d38 | 2014-07-30 20:04:08 +0800 | [diff] [blame] | 243 | BTRFS_ATTR(global_rsv_size, global_rsv_size_show); | 
| Jeff Mahoney | 6ab0a20 | 2013-11-01 13:07:04 -0400 | [diff] [blame] | 244 |  | 
|  | 245 | static ssize_t global_rsv_reserved_show(struct kobject *kobj, | 
|  | 246 | struct kobj_attribute *a, char *buf) | 
|  | 247 | { | 
|  | 248 | struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); | 
|  | 249 | struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; | 
|  | 250 | return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf); | 
|  | 251 | } | 
| Anand Jain | 98b3d38 | 2014-07-30 20:04:08 +0800 | [diff] [blame] | 252 | BTRFS_ATTR(global_rsv_reserved, global_rsv_reserved_show); | 
| Jeff Mahoney | 6ab0a20 | 2013-11-01 13:07:04 -0400 | [diff] [blame] | 253 |  | 
|  | 254 | #define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj) | 
| Jeff Mahoney | c189544 | 2014-05-27 12:59:57 -0400 | [diff] [blame] | 255 | #define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj) | 
| Jeff Mahoney | 6ab0a20 | 2013-11-01 13:07:04 -0400 | [diff] [blame] | 256 |  | 
|  | 257 | static ssize_t raid_bytes_show(struct kobject *kobj, | 
|  | 258 | struct kobj_attribute *attr, char *buf); | 
|  | 259 | BTRFS_RAID_ATTR(total_bytes, raid_bytes_show); | 
|  | 260 | BTRFS_RAID_ATTR(used_bytes, raid_bytes_show); | 
|  | 261 |  | 
|  | 262 | static ssize_t raid_bytes_show(struct kobject *kobj, | 
|  | 263 | struct kobj_attribute *attr, char *buf) | 
|  | 264 |  | 
|  | 265 | { | 
|  | 266 | struct btrfs_space_info *sinfo = to_space_info(kobj->parent); | 
|  | 267 | struct btrfs_block_group_cache *block_group; | 
| Jeff Mahoney | c189544 | 2014-05-27 12:59:57 -0400 | [diff] [blame] | 268 | int index = to_raid_kobj(kobj)->raid_type; | 
| Jeff Mahoney | 6ab0a20 | 2013-11-01 13:07:04 -0400 | [diff] [blame] | 269 | u64 val = 0; | 
|  | 270 |  | 
|  | 271 | down_read(&sinfo->groups_sem); | 
|  | 272 | list_for_each_entry(block_group, &sinfo->block_groups[index], list) { | 
|  | 273 | if (&attr->attr == BTRFS_RAID_ATTR_PTR(total_bytes)) | 
|  | 274 | val += block_group->key.offset; | 
|  | 275 | else | 
|  | 276 | val += btrfs_block_group_used(&block_group->item); | 
|  | 277 | } | 
|  | 278 | up_read(&sinfo->groups_sem); | 
|  | 279 | return snprintf(buf, PAGE_SIZE, "%llu\n", val); | 
|  | 280 | } | 
|  | 281 |  | 
|  | 282 | static struct attribute *raid_attributes[] = { | 
|  | 283 | BTRFS_RAID_ATTR_PTR(total_bytes), | 
|  | 284 | BTRFS_RAID_ATTR_PTR(used_bytes), | 
|  | 285 | NULL | 
|  | 286 | }; | 
|  | 287 |  | 
|  | 288 | static void release_raid_kobj(struct kobject *kobj) | 
|  | 289 | { | 
| Jeff Mahoney | c189544 | 2014-05-27 12:59:57 -0400 | [diff] [blame] | 290 | kfree(to_raid_kobj(kobj)); | 
| Jeff Mahoney | 6ab0a20 | 2013-11-01 13:07:04 -0400 | [diff] [blame] | 291 | } | 
|  | 292 |  | 
|  | 293 | struct kobj_type btrfs_raid_ktype = { | 
|  | 294 | .sysfs_ops = &kobj_sysfs_ops, | 
|  | 295 | .release = release_raid_kobj, | 
|  | 296 | .default_attrs = raid_attributes, | 
|  | 297 | }; | 
|  | 298 |  | 
|  | 299 | #define SPACE_INFO_ATTR(field)						\ | 
|  | 300 | static ssize_t btrfs_space_info_show_##field(struct kobject *kobj,	\ | 
|  | 301 | struct kobj_attribute *a,	\ | 
|  | 302 | char *buf)			\ | 
|  | 303 | {									\ | 
|  | 304 | struct btrfs_space_info *sinfo = to_space_info(kobj);		\ | 
|  | 305 | return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf);	\ | 
|  | 306 | }									\ | 
| Anand Jain | 98b3d38 | 2014-07-30 20:04:08 +0800 | [diff] [blame] | 307 | BTRFS_ATTR(field, btrfs_space_info_show_##field) | 
| Jeff Mahoney | 6ab0a20 | 2013-11-01 13:07:04 -0400 | [diff] [blame] | 308 |  | 
|  | 309 | static ssize_t btrfs_space_info_show_total_bytes_pinned(struct kobject *kobj, | 
|  | 310 | struct kobj_attribute *a, | 
|  | 311 | char *buf) | 
|  | 312 | { | 
|  | 313 | struct btrfs_space_info *sinfo = to_space_info(kobj); | 
|  | 314 | s64 val = percpu_counter_sum(&sinfo->total_bytes_pinned); | 
|  | 315 | return snprintf(buf, PAGE_SIZE, "%lld\n", val); | 
|  | 316 | } | 
|  | 317 |  | 
|  | 318 | SPACE_INFO_ATTR(flags); | 
|  | 319 | SPACE_INFO_ATTR(total_bytes); | 
|  | 320 | SPACE_INFO_ATTR(bytes_used); | 
|  | 321 | SPACE_INFO_ATTR(bytes_pinned); | 
|  | 322 | SPACE_INFO_ATTR(bytes_reserved); | 
|  | 323 | SPACE_INFO_ATTR(bytes_may_use); | 
|  | 324 | SPACE_INFO_ATTR(disk_used); | 
|  | 325 | SPACE_INFO_ATTR(disk_total); | 
| Anand Jain | 98b3d38 | 2014-07-30 20:04:08 +0800 | [diff] [blame] | 326 | BTRFS_ATTR(total_bytes_pinned, btrfs_space_info_show_total_bytes_pinned); | 
| Jeff Mahoney | 6ab0a20 | 2013-11-01 13:07:04 -0400 | [diff] [blame] | 327 |  | 
|  | 328 | static struct attribute *space_info_attrs[] = { | 
|  | 329 | BTRFS_ATTR_PTR(flags), | 
|  | 330 | BTRFS_ATTR_PTR(total_bytes), | 
|  | 331 | BTRFS_ATTR_PTR(bytes_used), | 
|  | 332 | BTRFS_ATTR_PTR(bytes_pinned), | 
|  | 333 | BTRFS_ATTR_PTR(bytes_reserved), | 
|  | 334 | BTRFS_ATTR_PTR(bytes_may_use), | 
|  | 335 | BTRFS_ATTR_PTR(disk_used), | 
|  | 336 | BTRFS_ATTR_PTR(disk_total), | 
|  | 337 | BTRFS_ATTR_PTR(total_bytes_pinned), | 
|  | 338 | NULL, | 
|  | 339 | }; | 
|  | 340 |  | 
|  | 341 | static void space_info_release(struct kobject *kobj) | 
|  | 342 | { | 
|  | 343 | struct btrfs_space_info *sinfo = to_space_info(kobj); | 
|  | 344 | percpu_counter_destroy(&sinfo->total_bytes_pinned); | 
|  | 345 | kfree(sinfo); | 
|  | 346 | } | 
|  | 347 |  | 
|  | 348 | struct kobj_type space_info_ktype = { | 
|  | 349 | .sysfs_ops = &kobj_sysfs_ops, | 
|  | 350 | .release = space_info_release, | 
|  | 351 | .default_attrs = space_info_attrs, | 
|  | 352 | }; | 
|  | 353 |  | 
|  | 354 | static const struct attribute *allocation_attrs[] = { | 
|  | 355 | BTRFS_ATTR_PTR(global_rsv_reserved), | 
|  | 356 | BTRFS_ATTR_PTR(global_rsv_size), | 
|  | 357 | NULL, | 
|  | 358 | }; | 
|  | 359 |  | 
| Jeff Mahoney | f8ba9c1 | 2013-11-01 13:07:06 -0400 | [diff] [blame] | 360 | static ssize_t btrfs_label_show(struct kobject *kobj, | 
|  | 361 | struct kobj_attribute *a, char *buf) | 
|  | 362 | { | 
|  | 363 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
| Satoru Takeuchi | 48fcc3f | 2014-07-01 17:00:07 +0900 | [diff] [blame] | 364 | char *label = fs_info->super_copy->label; | 
|  | 365 | return snprintf(buf, PAGE_SIZE, label[0] ? "%s\n" : "%s", label); | 
| Jeff Mahoney | f8ba9c1 | 2013-11-01 13:07:06 -0400 | [diff] [blame] | 366 | } | 
|  | 367 |  | 
|  | 368 | static ssize_t btrfs_label_store(struct kobject *kobj, | 
|  | 369 | struct kobj_attribute *a, | 
|  | 370 | const char *buf, size_t len) | 
|  | 371 | { | 
|  | 372 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
| Satoru Takeuchi | 48fcc3f | 2014-07-01 17:00:07 +0900 | [diff] [blame] | 373 | size_t p_len; | 
| Jeff Mahoney | f8ba9c1 | 2013-11-01 13:07:06 -0400 | [diff] [blame] | 374 |  | 
| Anand Jain | 79aec2b | 2014-07-30 20:04:10 +0800 | [diff] [blame] | 375 | if (fs_info->sb->s_flags & MS_RDONLY) | 
|  | 376 | return -EROFS; | 
|  | 377 |  | 
| Satoru Takeuchi | 48fcc3f | 2014-07-01 17:00:07 +0900 | [diff] [blame] | 378 | /* | 
|  | 379 | * p_len is the len until the first occurrence of either | 
|  | 380 | * '\n' or '\0' | 
|  | 381 | */ | 
|  | 382 | p_len = strcspn(buf, "\n"); | 
|  | 383 |  | 
|  | 384 | if (p_len >= BTRFS_LABEL_SIZE) | 
| Jeff Mahoney | f8ba9c1 | 2013-11-01 13:07:06 -0400 | [diff] [blame] | 385 | return -EINVAL; | 
| Jeff Mahoney | f8ba9c1 | 2013-11-01 13:07:06 -0400 | [diff] [blame] | 386 |  | 
| David Sterba | a6f69dc | 2014-05-30 19:29:05 +0200 | [diff] [blame] | 387 | spin_lock(&fs_info->super_lock); | 
| Satoru Takeuchi | 48fcc3f | 2014-07-01 17:00:07 +0900 | [diff] [blame] | 388 | memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE); | 
|  | 389 | memcpy(fs_info->super_copy->label, buf, p_len); | 
| David Sterba | a6f69dc | 2014-05-30 19:29:05 +0200 | [diff] [blame] | 390 | spin_unlock(&fs_info->super_lock); | 
| Jeff Mahoney | f8ba9c1 | 2013-11-01 13:07:06 -0400 | [diff] [blame] | 391 |  | 
| David Sterba | a6f69dc | 2014-05-30 19:29:05 +0200 | [diff] [blame] | 392 | /* | 
|  | 393 | * We don't want to do full transaction commit from inside sysfs | 
|  | 394 | */ | 
|  | 395 | btrfs_set_pending(fs_info, COMMIT); | 
|  | 396 | wake_up_process(fs_info->transaction_kthread); | 
| Jeff Mahoney | f8ba9c1 | 2013-11-01 13:07:06 -0400 | [diff] [blame] | 397 |  | 
| David Sterba | a6f69dc | 2014-05-30 19:29:05 +0200 | [diff] [blame] | 398 | return len; | 
| Jeff Mahoney | f8ba9c1 | 2013-11-01 13:07:06 -0400 | [diff] [blame] | 399 | } | 
| Anand Jain | 20ee082 | 2014-07-30 20:04:09 +0800 | [diff] [blame] | 400 | BTRFS_ATTR_RW(label, btrfs_label_show, btrfs_label_store); | 
| Jeff Mahoney | f8ba9c1 | 2013-11-01 13:07:06 -0400 | [diff] [blame] | 401 |  | 
| David Sterba | df93589 | 2014-05-07 18:17:16 +0200 | [diff] [blame] | 402 | static ssize_t btrfs_nodesize_show(struct kobject *kobj, | 
|  | 403 | struct kobj_attribute *a, char *buf) | 
|  | 404 | { | 
|  | 405 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
|  | 406 |  | 
|  | 407 | return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->nodesize); | 
|  | 408 | } | 
|  | 409 |  | 
| Anand Jain | 98b3d38 | 2014-07-30 20:04:08 +0800 | [diff] [blame] | 410 | BTRFS_ATTR(nodesize, btrfs_nodesize_show); | 
| David Sterba | df93589 | 2014-05-07 18:17:16 +0200 | [diff] [blame] | 411 |  | 
|  | 412 | static ssize_t btrfs_sectorsize_show(struct kobject *kobj, | 
|  | 413 | struct kobj_attribute *a, char *buf) | 
|  | 414 | { | 
|  | 415 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
|  | 416 |  | 
|  | 417 | return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->sectorsize); | 
|  | 418 | } | 
|  | 419 |  | 
| Anand Jain | 98b3d38 | 2014-07-30 20:04:08 +0800 | [diff] [blame] | 420 | BTRFS_ATTR(sectorsize, btrfs_sectorsize_show); | 
| David Sterba | df93589 | 2014-05-07 18:17:16 +0200 | [diff] [blame] | 421 |  | 
|  | 422 | static ssize_t btrfs_clone_alignment_show(struct kobject *kobj, | 
|  | 423 | struct kobj_attribute *a, char *buf) | 
|  | 424 | { | 
|  | 425 | struct btrfs_fs_info *fs_info = to_fs_info(kobj); | 
|  | 426 |  | 
|  | 427 | return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->sectorsize); | 
|  | 428 | } | 
|  | 429 |  | 
| Anand Jain | 98b3d38 | 2014-07-30 20:04:08 +0800 | [diff] [blame] | 430 | BTRFS_ATTR(clone_alignment, btrfs_clone_alignment_show); | 
| David Sterba | df93589 | 2014-05-07 18:17:16 +0200 | [diff] [blame] | 431 |  | 
| Anand Jain | 0dd2906 | 2015-03-10 06:38:27 +0800 | [diff] [blame] | 432 | static const struct attribute *btrfs_attrs[] = { | 
| Jeff Mahoney | f8ba9c1 | 2013-11-01 13:07:06 -0400 | [diff] [blame] | 433 | BTRFS_ATTR_PTR(label), | 
| David Sterba | df93589 | 2014-05-07 18:17:16 +0200 | [diff] [blame] | 434 | BTRFS_ATTR_PTR(nodesize), | 
|  | 435 | BTRFS_ATTR_PTR(sectorsize), | 
|  | 436 | BTRFS_ATTR_PTR(clone_alignment), | 
| Jeff Mahoney | f8ba9c1 | 2013-11-01 13:07:06 -0400 | [diff] [blame] | 437 | NULL, | 
|  | 438 | }; | 
|  | 439 |  | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 440 | static void btrfs_release_super_kobj(struct kobject *kobj) | 
|  | 441 | { | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 442 | struct btrfs_fs_devices *fs_devs = to_fs_devs(kobj); | 
| Anand Jain | 248d200 | 2015-03-10 06:38:19 +0800 | [diff] [blame] | 443 |  | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 444 | memset(&fs_devs->super_kobj, 0, sizeof(struct kobject)); | 
|  | 445 | complete(&fs_devs->kobj_unregister); | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 446 | } | 
|  | 447 |  | 
|  | 448 | static struct kobj_type btrfs_ktype = { | 
|  | 449 | .sysfs_ops	= &kobj_sysfs_ops, | 
|  | 450 | .release	= btrfs_release_super_kobj, | 
|  | 451 | }; | 
|  | 452 |  | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 453 | static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj) | 
|  | 454 | { | 
|  | 455 | if (kobj->ktype != &btrfs_ktype) | 
|  | 456 | return NULL; | 
|  | 457 | return container_of(kobj, struct btrfs_fs_devices, super_kobj); | 
|  | 458 | } | 
|  | 459 |  | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 460 | static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj) | 
|  | 461 | { | 
|  | 462 | if (kobj->ktype != &btrfs_ktype) | 
|  | 463 | return NULL; | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 464 | return to_fs_devs(kobj)->fs_info; | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 465 | } | 
| Josef Bacik | 58176a9 | 2007-08-29 15:47:34 -0400 | [diff] [blame] | 466 |  | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 467 | #define NUM_FEATURE_BITS 64 | 
|  | 468 | static char btrfs_unknown_feature_names[3][NUM_FEATURE_BITS][13]; | 
|  | 469 | static struct btrfs_feature_attr btrfs_feature_attrs[3][NUM_FEATURE_BITS]; | 
|  | 470 |  | 
| David Sterba | e8c9f18 | 2015-01-02 18:23:10 +0100 | [diff] [blame] | 471 | static const u64 supported_feature_masks[3] = { | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 472 | [FEAT_COMPAT]    = BTRFS_FEATURE_COMPAT_SUPP, | 
|  | 473 | [FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP, | 
|  | 474 | [FEAT_INCOMPAT]  = BTRFS_FEATURE_INCOMPAT_SUPP, | 
|  | 475 | }; | 
|  | 476 |  | 
|  | 477 | static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add) | 
| Jeff Mahoney | 5ac1d20 | 2013-11-01 13:06:58 -0400 | [diff] [blame] | 478 | { | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 479 | int set; | 
|  | 480 |  | 
|  | 481 | for (set = 0; set < FEAT_MAX; set++) { | 
|  | 482 | int i; | 
|  | 483 | struct attribute *attrs[2]; | 
|  | 484 | struct attribute_group agroup = { | 
|  | 485 | .name = "features", | 
|  | 486 | .attrs = attrs, | 
|  | 487 | }; | 
|  | 488 | u64 features = get_features(fs_info, set); | 
|  | 489 | features &= ~supported_feature_masks[set]; | 
|  | 490 |  | 
|  | 491 | if (!features) | 
|  | 492 | continue; | 
|  | 493 |  | 
|  | 494 | attrs[1] = NULL; | 
|  | 495 | for (i = 0; i < NUM_FEATURE_BITS; i++) { | 
|  | 496 | struct btrfs_feature_attr *fa; | 
|  | 497 |  | 
|  | 498 | if (!(features & (1ULL << i))) | 
|  | 499 | continue; | 
|  | 500 |  | 
|  | 501 | fa = &btrfs_feature_attrs[set][i]; | 
|  | 502 | attrs[0] = &fa->kobj_attr.attr; | 
|  | 503 | if (add) { | 
|  | 504 | int ret; | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 505 | ret = sysfs_merge_group(&fs_info->fs_devices->super_kobj, | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 506 | &agroup); | 
|  | 507 | if (ret) | 
|  | 508 | return ret; | 
|  | 509 | } else | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 510 | sysfs_unmerge_group(&fs_info->fs_devices->super_kobj, | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 511 | &agroup); | 
|  | 512 | } | 
|  | 513 |  | 
|  | 514 | } | 
|  | 515 | return 0; | 
|  | 516 | } | 
|  | 517 |  | 
| Anand Jain | 2e3e128 | 2015-03-10 06:38:32 +0800 | [diff] [blame] | 518 | static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 519 | { | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 520 | if (fs_devs->device_dir_kobj) { | 
|  | 521 | kobject_del(fs_devs->device_dir_kobj); | 
|  | 522 | kobject_put(fs_devs->device_dir_kobj); | 
|  | 523 | fs_devs->device_dir_kobj = NULL; | 
| Anand Jain | aaf1330 | 2015-03-10 06:38:24 +0800 | [diff] [blame] | 524 | } | 
|  | 525 |  | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 526 | kobject_del(&fs_devs->super_kobj); | 
|  | 527 | kobject_put(&fs_devs->super_kobj); | 
|  | 528 | wait_for_completion(&fs_devs->kobj_unregister); | 
| Jeff Mahoney | 5ac1d20 | 2013-11-01 13:06:58 -0400 | [diff] [blame] | 529 | } | 
|  | 530 |  | 
| Anand Jain | 2e3e128 | 2015-03-10 06:38:32 +0800 | [diff] [blame] | 531 | /* when fs_devs is NULL it will remove all fsid kobject */ | 
| Anand Jain | 1d1c1be | 2015-03-10 06:38:37 +0800 | [diff] [blame] | 532 | void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) | 
| Anand Jain | 2e3e128 | 2015-03-10 06:38:32 +0800 | [diff] [blame] | 533 | { | 
|  | 534 | struct list_head *fs_uuids = btrfs_get_fs_uuids(); | 
|  | 535 |  | 
|  | 536 | if (fs_devs) { | 
|  | 537 | __btrfs_sysfs_remove_fsid(fs_devs); | 
|  | 538 | return; | 
|  | 539 | } | 
|  | 540 |  | 
|  | 541 | list_for_each_entry(fs_devs, fs_uuids, list) { | 
|  | 542 | __btrfs_sysfs_remove_fsid(fs_devs); | 
|  | 543 | } | 
|  | 544 | } | 
|  | 545 |  | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 546 | void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info) | 
|  | 547 | { | 
| Anand Jain | 5a13f43 | 2015-03-10 06:38:31 +0800 | [diff] [blame] | 548 | btrfs_reset_fs_info_ptr(fs_info); | 
|  | 549 |  | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 550 | if (fs_info->space_info_kobj) { | 
|  | 551 | sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs); | 
|  | 552 | kobject_del(fs_info->space_info_kobj); | 
|  | 553 | kobject_put(fs_info->space_info_kobj); | 
|  | 554 | } | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 555 | addrm_unknown_feature_attrs(fs_info, false); | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 556 | sysfs_remove_group(&fs_info->fs_devices->super_kobj, &btrfs_feature_attr_group); | 
|  | 557 | sysfs_remove_files(&fs_info->fs_devices->super_kobj, btrfs_attrs); | 
| Anand Jain | 6c14a16 | 2015-03-10 06:38:34 +0800 | [diff] [blame] | 558 | btrfs_kobj_rm_device(fs_info->fs_devices, NULL); | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 559 | } | 
|  | 560 |  | 
| Jeff Mahoney | 79da4fa | 2013-11-01 13:07:00 -0400 | [diff] [blame] | 561 | const char * const btrfs_feature_set_names[3] = { | 
|  | 562 | [FEAT_COMPAT]	 = "compat", | 
|  | 563 | [FEAT_COMPAT_RO] = "compat_ro", | 
|  | 564 | [FEAT_INCOMPAT]	 = "incompat", | 
|  | 565 | }; | 
|  | 566 |  | 
| Jeff Mahoney | 3b02a68 | 2013-11-01 13:07:02 -0400 | [diff] [blame] | 567 | char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags) | 
|  | 568 | { | 
|  | 569 | size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */ | 
|  | 570 | int len = 0; | 
|  | 571 | int i; | 
|  | 572 | char *str; | 
|  | 573 |  | 
|  | 574 | str = kmalloc(bufsize, GFP_KERNEL); | 
|  | 575 | if (!str) | 
|  | 576 | return str; | 
|  | 577 |  | 
|  | 578 | for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { | 
|  | 579 | const char *name; | 
|  | 580 |  | 
|  | 581 | if (!(flags & (1ULL << i))) | 
|  | 582 | continue; | 
|  | 583 |  | 
|  | 584 | name = btrfs_feature_attrs[set][i].kobj_attr.attr.name; | 
|  | 585 | len += snprintf(str + len, bufsize - len, "%s%s", | 
|  | 586 | len ? "," : "", name); | 
|  | 587 | } | 
|  | 588 |  | 
|  | 589 | return str; | 
|  | 590 | } | 
|  | 591 |  | 
| Jeff Mahoney | 79da4fa | 2013-11-01 13:07:00 -0400 | [diff] [blame] | 592 | static void init_feature_attrs(void) | 
|  | 593 | { | 
|  | 594 | struct btrfs_feature_attr *fa; | 
|  | 595 | int set, i; | 
|  | 596 |  | 
|  | 597 | BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names) != | 
|  | 598 | ARRAY_SIZE(btrfs_feature_attrs)); | 
|  | 599 | BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) != | 
|  | 600 | ARRAY_SIZE(btrfs_feature_attrs[0])); | 
|  | 601 |  | 
| Jeff Mahoney | 3b02a68 | 2013-11-01 13:07:02 -0400 | [diff] [blame] | 602 | memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs)); | 
|  | 603 | memset(btrfs_unknown_feature_names, 0, | 
|  | 604 | sizeof(btrfs_unknown_feature_names)); | 
|  | 605 |  | 
| Jeff Mahoney | 79da4fa | 2013-11-01 13:07:00 -0400 | [diff] [blame] | 606 | for (i = 0; btrfs_supported_feature_attrs[i]; i++) { | 
|  | 607 | struct btrfs_feature_attr *sfa; | 
|  | 608 | struct attribute *a = btrfs_supported_feature_attrs[i]; | 
| Jeff Mahoney | 3b02a68 | 2013-11-01 13:07:02 -0400 | [diff] [blame] | 609 | int bit; | 
| Jeff Mahoney | 79da4fa | 2013-11-01 13:07:00 -0400 | [diff] [blame] | 610 | sfa = attr_to_btrfs_feature_attr(a); | 
| Jeff Mahoney | 3b02a68 | 2013-11-01 13:07:02 -0400 | [diff] [blame] | 611 | bit = ilog2(sfa->feature_bit); | 
|  | 612 | fa = &btrfs_feature_attrs[sfa->feature_set][bit]; | 
| Jeff Mahoney | 79da4fa | 2013-11-01 13:07:00 -0400 | [diff] [blame] | 613 |  | 
|  | 614 | fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name; | 
|  | 615 | } | 
|  | 616 |  | 
|  | 617 | for (set = 0; set < FEAT_MAX; set++) { | 
|  | 618 | for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { | 
|  | 619 | char *name = btrfs_unknown_feature_names[set][i]; | 
|  | 620 | fa = &btrfs_feature_attrs[set][i]; | 
|  | 621 |  | 
|  | 622 | if (fa->kobj_attr.attr.name) | 
|  | 623 | continue; | 
|  | 624 |  | 
|  | 625 | snprintf(name, 13, "%s:%u", | 
|  | 626 | btrfs_feature_set_names[set], i); | 
|  | 627 |  | 
|  | 628 | fa->kobj_attr.attr.name = name; | 
|  | 629 | fa->kobj_attr.attr.mode = S_IRUGO; | 
|  | 630 | fa->feature_set = set; | 
|  | 631 | fa->feature_bit = 1ULL << i; | 
|  | 632 | } | 
|  | 633 | } | 
|  | 634 | } | 
|  | 635 |  | 
| Anand Jain | e7e1aa9 | 2015-03-10 06:38:21 +0800 | [diff] [blame] | 636 | /* when one_device is NULL, it removes all device links */ | 
|  | 637 |  | 
| Anand Jain | 6c14a16 | 2015-03-10 06:38:34 +0800 | [diff] [blame] | 638 | int btrfs_kobj_rm_device(struct btrfs_fs_devices *fs_devices, | 
| Anand Jain | 99994cd | 2014-06-03 11:36:00 +0800 | [diff] [blame] | 639 | struct btrfs_device *one_device) | 
|  | 640 | { | 
|  | 641 | struct hd_struct *disk; | 
|  | 642 | struct kobject *disk_kobj; | 
|  | 643 |  | 
| Anand Jain | 6c14a16 | 2015-03-10 06:38:34 +0800 | [diff] [blame] | 644 | if (!fs_devices->device_dir_kobj) | 
| Anand Jain | 99994cd | 2014-06-03 11:36:00 +0800 | [diff] [blame] | 645 | return -EINVAL; | 
|  | 646 |  | 
| Liu Bo | 87fa3bb | 2014-07-29 19:09:39 +0800 | [diff] [blame] | 647 | if (one_device && one_device->bdev) { | 
| Anand Jain | 99994cd | 2014-06-03 11:36:00 +0800 | [diff] [blame] | 648 | disk = one_device->bdev->bd_part; | 
|  | 649 | disk_kobj = &part_to_dev(disk)->kobj; | 
|  | 650 |  | 
| Anand Jain | 6c14a16 | 2015-03-10 06:38:34 +0800 | [diff] [blame] | 651 | sysfs_remove_link(fs_devices->device_dir_kobj, | 
| Anand Jain | 99994cd | 2014-06-03 11:36:00 +0800 | [diff] [blame] | 652 | disk_kobj->name); | 
|  | 653 | } | 
|  | 654 |  | 
| Anand Jain | e7e1aa9 | 2015-03-10 06:38:21 +0800 | [diff] [blame] | 655 | if (one_device) | 
|  | 656 | return 0; | 
|  | 657 |  | 
|  | 658 | list_for_each_entry(one_device, | 
| Anand Jain | 6c14a16 | 2015-03-10 06:38:34 +0800 | [diff] [blame] | 659 | &fs_devices->devices, dev_list) { | 
| Anand Jain | e7e1aa9 | 2015-03-10 06:38:21 +0800 | [diff] [blame] | 660 | if (!one_device->bdev) | 
|  | 661 | continue; | 
|  | 662 | disk = one_device->bdev->bd_part; | 
|  | 663 | disk_kobj = &part_to_dev(disk)->kobj; | 
|  | 664 |  | 
| Anand Jain | 6c14a16 | 2015-03-10 06:38:34 +0800 | [diff] [blame] | 665 | sysfs_remove_link(fs_devices->device_dir_kobj, | 
| Anand Jain | e7e1aa9 | 2015-03-10 06:38:21 +0800 | [diff] [blame] | 666 | disk_kobj->name); | 
|  | 667 | } | 
|  | 668 |  | 
| Anand Jain | 99994cd | 2014-06-03 11:36:00 +0800 | [diff] [blame] | 669 | return 0; | 
|  | 670 | } | 
|  | 671 |  | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 672 | int btrfs_sysfs_add_device(struct btrfs_fs_devices *fs_devs) | 
| Anand Jain | 00c921c | 2015-03-10 06:38:28 +0800 | [diff] [blame] | 673 | { | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 674 | if (!fs_devs->device_dir_kobj) | 
|  | 675 | fs_devs->device_dir_kobj = kobject_create_and_add("devices", | 
|  | 676 | &fs_devs->super_kobj); | 
| Anand Jain | 00c921c | 2015-03-10 06:38:28 +0800 | [diff] [blame] | 677 |  | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 678 | if (!fs_devs->device_dir_kobj) | 
| Anand Jain | 00c921c | 2015-03-10 06:38:28 +0800 | [diff] [blame] | 679 | return -ENOMEM; | 
|  | 680 |  | 
|  | 681 | return 0; | 
|  | 682 | } | 
|  | 683 |  | 
| Anand Jain | 1ba4381 | 2015-03-10 06:38:33 +0800 | [diff] [blame] | 684 | int btrfs_kobj_add_device(struct btrfs_fs_devices *fs_devices, | 
|  | 685 | struct btrfs_device *one_device) | 
| Jeff Mahoney | 29e5be2 | 2013-11-01 13:07:05 -0400 | [diff] [blame] | 686 | { | 
|  | 687 | int error = 0; | 
| Jeff Mahoney | 29e5be2 | 2013-11-01 13:07:05 -0400 | [diff] [blame] | 688 | struct btrfs_device *dev; | 
|  | 689 |  | 
| Jeff Mahoney | 29e5be2 | 2013-11-01 13:07:05 -0400 | [diff] [blame] | 690 | list_for_each_entry(dev, &fs_devices->devices, dev_list) { | 
| Anand Jain | f085381 | 2014-01-15 17:22:28 +0800 | [diff] [blame] | 691 | struct hd_struct *disk; | 
|  | 692 | struct kobject *disk_kobj; | 
|  | 693 |  | 
|  | 694 | if (!dev->bdev) | 
|  | 695 | continue; | 
|  | 696 |  | 
| Anand Jain | 0d39376 | 2014-06-03 11:36:01 +0800 | [diff] [blame] | 697 | if (one_device && one_device != dev) | 
|  | 698 | continue; | 
|  | 699 |  | 
| Anand Jain | f085381 | 2014-01-15 17:22:28 +0800 | [diff] [blame] | 700 | disk = dev->bdev->bd_part; | 
|  | 701 | disk_kobj = &part_to_dev(disk)->kobj; | 
| Jeff Mahoney | 29e5be2 | 2013-11-01 13:07:05 -0400 | [diff] [blame] | 702 |  | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 703 | error = sysfs_create_link(fs_devices->device_dir_kobj, | 
| Jeff Mahoney | 29e5be2 | 2013-11-01 13:07:05 -0400 | [diff] [blame] | 704 | disk_kobj, disk_kobj->name); | 
|  | 705 | if (error) | 
|  | 706 | break; | 
|  | 707 | } | 
|  | 708 |  | 
|  | 709 | return error; | 
|  | 710 | } | 
|  | 711 |  | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 712 | /* /sys/fs/btrfs/ entry */ | 
|  | 713 | static struct kset *btrfs_kset; | 
|  | 714 |  | 
| David Sterba | 1bae309 | 2014-02-05 15:36:18 +0100 | [diff] [blame] | 715 | /* /sys/kernel/debug/btrfs */ | 
|  | 716 | static struct dentry *btrfs_debugfs_root_dentry; | 
|  | 717 |  | 
|  | 718 | /* Debugging tunables and exported data */ | 
|  | 719 | u64 btrfs_debugfs_test; | 
|  | 720 |  | 
| Anand Jain | 7205921 | 2015-03-10 06:38:26 +0800 | [diff] [blame] | 721 | /* | 
|  | 722 | * Can be called by the device discovery thread. | 
|  | 723 | * And parent can be specified for seed device | 
|  | 724 | */ | 
| Anand Jain | 0c10e2d | 2015-03-10 06:38:35 +0800 | [diff] [blame] | 725 | int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs, | 
| Anand Jain | 7205921 | 2015-03-10 06:38:26 +0800 | [diff] [blame] | 726 | struct kobject *parent) | 
| Jeff Mahoney | 5ac1d20 | 2013-11-01 13:06:58 -0400 | [diff] [blame] | 727 | { | 
|  | 728 | int error; | 
|  | 729 |  | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 730 | init_completion(&fs_devs->kobj_unregister); | 
|  | 731 | fs_devs->super_kobj.kset = btrfs_kset; | 
| Anand Jain | 24bd69c | 2015-03-10 06:38:39 +0800 | [diff] [blame^] | 732 | error = kobject_init_and_add(&fs_devs->super_kobj, | 
|  | 733 | &btrfs_ktype, parent, "%pU", fs_devs->fsid); | 
| Anand Jain | 7205921 | 2015-03-10 06:38:26 +0800 | [diff] [blame] | 734 | return error; | 
|  | 735 | } | 
|  | 736 |  | 
|  | 737 | int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info) | 
|  | 738 | { | 
|  | 739 | int error; | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 740 | struct btrfs_fs_devices *fs_devs = fs_info->fs_devices; | 
|  | 741 | struct kobject *super_kobj = &fs_devs->super_kobj; | 
| Anand Jain | 7205921 | 2015-03-10 06:38:26 +0800 | [diff] [blame] | 742 |  | 
| Anand Jain | 5a13f43 | 2015-03-10 06:38:31 +0800 | [diff] [blame] | 743 | btrfs_set_fs_info_ptr(fs_info); | 
|  | 744 |  | 
| Anand Jain | b7c35e8 | 2015-03-10 06:38:38 +0800 | [diff] [blame] | 745 | error = btrfs_kobj_add_device(fs_devs, NULL); | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 746 | if (error) | 
|  | 747 | return error; | 
| Jeff Mahoney | 510d736 | 2013-11-01 13:06:59 -0400 | [diff] [blame] | 748 |  | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 749 | error = sysfs_create_files(super_kobj, btrfs_attrs); | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 750 | if (error) { | 
| Anand Jain | b7c35e8 | 2015-03-10 06:38:38 +0800 | [diff] [blame] | 751 | btrfs_kobj_rm_device(fs_devs, NULL); | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 752 | return error; | 
|  | 753 | } | 
| Jeff Mahoney | 79da4fa | 2013-11-01 13:07:00 -0400 | [diff] [blame] | 754 |  | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 755 | error = sysfs_create_group(super_kobj, | 
| Anand Jain | 0dd2906 | 2015-03-10 06:38:27 +0800 | [diff] [blame] | 756 | &btrfs_feature_attr_group); | 
|  | 757 | if (error) | 
|  | 758 | goto failure; | 
|  | 759 |  | 
| Jeff Mahoney | e453d98 | 2013-11-21 10:37:16 -0500 | [diff] [blame] | 760 | error = addrm_unknown_feature_attrs(fs_info, true); | 
| Jeff Mahoney | 79da4fa | 2013-11-01 13:07:00 -0400 | [diff] [blame] | 761 | if (error) | 
|  | 762 | goto failure; | 
|  | 763 |  | 
| Jeff Mahoney | 6ab0a20 | 2013-11-01 13:07:04 -0400 | [diff] [blame] | 764 | fs_info->space_info_kobj = kobject_create_and_add("allocation", | 
| Anand Jain | 2e7910d | 2015-03-10 06:38:29 +0800 | [diff] [blame] | 765 | super_kobj); | 
| Jeff Mahoney | 6ab0a20 | 2013-11-01 13:07:04 -0400 | [diff] [blame] | 766 | if (!fs_info->space_info_kobj) { | 
|  | 767 | error = -ENOMEM; | 
|  | 768 | goto failure; | 
|  | 769 | } | 
|  | 770 |  | 
|  | 771 | error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs); | 
|  | 772 | if (error) | 
|  | 773 | goto failure; | 
|  | 774 |  | 
| Jeff Mahoney | 79da4fa | 2013-11-01 13:07:00 -0400 | [diff] [blame] | 775 | return 0; | 
|  | 776 | failure: | 
|  | 777 | btrfs_sysfs_remove_one(fs_info); | 
| Jeff Mahoney | 5ac1d20 | 2013-11-01 13:06:58 -0400 | [diff] [blame] | 778 | return error; | 
|  | 779 | } | 
|  | 780 |  | 
| David Sterba | 1bae309 | 2014-02-05 15:36:18 +0100 | [diff] [blame] | 781 | static int btrfs_init_debugfs(void) | 
|  | 782 | { | 
|  | 783 | #ifdef CONFIG_DEBUG_FS | 
|  | 784 | btrfs_debugfs_root_dentry = debugfs_create_dir("btrfs", NULL); | 
|  | 785 | if (!btrfs_debugfs_root_dentry) | 
|  | 786 | return -ENOMEM; | 
|  | 787 |  | 
|  | 788 | debugfs_create_u64("test", S_IRUGO | S_IWUGO, btrfs_debugfs_root_dentry, | 
|  | 789 | &btrfs_debugfs_test); | 
|  | 790 | #endif | 
|  | 791 | return 0; | 
|  | 792 | } | 
|  | 793 |  | 
| Christoph Hellwig | b214107 | 2008-09-05 16:43:31 -0400 | [diff] [blame] | 794 | int btrfs_init_sysfs(void) | 
| Josef Bacik | 58176a9 | 2007-08-29 15:47:34 -0400 | [diff] [blame] | 795 | { | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 796 | int ret; | 
| David Sterba | 1bae309 | 2014-02-05 15:36:18 +0100 | [diff] [blame] | 797 |  | 
| Greg KH | e3fe4e7 | 2008-02-20 14:14:16 -0500 | [diff] [blame] | 798 | btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); | 
|  | 799 | if (!btrfs_kset) | 
|  | 800 | return -ENOMEM; | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 801 |  | 
| David Sterba | 1bae309 | 2014-02-05 15:36:18 +0100 | [diff] [blame] | 802 | ret = btrfs_init_debugfs(); | 
|  | 803 | if (ret) | 
| Filipe Manana | 001a648 | 2015-01-23 18:27:00 +0000 | [diff] [blame] | 804 | goto out1; | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 805 |  | 
| David Sterba | 1bae309 | 2014-02-05 15:36:18 +0100 | [diff] [blame] | 806 | init_feature_attrs(); | 
|  | 807 | ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); | 
| Filipe Manana | 001a648 | 2015-01-23 18:27:00 +0000 | [diff] [blame] | 808 | if (ret) | 
|  | 809 | goto out2; | 
|  | 810 |  | 
|  | 811 | return 0; | 
|  | 812 | out2: | 
|  | 813 | debugfs_remove_recursive(btrfs_debugfs_root_dentry); | 
|  | 814 | out1: | 
|  | 815 | kset_unregister(btrfs_kset); | 
| David Sterba | 1bae309 | 2014-02-05 15:36:18 +0100 | [diff] [blame] | 816 |  | 
|  | 817 | return ret; | 
| Josef Bacik | 58176a9 | 2007-08-29 15:47:34 -0400 | [diff] [blame] | 818 | } | 
|  | 819 |  | 
| Christoph Hellwig | b214107 | 2008-09-05 16:43:31 -0400 | [diff] [blame] | 820 | void btrfs_exit_sysfs(void) | 
| Josef Bacik | 58176a9 | 2007-08-29 15:47:34 -0400 | [diff] [blame] | 821 | { | 
| Jeff Mahoney | 079b72b | 2013-11-01 13:06:57 -0400 | [diff] [blame] | 822 | sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); | 
| Greg KH | e3fe4e7 | 2008-02-20 14:14:16 -0500 | [diff] [blame] | 823 | kset_unregister(btrfs_kset); | 
| David Sterba | 1bae309 | 2014-02-05 15:36:18 +0100 | [diff] [blame] | 824 | debugfs_remove_recursive(btrfs_debugfs_root_dentry); | 
| Josef Bacik | 58176a9 | 2007-08-29 15:47:34 -0400 | [diff] [blame] | 825 | } | 
| Chris Mason | 55d4741 | 2008-02-20 16:02:51 -0500 | [diff] [blame] | 826 |  |