Skip to content

Commit 49e5fb4

Browse files
adam900710kdave
authored andcommitted
btrfs: qgroup: export qgroups in sysfs
This patch will add the following sysfs interface: /sys/fs/btrfs/<UUID>/qgroups/<qgroup_id>/referenced /sys/fs/btrfs/<UUID>/qgroups/<qgroup_id>/exclusive /sys/fs/btrfs/<UUID>/qgroups/<qgroup_id>/max_referenced /sys/fs/btrfs/<UUID>/qgroups/<qgroup_id>/max_exclusive /sys/fs/btrfs/<UUID>/qgroups/<qgroup_id>/limit_flags Which is also available in output of "btrfs qgroup show". /sys/fs/btrfs/<UUID>/qgroups/<qgroup_id>/rsv_data /sys/fs/btrfs/<UUID>/qgroups/<qgroup_id>/rsv_meta_pertrans /sys/fs/btrfs/<UUID>/qgroups/<qgroup_id>/rsv_meta_prealloc The last 3 rsv related members are not visible to users, but can be very useful to debug qgroup limit related bugs. Also, to avoid '/' used in <qgroup_id>, the separator between qgroup level and qgroup id is changed to '_'. The interface is not hidden behind 'debug' as we want this interface to be included into production build and to provide another way to read the qgroup information besides the ioctls. Signed-off-by: Qu Wenruo <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 06f67c4 commit 49e5fb4

File tree

5 files changed

+202
-9
lines changed

5 files changed

+202
-9
lines changed

fs/btrfs/ctree.h

+1
Original file line numberDiff line numberDiff line change
@@ -779,6 +779,7 @@ struct btrfs_fs_info {
779779
u32 thread_pool_size;
780780

781781
struct kobject *space_info_kobj;
782+
struct kobject *qgroups_kobj;
782783

783784
u64 total_pinned;
784785

fs/btrfs/qgroup.c

+35-9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "extent_io.h"
2323
#include "qgroup.h"
2424
#include "block-group.h"
25+
#include "sysfs.h"
2526

2627
/* TODO XXX FIXME
2728
* - subvol delete -> delete when ref goes to 0? delete limits also?
@@ -220,10 +221,12 @@ static struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info,
220221
return qgroup;
221222
}
222223

223-
static void __del_qgroup_rb(struct btrfs_qgroup *qgroup)
224+
static void __del_qgroup_rb(struct btrfs_fs_info *fs_info,
225+
struct btrfs_qgroup *qgroup)
224226
{
225227
struct btrfs_qgroup_list *list;
226228

229+
btrfs_sysfs_del_one_qgroup(fs_info, qgroup);
227230
list_del(&qgroup->dirty);
228231
while (!list_empty(&qgroup->groups)) {
229232
list = list_first_entry(&qgroup->groups,
@@ -252,7 +255,7 @@ static int del_qgroup_rb(struct btrfs_fs_info *fs_info, u64 qgroupid)
252255
return -ENOENT;
253256

254257
rb_erase(&qgroup->node, &fs_info->qgroup_tree);
255-
__del_qgroup_rb(qgroup);
258+
__del_qgroup_rb(fs_info, qgroup);
256259
return 0;
257260
}
258261

@@ -351,6 +354,9 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
351354
goto out;
352355
}
353356

357+
ret = btrfs_sysfs_add_qgroups(fs_info);
358+
if (ret < 0)
359+
goto out;
354360
/* default this to quota off, in case no status key is found */
355361
fs_info->qgroup_flags = 0;
356362

@@ -412,6 +418,10 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
412418
goto out;
413419
}
414420
}
421+
ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
422+
if (ret < 0)
423+
goto out;
424+
415425
switch (found_key.type) {
416426
case BTRFS_QGROUP_INFO_KEY: {
417427
struct btrfs_qgroup_info_item *ptr;
@@ -500,16 +510,12 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
500510
ulist_free(fs_info->qgroup_ulist);
501511
fs_info->qgroup_ulist = NULL;
502512
fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN;
513+
btrfs_sysfs_del_qgroups(fs_info);
503514
}
504515

505516
return ret < 0 ? ret : 0;
506517
}
507518

