Skip to content

Commit 6ab0a20

Browse files
jeffmahoneymasoncl
authored andcommitted
btrfs: publish allocation data in sysfs
While trying to debug ENOSPC issues, it's helpful to understand what the kernel's view of the available space is. We export this information via ioctl, but sysfs files are more easily used. Signed-off-by: Jeff Mahoney <[email protected]> Signed-off-by: Josef Bacik <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent 01e219e commit 6ab0a20

File tree

4 files changed

+238
-5
lines changed

4 files changed

+238
-5
lines changed

fs/btrfs/ctree.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,9 @@ struct btrfs_space_info {
11511151
spinlock_t lock;
11521152
struct rw_semaphore groups_sem;
11531153
wait_queue_head_t wait;
1154+
1155+
struct kobject kobj;
1156+
struct kobject block_group_kobjs[BTRFS_NR_RAID_TYPES];
11541157
};
11551158

11561159
#define BTRFS_BLOCK_RSV_GLOBAL 1
@@ -1526,6 +1529,7 @@ struct btrfs_fs_info {
15261529
int thread_pool_size;
15271530

15281531
struct kobject super_kobj;
1532+
struct kobject *space_info_kobj;
15291533
struct completion kobj_unregister;
15301534
int do_barriers;
15311535
int closing;
@@ -3178,6 +3182,7 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(
31783182
struct btrfs_fs_info *info,
31793183
u64 bytenr);
31803184
void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
3185+
int get_block_group_index(struct btrfs_block_group_cache *cache);
31813186
struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
31823187
struct btrfs_root *root, u32 blocksize,
31833188
u64 parent, u64 root_objectid,

fs/btrfs/extent-tree.c

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "locking.h"
3636
#include "free-space-cache.h"
3737
#include "math.h"
38+
#include "sysfs.h"
3839

3940
#undef SCRAMBLE_DELAYED_REFS
4041

@@ -3408,6 +3409,23 @@ int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr)
34083409
return readonly;
34093410
}
34103411

3412+
static const char *alloc_name(u64 flags)
3413+
{
3414+
switch (flags) {
3415+
case BTRFS_BLOCK_GROUP_METADATA|BTRFS_BLOCK_GROUP_DATA:
3416+
return "mixed";
3417+
case BTRFS_BLOCK_GROUP_METADATA:
3418+
return "metadata";
3419+
case BTRFS_BLOCK_GROUP_DATA:
3420+
return "data";
3421+
case BTRFS_BLOCK_GROUP_SYSTEM:
3422+
return "system";
3423+
default:
3424+
WARN_ON(1);
3425+
return "invalid-combination";
3426+
};
3427+
}
3428+
34113429
static int update_space_info(struct btrfs_fs_info *info, u64 flags,
34123430
u64 total_bytes, u64 bytes_used,
34133431
struct btrfs_space_info **space_info)
@@ -3463,11 +3481,21 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
34633481
found->chunk_alloc = 0;
34643482
found->flush = 0;
34653483
init_waitqueue_head(&found->wait);
3484+
3485+
ret = kobject_init_and_add(&found->kobj, &space_info_ktype,
3486+
info->space_info_kobj, "%s",
3487+
alloc_name(found->flags));
3488+
if (ret) {
3489+
kfree(found);
3490+
return ret;
3491+
}
3492+
34663493
*space_info = found;
34673494
list_add_rcu(&found->list, &info->space_info);
34683495
if (flags & BTRFS_BLOCK_GROUP_DATA)
34693496
info->data_sinfo = found;
3470-
return 0;
3497+
3498+
return ret;
34713499
}
34723500

34733501
static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
@@ -6152,11 +6180,29 @@ int __get_raid_index(u64 flags)
61526180
return BTRFS_RAID_SINGLE; /* BTRFS_BLOCK_GROUP_SINGLE */
61536181
}
61546182

6155-
static int get_block_group_index(struct btrfs_block_group_cache *cache)
6183+
int get_block_group_index(struct btrfs_block_group_cache *cache)
61566184
{
61576185
return __get_raid_index(cache->flags);
61586186
}
61596187

