All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup.
@ 2015-03-19  6:00 Dongsheng Yang
  2015-03-19  6:00 ` [PATCH 1/4] Btrfs-progs: qgroup: add incompatability feature for QGROUP_TYPE Dongsheng Yang
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:00 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

Hi all,
	Okey, this is the V2 for the qgroup type. In this version, we
account both of the data and metadata in a qgroup and you can limit
data or metadata or mixed. You can limit them at the same time.

(a). I restructed the btrfs_qgroup in memory:

btrfs_qgroup:                                     |-------------|
-----------------                                 |rfer         |
|data_info      |--------------->btrfs_qgroup_info|rfer_cmpr    |
|metadata_info  |                                 |excl         |
|               |                                 |excl_cmpr    |
|data_limits    |                                 ---------------
|metadata_limits|
|mixed_limits   |--------------->btrfs_qgroup_limits|-------------
|-------------- |                                   |lim_flags  |
                                                    |max_rfer   |
                                                    |max_excl   |
                                                    |rsv_rfer   |
                                                    |rsv_excl   |
                                                    ------------
In this way, we can store the information for data and metadata separately.
And we can limit then in three ways: data_limits, metadata_limits and mixed_limits.

(b). I have to add a incompatability feature for it.
I reuse the objectid to search btrfs_qgroup_info_item.

------------------------------------              ------------------------------------------------
|0 |BTRFS_QGROUP_INFO_KEY |qgroupid| ------------>|TYPE_OBJECTID |BTRFS_QGROUP_INFO_KEY |qgroupid|
------------------------------------              ------------------------------------------------

And introduce two macros for different type of infos.

	#define BTRFS_QGROUP_DATA_INFO_OBJECTID 1ULL
	#define BTRFS_QGROUP_METADATA_INFO_OBJECTID 2ULL
There is a similar change for limits.

(c). Testing.
	Hi Chris and David, as what I mentioned in a offline mail, there is a url for merging or
testing.
	btrfs: https://yangdongsheng@github.com/yangdongsheng/linux.git qgroup_type_v2
  btrfs-progs: https://yangdongsheng@github.com/yangdongsheng/btrfs-progs.git qgroup_type_v2


(1). btrfs/022 and btrfs/042
				kernel.v4.0-4c1		kernel.qgroup_type.patched
v3.19-rc2(progs)		 pass				pass
Patched(progs)			 pass				pass

(2). No qgroup type.
Script:
	# mkfs.btrfs  /dev/sdc -f
	# mount /dev/sdc /mnt
	# btrfs quota enable /mnt
	# btrfs quota rescan -w /mnt
	# btrfs sub create /mnt/sub
	# btrfs qgroup limit -e 10M 0/257 /mnt
	# dd if=/dev/zero of=/mnt/sub/data bs=1024 count=1000000
	# sync
	# btrfs qgroup show -prce --raw /mnt
Expected:
	dd: error writing '/mnt/sub/data': Disk quota exceeded
	10145+0 records in
	10144+0 records out
	10387456 bytes (10 MB) copied, 0.0368423 s, 282 MB/s
	qgroupid         rfer         excl     max_rfer     max_excl parent  child 
	--------         ----         ----     --------     -------- ------  ----- 
	0/5             16384        16384            0            0 ---     ---  
	0/257        10403840     10403840            0            0 ---     ---  


			kernel.v4.0-4c1.bugfix_patched		kernel.qgroup_type.patched
v3.19-rc2(progs)		 pass					pass
Patched(progs)			 pass					pass

(3) qgroup type.
Script:
	# mkfs.btrfs -O qgroup-type /dev/sdc -f
	# mount /dev/sdc /mnt
	# btrfs quota enable /mnt
	# btrfs quota rescan -w /mnt
	# btrfs sub create /mnt/sub
	# btrfs qgroup limit --type data -e 10M 0/257 /mnt
	# dd if=/dev/zero of=/mnt/sub/data bs=1024 count=1000000
	# sync
	# btrfs qgroup show -prce --raw --type data /mnt
	# btrfs qgroup show -prce --raw --type metadata /mnt
	# btrfs qgroup show -prce --raw --type mixed /mnt

			kernel.v4.0-4c1.bugfix_patched		kernel.qgroup_type.patched
v3.19-rc2(progs)	mkfs fail(no feature for qgroup-type)	mkfs fail(no feature for qgroup-type)
Patched(progs)		open_ctree failed. (Expected)			result as below. (pass)

Result:
	dd: error writing '/mnt/sub/data': Disk quota exceeded
	10241+0 records in
	10240+0 records out							  <------10240 means 10M
	10485760 bytes (10 MB) copied, 0.0331533 s, 316 MB/s
	qgroupid         rfer         excl     max_rfer     max_excl parent  child 
	--------         ----         ----     --------     -------- ------  ----- 
	0/5                 0            0            0            0 ---     ---  
	0/257        10485760     10485760            0     10485760 ---     ---  <------DATA info and limits
	qgroupid         rfer         excl     max_rfer     max_excl parent  child 
	--------         ----         ----     --------     -------- ------  ----- 
	0/5             16384        16384            0            0 ---     ---  
	0/257           16384        16384            0            0 ---     ---  <------METADATA info and limits
	qgroupid         rfer         excl     max_rfer     max_excl parent  child 
	--------         ----         ----     --------     -------- ------  ----- 
	0/5             16384        16384            0            0 ---     ---  
	0/257        10502144     10502144            0            0 ---     ---  <------MIXED info and limits

After all, you can use btrfs-debug-tree tool to show the details for each items.

Any comment or test are welcome !!!

Thanx
Yang

Dongsheng Yang (7):
  Btrfs: qgroup: split information and limits in qgroup to other
    structures.
  Btrfs: qgroup: add incompatability feature for QGROUP_TYPE.
  Btrfs: qgroup: record and account ref for qgroup in different type.
  Btrfs: qgroup: update all infos and limits to disk.
  Btrfs: qgroup: update quota numbers in btrfs_qgroup_inherit.
  Btrfs: qgroup: account data and metadata separately in rescan.
  Btrfs: qgroup: allow user to limit qgroup in different type.

 fs/btrfs/ctree.h              |  20 +-
 fs/btrfs/extent-tree.c        |  48 ++--
 fs/btrfs/qgroup.c             | 536 +++++++++++++++++++++++++++++++++---------
 fs/btrfs/qgroup.h             |  52 +++-
 fs/btrfs/tests/qgroup-tests.c |  15 +-
 fs/btrfs/transaction.c        |  11 +-
 6 files changed, 534 insertions(+), 148 deletions(-)

-- 
1.8.4.2


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/4] Btrfs-progs: qgroup: add incompatability feature for QGROUP_TYPE.
  2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
@ 2015-03-19  6:00 ` Dongsheng Yang
  2015-03-19  6:00 ` [PATCH 1/7] Btrfs: qgroup: split information and limits in qgroup to other structures Dongsheng Yang
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:00 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

This patch splits info and limits from qgroup.

    btrfs_qgroup:                                     |-------------|
    -----------------                                 |rfer         |
    |data_info      |--------------->btrfs_qgroup_info|rfer_cmpr    |
    |metadata_info  |                                 |excl         |
    |               |                                 |excl_cmpr    |
    |data_limits    |                                 ---------------
    |metadata_limits|
    |mixed_limits   |--------------->btrfs_qgroup_limits|-------------
    |-------------- |                                   |lim_flags  |
                                                        |max_rfer   |
                                                        |max_excl   |
                                                        |rsv_rfer   |
                                                        |rsv_excl   |
                                                        ------------

And the objectid for each items are changed:
    ------------------------------------              ------------------------------------------------
    |0 |BTRFS_QGROUP_INFO_KEY |qgroupid| ------------>|TYPE_OBJECTID |BTRFS_QGROUP_INFO_KEY |qgroupid|
    ------------------------------------              ------------------------------------------------

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 ctree.h  |  20 ++++++-
 mkfs.c   |   2 +
 qgroup.c | 184 +++++++++++++++++++++++++++++++++++++++++++--------------------
 3 files changed, 147 insertions(+), 59 deletions(-)

diff --git a/ctree.h b/ctree.h
index 2d2988b..85d4992 100644
--- a/ctree.h
+++ b/ctree.h
@@ -125,6 +125,22 @@ struct btrfs_free_space_ctl;
 #define BTRFS_DEV_ITEMS_OBJECTID 1ULL
 
 /*
+ *  * the items for qgroup info.
+ *   */
+#define BTRFS_QGROUP_DATA_INFO_OBJECTID 1ULL
+
+#define BTRFS_QGROUP_METADATA_INFO_OBJECTID 2ULL
+
+/*
+ *  * the items for qgroup limits.
+ *   */
+#define BTRFS_QGROUP_DATA_LIMIT_OBJECTID 1ULL
+
+#define BTRFS_QGROUP_METADATA_LIMIT_OBJECTID 2ULL
+
+#define BTRFS_QGROUP_MIXED_LIMIT_OBJECTID 3ULL
+
+/*
  * the max metadata block size.  This limit is somewhat artificial,
  * but the memmove costs go through the roof for larger blocks.
  */
@@ -473,6 +489,7 @@ struct btrfs_super_block {
 #define BTRFS_FEATURE_INCOMPAT_RAID56		(1ULL << 7)
 #define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA	(1ULL << 8)
 #define BTRFS_FEATURE_INCOMPAT_NO_HOLES		(1ULL << 9)
+#define BTRFS_FEATURE_INCOMPAT_QGROUP_TYPE	(1ULL << 10)
 
 
 #define BTRFS_FEATURE_COMPAT_SUPP		0ULL
@@ -486,7 +503,8 @@ struct btrfs_super_block {
 	 BTRFS_FEATURE_INCOMPAT_RAID56 |		\
 	 BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS |		\
 	 BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA |	\
-	 BTRFS_FEATURE_INCOMPAT_NO_HOLES)
+	 BTRFS_FEATURE_INCOMPAT_NO_HOLES |		\
+	 BTRFS_FEATURE_INCOMPAT_QGROUP_TYPE)
 
 /*
  * A leaf is full of items. offset and size tell us where to find
diff --git a/mkfs.c b/mkfs.c
index f83554d..de7612b 100644
--- a/mkfs.c
+++ b/mkfs.c
@@ -1143,6 +1143,8 @@ static const struct btrfs_fs_feature {
 		"reduced-size metadata extent refs" },
 	{ "no-holes", BTRFS_FEATURE_INCOMPAT_NO_HOLES,
 		"no explicit hole extents for files" },
+	{ "qgroup-type", BTRFS_FEATURE_INCOMPAT_QGROUP_TYPE,
+		"account data and metadata separately" },
 	/* Keep this one last */
 	{ "list-all", BTRFS_FEATURE_LIST_ALL, NULL }
 };
diff --git a/qgroup.c b/qgroup.c
index 5a4e393..91e25ea 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -30,6 +30,26 @@ struct qgroup_lookup {
 	struct rb_root root;
 };
 
+struct btrfs_qgroup_info {
+        u64 rfer;       /* referenced */
+        u64 rfer_cmpr;  /* referenced compressed */
+        u64 excl;       /* exclusive */
+        u64 excl_cmpr;  /* exclusive compressed */
+
+        /*
+	 * reservation tracking
+	 */
+        u64 reserved;
+};
+
+struct btrfs_qgroup_limits {
+        u64 flags;  /* which limits are set */
+        u64 max_rfer;
+        u64 max_excl;
+        u64 rsv_rfer;
+        u64 rsv_excl;
+};
+
 struct btrfs_qgroup {
 	struct rb_node rb_node;
 	struct rb_node sort_node;
@@ -40,23 +60,20 @@ struct btrfs_qgroup {
 	struct rb_node all_parent_node;
 	u64 qgroupid;
 
+	u64 generation;
+
 	/*
 	 * info_item
 	 */
-	u64 generation;
-	u64 rfer;	/*referenced*/
-	u64 rfer_cmpr;	/*referenced compressed*/
-	u64 excl;	/*exclusive*/
-	u64 excl_cmpr;	/*exclusive compressed*/
+	struct btrfs_qgroup_info        data_info;
+	struct btrfs_qgroup_info        metadata_info;
 
 	/*
 	 *limit_item
 	 */
-	u64 flags;	/*which limits are set*/
-	u64 max_rfer;
-	u64 max_excl;
-	u64 rsv_rfer;
-	u64 rsv_excl;
+	struct btrfs_qgroup_limits      data_limits;
+	struct btrfs_qgroup_limits      metadata_limits;
+	struct btrfs_qgroup_limits      mixed_limits;
 
 	/*qgroups this group is member of*/
 	struct list_head qgroups;
@@ -215,6 +232,8 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 	int len;
 	int unit_mode = btrfs_qgroup_columns[column].unit_mode;
 	int max_len = btrfs_qgroup_columns[column].max_len;
+	struct btrfs_qgroup_info *info = &qgroup->data_info;
+	struct btrfs_qgroup_limits *limits = &qgroup->mixed_limits;
 
 	switch (column) {
 
@@ -224,20 +243,20 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 		print_qgroup_column_add_blank(BTRFS_QGROUP_QGROUPID, len);
 		break;
 	case BTRFS_QGROUP_RFER:
-		len = printf("%*s", max_len, pretty_size_mode(qgroup->rfer, unit_mode));
+		len = printf("%*s", max_len, pretty_size_mode(info->rfer, unit_mode));
 		break;
 	case BTRFS_QGROUP_EXCL:
-		len = printf("%*s", max_len, pretty_size_mode(qgroup->excl, unit_mode));
+		len = printf("%*s", max_len, pretty_size_mode(info->excl, unit_mode));
 		break;
 	case BTRFS_QGROUP_PARENT:
 		len = print_parent_column(qgroup);
 		print_qgroup_column_add_blank(BTRFS_QGROUP_PARENT, len);
 		break;
 	case BTRFS_QGROUP_MAX_RFER:
-		len = printf("%*s", max_len, pretty_size_mode(qgroup->max_rfer, unit_mode));
+		len = printf("%*s", max_len, pretty_size_mode(limits->max_rfer, unit_mode));
 		break;
 	case BTRFS_QGROUP_MAX_EXCL:
-		len = printf("%*s", max_len, pretty_size_mode(qgroup->max_excl, unit_mode));
+		len = printf("%*s", max_len, pretty_size_mode(limits->max_excl, unit_mode));
 		break;
 	case BTRFS_QGROUP_CHILD:
 		len = print_child_column(qgroup);
@@ -333,10 +352,12 @@ static int comp_entry_with_rfer(struct btrfs_qgroup *entry1,
 				int is_descending)
 {
 	int ret;
+	struct btrfs_qgroup_info *info1 = &entry1->data_info;
+	struct btrfs_qgroup_info *info2 = &entry2->data_info;
 
-	if (entry1->rfer > entry2->rfer)
+	if (info1->rfer > info2->rfer)
 		ret = 1;
-	else if (entry1->rfer < entry2->rfer)
+	else if (info1->rfer < info2->rfer)
 		ret = -1;
 	else
 		ret = 0;
@@ -349,10 +370,12 @@ static int comp_entry_with_excl(struct btrfs_qgroup *entry1,
 				int is_descending)
 {
 	int ret;
+	struct btrfs_qgroup_info *info1 = &entry1->data_info;
+	struct btrfs_qgroup_info *info2 = &entry2->data_info;
 
-	if (entry1->excl > entry2->excl)
+	if (info1->excl > info2->excl)
 		ret = 1;
-	else if (entry1->excl < entry2->excl)
+	else if (info1->excl < info2->excl)
 		ret = -1;
 	else
 		ret = 0;
@@ -365,10 +388,12 @@ static int comp_entry_with_max_rfer(struct btrfs_qgroup *entry1,
 				    int is_descending)
 {
 	int ret;
+	struct btrfs_qgroup_limits *limits1 = &entry1->mixed_limits;
+	struct btrfs_qgroup_limits *limits2 = &entry2->mixed_limits;
 
-	if (entry1->max_rfer > entry2->max_rfer)
+	if (limits1->max_rfer > limits2->max_rfer)
 		ret = 1;
-	else if (entry1->max_rfer < entry2->max_rfer)
+	else if (limits1->max_rfer < limits2->max_rfer)
 		ret = -1;
 	else
 		ret = 0;
@@ -381,10 +406,12 @@ static int comp_entry_with_max_excl(struct btrfs_qgroup *entry1,
 				    int is_descending)
 {
 	int ret;
+	struct btrfs_qgroup_limits *limits1 = &entry1->mixed_limits;
+	struct btrfs_qgroup_limits *limits2 = &entry2->mixed_limits;
 
-	if (entry1->max_excl > entry2->max_excl)
+	if (limits1->max_excl > limits2->max_excl)
 		ret = 1;
-	else if (entry1->max_excl < entry2->max_excl)
+	else if (limits1->max_excl < limits2->max_excl)
 		ret = -1;
 	else
 		ret = 0;
@@ -571,12 +598,14 @@ static struct btrfs_qgroup *qgroup_tree_search(struct qgroup_lookup *root_tree,
 }
 
 static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
-			 u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
-			 u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
-			 u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *pa,
-			 struct btrfs_qgroup *child)
+			 u64 generation, u64 info_id, u64 rfer, u64 rfer_cmpr,
+			 u64 excl, u64 excl_cmpr, u64 limit_id, u64 flags,
+			 u64 max_rfer, u64 max_excl, u64 rsv_rfer, u64 rsv_excl,
+			 struct btrfs_qgroup *pa, struct btrfs_qgroup *child)
 {
 	struct btrfs_qgroup *bq;
+	struct btrfs_qgroup_info *info;
+	struct btrfs_qgroup_limits *limits;
 	struct btrfs_qgroup_list *list;
 
 	bq = qgroup_tree_search(qgroup_lookup, qgroupid);
@@ -585,22 +614,32 @@ static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
 
 	if (generation)
 		bq->generation = generation;
+	if (info_id == BTRFS_QGROUP_DATA_INFO_OBJECTID)
+		info = &bq->data_info;
+	else
+		info = &bq->metadata_info;
 	if (rfer)
-		bq->rfer = rfer;
+		info->rfer = rfer;
 	if (rfer_cmpr)
-		bq->rfer_cmpr = rfer_cmpr;
+		info->rfer_cmpr = rfer_cmpr;
 	if (excl)
-		bq->excl = excl;
+		info->excl = excl;
 	if (excl_cmpr)
-		bq->excl_cmpr = excl_cmpr;
+		info->excl_cmpr = excl_cmpr;
+	if (limit_id == BTRFS_QGROUP_DATA_LIMIT_OBJECTID)
+		limits = &bq->data_limits;
+	else if (limit_id == BTRFS_QGROUP_METADATA_LIMIT_OBJECTID)
+		limits = &bq->metadata_limits;
+	else
+		limits = &bq->mixed_limits;
 	if (flags)
-		bq->flags = flags;
+		limits->flags = flags;
 	if (max_rfer)
-		bq->max_rfer = max_rfer;
+		limits->max_rfer = max_rfer;
 	if (max_excl)
-		bq->max_excl = max_excl;
+		limits->max_excl = max_excl;
 	if (rsv_rfer)
-		bq->rsv_rfer = rsv_rfer;
+		limits->rsv_rfer = rsv_rfer;
 	if (pa && child) {
 		list = malloc(sizeof(*list));
 		if (!list) {
@@ -616,17 +655,19 @@ static int update_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
 }
 
 static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
-		      u64 generation, u64 rfer, u64 rfer_cmpr, u64 excl,
-		      u64 excl_cmpr, u64 flags, u64 max_rfer, u64 max_excl,
-		      u64 rsv_rfer, u64 rsv_excl, struct btrfs_qgroup *parent,
-		      struct btrfs_qgroup *child)
+		      u64 generation, u64 info_id, u64 rfer, u64 rfer_cmpr,
+		      u64 excl, u64 excl_cmpr, u64 limit_id, u64 flags,
+		      u64 max_rfer, u64 max_excl, u64 rsv_rfer, u64 rsv_excl,
+		      struct btrfs_qgroup *parent, struct btrfs_qgroup *child)
 {
 	struct btrfs_qgroup *bq;
+	struct btrfs_qgroup_info *info;
+	struct btrfs_qgroup_limits *limits;
 	struct btrfs_qgroup_list *list;
 	int ret;
 
-	ret = update_qgroup(qgroup_lookup, qgroupid, generation, rfer,
-			    rfer_cmpr, excl, excl_cmpr, flags, max_rfer,
+	ret = update_qgroup(qgroup_lookup, qgroupid, generation, info_id, rfer,
+			    rfer_cmpr, excl, excl_cmpr, limit_id, flags, max_rfer,
 			    max_excl, rsv_rfer, rsv_excl, parent, child);
 	if (!ret)
 		return 0;
@@ -644,22 +685,32 @@ static int add_qgroup(struct qgroup_lookup *qgroup_lookup, u64 qgroupid,
 	}
 	if (generation)
 		bq->generation = generation;
+	if (info_id == BTRFS_QGROUP_DATA_INFO_OBJECTID)
+		info = &bq->data_info;
+	else
+		info = &bq->metadata_info;
 	if (rfer)
-		bq->rfer = rfer;
+		info->rfer = rfer;
 	if (rfer_cmpr)
-		bq->rfer_cmpr = rfer_cmpr;
+		info->rfer_cmpr = rfer_cmpr;
 	if (excl)
-		bq->excl = excl;
+		info->excl = excl;
 	if (excl_cmpr)
-		bq->excl_cmpr = excl_cmpr;
+		info->excl_cmpr = excl_cmpr;
+	if (limit_id == BTRFS_QGROUP_DATA_LIMIT_OBJECTID)
+		limits = &bq->data_limits;
+	else if (limit_id == BTRFS_QGROUP_METADATA_LIMIT_OBJECTID)
+		limits = &bq->metadata_limits;
+	else
+		limits = &bq->mixed_limits;
 	if (flags)
-		bq->flags = flags;
+		limits->flags = flags;
 	if (max_rfer)
-		bq->max_rfer = max_rfer;
+		limits->max_rfer = max_rfer;
 	if (max_excl)
-		bq->max_excl = max_excl;
+		limits->max_excl = max_excl;
 	if (rsv_rfer)
-		bq->rsv_rfer = rsv_rfer;
+		limits->rsv_rfer = rsv_rfer;
 	if (parent && child) {
 		list = malloc(sizeof(*list));
 		if (!list) {
@@ -917,6 +968,8 @@ static void __update_columns_max_len(struct btrfs_qgroup *bq,
 	char tmp[100];
 	int len;
 	unsigned unit_mode = btrfs_qgroup_columns[column].unit_mode;
+	struct btrfs_qgroup_info *info = &bq->data_info;
+	struct btrfs_qgroup_limits *limits = &bq->mixed_limits;
 
 	switch (column) {
 
@@ -928,22 +981,22 @@ static void __update_columns_max_len(struct btrfs_qgroup *bq,
 			btrfs_qgroup_columns[column].max_len = len;
 		break;
 	case BTRFS_QGROUP_RFER:
-		len = strlen(pretty_size_mode(bq->rfer, unit_mode));
+		len = strlen(pretty_size_mode(info->rfer, unit_mode));
 		if (btrfs_qgroup_columns[column].max_len < len)
 			btrfs_qgroup_columns[column].max_len = len;
 		break;
 	case BTRFS_QGROUP_EXCL:
-		len = strlen(pretty_size_mode(bq->excl, unit_mode));
+		len = strlen(pretty_size_mode(info->excl, unit_mode));
 		if (btrfs_qgroup_columns[column].max_len < len)
 			btrfs_qgroup_columns[column].max_len = len;
 		break;
 	case BTRFS_QGROUP_MAX_RFER:
-		len = strlen(pretty_size_mode(bq->max_rfer, unit_mode));
+		len = strlen(pretty_size_mode(limits->max_rfer, unit_mode));
 		if (btrfs_qgroup_columns[column].max_len < len)
 			btrfs_qgroup_columns[column].max_len = len;
 		break;
 	case BTRFS_QGROUP_MAX_EXCL:
-		len = strlen(pretty_size_mode(bq->max_excl, unit_mode));
+		len = strlen(pretty_size_mode(limits->max_excl, unit_mode));
 		if (btrfs_qgroup_columns[column].max_len < len)
 			btrfs_qgroup_columns[column].max_len = len;
 		break;
@@ -1063,6 +1116,8 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 		 * read the root_ref item it contains
 		 */
 		for (i = 0; i < sk->nr_items; i++) {
+			u64 objectid = 0;
+
 			sh = (struct btrfs_ioctl_search_header *)(args.buf +
 								  off);
 			off += sizeof(*sh);
@@ -1079,8 +1134,15 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 				a5 =
 				  btrfs_stack_qgroup_info_exclusive_compressed
 				  (info);
-				add_qgroup(qgroup_lookup, sh->offset, a1, a2,
-					   a3, a4, a5, 0, 0, 0, 0, 0, 0, 0);
+
+				objectid = BTRFS_QGROUP_DATA_INFO_OBJECTID;
+				/*
+				 * Check incompatability of qgroup->type.
+				 */
+				if (sh->objectid != 0)
+					objectid = sh->objectid;
+				add_qgroup(qgroup_lookup, sh->offset, a1, objectid,
+					   a2, a3, a4, a5, 0, 0, 0, 0, 0, 0, 0, 0);
 			} else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) {
 				limit = (struct btrfs_qgroup_limit_item *)
 				    (args.buf + off);
@@ -1094,8 +1156,14 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 				     (limit);
 				a5 = btrfs_stack_qgroup_limit_rsv_exclusive
 				     (limit);
-				add_qgroup(qgroup_lookup, sh->offset, 0, 0,
-					   0, 0, 0, a1, a2, a3, a4, a5, 0, 0);
+				objectid = BTRFS_QGROUP_MIXED_LIMIT_OBJECTID;
+				/*
+				 * Check incompatability of qgroup->type.
+				 */
+				if (sh->objectid != 0)
+					objectid = sh->objectid;
+				add_qgroup(qgroup_lookup, sh->offset, 0, 0, 0,
+					   0, 0, 0, objectid, a1, a2, a3, a4, a5, 0, 0);
 			} else if (sh->type == BTRFS_QGROUP_RELATION_KEY) {
 				if (sh->offset < sh->objectid)
 					goto skip;
@@ -1107,8 +1175,8 @@ static int __qgroups_search(int fd, struct qgroup_lookup *qgroup_lookup)
 							 sh->objectid);
 				if (!bq1)
 					goto skip;
-				add_qgroup(qgroup_lookup, sh->offset, 0, 0,
-					   0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
+				add_qgroup(qgroup_lookup, sh->offset, 0, 0, 0,
+					   0, 0, 0, 0, 0, 0, 0, 0, 0, bq, bq1);
 			} else
 				goto done;
 skip:
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 1/7] Btrfs: qgroup: split information and limits in qgroup to other structures.
  2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
  2015-03-19  6:00 ` [PATCH 1/4] Btrfs-progs: qgroup: add incompatability feature for QGROUP_TYPE Dongsheng Yang