508-
static u64 btrfs_qgroup_subvolid(u64 qgroupid)
509-
{
510-
return (qgroupid & ((1ULL << BTRFS_QGROUP_LEVEL_SHIFT) - 1));
511-
}
512-
513519
/*
514520
* Called in close_ctree() when quota is still enabled. This verifies we don't
515521
* leak some reserved space.
@@ -562,7 +568,7 @@ void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info)
562568
while ((n = rb_first(&fs_info->qgroup_tree))) {
563569
qgroup = rb_entry(n, struct btrfs_qgroup, node);
564570
rb_erase(n, &fs_info->qgroup_tree);
565-
__del_qgroup_rb(qgroup);
571+
__del_qgroup_rb(fs_info, qgroup);
566572
}
567573
/*
568574
* We call btrfs_free_qgroup_config() when unmounting
@@ -571,6 +577,7 @@ void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info)
571577
*/
572578
ulist_free(fs_info->qgroup_ulist);
573579
fs_info->qgroup_ulist = NULL;
580+
btrfs_sysfs_del_qgroups(fs_info);
574581
}
575582

576583
static int add_qgroup_relation_item(struct btrfs_trans_handle *trans, u64 src,
@@ -943,6 +950,9 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
943950
goto out;
944951
}
945952

953+
ret = btrfs_sysfs_add_qgroups(fs_info);
954+
if (ret < 0)
955+
goto out;
946956
/*
947957
* 1 for quota root item
948958
* 1 for BTRFS_QGROUP_STATUS item
@@ -1030,6 +1040,11 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
10301040
btrfs_abort_transaction(trans, ret);
10311041
goto out_free_path;
10321042
}
1043+
ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
1044+
if (ret < 0) {
1045+
btrfs_abort_transaction(trans, ret);
1046+
goto out_free_path;
1047+
}
10331048
}
10341049
ret = btrfs_next_item(tree_root, path);
10351050
if (ret < 0) {
@@ -1054,6 +1069,11 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
10541069
btrfs_abort_transaction(trans, ret);
10551070
goto out_free_path;
10561071
}
1072+
ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
1073+
if (ret < 0) {
1074+
btrfs_abort_transaction(trans, ret);
1075+
goto out_free_path;
1076+
}
10571077

10581078
ret = btrfs_commit_transaction(trans);
10591079
trans = NULL;
@@ -1089,6 +1109,7 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info)
10891109
fs_info->qgroup_ulist = NULL;
10901110
if (trans)
10911111
btrfs_end_transaction(trans);
1112+
btrfs_sysfs_del_qgroups(fs_info);
10921113
}
10931114
mutex_unlock(&fs_info->qgroup_ioctl_lock);
10941115
return ret;
@@ -1441,8 +1462,11 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid)
14411462
qgroup = add_qgroup_rb(fs_info, qgroupid);
14421463
spin_unlock(&fs_info->qgroup_lock);
14431464

1444-
if (IS_ERR(qgroup))
1465+
if (IS_ERR(qgroup)) {
14451466
ret = PTR_ERR(qgroup);
1467+
goto out;
1468+
}
1469+
ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
14461470
out:
14471471
mutex_unlock(&fs_info->qgroup_ioctl_lock);
14481472
return ret;
@@ -2861,6 +2885,8 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,
28612885

28622886
unlock:
28632887
spin_unlock(&fs_info->qgroup_lock);
2888+
if (!ret)
2889+
ret = btrfs_sysfs_add_one_qgroup(fs_info, dstgroup);
28642890
out:
28652891
if (!committing)
28662892
mutex_unlock(&fs_info->qgroup_ioctl_lock);

fs/btrfs/qgroup.h

+11
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <linux/spinlock.h>
1010
#include <linux/rbtree.h>
11+
#include <linux/kobject.h>
1112
#include "ulist.h"
1213
#include "delayed-ref.h"
1314

@@ -223,8 +224,18 @@ struct btrfs_qgroup {
223224
*/
224225
u64 old_refcnt;
225226
u64 new_refcnt;
227+
228+
/*
229+
* Sysfs kobjectid
230+
*/
231+
struct kobject kobj;
226232
};
227233

234+
static inline u64 btrfs_qgroup_subvolid(u64 qgroupid)
235+
{
236+
return (qgroupid & ((1ULL << BTRFS_QGROUP_LEVEL_SHIFT) - 1));
237+
}
238+
228239
/*
229240
* For qgroup event trace points only
230241
*/