6188+
static const char *btrfs_raid_type_names[BTRFS_NR_RAID_TYPES] = {
6189+
[BTRFS_RAID_RAID10] = "raid10",
6190+
[BTRFS_RAID_RAID1] = "raid1",
6191+
[BTRFS_RAID_DUP] = "dup",
6192+
[BTRFS_RAID_RAID0] = "raid0",
6193+
[BTRFS_RAID_SINGLE] = "single",
6194+
[BTRFS_RAID_RAID5] = "raid5",
6195+
[BTRFS_RAID_RAID6] = "raid6",
6196+
};
6197+
6198+
const char *get_raid_name(enum btrfs_raid_types type)
6199+
{
6200+
if (type >= BTRFS_NR_RAID_TYPES)
6201+
return NULL;
6202+
6203+
return btrfs_raid_type_names[type];
6204+
}
6205+
61606206
enum btrfs_loop_type {
61616207
LOOP_CACHING_NOWAIT = 0,
61626208
LOOP_CACHING_WAIT = 1,
@@ -8340,6 +8386,8 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
83408386
release_global_block_rsv(info);
83418387

83428388
while (!list_empty(&info->space_info)) {
8389+
int i;
8390+
83438391
space_info = list_entry(info->space_info.next,
83448392
struct btrfs_space_info,
83458393
list);
@@ -8350,9 +8398,17 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
83508398
dump_space_info(space_info, 0, 0);
83518399
}
83528400
}
8353-
percpu_counter_destroy(&space_info->total_bytes_pinned);
83548401
list_del(&space_info->list);
8355-
kfree(space_info);
8402+
for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
8403+
struct kobject *kobj;
8404+
kobj = &space_info->block_group_kobjs[i];
8405+
if (kobj->parent) {
8406+
kobject_del(kobj);
8407+
kobject_put(kobj);
8408+
}
8409+
}
8410+
kobject_del(&space_info->kobj);
8411+
kobject_put(&space_info->kobj);
83568412
}
83578413
return 0;
83588414
}
@@ -8363,6 +8419,19 @@ static void __link_block_group(struct btrfs_space_info *space_info,
83638419
int index = get_block_group_index(cache);
83648420

83658421
down_write(&space_info->groups_sem);
8422+
if (list_empty(&space_info->block_groups[index])) {
8423+
struct kobject *kobj = &space_info->block_group_kobjs[index];
8424+
int ret;
8425+
8426+
kobject_get(&space_info->kobj); /* put in release */
8427+
ret = kobject_init_and_add(kobj, &btrfs_raid_ktype,
8428+
&space_info->kobj,
8429+
get_raid_name(index));
8430+
if (ret) {
8431+
pr_warn("btrfs: failed to add kobject for block cache. ignoring.\n");
8432+
kobject_put(&space_info->kobj);
8433+
}
8434+
}
83668435
list_add_tail(&cache->list, &space_info->block_groups[index]);
83678436
up_write(&space_info->groups_sem);
83688437
}
@@ -8803,8 +8872,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
88038872
* are still on the list after taking the semaphore
88048873
*/
88058874
list_del_init(&block_group->list);
8806-
if (list_empty(&block_group->space_info->block_groups[index]))
8875+
if (list_empty(&block_group->space_info->block_groups[index])) {
8876+
kobject_del(&block_group->space_info->block_group_kobjs[index]);
8877+
kobject_put(&block_group->space_info->block_group_kobjs[index]);
88078878
clear_avail_alloc_bits(root->fs_info, block_group->flags);
8879+
}
88088880
up_write(&block_group->space_info->groups_sem);
88098881

88108882
if (block_group->cached == BTRFS_CACHE_STARTED)

fs/btrfs/sysfs.c

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,140 @@ static const struct attribute_group btrfs_feature_attr_group = {
219219
.attrs = btrfs_supported_feature_attrs,
220220
};
221221

