|  | 
| 19 | 19 | #include "volumes.h" | 
| 20 | 20 | #include "space-info.h" | 
| 21 | 21 | #include "block-group.h" | 
|  | 22 | +#include "qgroup.h" | 
| 22 | 23 | 
 | 
| 23 | 24 | struct btrfs_feature_attr { | 
| 24 | 25 | 	struct kobj_attribute kobj_attr; | 
| @@ -1455,6 +1456,153 @@ int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info) | 
| 1455 | 1456 | 	return error; | 
| 1456 | 1457 | } | 
| 1457 | 1458 | 
 | 
|  | 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 | +} | 
| 1458 | 1606 | 
 | 
| 1459 | 1607 | /* | 
| 1460 | 1608 |  * Change per-fs features in /sys/fs/btrfs/UUID/features to match current | 
|  | 
0 commit comments