fs/btrfs/sysfs.c

+148
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "volumes.h"
2020
#include "space-info.h"
2121
#include "block-group.h"
22+
#include "qgroup.h"
2223

2324
struct btrfs_feature_attr {
2425
struct kobj_attribute kobj_attr;
@@ -1455,6 +1456,153 @@ int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info)
14551456
return error;
14561457
}
14571458

1459+
static inline struct btrfs_fs_info *qgroup_kobj_to_fs_info(struct kobject *kobj)
1460+
{
1461+
return to_fs_info(kobj->parent->parent);
1462+
}
1463+
1464+
#define QGROUP_ATTR(_member, _show_name) \
1465+
static ssize_t btrfs_qgroup_show_##_member(struct kobject *qgroup_kobj, \
1466+
struct kobj_attribute *a, \
1467+
char *buf) \
1468+
{ \
1469+
struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj); \
1470+
struct btrfs_qgroup *qgroup = container_of(qgroup_kobj, \
1471+
struct btrfs_qgroup, kobj); \
1472+
return btrfs_show_u64(&qgroup->_member, &fs_info->qgroup_lock, buf); \
1473+
} \
1474+
BTRFS_ATTR(qgroup, _show_name, btrfs_qgroup_show_##_member)
1475+
1476+
#define QGROUP_RSV_ATTR(_name, _type) \
1477+
static ssize_t btrfs_qgroup_rsv_show_##_name(struct kobject *qgroup_kobj, \
1478+
struct kobj_attribute *a, \
1479+
char *buf) \
1480+
{ \
1481+
struct btrfs_fs_info *fs_info = qgroup_kobj_to_fs_info(qgroup_kobj); \
1482+
struct btrfs_qgroup *qgroup = container_of(qgroup_kobj, \
1483+
struct btrfs_qgroup, kobj); \
1484+
return btrfs_show_u64(&qgroup->rsv.values[_type], \
1485+
&fs_info->qgroup_lock, buf); \
1486+
} \
1487+
BTRFS_ATTR(qgroup, rsv_##_name, btrfs_qgroup_rsv_show_##_name)
1488+
1489+
QGROUP_ATTR(rfer, referenced);
1490+
QGROUP_ATTR(excl, exclusive);
1491+
QGROUP_ATTR(max_rfer, max_referenced);
1492+
QGROUP_ATTR(max_excl, max_exclusive);
1493+
QGROUP_ATTR(lim_flags, limit_flags);
1494+
QGROUP_RSV_ATTR(data, BTRFS_QGROUP_RSV_DATA);
1495+
QGROUP_RSV_ATTR(meta_pertrans, BTRFS_QGROUP_RSV_META_PERTRANS);
1496+
QGROUP_RSV_ATTR(meta_prealloc, BTRFS_QGROUP_RSV_META_PREALLOC);
1497+
1498+
static struct attribute *qgroup_attrs[] = {
1499+
BTRFS_ATTR_PTR(qgroup, referenced),
1500+
BTRFS_ATTR_PTR(qgroup, exclusive),
1501+
BTRFS_ATTR_PTR(qgroup, max_referenced),
1502+
BTRFS_ATTR_PTR(qgroup, max_exclusive),
1503+
BTRFS_ATTR_PTR(qgroup, limit_flags),
1504+
BTRFS_ATTR_PTR(qgroup, rsv_data),
1505+
BTRFS_ATTR_PTR(qgroup, rsv_meta_pertrans),
1506+
BTRFS_ATTR_PTR(qgroup, rsv_meta_prealloc),
1507+
NULL
1508+
};
1509+
ATTRIBUTE_GROUPS(qgroup);
1510+
1511+
static void qgroup_release(struct kobject *kobj)
1512+
{
1513+
struct btrfs_qgroup *qgroup = container_of(kobj, struct btrfs_qgroup, kobj);
1514+
1515+
memset(&qgroup->kobj, 0, sizeof(*kobj));
1516+
}
1517+
1518+
static struct kobj_type qgroup_ktype = {
1519+
.sysfs_ops = &kobj_sysfs_ops,
1520+
.release = qgroup_release,
1521+
.default_groups = qgroup_groups,
1522+
};
1523+
1524+
int btrfs_sysfs_add_one_qgroup(struct btrfs_fs_info *fs_info,
1525+
struct btrfs_qgroup *qgroup)
1526+
{
1527+
struct kobject *qgroups_kobj = fs_info->qgroups_kobj;
1528+
int ret;
1529+
1530+
if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
1531+
return 0;
1532+
if (qgroup->kobj.state_initialized)
1533+
return 0;
1534+
if (!qgroups_kobj)
1535+
return -EINVAL;
1536+
1537+
ret = kobject_init_and_add(&qgroup->kobj, &qgroup_ktype, qgroups_kobj,
1538+
"%hu_%llu", btrfs_qgroup_level(qgroup->qgroupid),
1539+
btrfs_qgroup_subvolid(qgroup->qgroupid));
1540+
if (ret < 0)
1541+
kobject_put(&qgroup->kobj);
1542+
1543+
return ret;
1544+
}
1545+
1546+
void btrfs_sysfs_del_qgroups(struct btrfs_fs_info *fs_info)
1547+
{
1548+
struct btrfs_qgroup *qgroup;
1549+
struct btrfs_qgroup *next;
1550+
1551+
if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
1552+
return;
1553+
1554+
rbtree_postorder_for_each_entry_safe(qgroup, next,
1555+
&fs_info->qgroup_tree, node)
1556+
btrfs_sysfs_del_one_qgroup(fs_info, qgroup);
1557+
kobject_del(fs_info->qgroups_kobj);
1558+
kobject_put(fs_info->qgroups_kobj);
1559+
fs_info->qgroups_kobj = NULL;
1560+
}
1561+
1562+
/* Called when qgroups get initialized, thus there is no need for locking */
1563+
int btrfs_sysfs_add_qgroups(struct btrfs_fs_info *fs_info)
1564+
{
1565+
struct kobject *fsid_kobj = &fs_info->fs_devices->fsid_kobj;
1566+
struct btrfs_qgroup *qgroup;
1567+
struct btrfs_qgroup *next;
1568+
int ret = 0;
1569+
1570+
if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
1571+
return 0;
1572+
1573+
ASSERT(fsid_kobj);
1574+
if (fs_info->qgroups_kobj)
1575+
return 0;
1576+
1577+
fs_info->qgroups_kobj = kobject_create_and_add("qgroups", fsid_kobj);
1578+
if (!fs_info->qgroups_kobj) {
1579+
ret = -ENOMEM;
1580+
goto out;
1581+
}
1582+
rbtree_postorder_for_each_entry_safe(qgroup, next,
1583+
&fs_info->qgroup_tree, node) {
1584+
ret = btrfs_sysfs_add_one_qgroup(fs_info, qgroup);
1585+
if (ret < 0)
1586+
goto out;
1587+
}
1588+
1589+
out:
1590+
if (ret < 0)
1591+
btrfs_sysfs_del_qgroups(fs_info);
1592+
return ret;
1593+
}
1594+
1595+
void btrfs_sysfs_del_one_qgroup(struct btrfs_fs_info *fs_info,
1596+
struct btrfs_qgroup *qgroup)
1597+
{
1598+
if (test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state))
1599+
return;
1600+
1601+
if (qgroup->kobj.state_initialized) {
1602+
kobject_del(&qgroup->kobj);
1603+
kobject_put(&qgroup->kobj);
1604+
}
1605+
}
14581606

14591607
/*
14601608
* Change per-fs features in /sys/fs/btrfs/UUID/features to match current

fs/btrfs/sysfs.h

+7
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,11 @@ int btrfs_sysfs_add_space_info_type(struct btrfs_fs_info *fs_info,
3636
void btrfs_sysfs_remove_space_info(struct btrfs_space_info *space_info);
3737
void btrfs_sysfs_update_devid(struct btrfs_device *device);
3838

39+
int btrfs_sysfs_add_one_qgroup(struct btrfs_fs_info *fs_info,
40+
struct btrfs_qgroup *qgroup);
41+
void btrfs_sysfs_del_qgroups(struct btrfs_fs_info *fs_info);
42+
int btrfs_sysfs_add_qgroups(struct btrfs_fs_info *fs_info);
43+
void btrfs_sysfs_del_one_qgroup(struct btrfs_fs_info *fs_info,
44+
struct btrfs_qgroup *qgroup);
45+
3946
#endif

0 commit comments

Comments
 (0)