@ 2015-03-19  6:00 ` Dongsheng Yang
  2015-03-19  6:00 ` [PATCH 2/4] Btrfs-progs: qgroup: print info and limits type in btrfs-debug-tree Dongsheng Yang
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:00 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

Restruct the btrfs_qgroup structure:

btrfs_qgroup:                                     |-------------|
-----------------                                 |rfer         |
|data_info      |--------------->btrfs_qgroup_info|rfer_cmpr    |
|metadata_info  |                                 |excl         |
|               |                                 |excl_cmpr    |
|data_limits    |                                 ---------------
|metadata_limits|
|mixed_limits   |--------------->btrfs_qgroup_limits|-------------
|-------------- |                                   |lim_flags  |
                                                    |max_rfer   |
                                                    |max_excl   |
                                                    |rsv_rfer   |
                                                    |rsv_excl   |
                                                    ------------

Then we can account data and metadata separately. And we can limit them
separately. mixed_limits is provided to limit the sum of data and metadata.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 fs/btrfs/qgroup.c | 308 +++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 214 insertions(+), 94 deletions(-)

diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 28b0aa5..dd99908 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -46,33 +46,44 @@
  *  - check all ioctl parameters
  */
 
-/*
- * one struct for each qgroup, organized in fs_info->qgroup_tree.
- */
-struct btrfs_qgroup {
-	u64 qgroupid;
-
-	/*
-	 * state
-	 */
+struct btrfs_qgroup_info {
 	u64 rfer;	/* referenced */
 	u64 rfer_cmpr;	/* referenced compressed */
 	u64 excl;	/* exclusive */
 	u64 excl_cmpr;	/* exclusive compressed */
 
 	/*
-	 * limits
+	 * reservation tracking
 	 */
+	u64 reserved;
+};
+
+struct btrfs_qgroup_limits {
 	u64 lim_flags;	/* which limits are set */
 	u64 max_rfer;
 	u64 max_excl;
 	u64 rsv_rfer;
 	u64 rsv_excl;
+};
+
+/*
+ * one struct for each qgroup, organized in fs_info->qgroup_tree.
+ */
+struct btrfs_qgroup {
+	u64 qgroupid;
 
 	/*
-	 * reservation tracking
+	 * infos
 	 */
-	u64 reserved;
+	struct btrfs_qgroup_info	data_info;
+	struct btrfs_qgroup_info	metadata_info;
+
+	/*
+	 * limits
+	 */
+	struct btrfs_qgroup_limits	data_limits;
+	struct btrfs_qgroup_limits	metadata_limits;
+	struct btrfs_qgroup_limits	mixed_limits;
 
 	/*
 	 * lists
@@ -251,11 +262,13 @@ int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid,
 			       u64 rfer, u64 excl)
 {
 	struct btrfs_qgroup *qgroup;
+	struct btrfs_qgroup_info *info;
 
 	qgroup = find_qgroup_rb(fs_info, qgroupid);
 	if (!qgroup)
 		return -EINVAL;
-	if (qgroup->rfer != rfer || qgroup->excl != excl)
+	info = &qgroup->data_info;
+	if (info->rfer != rfer || info->excl != excl)
 		return -EINVAL;
 	return 0;
 }
@@ -357,26 +370,30 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
 		switch (found_key.type) {
 		case BTRFS_QGROUP_INFO_KEY: {
 			struct btrfs_qgroup_info_item *ptr;
+			struct btrfs_qgroup_info *info;
 
+			info = &qgroup->data_info;
 			ptr = btrfs_item_ptr(l, slot,
 					     struct btrfs_qgroup_info_item);
-			qgroup->rfer = btrfs_qgroup_info_rfer(l, ptr);
-			qgroup->rfer_cmpr = btrfs_qgroup_info_rfer_cmpr(l, ptr);
-			qgroup->excl = btrfs_qgroup_info_excl(l, ptr);
-			qgroup->excl_cmpr = btrfs_qgroup_info_excl_cmpr(l, ptr);
+			info->rfer = btrfs_qgroup_info_rfer(l, ptr);
+			info->rfer_cmpr = btrfs_qgroup_info_rfer_cmpr(l, ptr);
+			info->excl = btrfs_qgroup_info_excl(l, ptr);
+			info->excl_cmpr = btrfs_qgroup_info_excl_cmpr(l, ptr);
 			/* generation currently unused */
 			break;
 		}
 		case BTRFS_QGROUP_LIMIT_KEY: {
 			struct btrfs_qgroup_limit_item *ptr;
+			struct btrfs_qgroup_limits *limits;
 
+			limits = &qgroup->mixed_limits;
 			ptr = btrfs_item_ptr(l, slot,
 					     struct btrfs_qgroup_limit_item);
-			qgroup->lim_flags = btrfs_qgroup_limit_flags(l, ptr);
-			qgroup->max_rfer = btrfs_qgroup_limit_max_rfer(l, ptr);
-			qgroup->max_excl = btrfs_qgroup_limit_max_excl(l, ptr);
-			qgroup->rsv_rfer = btrfs_qgroup_limit_rsv_rfer(l, ptr);
-			qgroup->rsv_excl = btrfs_qgroup_limit_rsv_excl(l, ptr);
+			limits->lim_flags = btrfs_qgroup_limit_flags(l, ptr);
+			limits->max_rfer = btrfs_qgroup_limit_max_rfer(l, ptr);
+			limits->max_excl = btrfs_qgroup_limit_max_excl(l, ptr);
+			limits->rsv_rfer = btrfs_qgroup_limit_rsv_rfer(l, ptr);
+			limits->rsv_excl = btrfs_qgroup_limit_rsv_excl(l, ptr);
 			break;
 		}
 		}