222+
static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf)
223+
{
224+
u64 val;
225+
if (lock)
226+
spin_lock(lock);
227+
val = *value_ptr;
228+
if (lock)
229+
spin_unlock(lock);
230+
return snprintf(buf, PAGE_SIZE, "%llu\n", val);
231+
}
232+
233+
static ssize_t global_rsv_size_show(struct kobject *kobj,
234+
struct kobj_attribute *ka, char *buf)
235+
{
236+
struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
237+
struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
238+
return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf);
239+
}
240+
BTRFS_ATTR(global_rsv_size, 0444, global_rsv_size_show);
241+
242+
static ssize_t global_rsv_reserved_show(struct kobject *kobj,
243+
struct kobj_attribute *a, char *buf)
244+
{
245+
struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
246+
struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv;
247+
return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf);
248+
}
249+
BTRFS_ATTR(global_rsv_reserved, 0444, global_rsv_reserved_show);
250+
251+
#define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj)
252+
253+
static ssize_t raid_bytes_show(struct kobject *kobj,
254+
struct kobj_attribute *attr, char *buf);
255+
BTRFS_RAID_ATTR(total_bytes, raid_bytes_show);
256+
BTRFS_RAID_ATTR(used_bytes, raid_bytes_show);
257+
258+
static ssize_t raid_bytes_show(struct kobject *kobj,
259+
struct kobj_attribute *attr, char *buf)
260+
261+
{
262+
struct btrfs_space_info *sinfo = to_space_info(kobj->parent);
263+
struct btrfs_block_group_cache *block_group;
264+
int index = kobj - sinfo->block_group_kobjs;
265+
u64 val = 0;
266+
267+
down_read(&sinfo->groups_sem);
268+
list_for_each_entry(block_group, &sinfo->block_groups[index], list) {
269+
if (&attr->attr == BTRFS_RAID_ATTR_PTR(total_bytes))
270+
val += block_group->key.offset;
271+
else
272+
val += btrfs_block_group_used(&block_group->item);
273+
}
274+
up_read(&sinfo->groups_sem);
275+
return snprintf(buf, PAGE_SIZE, "%llu\n", val);
276+
}
277+
278+
static struct attribute *raid_attributes[] = {
279+
BTRFS_RAID_ATTR_PTR(total_bytes),
280+
BTRFS_RAID_ATTR_PTR(used_bytes),
281+
NULL
282+
};
283+
284+
static void release_raid_kobj(struct kobject *kobj)
285+
{
286+
kobject_put(kobj->parent);
287+
}
288+
289+
struct kobj_type btrfs_raid_ktype = {
290+
.sysfs_ops = &kobj_sysfs_ops,
291+
.release = release_raid_kobj,
292+
.default_attrs = raid_attributes,
293+
};
294+
295+
#define SPACE_INFO_ATTR(field) \
296+
static ssize_t btrfs_space_info_show_##field(struct kobject *kobj, \
297+
struct kobj_attribute *a, \
298+
char *buf) \
299+
{ \
300+
struct btrfs_space_info *sinfo = to_space_info(kobj); \
301+
return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf); \
302+
} \
303+
BTRFS_ATTR(field, 0444, btrfs_space_info_show_##field)
304+
305+
static ssize_t btrfs_space_info_show_total_bytes_pinned(struct kobject *kobj,
306+
struct kobj_attribute *a,
307+
char *buf)
308+
{
309+
struct btrfs_space_info *sinfo = to_space_info(kobj);
310+
s64 val = percpu_counter_sum(&sinfo->total_bytes_pinned);
311+
return snprintf(buf, PAGE_SIZE, "%lld\n", val);
312+
}
313+
314+
SPACE_INFO_ATTR(flags);
315+
SPACE_INFO_ATTR(total_bytes);
316+
SPACE_INFO_ATTR(bytes_used);
317+
SPACE_INFO_ATTR(bytes_pinned);
318+
SPACE_INFO_ATTR(bytes_reserved);
319+
SPACE_INFO_ATTR(bytes_may_use);
320+
SPACE_INFO_ATTR(disk_used);
321+
SPACE_INFO_ATTR(disk_total);
322+
BTRFS_ATTR(total_bytes_pinned, 0444, btrfs_space_info_show_total_bytes_pinned);
323+
324+
static struct attribute *space_info_attrs[] = {
325+
BTRFS_ATTR_PTR(flags),
326+
BTRFS_ATTR_PTR(total_bytes),
327+
BTRFS_ATTR_PTR(bytes_used),
328+
BTRFS_ATTR_PTR(bytes_pinned),
329+
BTRFS_ATTR_PTR(bytes_reserved),
330+
BTRFS_ATTR_PTR(bytes_may_use),
331+
BTRFS_ATTR_PTR(disk_used),
332+
BTRFS_ATTR_PTR(disk_total),
333+
BTRFS_ATTR_PTR(total_bytes_pinned),
334+
NULL,
335+
};
336+
337+
static void space_info_release(struct kobject *kobj)
338+
{
339+
struct btrfs_space_info *sinfo = to_space_info(kobj);
340+
percpu_counter_destroy(&sinfo->total_bytes_pinned);
341+
kfree(sinfo);
342+
}
343+
344+
struct kobj_type space_info_ktype = {
345+
.sysfs_ops = &kobj_sysfs_ops,
346+
.release = space_info_release,
347+
.default_attrs = space_info_attrs,
348+
};
349+
350+
static const struct attribute *allocation_attrs[] = {
351+
BTRFS_ATTR_PTR(global_rsv_reserved),
352+
BTRFS_ATTR_PTR(global_rsv_size),
353+
NULL,
354+
};
355+
222356
static void btrfs_release_super_kobj(struct kobject *kobj)
223357
{
224358
struct btrfs_fs_info *fs_info = to_fs_info(kobj);
@@ -239,6 +373,9 @@ static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj)
239373

240374
void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info)
241375
{
376+
sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs);
377+
kobject_del(fs_info->space_info_kobj);
378+
kobject_put(fs_info->space_info_kobj);
242379
kobject_del(&fs_info->super_kobj);
243380
kobject_put(&fs_info->super_kobj);
244381
wait_for_completion(&fs_info->kobj_unregister);
@@ -391,6 +528,17 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info)
391528
if (error)
392529
goto failure;
393530