@@ -651,6 +668,7 @@ static int update_qgroup_limit_item(struct btrfs_trans_handle *trans,
 	struct btrfs_key key;
 	struct extent_buffer *l;
 	struct btrfs_qgroup_limit_item *qgroup_limit;
+	struct btrfs_qgroup_limits *limits;
 	int ret;
 	int slot;
 
@@ -669,14 +687,16 @@ static int update_qgroup_limit_item(struct btrfs_trans_handle *trans,
 	if (ret)
 		goto out;
 
+	limits = &qgroup->mixed_limits;
+
 	l = path->nodes[0];
 	slot = path->slots[0];
 	qgroup_limit = btrfs_item_ptr(l, slot, struct btrfs_qgroup_limit_item);
-	btrfs_set_qgroup_limit_flags(l, qgroup_limit, qgroup->lim_flags);
-	btrfs_set_qgroup_limit_max_rfer(l, qgroup_limit, qgroup->max_rfer);
-	btrfs_set_qgroup_limit_max_excl(l, qgroup_limit, qgroup->max_excl);
-	btrfs_set_qgroup_limit_rsv_rfer(l, qgroup_limit, qgroup->rsv_rfer);
-	btrfs_set_qgroup_limit_rsv_excl(l, qgroup_limit, qgroup->rsv_excl);
+	btrfs_set_qgroup_limit_flags(l, qgroup_limit, limits->lim_flags);
+	btrfs_set_qgroup_limit_max_rfer(l, qgroup_limit, limits->max_rfer);
+	btrfs_set_qgroup_limit_max_excl(l, qgroup_limit, limits->max_excl);
+	btrfs_set_qgroup_limit_rsv_rfer(l, qgroup_limit, limits->rsv_rfer);
+	btrfs_set_qgroup_limit_rsv_excl(l, qgroup_limit, limits->rsv_excl);
 
 	btrfs_mark_buffer_dirty(l);
 
@@ -693,6 +713,7 @@ static int update_qgroup_info_item(struct btrfs_trans_handle *trans,
 	struct btrfs_key key;
 	struct extent_buffer *l;
 	struct btrfs_qgroup_info_item *qgroup_info;
+	struct btrfs_qgroup_info *data_info;
 	int ret;
 	int slot;
 
@@ -714,14 +735,16 @@ static int update_qgroup_info_item(struct btrfs_trans_handle *trans,
 	if (ret)
 		goto out;
 
+	data_info = &qgroup->data_info;
+
 	l = path->nodes[0];
 	slot = path->slots[0];
 	qgroup_info = btrfs_item_ptr(l, slot, struct btrfs_qgroup_info_item);
 	btrfs_set_qgroup_info_generation(l, qgroup_info, trans->transid);
-	btrfs_set_qgroup_info_rfer(l, qgroup_info, qgroup->rfer);
-	btrfs_set_qgroup_info_rfer_cmpr(l, qgroup_info, qgroup->rfer_cmpr);
-	btrfs_set_qgroup_info_excl(l, qgroup_info, qgroup->excl);
-	btrfs_set_qgroup_info_excl_cmpr(l, qgroup_info, qgroup->excl_cmpr);
+	btrfs_set_qgroup_info_rfer(l, qgroup_info, data_info->rfer);
+	btrfs_set_qgroup_info_rfer_cmpr(l, qgroup_info, data_info->rfer_cmpr);
+	btrfs_set_qgroup_info_excl(l, qgroup_info, data_info->excl);
+	btrfs_set_qgroup_info_excl_cmpr(l, qgroup_info, data_info->excl_cmpr);
 
 	btrfs_mark_buffer_dirty(l);
 
@@ -1203,6 +1226,7 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
 {
 	struct btrfs_root *quota_root;
 	struct btrfs_qgroup *qgroup;
+	struct btrfs_qgroup_limits *limits;
 	int ret = 0;
 
 	mutex_lock(&fs_info->qgroup_ioctl_lock);
@@ -1218,16 +1242,20 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
 		goto out;
 	}
 
+	/* To the compatibility, treat the mixed limits as the
+	 * default limits now. will change it later. */
+	limits = &qgroup->mixed_limits;
+
 	spin_lock(&fs_info->qgroup_lock);
 	if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_RFER)
-		qgroup->max_rfer = limit->max_rfer;
+		limits->max_rfer = limit->max_rfer;
 	if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_EXCL)
-		qgroup->max_excl = limit->max_excl;
+		limits->max_excl = limit->max_excl;
 	if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_RFER)
-		qgroup->rsv_rfer = limit->rsv_rfer;
+		limits->rsv_rfer = limit->rsv_rfer;
 	if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_EXCL)
-		qgroup->rsv_excl = limit->rsv_excl;
-	qgroup->lim_flags |= limit->flags;
+		limits->rsv_excl = limit->rsv_excl;
+	limits->lim_flags |= limit->flags;
 
 	spin_unlock(&fs_info->qgroup_lock);
 
@@ -1418,6 +1446,7 @@ static int qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
 				  struct btrfs_qgroup_operation *oper)
 {
 	struct btrfs_qgroup *qgroup;
+	struct btrfs_qgroup_info *info;
 	struct ulist *tmp;
 	struct btrfs_qgroup_list *glist;
 	struct ulist_node *unode;
@@ -1445,14 +1474,21 @@ static int qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
 	default:
 		ASSERT(0);
 	}
-	qgroup->rfer += sign * oper->num_bytes;
-	qgroup->rfer_cmpr += sign * oper->num_bytes;
 
-	WARN_ON(sign < 0 && qgroup->excl < oper->num_bytes);
-	qgroup->excl += sign * oper->num_bytes;
-	qgroup->excl_cmpr += sign * oper->num_bytes;
+	/*
+	 * FIXME: use the data_info to store all information currently.
+	 * will seperate the information into data and metadata later.
+	 **/
+	info = &qgroup->data_info;
+
+	info->rfer += sign * oper->num_bytes;
+	info->rfer_cmpr += sign * oper->num_bytes;
+
+	WARN_ON(sign < 0 && info->excl < oper->num_bytes);
+	info->excl += sign * oper->num_bytes;
+	info->excl_cmpr += sign * oper->num_bytes;
 	if (sign > 0)
-		qgroup->reserved -= oper->num_bytes;
+		info->reserved -= oper->num_bytes;
 
 	qgroup_dirty(fs_info, qgroup);
 
@@ -1468,13 +1504,18 @@ static int qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
 	ULIST_ITER_INIT(&uiter);
 	while ((unode = ulist_next(tmp, &uiter))) {
 		qgroup = u64_to_ptr(unode->aux);
-		qgroup->rfer += sign * oper->num_bytes;
-		qgroup->rfer_cmpr += sign * oper->num_bytes;
-		WARN_ON(sign < 0 && qgroup->excl < oper->num_bytes);
-		qgroup->excl += sign * oper->num_bytes;
+		/*
+		 * FIXME: use the data_info to store all information currently.
+		 * will seperate the information into data and metadata later.
+		 **/
+		info = &qgroup->data_info;
+		info->rfer += sign * oper->num_bytes;
+		info->rfer_cmpr += sign * oper->num_bytes;
+		WARN_ON(sign < 0 && info->excl < oper->num_bytes);
+		info->excl += sign * oper->num_bytes;
 		if (sign > 0)
-			qgroup->reserved -= oper->num_bytes;
-		qgroup->excl_cmpr += sign * oper->num_bytes;
+			info->reserved -= oper->num_bytes;
+		info->excl_cmpr += sign * oper->num_bytes;
 		qgroup_dirty(fs_info, qgroup);
 
 		/* Add any parents of the parents */
@@ -1740,6 +1781,7 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
 	struct ulist_node *unode;
 	struct ulist_iterator uiter;
 	struct btrfs_qgroup *qg;
+	struct btrfs_qgroup_info *data_info;
 	u64 cur_new_count, cur_old_count;
 
 	ULIST_ITER_INIT(&uiter);
@@ -1747,13 +1789,15 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
 		bool dirty = false;
 
 		qg = u64_to_ptr(unode->aux);
+
+		data_info = &qg->data_info;
 		/*
 		 * Wasn't referenced before but is now, add to the reference
 		 * counters.
 		 */
 		if (qg->old_refcnt <= seq && qg->new_refcnt > seq) {
-			qg->rfer += num_bytes;
-			qg->rfer_cmpr += num_bytes;
+			data_info->rfer += num_bytes;
+			data_info->rfer_cmpr += num_bytes;
 			dirty = true;
 		}
 
@@ -1762,8 +1806,8 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
 		 * reference counters.
 		 */
 		if (qg->old_refcnt > seq && qg->new_refcnt <= seq) {
-			qg->rfer -= num_bytes;
-			qg->rfer_cmpr -= num_bytes;
+			data_info->rfer -= num_bytes;
+			data_info->rfer_cmpr -= num_bytes;
 			dirty = true;
 		}
 
@@ -1784,8 +1828,13 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
 		if (old_roots && cur_old_count == old_roots &&
 		    (cur_new_count != new_roots || new_roots == 0)) {
 			WARN_ON(cur_new_count != new_roots && new_roots == 0);
-			qg->excl -= num_bytes;
-			qg->excl_cmpr -= num_bytes;
+			/*
+			 * FIXME: use the data_info to store all information currently.
+			 * will seperate the information into data and metadata later.
+			 **/
+			data_info = &qg->data_info;
+			data_info->excl -= num_bytes;
+			data_info->excl_cmpr -= num_bytes;
 			dirty = true;
 		}
 
@@ -1795,8 +1844,13 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
 		 */
 		if ((!old_roots || (old_roots && cur_old_count != old_roots))
 		    && cur_new_count == new_roots) {
-			qg->excl += num_bytes;
-			qg->excl_cmpr += num_bytes;
+			/*
+			 * FIXME: use the data_info to store all information currently.
+			 * will seperate the information into data and metadata later.
+			 **/
+			data_info = &qg->data_info;
+			data_info->excl += num_bytes;
+			data_info->excl_cmpr += num_bytes;
 			dirty = true;
 		}
 
@@ -2004,6 +2058,7 @@ static int qgroup_subtree_accounting(struct btrfs_trans_handle *trans,
 	struct ulist_iterator uiter;
 	struct btrfs_qgroup_list *glist;
 	struct ulist *parents;
+	struct btrfs_qgroup_info *info;
 	int ret = 0;
 	int err;
 	struct btrfs_qgroup *qg;
@@ -2049,9 +2104,13 @@ static int qgroup_subtree_accounting(struct btrfs_trans_handle *trans,
 	qg = find_qgroup_rb(fs_info, root_obj);
 	if (!qg)
 		goto out_unlock;
-
-	qg->excl += oper->num_bytes;
-	qg->excl_cmpr += oper->num_bytes;
+	/*
+	 * FIXME: use the data_info to store all information currently.
+	 * will seperate the information into data and metadata later.
+	 **/
+	info = &qg->data_info;
+	info->excl += oper->num_bytes;
+	info->excl_cmpr += oper->num_bytes;
 	qgroup_dirty(fs_info, qg);
 
 	/*
@@ -2071,8 +2130,13 @@ static int qgroup_subtree_accounting(struct btrfs_trans_handle *trans,
 	ULIST_ITER_INIT(&uiter);
 	while ((unode = ulist_next(parents, &uiter))) {
 		qg = u64_to_ptr(unode->aux);
-		qg->excl += oper->num_bytes;
-		qg->excl_cmpr += oper->num_bytes;
+		/*
+		 * FIXME: use the data_info to store all information currently.
+		 * will seperate the information into data and metadata later.
+		 **/
+		info = &qg->data_info;
+		info->excl += oper->num_bytes;
+		info->excl_cmpr += oper->num_bytes;
 		qgroup_dirty(fs_info, qg);
 
 		/* Add any parents of the parents */
@@ -2242,6 +2306,10 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
 	struct btrfs_root *quota_root = fs_info->quota_root;
 	struct btrfs_qgroup *srcgroup;
 	struct btrfs_qgroup *dstgroup;
+	struct btrfs_qgroup_info *srcinfo;
+	struct btrfs_qgroup_info *dstinfo;
+	struct btrfs_qgroup_limits *srclimits;
+	struct btrfs_qgroup_limits *dstlimits;
 	u32 level_size = 0;
 	u64 nums;
 
@@ -2326,11 +2394,12 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
 	}
 
 	if (inherit && inherit->flags & BTRFS_QGROUP_INHERIT_SET_LIMITS) {
-		dstgroup->lim_flags = inherit->lim.flags;
-		dstgroup->max_rfer = inherit->lim.max_rfer;
-		dstgroup->max_excl = inherit->lim.max_excl;
-		dstgroup->rsv_rfer = inherit->lim.rsv_rfer;
-		dstgroup->rsv_excl = inherit->lim.rsv_excl;
+		dstlimits = &dstgroup->mixed_limits;
+		dstlimits->lim_flags = inherit->lim.flags;
+		dstlimits->max_rfer = inherit->lim.max_rfer;
+		dstlimits->max_excl = inherit->lim.max_excl;
+		dstlimits->rsv_rfer = inherit->lim.rsv_rfer;
+		dstlimits->rsv_excl = inherit->lim.rsv_excl;
 
 		ret = update_qgroup_limit_item(trans, quota_root, dstgroup);
 		if (ret) {
@@ -2345,25 +2414,33 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
 		srcgroup = find_qgroup_rb(fs_info, srcid);
 		if (!srcgroup)
 			goto unlock;
+		/*
+		 * FIXME: use the data_info to store all information currently.
+		 * will seperate the information into data and metadata later.
+		 **/
+		dstinfo = &dstgroup->data_info;
+		srcinfo = &srcgroup->data_info;
 
 		/*
 		 * We call inherit after we clone the root in order to make sure
 		 * our counts don't go crazy, so at this point the only
 		 * difference between the two roots should be the root node.
 		 */
-		dstgroup->rfer = srcgroup->rfer;
-		dstgroup->rfer_cmpr = srcgroup->rfer_cmpr;
-		dstgroup->excl = level_size;
-		dstgroup->excl_cmpr = level_size;
-		srcgroup->excl = level_size;
-		srcgroup->excl_cmpr = level_size;
-
+		dstinfo->rfer = srcinfo->rfer;
+		dstinfo->rfer_cmpr = srcinfo->rfer_cmpr;
+		dstinfo->excl = level_size;
+		dstinfo->excl_cmpr = level_size;
+		srcinfo->excl = level_size;
+		srcinfo->excl_cmpr = level_size;
+
+		dstlimits = &dstgroup->mixed_limits;
+		srclimits = &srcgroup->mixed_limits;
 		/* inherit the limit info */
-		dstgroup->lim_flags = srcgroup->lim_flags;
-		dstgroup->max_rfer = srcgroup->max_rfer;
-		dstgroup->max_excl = srcgroup->max_excl;
-		dstgroup->rsv_rfer = srcgroup->rsv_rfer;
-		dstgroup->rsv_excl = srcgroup->rsv_excl;
+		dstlimits->lim_flags = srclimits->lim_flags;
+		dstlimits->max_rfer = srclimits->max_rfer;
+		dstlimits->max_excl = srclimits->max_excl;
+		dstlimits->rsv_rfer = srclimits->rsv_rfer;
+		dstlimits->rsv_excl = srclimits->rsv_excl;
 
 		qgroup_dirty(fs_info, dstgroup);
 		qgroup_dirty(fs_info, srcgroup);
@@ -2393,8 +2470,15 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
 			goto unlock;
 		}
 
-		dst->rfer = src->rfer - level_size;
-		dst->rfer_cmpr = src->rfer_cmpr - level_size;
+		/*
+		 * FIXME: use the data_info to store all information currently.
+		 * will seperate the information into data and metadata later.
+		 **/
+		dstinfo = &dst->data_info;
+		srcinfo = &src->data_info;
+
+		dstinfo->rfer = srcinfo->rfer - level_size;
+		dstinfo->rfer_cmpr = srcinfo->rfer_cmpr - level_size;
 		i_qgroups += 2;
 	}
 	for (i = 0; i <  inherit->num_excl_copies; ++i) {
@@ -2409,8 +2493,15 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
 			goto unlock;
 		}
 
-		dst->excl = src->excl + level_size;
-		dst->excl_cmpr = src->excl_cmpr + level_size;
+		/*
+		 * FIXME: use the data_info to store all information currently.
+		 * will seperate the information into data and metadata later.
+		 **/
+		dstinfo = &dst->data_info;
+		srcinfo = &src->data_info;
+
+		dstinfo->excl = srcinfo->excl + level_size;
+		dstinfo->excl_cmpr = srcinfo->excl_cmpr + level_size;
 		i_qgroups += 2;
 	}
 
@@ -2425,6 +2516,8 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
 {
 	struct btrfs_root *quota_root;
 	struct btrfs_qgroup *qgroup;
+	struct btrfs_qgroup_info *data_info;
+	struct btrfs_qgroup_limits *mixed_limits;
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	u64 ref_root = root->root_key.objectid;
 	int ret = 0;
@@ -2462,16 +2555,23 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
 
 		qg = u64_to_ptr(unode->aux);
 
-		if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
-		    qg->reserved + (s64)qg->rfer + num_bytes >
-		    qg->max_rfer) {
+		/*
+		 * FIXME: use the data_info to store all information currently.
+		 * will seperate the information into data and metadata later.
+		 **/
+		data_info = &qgroup->data_info;
+		mixed_limits = &qgroup->mixed_limits;
+
+		if ((mixed_limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
+		    data_info->reserved + (s64)data_info->rfer + num_bytes >
+		    mixed_limits->max_rfer) {
 			ret = -EDQUOT;
 			goto out;
 		}
 
-		if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) &&
-		    qg->reserved + (s64)qg->excl + num_bytes >
-		    qg->max_excl) {
+		if ((mixed_limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) &&
+		    data_info->reserved + (s64)data_info->excl + num_bytes >
+		    mixed_limits->max_excl) {
 			ret = -EDQUOT;
 			goto out;
 		}
@@ -2494,7 +2594,13 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
 
 		qg = u64_to_ptr(unode->aux);
 
-		qg->reserved += num_bytes;
+		/*
+		 * FIXME: use the data_info to store all information currently.
+		 * will seperate the information into data and metadata later.
+		 **/
+		data_info = &qg->data_info;
+
+		data_info->reserved += num_bytes;
 	}
 
 out:
@@ -2506,6 +2612,7 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes)
 {
 	struct btrfs_root *quota_root;
 	struct btrfs_qgroup *qgroup;
+	struct btrfs_qgroup_info *data_info;
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct ulist_node *unode;
 	struct ulist_iterator uiter;
@@ -2540,7 +2647,13 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes)
 
 		qg = u64_to_ptr(unode->aux);
 
-		qg->reserved -= num_bytes;
+		/*
+		 * FIXME: use the data_info to store all information currently.
+		 * will seperate the information into data and metadata later.
+		 **/
+		data_info = &qg->data_info;
+
+		data_info->reserved -= num_bytes;
 
 		list_for_each_entry(glist, &qg->groups, next_group) {
 			ret = ulist_add(fs_info->qgroup_ulist,
@@ -2799,15 +2912,22 @@ qgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info)
 {
 	struct rb_node *n;
 	struct btrfs_qgroup *qgroup;
+	struct btrfs_qgroup_info *data_info;
 
 	spin_lock(&fs_info->qgroup_lock);
 	/* clear all current qgroup tracking information */
 	for (n = rb_first(&fs_info->qgroup_tree); n; n = rb_next(n)) {
 		qgroup = rb_entry(n, struct btrfs_qgroup, node);
-		qgroup->rfer = 0;
-		qgroup->rfer_cmpr = 0;
-		qgroup->excl = 0;
-		qgroup->excl_cmpr = 0;
+		/*
+		 * FIXME: use the data_info to store all information currently.
+		 * will seperate the information into data and metadata later.
+		 **/
+		data_info = &qgroup->data_info;
+
+		data_info->rfer = 0;
+		data_info->rfer_cmpr = 0;
+		data_info->excl = 0;
+		data_info->excl_cmpr = 0;
 	}
 	spin_unlock(&fs_info->qgroup_lock);
 }
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/4] Btrfs-progs: qgroup: print info and limits type in btrfs-debug-tree.
  2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
  2015-03-19  6:00 ` [PATCH 1/4] Btrfs-progs: qgroup: add incompatability feature for QGROUP_TYPE Dongsheng Yang
  2015-03-19  6:00 ` [PATCH 1/7] Btrfs: qgroup: split information and limits in qgroup to other structures Dongsheng Yang
@ 2015-03-19  6:00 ` Dongsheng Yang
  2015-03-19  6:00 ` [PATCH 2/7] Btrfs: qgroup: add incompatability feature for QGROUP_TYPE Dongsheng Yang
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:00 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

We have restructured the btrfs_qgroup, and we are using
objectid for btrfs_qgroup_info_item now. Then we need to
print the objectid in btrfs-debug-tree.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 print-tree.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/print-tree.c b/print-tree.c
index 3a7c13c..7cb9563 100644
--- a/print-tree.c
+++ b/print-tree.c
@@ -644,6 +644,22 @@ static void print_objectid(u64 objectid, u8 type)
 		printf("%llu/%llu", objectid >> 48,
 			objectid & ((1ll << 48) - 1));
 		return;
+	case BTRFS_QGROUP_INFO_KEY:
+		if (objectid == 0)
+			printf("MIXED");
+		else if (objectid == BTRFS_QGROUP_DATA_INFO_OBJECTID)
+			printf("DATA");
+		else
+			printf("METADATA");
+		return;
+	case BTRFS_QGROUP_LIMIT_KEY:
+		if (objectid == BTRFS_QGROUP_DATA_LIMIT_OBJECTID)
+			printf("DATA");
+		else if (objectid == BTRFS_QGROUP_METADATA_LIMIT_OBJECTID)
+			printf("METADATA");
+		else
+			printf("MIXED");
+		return;
 	case BTRFS_UUID_KEY_SUBVOL:
 	case BTRFS_UUID_KEY_RECEIVED_SUBVOL:
 		printf("0x%016llx", (unsigned long long)objectid);
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/7] Btrfs: qgroup: add incompatability feature for QGROUP_TYPE.
  2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
                   ` (2 preceding siblings ...)
  2015-03-19  6:00 ` [PATCH 2/4] Btrfs-progs: qgroup: print info and limits type in btrfs-debug-tree Dongsheng Yang
@ 2015-03-19  6:00 ` Dongsheng Yang
  2015-03-19  6:00 ` [PATCH 3/4] Btrfs-progs: qgroup: add a opt for type of qgroup limit Dongsheng Yang
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:00 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

As we need to change the structure in disk for qgroup, we have
to introduce a incompatability feature for it.

------------------------------------              ------------------------------------------------
|0 |BTRFS_QGROUP_INFO_KEY |qgroupid| ------------>|TYPE_OBJECTID |BTRFS_QGROUP_INFO_KEY |qgroupid|
------------------------------------              ------------------------------------------------

similar for the limits.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 fs/btrfs/ctree.h  | 20 ++++++++++++++-
 fs/btrfs/qgroup.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 91 insertions(+), 6 deletions(-)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index f00eacd..d029119 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -150,6 +150,22 @@ struct btrfs_ordered_sum;
 #define BTRFS_DEV_REPLACE_DEVID 0ULL
 
 /*
+ * the items for qgroup info.
+ */
+#define BTRFS_QGROUP_DATA_INFO_OBJECTID 1ULL
+
+#define BTRFS_QGROUP_METADATA_INFO_OBJECTID 2ULL
+
+/*
+ * the items for qgroup limits.
+ */
+#define BTRFS_QGROUP_DATA_LIMIT_OBJECTID 1ULL
+
+#define BTRFS_QGROUP_METADATA_LIMIT_OBJECTID 2ULL
+
+#define BTRFS_QGROUP_MIXED_LIMIT_OBJECTID 3ULL
+
+/*
  * the max metadata block size.  This limit is somewhat artificial,
  * but the memmove costs go through the roof for larger blocks.
  */
@@ -522,6 +538,7 @@ struct btrfs_super_block {
 #define BTRFS_FEATURE_INCOMPAT_RAID56		(1ULL << 7)
 #define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA	(1ULL << 8)
 #define BTRFS_FEATURE_INCOMPAT_NO_HOLES		(1ULL << 9)
+#define BTRFS_FEATURE_INCOMPAT_QGROUP_TYPE	(1ULL << 10)
 
 #define BTRFS_FEATURE_COMPAT_SUPP		0ULL
 #define BTRFS_FEATURE_COMPAT_SAFE_SET		0ULL
@@ -539,7 +556,8 @@ struct btrfs_super_block {
 	 BTRFS_FEATURE_INCOMPAT_RAID56 |		\
 	 BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF |		\
 	 BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA |	\
-	 BTRFS_FEATURE_INCOMPAT_NO_HOLES)
+	 BTRFS_FEATURE_INCOMPAT_NO_HOLES |		\
+	 BTRFS_FEATURE_INCOMPAT_QGROUP_TYPE)
 
 #define BTRFS_FEATURE_INCOMPAT_SAFE_SET			\
 	(BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index dd99908..34eb4f5 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -372,7 +372,19 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
 			struct btrfs_qgroup_info_item *ptr;
 			struct btrfs_qgroup_info *info;
 
-			info = &qgroup->data_info;
+			/*
+			 * In newer qgroup, we store the quota data in
+			 * different info_items.
+			 */
+			if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+				info = &qgroup->data_info;
+			} else {
+				if (found_key.objectid == BTRFS_QGROUP_DATA_INFO_OBJECTID)
+					info = &qgroup->data_info;
+				else
+					info = &qgroup->metadata_info;
+			}
+
 			ptr = btrfs_item_ptr(l, slot,
 					     struct btrfs_qgroup_info_item);
 			info->rfer = btrfs_qgroup_info_rfer(l, ptr);
@@ -386,7 +398,17 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
 			struct btrfs_qgroup_limit_item *ptr;
 			struct btrfs_qgroup_limits *limits;
 
-			limits = &qgroup->mixed_limits;
+			if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+				limits = &qgroup->mixed_limits;
+			} else {
+				if (found_key.objectid == BTRFS_QGROUP_DATA_LIMIT_OBJECTID)
+					limits = &qgroup->data_limits;
+				else if (found_key.objectid == BTRFS_QGROUP_METADATA_LIMIT_OBJECTID)
+					limits = &qgroup->metadata_limits;
+				else
+					limits = &qgroup->mixed_limits;
+			}
+
 			ptr = btrfs_item_ptr(l, slot,
 					     struct btrfs_qgroup_limit_item);
 			limits->lim_flags = btrfs_qgroup_limit_flags(l, ptr);
@@ -563,7 +585,10 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans,
 	if (!path)
 		return -ENOMEM;
 
-	key.objectid = 0;
+	if (!btrfs_fs_incompat(quota_root->fs_info, QGROUP_TYPE))
+		key.objectid = 0;
+	else
+		key.objectid = BTRFS_QGROUP_DATA_INFO_OBJECTID;
 	key.type = BTRFS_QGROUP_INFO_KEY;
 	key.offset = qgroupid;
 
@@ -573,6 +598,7 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans,
 	 * on disk.
 	 */
 
+info_again:
 	ret = btrfs_insert_empty_item(trans, quota_root, path, &key,
 				      sizeof(*qgroup_info));
 	if (ret && ret != -EEXIST)
@@ -588,10 +614,20 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans,
 	btrfs_set_qgroup_info_excl_cmpr(leaf, qgroup_info, 0);
 
 	btrfs_mark_buffer_dirty(leaf);
-
 	btrfs_release_path(path);
 
+	if (btrfs_fs_incompat(quota_root->fs_info, QGROUP_TYPE) &&
+	    key.objectid != BTRFS_QGROUP_METADATA_INFO_OBJECTID) {
+		key.objectid++;
+		goto info_again;
+	}
+
+	if (btrfs_fs_incompat(quota_root->fs_info, QGROUP_TYPE))
+		key.objectid = BTRFS_QGROUP_DATA_LIMIT_OBJECTID;
+
 	key.type = BTRFS_QGROUP_LIMIT_KEY;
+
+limits_again:
 	ret = btrfs_insert_empty_item(trans, quota_root, path, &key,
 				      sizeof(*qgroup_limit));
 	if (ret && ret != -EEXIST)
@@ -607,6 +643,13 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans,
 	btrfs_set_qgroup_limit_rsv_excl(leaf, qgroup_limit, 0);
 
 	btrfs_mark_buffer_dirty(leaf);
+	btrfs_release_path(path);
+
+	if (btrfs_fs_incompat(quota_root->fs_info, QGROUP_TYPE) &&
+	    key.objectid != BTRFS_QGROUP_MIXED_LIMIT_OBJECTID) {
+		key.objectid++;
+		goto limits_again;
+	}
 
 	ret = 0;
 out:
@@ -625,9 +668,15 @@ static int del_qgroup_item(struct btrfs_trans_handle *trans,
 	if (!path)
 		return -ENOMEM;
 
-	key.objectid = 0;
+	if (!btrfs_fs_incompat(quota_root->fs_info, QGROUP_TYPE))
+		key.objectid = 0;
+	else
+		key.objectid = BTRFS_QGROUP_DATA_INFO_OBJECTID;
+
 	key.type = BTRFS_QGROUP_INFO_KEY;
 	key.offset = qgroupid;
+
+info_again:
 	ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1);
 	if (ret < 0)
 		goto out;