531+
fs_info->space_info_kobj = kobject_create_and_add("allocation",
532+
&fs_info->super_kobj);
533+
if (!fs_info->space_info_kobj) {
534+
error = -ENOMEM;
535+
goto failure;
536+
}
537+
538+
error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs);
539+
if (error)
540+
goto failure;
541+
394542
return 0;
395543
failure:
396544
btrfs_sysfs_remove_one(fs_info);

fs/btrfs/sysfs.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ static struct kobj_attribute btrfs_attr_##_name = \
2222
BTRFS_ATTR_RW(_name, _mode, _show, NULL)
2323
#define BTRFS_ATTR_PTR(_name) (&btrfs_attr_##_name.attr)
2424

25+
#define BTRFS_RAID_ATTR(_name, _show) \
26+
static struct kobj_attribute btrfs_raid_attr_##_name = \
27+
__INIT_KOBJ_ATTR(_name, 0444, _show, NULL)
28+
#define BTRFS_RAID_ATTR_PTR(_name) (&btrfs_raid_attr_##_name.attr)
29+
30+
2531
struct btrfs_feature_attr {
2632
struct kobj_attribute kobj_attr;
2733
enum btrfs_feature_set feature_set;
@@ -53,4 +59,6 @@ static struct btrfs_feature_attr btrfs_attr_##_name = { \
5359
to_btrfs_feature_attr(attr_to_btrfs_attr(a))
5460
char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags);
5561
extern const char * const btrfs_feature_set_names[3];
62+
extern struct kobj_type space_info_ktype;
63+
extern struct kobj_type btrfs_raid_ktype;
5664
#endif /* _BTRFS_SYSFS_H_ */

0 commit comments

Comments
 (0)