@@ -643,7 +692,18 @@ static int del_qgroup_item(struct btrfs_trans_handle *trans,
 
 	btrfs_release_path(path);
 
+	if (btrfs_fs_incompat(quota_root->fs_info, QGROUP_TYPE) &&
+	    key.objectid != BTRFS_QGROUP_METADATA_INFO_OBJECTID) {
+		key.objectid++;
+		goto info_again;
+	}
+
+	if (btrfs_fs_incompat(quota_root->fs_info, QGROUP_TYPE))
+		key.objectid = BTRFS_QGROUP_DATA_LIMIT_OBJECTID;
+
 	key.type = BTRFS_QGROUP_LIMIT_KEY;
+
+limits_again:
 	ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1);
 	if (ret < 0)
 		goto out;
@@ -654,6 +714,13 @@ static int del_qgroup_item(struct btrfs_trans_handle *trans,
 	}
 
 	ret = btrfs_del_item(trans, quota_root, path);
+	btrfs_release_path(path);
+
+	if (btrfs_fs_incompat(quota_root->fs_info, QGROUP_TYPE) &&
+	    key.objectid != BTRFS_QGROUP_MIXED_LIMIT_OBJECTID) {
+		key.objectid++;
+		goto limits_again;
+	}
 
 out:
 	btrfs_free_path(path);
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/4] Btrfs-progs: qgroup: add a opt for type of qgroup limit.
  2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
                   ` (3 preceding siblings ...)
  2015-03-19  6:00 ` [PATCH 2/7] Btrfs: qgroup: add incompatability feature for QGROUP_TYPE Dongsheng Yang
@ 2015-03-19  6:00 ` Dongsheng Yang
  2015-03-19  6:00 ` [PATCH 3/7] Btrfs: qgroup: record and account ref for qgroup in different type Dongsheng Yang
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:00 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

This patch add a support for user to limit the data, metadata,
or mixed of a qgroup. Even you can set these three limits at
one time for a qgroup.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 cmds-qgroup.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
 ioctl.h       | 13 +++++++++++++
 2 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index c5082f7..1c42fc8 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -367,14 +367,46 @@ static const char * const cmd_qgroup_limit_usage[] = {
 	"-c   limit amount of data after compression. This is the default,",
 	"     it is currently not possible to turn off this option.",
 	"-e   limit space exclusively assigned to this qgroup",
+	"-t   limit space for data, metadata or mixed",
 	NULL
 };
 
+inline u8 get_limit_type(u64 flag)
+{
+	return (flag >> BTRFS_QGROUP_LIMIT_TYPE_SHIFT);
+}
+
+inline u64 set_limit_type(u64 flag, u8 type)
+{
+	u64 temp = (flag >> BTRFS_QGROUP_LIMIT_TYPE_SHIFT);
+
+	temp |= type;
+	flag |= (temp << BTRFS_QGROUP_LIMIT_TYPE_SHIFT);
+
+	return flag;
+}
+
+static int parse_limit_type(u8 *qgroup_type, char *arg)
+{
+	if (strcmp(arg, "data") == 0)
+		*qgroup_type = BTRFS_QGROUP_LIMIT_DATA;
+	else if (strcmp(arg, "metadata") == 0)
+		*qgroup_type = BTRFS_QGROUP_LIMIT_METADATA;
+	else if (strcmp(arg, "mixed") == 0) {
+		*qgroup_type = BTRFS_QGROUP_LIMIT_MIXED;
+	} else {
+		fprintf(stderr, "ERROR: Invalid qgroup type arguments given\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int cmd_qgroup_limit(int argc, char **argv)
 {
 	int ret = 0;
 	int fd;
 	int e;
+	u8 type = BTRFS_QGROUP_LIMIT_MIXED;
 	char *path = NULL;
 	struct btrfs_ioctl_qgroup_limit_args args;
 	unsigned long long size;
@@ -384,7 +416,14 @@ static int cmd_qgroup_limit(int argc, char **argv)
 
 	optind = 1;
 	while (1) {
-		int c = getopt(argc, argv, "ce");
+		int c;
+		static const struct option long_options[] = {
+			{"type", required_argument, NULL, 't'},
+			{NULL, 0, NULL, 0}
+		};
+
+		c = getopt_long(argc, argv, "ce",
+			long_options, NULL);
 		if (c < 0)
 			break;
 		switch (c) {
@@ -394,6 +433,11 @@ static int cmd_qgroup_limit(int argc, char **argv)
 		case 'e':
 			exclusive = 1;
 			break;
+		case 't':
+			ret = parse_limit_type(&type, optarg);
+			if (ret)
+				return -EINVAL;
+			break;
 		default:
 			usage(cmd_qgroup_limit_usage);
 		}
@@ -419,6 +463,8 @@ static int cmd_qgroup_limit(int argc, char **argv)
 			args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_RFER;
 			args.lim.max_referenced = size;
 		}
+
+		args.lim.flags = set_limit_type(args.lim.flags, type);
 	}
 
 	if (argc - optind == 2) {
diff --git a/ioctl.h b/ioctl.h
index d550ca6..a1ebbb5 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -45,6 +45,19 @@ struct btrfs_ioctl_vol_args {
 
 #define BTRFS_QGROUP_INHERIT_SET_LIMITS	(1ULL << 0)
 
+/*
+ * As we can account and limit data and metadata in
+ * a qgroup separately. We use the first 8 bits in
+ * btrfs_qgroup_limit->flags to specify the type we
+ * want to limit. Currently, there are three choice:
+ * DATA, METADATA, MIXED.
+ */
+#define BTRFS_QGROUP_LIMIT_TYPE_SHIFT	56
+
+#define BTRFS_QGROUP_LIMIT_DATA		1
+#define BTRFS_QGROUP_LIMIT_METADATA	2
+#define BTRFS_QGROUP_LIMIT_MIXED	4
+
 struct btrfs_qgroup_limit {
 	__u64	flags;
 	__u64	max_referenced;
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/7] Btrfs: qgroup: record and account ref for qgroup in different type.
  2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
                   ` (4 preceding siblings ...)
  2015-03-19  6:00 ` [PATCH 3/4] Btrfs-progs: qgroup: add a opt for type of qgroup limit Dongsheng Yang
@ 2015-03-19  6:00 ` Dongsheng Yang
  2015-03-19  6:01 ` [PATCH 4/4] Btrfs-progs: qgroup: show specified quota data Dongsheng Yang
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:00 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

This patch make the qgroup account the information of data or metadata
by different infos.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 fs/btrfs/extent-tree.c        |  48 +++++----
 fs/btrfs/qgroup.c             | 239 ++++++++++++++++++++++++++----------------
 fs/btrfs/qgroup.h             |  25 ++++-
 fs/btrfs/tests/qgroup-tests.c |  15 ++-
 fs/btrfs/transaction.c        |  11 +-
 5 files changed, 217 insertions(+), 121 deletions(-)

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 3f49316..cb27da6 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -83,7 +83,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
 				u64 root_objectid, u64 owner_objectid,
 				u64 owner_offset, int refs_to_drop,
 				struct btrfs_delayed_extent_op *extra_op,
-				int no_quota);
+				int no_quota, unsigned int quota_type);
 static void __run_delayed_extent_op(struct btrfs_delayed_extent_op *extent_op,
 				    struct extent_buffer *leaf,
 				    struct btrfs_extent_item *ei);
@@ -1971,7 +1971,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
 				  u64 parent, u64 root_objectid,
 				  u64 owner, u64 offset, int refs_to_add,
 				  int no_quota,
-				  struct btrfs_delayed_extent_op *extent_op)
+				  struct btrfs_delayed_extent_op *extent_op,
+				  unsigned int quota_type)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct btrfs_path *path;
@@ -2013,7 +2014,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
 		btrfs_release_path(path);
 
 		ret = btrfs_qgroup_record_ref(trans, fs_info, root_objectid,
-					      bytenr, num_bytes, type, 0);
+					      bytenr, num_bytes, type,
+					      quota_type, 0);
 		goto out;
 	}
 
@@ -2037,7 +2039,8 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
 
 	if (!no_quota) {
 		ret = btrfs_qgroup_record_ref(trans, fs_info, root_objectid,
-					      bytenr, num_bytes, type, 0);
+					      bytenr, num_bytes, type,
+					      quota_type, 0);
 		if (ret)
 			goto out;
 	}
@@ -2091,13 +2094,15 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
 					     node->num_bytes, parent,
 					     ref_root, ref->objectid,
 					     ref->offset, node->ref_mod,
-					     node->no_quota, extent_op);
+					     node->no_quota, extent_op,
+					     BTRFS_QGROUP_REF_TYPE_DATA);
 	} else if (node->action == BTRFS_DROP_DELAYED_REF) {
 		ret = __btrfs_free_extent(trans, root, node->bytenr,
 					  node->num_bytes, parent,
 					  ref_root, ref->objectid,
 					  ref->offset, node->ref_mod,
-					  extent_op, node->no_quota);
+					  extent_op, node->no_quota,
+					  BTRFS_QGROUP_REF_TYPE_DATA);
 	} else {
 		BUG();
 	}
@@ -2258,12 +2263,12 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
 		ret = __btrfs_inc_extent_ref(trans, root, node->bytenr,
 					     node->num_bytes, parent, ref_root,
 					     ref->level, 0, 1, node->no_quota,
-					     extent_op);
+					     extent_op, BTRFS_QGROUP_REF_TYPE_METADATA);
 	} else if (node->action == BTRFS_DROP_DELAYED_REF) {
 		ret = __btrfs_free_extent(trans, root, node->bytenr,
 					  node->num_bytes, parent, ref_root,
 					  ref->level, 0, 1, extent_op,
-					  node->no_quota);
+					  node->no_quota, BTRFS_QGROUP_REF_TYPE_METADATA);
 	} else {
 		BUG();
 	}
@@ -3694,7 +3699,7 @@ commit_trans:
 					      data_sinfo->flags, bytes, 1);
 		return -ENOSPC;
 	}
-	ret = btrfs_qgroup_reserve(root, write_bytes);
+	ret = btrfs_qgroup_reserve(root, write_bytes, BTRFS_QGROUP_REF_TYPE_DATA);
 	if (ret)
 		goto out;
 	data_sinfo->bytes_may_use += bytes;
@@ -4929,7 +4934,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
 	if (root->fs_info->quota_enabled) {
 		/* One for parent inode, two for dir entries */
 		num_bytes = 3 * root->nodesize;
-		ret = btrfs_qgroup_reserve(root, num_bytes);
+		ret = btrfs_qgroup_reserve(root, num_bytes, BTRFS_QGROUP_REF_TYPE_METADATA);
 		if (ret)
 			return ret;
 	} else {
@@ -4949,7 +4954,7 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
 
 	if (ret) {
 		if (*qgroup_reserved)
-			btrfs_qgroup_free(root, *qgroup_reserved);
+			btrfs_qgroup_free(root, *qgroup_reserved, BTRFS_QGROUP_REF_TYPE_METADATA);
 	}
 
 	return ret;
@@ -5119,7 +5124,8 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
 	spin_unlock(&BTRFS_I(inode)->lock);
 
 	if (root->fs_info->quota_enabled) {
-		ret = btrfs_qgroup_reserve(root, nr_extents * root->nodesize);
+		ret = btrfs_qgroup_reserve(root, nr_extents * root->nodesize,
+					   BTRFS_QGROUP_REF_TYPE_METADATA);
 		if (ret)
 			goto out_fail;
 	}
@@ -5127,7 +5133,8 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
 	ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush);
 	if (unlikely(ret)) {
 		if (root->fs_info->quota_enabled)
-			btrfs_qgroup_free(root, nr_extents * root->nodesize);
+			btrfs_qgroup_free(root, nr_extents * root->nodesize,
+					  BTRFS_QGROUP_REF_TYPE_METADATA);
 		goto out_fail;
 	}
 
@@ -5785,7 +5792,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
 				u64 root_objectid, u64 owner_objectid,
 				u64 owner_offset, int refs_to_drop,
 				struct btrfs_delayed_extent_op *extent_op,
-				int no_quota)
+				int no_quota, unsigned int quota_type)
 {
 	struct btrfs_key key;
 	struct btrfs_path *path;
@@ -6055,7 +6062,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
 
 		ret = btrfs_qgroup_record_ref(trans, info, root_objectid,
 					      bytenr, num_bytes, type,
-					      mod_seq);
+					      quota_type, mod_seq);
 	}
 out:
 	btrfs_free_path(path);
@@ -6996,7 +7003,8 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
 	/* Always set parent to 0 here since its exclusive anyway. */
 	ret = btrfs_qgroup_record_ref(trans, fs_info, root_objectid,
 				      ins->objectid, ins->offset,
-				      BTRFS_QGROUP_OPER_ADD_EXCL, 0);
+				      BTRFS_QGROUP_OPER_ADD_EXCL,
+				      BTRFS_QGROUP_REF_TYPE_DATA, 0);
 	if (ret)
 		return ret;
 
@@ -7084,7 +7092,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
 	if (!no_quota) {
 		ret = btrfs_qgroup_record_ref(trans, fs_info, root_objectid,
 					      ins->objectid, num_bytes,
-					      BTRFS_QGROUP_OPER_ADD_EXCL, 0);
+					      BTRFS_QGROUP_OPER_ADD_EXCL,
+					      BTRFS_QGROUP_REF_TYPE_METADATA, 0);
 		if (ret)
 			return ret;
 	}
@@ -7462,7 +7471,8 @@ static int account_leaf_items(struct btrfs_trans_handle *trans,
 		ret = btrfs_qgroup_record_ref(trans, root->fs_info,
 					      root->objectid,
 					      bytenr, num_bytes,
-					      BTRFS_QGROUP_OPER_SUB_SUBTREE, 0);
+					      BTRFS_QGROUP_OPER_SUB_SUBTREE,
+					      BTRFS_QGROUP_REF_TYPE_METADATA, 0);
 		if (ret)
 			return ret;
 	}
@@ -7612,7 +7622,7 @@ walk_down:
 						child_bytenr,
 						root->nodesize,
 						BTRFS_QGROUP_OPER_SUB_SUBTREE,
-						0);
+						BTRFS_QGROUP_REF_TYPE_METADATA, 0);
 			if (ret)
 				goto out;
 
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 34eb4f5..9dd2627 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1451,7 +1451,8 @@ static int insert_qgroup_oper(struct btrfs_fs_info *fs_info,
 int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
 			    struct btrfs_fs_info *fs_info, u64 ref_root,
 			    u64 bytenr, u64 num_bytes,
-			    enum btrfs_qgroup_operation_type type, int mod_seq)
+			    enum btrfs_qgroup_operation_type type,
+			    unsigned int quota_type, int mod_seq)
 {
 	struct btrfs_qgroup_operation *oper;
 	int ret;
@@ -1467,6 +1468,7 @@ int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
 	oper->bytenr = bytenr;
 	oper->num_bytes = num_bytes;
 	oper->type = type;
+	oper->quota_type = quota_type;
 	oper->seq = atomic_inc_return(&fs_info->qgroup_op_seq);
 	INIT_LIST_HEAD(&oper->elem.list);
 	oper->elem.seq = 0;
@@ -1542,11 +1544,14 @@ static int qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
 		ASSERT(0);
 	}
 
-	/*
-	 * FIXME: use the data_info to store all information currently.
-	 * will seperate the information into data and metadata later.
-	 **/
-	info = &qgroup->data_info;
+	if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+		info = &qgroup->data_info;
+	} else {
+		if (oper->quota_type == BTRFS_QGROUP_REF_TYPE_DATA)
+			info = &qgroup->data_info;
+		else
+			info = &qgroup->metadata_info;
+	}
 
 	info->rfer += sign * oper->num_bytes;
 	info->rfer_cmpr += sign * oper->num_bytes;
@@ -1571,11 +1576,14 @@ static int qgroup_excl_accounting(struct btrfs_fs_info *fs_info,
 	ULIST_ITER_INIT(&uiter);
 	while ((unode = ulist_next(tmp, &uiter))) {
 		qgroup = u64_to_ptr(unode->aux);
-		/*
-		 * FIXME: use the data_info to store all information currently.
-		 * will seperate the information into data and metadata later.
-		 **/
-		info = &qgroup->data_info;
+		if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+			info = &qgroup->data_info;
+		} else {
+			if (oper->quota_type == BTRFS_QGROUP_REF_TYPE_DATA)
+				info = &qgroup->data_info;
+			else
+				info = &qgroup->metadata_info;
+		}
 		info->rfer += sign * oper->num_bytes;
 		info->rfer_cmpr += sign * oper->num_bytes;
 		WARN_ON(sign < 0 && info->excl < oper->num_bytes);
@@ -1842,13 +1850,14 @@ static int qgroup_calc_new_refcnt(struct btrfs_fs_info *fs_info,
  */
 static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
 				  u64 root_to_skip, u64 num_bytes,
-				  struct ulist *qgroups, u64 seq,
-				  int old_roots, int new_roots, int rescan)
+				  u8 quota_type, struct ulist *qgroups,
+				  u64 seq, int old_roots, int new_roots,
+				  int rescan)
 {
 	struct ulist_node *unode;
 	struct ulist_iterator uiter;
 	struct btrfs_qgroup *qg;
-	struct btrfs_qgroup_info *data_info;
+	struct btrfs_qgroup_info *info;
 	u64 cur_new_count, cur_old_count;
 
 	ULIST_ITER_INIT(&uiter);
@@ -1857,14 +1866,21 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
 
 		qg = u64_to_ptr(unode->aux);
 
-		data_info = &qg->data_info;
+		if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+			info = &qg->data_info;
+		} else {
+			if (quota_type == BTRFS_QGROUP_REF_TYPE_DATA)
+				info = &qg->data_info;
+			else
+				info = &qg->metadata_info;
+		}
 		/*
 		 * Wasn't referenced before but is now, add to the reference
 		 * counters.
 		 */
 		if (qg->old_refcnt <= seq && qg->new_refcnt > seq) {
-			data_info->rfer += num_bytes;
-			data_info->rfer_cmpr += num_bytes;
+			info->rfer += num_bytes;
+			info->rfer_cmpr += num_bytes;
 			dirty = true;
 		}
 
@@ -1873,8 +1889,8 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
 		 * reference counters.
 		 */
 		if (qg->old_refcnt > seq && qg->new_refcnt <= seq) {
-			data_info->rfer -= num_bytes;
-			data_info->rfer_cmpr -= num_bytes;
+			info->rfer -= num_bytes;
+			info->rfer_cmpr -= num_bytes;
 			dirty = true;
 		}
 
@@ -1895,13 +1911,8 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
 		if (old_roots && cur_old_count == old_roots &&
 		    (cur_new_count != new_roots || new_roots == 0)) {
 			WARN_ON(cur_new_count != new_roots && new_roots == 0);
-			/*
-			 * FIXME: use the data_info to store all information currently.
-			 * will seperate the information into data and metadata later.
-			 **/
-			data_info = &qg->data_info;
-			data_info->excl -= num_bytes;
-			data_info->excl_cmpr -= num_bytes;
+			info->excl -= num_bytes;
+			info->excl_cmpr -= num_bytes;
 			dirty = true;
 		}
 
@@ -1911,13 +1922,8 @@ static int qgroup_adjust_counters(struct btrfs_fs_info *fs_info,
 		 */
 		if ((!old_roots || (old_roots && cur_old_count != old_roots))
 		    && cur_new_count == new_roots) {
-			/*
-			 * FIXME: use the data_info to store all information currently.
-			 * will seperate the information into data and metadata later.
-			 **/
-			data_info = &qg->data_info;
-			data_info->excl += num_bytes;
-			data_info->excl_cmpr += num_bytes;
+			info->excl += num_bytes;
+			info->excl_cmpr += num_bytes;
 			dirty = true;
 		}
 
@@ -2102,7 +2108,8 @@ static int qgroup_shared_accounting(struct btrfs_trans_handle *trans,
 	 * solution for this.
 	 */
 	qgroup_adjust_counters(fs_info, oper->ref_root, oper->num_bytes,
-			       qgroups, seq, old_roots, new_roots, 0);
+			       oper->quota_type, qgroups, seq, old_roots,
+			       new_roots, 0);
 out:
 	spin_unlock(&fs_info->qgroup_lock);
 	ulist_free(qgroups);
@@ -2171,11 +2178,16 @@ static int qgroup_subtree_accounting(struct btrfs_trans_handle *trans,
 	qg = find_qgroup_rb(fs_info, root_obj);
 	if (!qg)
 		goto out_unlock;
-	/*
-	 * FIXME: use the data_info to store all information currently.
-	 * will seperate the information into data and metadata later.
-	 **/
-	info = &qg->data_info;
+
+	if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+		info = &qg->data_info;
+	} else {
+		if (oper->quota_type == BTRFS_QGROUP_REF_TYPE_DATA)
+			info = &qg->data_info;
+		else
+			info = &qg->metadata_info;
+	}
+
 	info->excl += oper->num_bytes;
 	info->excl_cmpr += oper->num_bytes;
 	qgroup_dirty(fs_info, qg);
@@ -2197,11 +2209,15 @@ static int qgroup_subtree_accounting(struct btrfs_trans_handle *trans,
 	ULIST_ITER_INIT(&uiter);
 	while ((unode = ulist_next(parents, &uiter))) {
 		qg = u64_to_ptr(unode->aux);
-		/*
-		 * FIXME: use the data_info to store all information currently.
-		 * will seperate the information into data and metadata later.
-		 **/
-		info = &qg->data_info;
+
+		if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+			info = &qg->data_info;
+		} else {
+			if (oper->quota_type == BTRFS_QGROUP_REF_TYPE_DATA)
+				info = &qg->data_info;
+			else
+				info = &qg->metadata_info;
+		}
 		info->excl += oper->num_bytes;
 		info->excl_cmpr += oper->num_bytes;
 		qgroup_dirty(fs_info, qg);
@@ -2579,12 +2595,47 @@ out:
 	return ret;
 }
 
-int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
+static int exceed_limits(struct btrfs_qgroup_info *info,
+			 struct btrfs_qgroup_limits *limits,
+			 struct btrfs_qgroup_info *another_info,
+			 u64 num_bytes)
+{
+	if (another_info) {
+		/*
+		 * For the mixed limits.
+		 */
+		if ((limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) &&
+		    info->reserved + (s64)info->excl +
+		    another_info->reserved + (s64)another_info->excl +
+		    num_bytes > limits->max_excl)
+			return 1;
+
+		if ((limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
+		    info->reserved + (s64)info->rfer +
+		    another_info->reserved + (s64)another_info->rfer +
+		    num_bytes > limits->max_rfer)
+			return 1;
+		
+	} else {
+		if ((limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) &&
+		    info->reserved + (s64)info->excl + num_bytes >
+		    limits->max_excl)
+			return 1;
+
+		if ((limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
+		    info->reserved + (s64)info->rfer + num_bytes >
+		    limits->max_rfer)
+			return 1;
+	}
+
+	return 0;
+}
+
+int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes, u8 type)
 {
 	struct btrfs_root *quota_root;
 	struct btrfs_qgroup *qgroup;
-	struct btrfs_qgroup_info *data_info;
-	struct btrfs_qgroup_limits *mixed_limits;
+	struct btrfs_qgroup_info *info;
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	u64 ref_root = root->root_key.objectid;
 	int ret = 0;
@@ -2617,33 +2668,32 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
 		goto out;
 	ULIST_ITER_INIT(&uiter);
 	while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) {
-		struct btrfs_qgroup *qg;
+		struct btrfs_qgroup *qgroup;
 		struct btrfs_qgroup_list *glist;
 
-		qg = u64_to_ptr(unode->aux);
-
-		/*
-		 * FIXME: use the data_info to store all information currently.
-		 * will seperate the information into data and metadata later.
-		 **/
-		data_info = &qgroup->data_info;
-		mixed_limits = &qgroup->mixed_limits;
+		qgroup = u64_to_ptr(unode->aux);
 
-		if ((mixed_limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) &&
-		    data_info->reserved + (s64)data_info->rfer + num_bytes >
-		    mixed_limits->max_rfer) {
-			ret = -EDQUOT;
-			goto out;
+		if (type == BTRFS_QGROUP_REF_TYPE_DATA) {
+			info = &qgroup->data_info;
+			if (exceed_limits(info, &qgroup->data_limits, NULL, num_bytes)) {
+				ret = -EDQUOT;
+				goto out;
+			}
+		} else {
+			info = &qgroup->metadata_info;
+			if (exceed_limits(info, &qgroup->metadata_limits, NULL, num_bytes)) {
+				ret = -EDQUOT;
+				goto out;
+			}
 		}
 
-		if ((mixed_limits->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) &&
-		    data_info->reserved + (s64)data_info->excl + num_bytes >
-		    mixed_limits->max_excl) {
+		if (exceed_limits(&qgroup->data_info, &qgroup->mixed_limits,
+				  &qgroup->metadata_info, num_bytes)) {
 			ret = -EDQUOT;
 			goto out;
 		}
 
-		list_for_each_entry(glist, &qg->groups, next_group) {
+		list_for_each_entry(glist, &qgroup->groups, next_group) {
 			ret = ulist_add(fs_info->qgroup_ulist,
 					glist->group->qgroupid,
 					(uintptr_t)glist->group, GFP_ATOMIC);
@@ -2661,13 +2711,16 @@ int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes)
 
 		qg = u64_to_ptr(unode->aux);
 
-		/*
-		 * FIXME: use the data_info to store all information currently.
-		 * will seperate the information into data and metadata later.
-		 **/
-		data_info = &qg->data_info;
+		if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+			info = &qg->data_info;
+		} else {
+			if (type == BTRFS_QGROUP_REF_TYPE_DATA)
+				info = &qg->data_info;
+			else
+				info = &qg->metadata_info;
+		}
 
-		data_info->reserved += num_bytes;
+		info->reserved += num_bytes;
 	}
 
 out:
@@ -2675,11 +2728,11 @@ out:
 	return ret;
 }
 
-void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes)
+void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes, u8 type)
 {
 	struct btrfs_root *quota_root;
 	struct btrfs_qgroup *qgroup;
-	struct btrfs_qgroup_info *data_info;
+	struct btrfs_qgroup_info *info;
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct ulist_node *unode;
 	struct ulist_iterator uiter;
@@ -2714,13 +2767,16 @@ void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes)
 
 		qg = u64_to_ptr(unode->aux);
 
-		/*
-		 * FIXME: use the data_info to store all information currently.
-		 * will seperate the information into data and metadata later.
-		 **/
-		data_info = &qg->data_info;
+		if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+			info = &qg->data_info;
+		} else {
+			if (type == BTRFS_QGROUP_REF_TYPE_DATA)
+				info = &qg->data_info;
+			else
+				info = &qg->metadata_info;
+		}
 
-		data_info->reserved -= num_bytes;
+		info->reserved -= num_bytes;
 
 		list_for_each_entry(glist, &qg->groups, next_group) {
 			ret = ulist_add(fs_info->qgroup_ulist,
@@ -2830,7 +2886,7 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
 			goto out;
 		}
 
-		ret = qgroup_adjust_counters(fs_info, 0, num_bytes, qgroups,
+		ret = qgroup_adjust_counters(fs_info, 0, num_bytes, 0, qgroups,
 					     seq, 0, new_roots, 1);
 		if (ret < 0) {
 			spin_unlock(&fs_info->qgroup_lock);
@@ -2979,22 +3035,25 @@ qgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info)
 {
 	struct rb_node *n;
 	struct btrfs_qgroup *qgroup;
-	struct btrfs_qgroup_info *data_info;
+	struct btrfs_qgroup_info *info;
 
 	spin_lock(&fs_info->qgroup_lock);
 	/* clear all current qgroup tracking information */
 	for (n = rb_first(&fs_info->qgroup_tree); n; n = rb_next(n)) {
 		qgroup = rb_entry(n, struct btrfs_qgroup, node);
-		/*
-		 * FIXME: use the data_info to store all information currently.
-		 * will seperate the information into data and metadata later.
-		 **/
-		data_info = &qgroup->data_info;
 
-		data_info->rfer = 0;
-		data_info->rfer_cmpr = 0;
-		data_info->excl = 0;
-		data_info->excl_cmpr = 0;
+		info = &qgroup->data_info;
+
+again:
+		info->rfer = 0;
+		info->rfer_cmpr = 0;
+		info->excl = 0;
+		info->excl_cmpr = 0;
+
+		if (info != &qgroup->metadata_info) {
+			info = &qgroup->metadata_info;
+			goto again;
+		}
 	}
 	spin_unlock(&fs_info->qgroup_lock);
 }
diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h
index 52d8b19..11b73f3 100644
--- a/fs/btrfs/qgroup.h
+++ b/fs/btrfs/qgroup.h
@@ -20,6 +20,22 @@
 #define __BTRFS_QGROUP__
 
 /*
+ * Type for quota reference. Caller of qgroup_record_ref()
+ * should choose one type of the reference passed to qgroup.
+ * Then qgroup will account the reference in the chosen info.
+ */
+#define BTRFS_QGROUP_REF_TYPE_DATA          (1 << 0)
+#define BTRFS_QGROUP_REF_TYPE_METADATA      (1 << 1)
+
+/*
+ * To keep the compatibility, define a default type to manage
+ * the all reference in the older kernel. Choose the data_info
+ * to account all reference in older kernel which did not record
+ * and account reference for data and metadata separately.
+ */
+#define BTRFS_QGROUP_REF_TYPE_DEFAULT	BTRFS_QGROUP_REF_TYPE_DATA
+
+/*
  * A description of the operations, all of these operations only happen when we
  * are adding the 1st reference for that subvolume in the case of adding space
  * or on the last reference delete in the case of subtraction.  The only
@@ -53,6 +69,10 @@ struct btrfs_qgroup_operation {
 	u64 num_bytes;
 	u64 seq;
 	enum btrfs_qgroup_operation_type type;
+	/*
+	 * DATA or METADATA;
+	 **/
+	unsigned int quota_type;
 	struct seq_list elem;
 	struct rb_node n;
 	struct list_head list;
@@ -86,6 +106,7 @@ int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
 			    struct btrfs_fs_info *fs_info, u64 ref_root,
 			    u64 bytenr, u64 num_bytes,
 			    enum btrfs_qgroup_operation_type type,
+			    unsigned int quota_type,
 			    int mod_seq);
 int btrfs_delayed_qgroup_accounting(struct btrfs_trans_handle *trans,
 				    struct btrfs_fs_info *fs_info);
@@ -97,8 +118,8 @@ int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
 int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
 			 struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid,
 			 struct btrfs_qgroup_inherit *inherit);
-int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes);
-void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes);
+int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes, u8 type);
+void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes, u8 type);
 
 void assert_qgroups_uptodate(struct btrfs_trans_handle *trans);
 
diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c
index c32a7ba..2c978ce 100644
--- a/fs/btrfs/tests/qgroup-tests.c
+++ b/fs/btrfs/tests/qgroup-tests.c
@@ -239,7 +239,8 @@ static int test_no_shared_qgroup(struct btrfs_root *root)
 	}
 
 	ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096,
-				      BTRFS_QGROUP_OPER_ADD_EXCL, 0);
+				      BTRFS_QGROUP_OPER_ADD_EXCL,
+				      BTRFS_QGROUP_REF_TYPE_DEFAULT, 0);
 	if (ret) {
 		test_msg("Couldn't add space to a qgroup %d\n", ret);
 		return ret;
@@ -265,7 +266,8 @@ static int test_no_shared_qgroup(struct btrfs_root *root)
 		return -EINVAL;
 
 	ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096,
-				      BTRFS_QGROUP_OPER_SUB_EXCL, 0);
+				      BTRFS_QGROUP_OPER_SUB_EXCL,
+				      BTRFS_QGROUP_REF_TYPE_DEFAULT, 0);
 	if (ret) {
 		test_msg("Couldn't remove space from the qgroup %d\n", ret);
 		return -EINVAL;
@@ -312,7 +314,8 @@ static int test_multiple_refs(struct btrfs_root *root)
 		return ret;
 
 	ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096,
-				      BTRFS_QGROUP_OPER_ADD_EXCL, 0);
+				      BTRFS_QGROUP_OPER_ADD_EXCL,
+				      BTRFS_QGROUP_REF_TYPE_DEFAULT, 0);
 	if (ret) {
 		test_msg("Couldn't add space to a qgroup %d\n", ret);
 		return ret;
@@ -334,7 +337,8 @@ static int test_multiple_refs(struct btrfs_root *root)
 		return ret;
 
 	ret = btrfs_qgroup_record_ref(&trans, fs_info, 256, 4096, 4096,
-				      BTRFS_QGROUP_OPER_ADD_SHARED, 0);
+				      BTRFS_QGROUP_OPER_ADD_SHARED,
+				      BTRFS_QGROUP_REF_TYPE_DEFAULT, 0);
 	if (ret) {
 		test_msg("Qgroup record ref failed %d\n", ret);
 		return ret;
@@ -361,7 +365,8 @@ static int test_multiple_refs(struct btrfs_root *root)
 		return ret;
 
 	ret = btrfs_qgroup_record_ref(&trans, fs_info, 256, 4096, 4096,
-				      BTRFS_QGROUP_OPER_SUB_SHARED, 0);
+				      BTRFS_QGROUP_OPER_SUB_SHARED,
+				      BTRFS_QGROUP_REF_TYPE_DEFAULT, 0);
 	if (ret) {
 		test_msg("Qgroup record ref failed %d\n", ret);
 		return ret;
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 7e80f32..8d4bffb 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -440,7 +440,8 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
 		if (root->fs_info->quota_enabled &&
 		    is_fstree(root->root_key.objectid)) {
 			qgroup_reserved = num_items * root->nodesize;
-			ret = btrfs_qgroup_reserve(root, qgroup_reserved);
+			ret = btrfs_qgroup_reserve(root, qgroup_reserved,
+						   BTRFS_QGROUP_REF_TYPE_METADATA);
 			if (ret)
 				return ERR_PTR(ret);
 		}
@@ -555,7 +556,7 @@ alloc_fail:
 					num_bytes);
 reserve_fail:
 	if (qgroup_reserved)
-		btrfs_qgroup_free(root, qgroup_reserved);
+		btrfs_qgroup_free(root, qgroup_reserved, BTRFS_QGROUP_REF_TYPE_METADATA);
 	return ERR_PTR(ret);
 }
 
@@ -777,7 +778,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
 		 * the same root has to be passed here between start_transaction
 		 * and end_transaction. Subvolume quota depends on this.
 		 */
-		btrfs_qgroup_free(trans->root, trans->qgroup_reserved);
+		btrfs_qgroup_free(trans->root, trans->qgroup_reserved, BTRFS_QGROUP_REF_TYPE_METADATA);
 		trans->qgroup_reserved = 0;
 	}
 
@@ -1783,7 +1784,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 	btrfs_trans_release_metadata(trans, root);
 	trans->block_rsv = NULL;
 	if (trans->qgroup_reserved) {
-		btrfs_qgroup_free(root, trans->qgroup_reserved);
+		btrfs_qgroup_free(root, trans->qgroup_reserved, BTRFS_QGROUP_REF_TYPE_METADATA);
 		trans->qgroup_reserved = 0;
 	}
 
@@ -2079,7 +2080,7 @@ cleanup_transaction:
 	btrfs_trans_release_metadata(trans, root);
 	trans->block_rsv = NULL;
 	if (trans->qgroup_reserved) {
-		btrfs_qgroup_free(root, trans->qgroup_reserved);
+		btrfs_qgroup_free(root, trans->qgroup_reserved, BTRFS_QGROUP_REF_TYPE_METADATA);
 		trans->qgroup_reserved = 0;
 	}
 	btrfs_warn(root->fs_info, "Skipping commit of aborted transaction.");
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/4] Btrfs-progs: qgroup: show specified quota data.
  2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
                   ` (5 preceding siblings ...)
  2015-03-19  6:00 ` [PATCH 3/7] Btrfs: qgroup: record and account ref for qgroup in different type Dongsheng Yang
@ 2015-03-19  6:01 ` Dongsheng Yang
  2015-03-19  6:01 ` [PATCH 4/7] Btrfs: qgroup: update all infos and limits to disk Dongsheng Yang
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:01 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

This patch allow user to choose the information type
in command of qgroup show.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 cmds-qgroup.c | 24 +++++++++++++++++++++++-
 qgroup.c      | 44 +++++++++++++++++++++++++++++++++++---------
 qgroup.h      |  7 ++++++-
 3 files changed, 64 insertions(+), 11 deletions(-)

diff --git a/cmds-qgroup.c b/cmds-qgroup.c
index 1c42fc8..86b6d2d 100644
--- a/cmds-qgroup.c
+++ b/cmds-qgroup.c
@@ -204,6 +204,21 @@ static int cmd_qgroup_destroy(int argc, char **argv)
 	return ret;
 }
 
+static int parse_show_type(u8 *qgroup_type, char *arg)
+{
+	if (strcmp(arg, "data") == 0)
+		*qgroup_type = BTRFS_QGROUP_SHOW_TYPE_DATA;
+	else if (strcmp(arg, "metadata") == 0)
+		*qgroup_type = BTRFS_QGROUP_SHOW_TYPE_METADATA;
+	else if (strcmp(arg, "mixed") == 0) {
+		*qgroup_type = BTRFS_QGROUP_SHOW_TYPE_MIXED;
+	} else {
+		fprintf(stderr, "ERROR: Invalid qgroup type arguments given\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static const char * const cmd_qgroup_show_usage[] = {
 	"btrfs qgroup show -pcreFf "
 	"[--sort=qgroupid,rfer,excl,max_rfer,max_excl] <path>",
@@ -238,6 +253,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 	int ret = 0;
 	int fd;
 	int e;
+	u8 type = BTRFS_QGROUP_SHOW_TYPE_MIXED;
 	DIR *dirstream = NULL;
 	u64 qgroupid;
 	int filter_flag = 0;
@@ -253,6 +269,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 		int c;
 		int option_index = 0;
 		static const struct option long_options[] = {
+			{"type", required_argument, NULL, 't'},
 			{"sort", 1, NULL, 'S'},
 			{"raw", no_argument, NULL, GETOPT_VAL_RAW},
 			{"kbytes", no_argument, NULL, GETOPT_VAL_KBYTES},
@@ -299,6 +316,11 @@ static int cmd_qgroup_show(int argc, char **argv)
 			if (ret)
 				usage(cmd_qgroup_show_usage);
 			break;
+		case 't':
+			ret = parse_show_type(&type, optarg);
+			if (ret)
+				usage(cmd_qgroup_show_usage);
+			break;
 		case GETOPT_VAL_RAW:
 			unit_mode = UNITS_RAW;
 			break;
@@ -350,7 +372,7 @@ static int cmd_qgroup_show(int argc, char **argv)
 					BTRFS_QGROUP_FILTER_PARENT,
 					qgroupid);
 	}
-	ret = btrfs_show_qgroups(fd, filter_set, comparer_set);
+	ret = btrfs_show_qgroups(fd, filter_set, comparer_set, type);
 	e = errno;
 	close_file_or_dir(fd, dirstream);
 	if (ret < 0)
diff --git a/qgroup.c b/qgroup.c
index 91e25ea..0e32284 100644
--- a/qgroup.c
+++ b/qgroup.c
@@ -226,14 +226,36 @@ static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column,
 }
 
 static void print_qgroup_column(struct btrfs_qgroup *qgroup,
-				enum btrfs_qgroup_column_enum column)
+				enum btrfs_qgroup_column_enum column,
+				u8 type)
 {
 	BUG_ON(column >= BTRFS_QGROUP_ALL || column < 0);
 	int len;
 	int unit_mode = btrfs_qgroup_columns[column].unit_mode;
 	int max_len = btrfs_qgroup_columns[column].max_len;
-	struct btrfs_qgroup_info *info = &qgroup->data_info;
-	struct btrfs_qgroup_limits *limits = &qgroup->mixed_limits;
+	struct btrfs_qgroup_limits *limits = NULL;
+	struct btrfs_qgroup_info *info = NULL;
+	int need_free = 0;
+
+
+	if (type == BTRFS_QGROUP_SHOW_TYPE_DATA) {
+		info = &qgroup->data_info;
+		limits = &qgroup->data_limits;
+	} else if (type == BTRFS_QGROUP_SHOW_TYPE_METADATA) {
+		info = &qgroup->metadata_info;
+		limits = &qgroup->metadata_limits;
+	} else {
+		/*
+		 * For mixed type show.
+		 */ 
+		info = malloc(sizeof(*info));
+		info->rfer = qgroup->data_info.rfer +
+				qgroup->metadata_info.rfer;
+		info->excl = qgroup->data_info.excl +
+				qgroup->metadata_info.excl;
+		limits = &qgroup->mixed_limits;
+		need_free = 1;
+	}
 
 	switch (column) {
 
@@ -265,16 +287,19 @@ static void print_qgroup_column(struct btrfs_qgroup *qgroup,
 	default:
 		break;
 	}
+
+	if (need_free)
+		free(info);
 }
 
-static void print_single_qgroup_table(struct btrfs_qgroup *qgroup)
+static void print_single_qgroup_table(struct btrfs_qgroup *qgroup, u8 type)
 {
 	int i;
 
 	for (i = 0; i < BTRFS_QGROUP_ALL; i++) {
 		if (!btrfs_qgroup_columns[i].need_print)
 			continue;
-		print_qgroup_column(qgroup, i);
+		print_qgroup_column(qgroup, i, type);
 
 		if (i != BTRFS_QGROUP_CHILD)
 			printf(" ");
@@ -1205,7 +1230,7 @@ done:
 	return ret;
 }
 
-static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
+static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup, u8 type)
 {
 
 	struct rb_node *n;
@@ -1216,14 +1241,15 @@ static void print_all_qgroups(struct qgroup_lookup *qgroup_lookup)
 	n = rb_first(&qgroup_lookup->root);
 	while (n) {
 		entry = rb_entry(n, struct btrfs_qgroup, sort_node);
-		print_single_qgroup_table(entry);
+		print_single_qgroup_table(entry, type);
 		n = rb_next(n);
 	}
 }
 
 int btrfs_show_qgroups(int fd,
 		       struct btrfs_qgroup_filter_set *filter_set,
-		       struct btrfs_qgroup_comparer_set *comp_set)
+		       struct btrfs_qgroup_comparer_set *comp_set,
+		       u8 type)
 {
 
 	struct qgroup_lookup qgroup_lookup;
@@ -1235,7 +1261,7 @@ int btrfs_show_qgroups(int fd,
 		return ret;
 	__filter_and_sort_qgroups(&qgroup_lookup, &sort_tree,
 				  filter_set, comp_set);
-	print_all_qgroups(&sort_tree);
+	print_all_qgroups(&sort_tree, type);
 
 	__free_all_qgroups(&qgroup_lookup);
 	btrfs_qgroup_free_filter_set(filter_set);
diff --git a/qgroup.h b/qgroup.h
index 6e65ef7..474db75 100644
--- a/qgroup.h
+++ b/qgroup.h
@@ -22,6 +22,10 @@
 #include "ioctl.h"
 #include "kerncompat.h"
 
+#define BTRFS_QGROUP_SHOW_TYPE_DATA		(1 << 0)
+#define BTRFS_QGROUP_SHOW_TYPE_METADATA		(1 << 1)
+#define BTRFS_QGROUP_SHOW_TYPE_MIXED		(1 << 2)
+
 struct btrfs_qgroup;
 
 typedef int (*btrfs_qgroup_filter_func)(struct btrfs_qgroup *, u64);
@@ -81,7 +85,8 @@ int btrfs_qgroup_parse_sort_string(char *opt_arg,
 				struct btrfs_qgroup_comparer_set **comps);
 u64 btrfs_get_path_rootid(int fd);
 int btrfs_show_qgroups(int fd, struct btrfs_qgroup_filter_set *,
-		       struct btrfs_qgroup_comparer_set *);
+		       struct btrfs_qgroup_comparer_set *,
+		       u8 type);
 void btrfs_qgroup_setup_print_column(enum btrfs_qgroup_column_enum column);
 void btrfs_qgroup_setup_units(unsigned unit_mode);
 struct btrfs_qgroup_filter_set *btrfs_qgroup_alloc_filter_set(void);
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/7] Btrfs: qgroup: update all infos and limits to disk.
  2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
                   ` (6 preceding siblings ...)
  2015-03-19  6:01 ` [PATCH 4/4] Btrfs-progs: qgroup: show specified quota data Dongsheng Yang
@ 2015-03-19  6:01 ` Dongsheng Yang
  2015-03-19  6:01 ` [PATCH 5/7] Btrfs: qgroup: update quota numbers in btrfs_qgroup_inherit Dongsheng Yang
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:01 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

There are not only one info for a qgroup, then we need
to store the all infos and limits to disk.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 fs/btrfs/qgroup.c | 52 ++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 40 insertions(+), 12 deletions(-)

diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 9dd2627..5df8527 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -624,6 +624,8 @@ info_again:
 
 	if (btrfs_fs_incompat(quota_root->fs_info, QGROUP_TYPE))
 		key.objectid = BTRFS_QGROUP_DATA_LIMIT_OBJECTID;
+	else
+		key.objectid = 0;
 
 	key.type = BTRFS_QGROUP_LIMIT_KEY;
 
@@ -700,6 +702,8 @@ info_again:
 
 	if (btrfs_fs_incompat(quota_root->fs_info, QGROUP_TYPE))
 		key.objectid = BTRFS_QGROUP_DATA_LIMIT_OBJECTID;
+	else
+		key.objectid = 0;
 
 	key.type = BTRFS_QGROUP_LIMIT_KEY;
 
@@ -739,14 +743,21 @@ static int update_qgroup_limit_item(struct btrfs_trans_handle *trans,
 	int ret;
 	int slot;
 
-	key.objectid = 0;
+	if (!btrfs_fs_incompat(root->fs_info, QGROUP_TYPE)) {
+		key.objectid = 0;
+		limits = &qgroup->mixed_limits;
+	} else {
+		key.objectid = BTRFS_QGROUP_DATA_LIMIT_OBJECTID;
+		limits = &qgroup->data_limits;
+	}
+
 	key.type = BTRFS_QGROUP_LIMIT_KEY;
 	key.offset = qgroup->qgroupid;
 
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
-
+again:
 	ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
 	if (ret > 0)
 		ret = -ENOENT;
@@ -754,8 +765,6 @@ static int update_qgroup_limit_item(struct btrfs_trans_handle *trans,
 	if (ret)
 		goto out;
 
-	limits = &qgroup->mixed_limits;
-
 	l = path->nodes[0];
 	slot = path->slots[0];
 	qgroup_limit = btrfs_item_ptr(l, slot, struct btrfs_qgroup_limit_item);
@@ -766,6 +775,14 @@ static int update_qgroup_limit_item(struct btrfs_trans_handle *trans,
 	btrfs_set_qgroup_limit_rsv_excl(l, qgroup_limit, limits->rsv_excl);
 
 	btrfs_mark_buffer_dirty(l);
+	btrfs_release_path(path);
+
+	if (btrfs_fs_incompat(root->fs_info, QGROUP_TYPE) &&
+	    key.objectid != BTRFS_QGROUP_MIXED_LIMIT_OBJECTID) {
+		key.objectid++;
+		limits++;
+		goto again;
+	}
 
 out:
 	btrfs_free_path(path);
@@ -780,14 +797,18 @@ static int update_qgroup_info_item(struct btrfs_trans_handle *trans,
 	struct btrfs_key key;
 	struct extent_buffer *l;
 	struct btrfs_qgroup_info_item *qgroup_info;
-	struct btrfs_qgroup_info *data_info;
+	struct btrfs_qgroup_info *info;
 	int ret;
 	int slot;
 
 	if (btrfs_test_is_dummy_root(root))
 		return 0;
 
-	key.objectid = 0;
+	if (!btrfs_fs_incompat(root->fs_info, QGROUP_TYPE))
+		key.objectid = 0;
+	else
+		key.objectid = BTRFS_QGROUP_DATA_INFO_OBJECTID;
+
 	key.type = BTRFS_QGROUP_INFO_KEY;
 	key.offset = qgroup->qgroupid;
 
@@ -795,6 +816,8 @@ static int update_qgroup_info_item(struct btrfs_trans_handle *trans,
 	if (!path)
 		return -ENOMEM;
 
+	info = &qgroup->data_info;
+again:
 	ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
 	if (ret > 0)
 		ret = -ENOENT;
@@ -802,19 +825,24 @@ static int update_qgroup_info_item(struct btrfs_trans_handle *trans,
 	if (ret)
 		goto out;
 
-	data_info = &qgroup->data_info;
-
 	l = path->nodes[0];
 	slot = path->slots[0];
 	qgroup_info = btrfs_item_ptr(l, slot, struct btrfs_qgroup_info_item);
 	btrfs_set_qgroup_info_generation(l, qgroup_info, trans->transid);
-	btrfs_set_qgroup_info_rfer(l, qgroup_info, data_info->rfer);
-	btrfs_set_qgroup_info_rfer_cmpr(l, qgroup_info, data_info->rfer_cmpr);
-	btrfs_set_qgroup_info_excl(l, qgroup_info, data_info->excl);
-	btrfs_set_qgroup_info_excl_cmpr(l, qgroup_info, data_info->excl_cmpr);
+	btrfs_set_qgroup_info_rfer(l, qgroup_info, info->rfer);
+	btrfs_set_qgroup_info_rfer_cmpr(l, qgroup_info, info->rfer_cmpr);
+	btrfs_set_qgroup_info_excl(l, qgroup_info, info->excl);
+	btrfs_set_qgroup_info_excl_cmpr(l, qgroup_info, info->excl_cmpr);
 
 	btrfs_mark_buffer_dirty(l);
+	btrfs_release_path(path);
 
+	if (btrfs_fs_incompat(root->fs_info, QGROUP_TYPE) &&
+	    key.objectid != BTRFS_QGROUP_METADATA_INFO_OBJECTID) {
+		key.objectid++;
+		info++;
+		goto again;
+	}
 out:
 	btrfs_free_path(path);
 	return ret;
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/7] Btrfs: qgroup: update quota numbers in btrfs_qgroup_inherit.
  2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
                   ` (7 preceding siblings ...)
  2015-03-19  6:01 ` [PATCH 4/7] Btrfs: qgroup: update all infos and limits to disk Dongsheng Yang
@ 2015-03-19  6:01 ` Dongsheng Yang
  2015-03-19  6:01 ` [PATCH 6/7] Btrfs: qgroup: account data and metadata separately in rescan Dongsheng Yang
  2015-03-19  6:01 ` [PATCH 7/7] Btrfs: qgroup: allow user to limit qgroup in different type Dongsheng Yang
  10 siblings, 0 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:01 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

Original, the all quota numbers are stored in data_info, but
now, we store them separately in data_info and metadata_info.
Then, when we create a snapshot and update the quota number,
we need to update both of the data_info and metadata_info.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 fs/btrfs/qgroup.c | 57 ++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 40 insertions(+), 17 deletions(-)

diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 5df8527..9363fd0 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -2525,34 +2525,57 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
 		srcgroup = find_qgroup_rb(fs_info, srcid);
 		if (!srcgroup)
 			goto unlock;
-		/*
-		 * FIXME: use the data_info to store all information currently.
-		 * will seperate the information into data and metadata later.
-		 **/
 		dstinfo = &dstgroup->data_info;
 		srcinfo = &srcgroup->data_info;
 
-		/*
-		 * We call inherit after we clone the root in order to make sure
-		 * our counts don't go crazy, so at this point the only
-		 * difference between the two roots should be the root node.
-		 */
-		dstinfo->rfer = srcinfo->rfer;
-		dstinfo->rfer_cmpr = srcinfo->rfer_cmpr;
-		dstinfo->excl = level_size;
-		dstinfo->excl_cmpr = level_size;
-		srcinfo->excl = level_size;
-		srcinfo->excl_cmpr = level_size;
+		if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+			/*
+			 * We call inherit after we clone the root in order to make sure
+			 * our counts don't go crazy, so at this point the only
+			 * difference between the two roots should be the root node.
+			 */
+			dstinfo->rfer = srcinfo->rfer;
+			dstinfo->rfer_cmpr = srcinfo->rfer_cmpr;
+			dstinfo->excl = level_size;
+			dstinfo->excl_cmpr = level_size;
+			srcinfo->excl = level_size;
+			srcinfo->excl_cmpr = level_size;
+		} else {
+			dstinfo->rfer = srcinfo->rfer;
+			dstinfo->rfer_cmpr = srcinfo->rfer_cmpr;
+			/*
+			 * add the metadata for dstqgroup.
+			 */
+			dstinfo = &dstgroup->metadata_info;
+			dstinfo->rfer = level_size;
+			dstinfo->rfer_cmpr = level_size;
+			dstinfo->excl = level_size;
+			dstinfo->excl_cmpr = level_size;
+			srcinfo->excl = 0;
+			srcinfo->excl_cmpr = 0;
+		}
 
-		dstlimits = &dstgroup->mixed_limits;
-		srclimits = &srcgroup->mixed_limits;
+		if (!btrfs_fs_incompat(fs_info, QGROUP_TYPE)) {
+			dstlimits = &dstgroup->mixed_limits;
+			srclimits = &srcgroup->mixed_limits;
+		} else {
+			dstlimits = &dstgroup->data_limits;
+			srclimits = &srcgroup->data_limits;
+		}
 		/* inherit the limit info */
+again:
 		dstlimits->lim_flags = srclimits->lim_flags;
 		dstlimits->max_rfer = srclimits->max_rfer;
 		dstlimits->max_excl = srclimits->max_excl;
 		dstlimits->rsv_rfer = srclimits->rsv_rfer;
 		dstlimits->rsv_excl = srclimits->rsv_excl;
 
+		if (dstlimits != &dstgroup->mixed_limits) {
+			dstlimits++;
+			srclimits++;
+			goto again;
+		}
+
 		qgroup_dirty(fs_info, dstgroup);
 		qgroup_dirty(fs_info, srcgroup);
 	}
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 6/7] Btrfs: qgroup: account data and metadata separately in rescan.
  2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
                   ` (8 preceding siblings ...)
  2015-03-19  6:01 ` [PATCH 5/7] Btrfs: qgroup: update quota numbers in btrfs_qgroup_inherit Dongsheng Yang
@ 2015-03-19  6:01 ` Dongsheng Yang
  2015-03-19  6:01 ` [PATCH 7/7] Btrfs: qgroup: allow user to limit qgroup in different type Dongsheng Yang
  10 siblings, 0 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:01 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

So far, we can account quota number for data and metadata separately,
but in quota resan, we have not implemented this feature. This patch
make the rescan smart to distingush data and metadata and account them
separately.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 fs/btrfs/qgroup.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 9363fd0..bb98bdd 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -2872,6 +2872,8 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
 	int new_roots;
 	int slot;
 	int ret;
+	bool skinny_metadata = btrfs_fs_incompat(fs_info,
+						 SKINNY_METADATA);
 
 	path->leave_spinning = 1;
 	mutex_lock(&fs_info->qgroup_rescan_lock);
@@ -2910,14 +2912,27 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
 	mutex_unlock(&fs_info->qgroup_rescan_lock);
 
 	for (; slot < btrfs_header_nritems(scratch_leaf); ++slot) {
+		u8 quota_type = BTRFS_QGROUP_REF_TYPE_DATA;
+		struct btrfs_extent_item *ei;
+		u64 flags;
+
+		ei = btrfs_item_ptr(scratch_leaf, slot, struct btrfs_extent_item);
+		flags = btrfs_extent_flags(scratch_leaf, ei);
+
 		btrfs_item_key_to_cpu(scratch_leaf, &found, slot);
 		if (found.type != BTRFS_EXTENT_ITEM_KEY &&
 		    found.type != BTRFS_METADATA_ITEM_KEY)
 			continue;
-		if (found.type == BTRFS_METADATA_ITEM_KEY)
+		if (found.type == BTRFS_METADATA_ITEM_KEY) {
 			num_bytes = fs_info->extent_root->nodesize;
-		else
+			if (btrfs_fs_incompat(fs_info, QGROUP_TYPE))
+				quota_type = BTRFS_QGROUP_REF_TYPE_METADATA;
+		} else {
 			num_bytes = found.offset;
+			if (!skinny_metadata && (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) &&
+			    btrfs_fs_incompat(fs_info, QGROUP_TYPE))
+				quota_type = BTRFS_QGROUP_REF_TYPE_METADATA;
+		}
 
 		ulist_reinit(qgroups);
 		ret = btrfs_find_all_roots(NULL, fs_info, found.objectid, 0,
@@ -2937,7 +2952,7 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
 			goto out;
 		}
 
-		ret = qgroup_adjust_counters(fs_info, 0, num_bytes, 0, qgroups,
+		ret = qgroup_adjust_counters(fs_info, 0, num_bytes, quota_type, qgroups,
 					     seq, 0, new_roots, 1);
 		if (ret < 0) {
 			spin_unlock(&fs_info->qgroup_lock);
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 7/7] Btrfs: qgroup: allow user to limit qgroup in different type.
  2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
                   ` (9 preceding siblings ...)
  2015-03-19  6:01 ` [PATCH 6/7] Btrfs: qgroup: account data and metadata separately in rescan Dongsheng Yang
@ 2015-03-19  6:01 ` Dongsheng Yang
  10 siblings, 0 replies; 12+ messages in thread
From: Dongsheng Yang @ 2015-03-19  6:01 UTC (permalink / raw)
  To: linux-btrfs, dsterba, jbacik, clm; +Cc: Dongsheng Yang

until now, we can account the quota number for data and metadata
separately, but we can not limit only one of them. This patch
add the support to only limit one of the data or metadata.

Also you can limit them at the same time.

Even you can limit data quota, metadata quota and mixed quota
at the same time.

Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 fs/btrfs/qgroup.c | 10 +++++++---
 fs/btrfs/qgroup.h | 26 ++++++++++++++++++++++++++
 2 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index bb98bdd..793c7bb 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -1322,6 +1322,7 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
 	struct btrfs_root *quota_root;
 	struct btrfs_qgroup *qgroup;
 	struct btrfs_qgroup_limits *limits;
+	u8 limits_type = get_limit_type(limit->flags);
 	int ret = 0;
 
 	mutex_lock(&fs_info->qgroup_ioctl_lock);
@@ -1337,9 +1338,12 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
 		goto out;
 	}
 
-	/* To the compatibility, treat the mixed limits as the
-	 * default limits now. will change it later. */
-	limits = &qgroup->mixed_limits;
+	if (limits_type == BTRFS_QGROUP_LIMIT_DATA)
+		limits = &qgroup->data_limits;
+	else if (limits_type == BTRFS_QGROUP_LIMIT_METADATA)
+		limits = &qgroup->metadata_limits;
+	else
+		limits = &qgroup->mixed_limits;
 
 	spin_lock(&fs_info->qgroup_lock);
 	if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_RFER)
diff --git a/fs/btrfs/qgroup.h b/fs/btrfs/qgroup.h
index 11b73f3..6e4565f 100644
--- a/fs/btrfs/qgroup.h
+++ b/fs/btrfs/qgroup.h
@@ -36,6 +36,32 @@
 #define BTRFS_QGROUP_REF_TYPE_DEFAULT	BTRFS_QGROUP_REF_TYPE_DATA
 
 /*
+ * As we can account and limit data and metadata in
+ * a qgroup separately. We use the first 8 bits in
+ * btrfs_qgroup_limit->flags to specify the type we
+ * want to limit. Currently, there are three choice:
+ * DATA, METADATA, MIXED.
+ */
+#define BTRFS_QGROUP_LIMIT_TYPE_SHIFT   56
+
+#define BTRFS_QGROUP_LIMIT_DATA         1
+#define BTRFS_QGROUP_LIMIT_METADATA     2
+#define BTRFS_QGROUP_LIMIT_MIXED        4
+
+static inline u8 get_limit_type(u64 flag)
+{
+        u8 type = (flag >> BTRFS_QGROUP_LIMIT_TYPE_SHIFT);
+	/*
+	 * If user did not set the type for limit, default
+	 * for mixed_limits;
+	 */
+	if (!type)
+		type = BTRFS_QGROUP_LIMIT_MIXED;
+	return type;
+}
+
+
+/*
  * A description of the operations, all of these operations only happen when we
  * are adding the 1st reference for that subvolume in the case of adding space
  * or on the last reference delete in the case of subtraction.  The only
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2015-03-19  6:05 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-19  6:00 [PATCH 0/7 V2] Btrfs: qgroup: part-4: Add type to btrfs qgroup Dongsheng Yang
2015-03-19  6:00 ` [PATCH 1/4] Btrfs-progs: qgroup: add incompatability feature for QGROUP_TYPE Dongsheng Yang
2015-03-19  6:00 ` [PATCH 1/7] Btrfs: qgroup: split information and limits in qgroup to other structures Dongsheng Yang
2015-03-19  6:00 ` [PATCH 2/4] Btrfs-progs: qgroup: print info and limits type in btrfs-debug-tree Dongsheng Yang
2015-03-19  6:00 ` [PATCH 2/7] Btrfs: qgroup: add incompatability feature for QGROUP_TYPE Dongsheng Yang
2015-03-19  6:00 ` [PATCH 3/4] Btrfs-progs: qgroup: add a opt for type of qgroup limit Dongsheng Yang
2015-03-19  6:00 ` [PATCH 3/7] Btrfs: qgroup: record and account ref for qgroup in different type Dongsheng Yang
2015-03-19  6:01 ` [PATCH 4/4] Btrfs-progs: qgroup: show specified quota data Dongsheng Yang
2015-03-19  6:01 ` [PATCH 4/7] Btrfs: qgroup: update all infos and limits to disk Dongsheng Yang
2015-03-19  6:01 ` [PATCH 5/7] Btrfs: qgroup: update quota numbers in btrfs_qgroup_inherit Dongsheng Yang
2015-03-19  6:01 ` [PATCH 6/7] Btrfs: qgroup: account data and metadata separately in rescan Dongsheng Yang
2015-03-19  6:01 ` [PATCH 7/7] Btrfs: qgroup: allow user to limit qgroup in different type Dongsheng Yang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.