Skip to contentSkip to conversation

Btrfs: cleanup duplicated division functions

PATCH Superseded Miao Xie 3 participants 24 messages Sep 13, 2012 – Sep 28, 2012 Btrfs file system

lore
Share & tools
lore

Miao Xie

author
#0 lore raw

PATCH 1/2 Btrfs: cleanup duplicated division functions

div_factor{_fine} has been implemented for two times, cleanup it. And I move them into a independent file named math.h because they are common math functions.

---
 fs/btrfs/extent-tree.c |   19 +------------------
 fs/btrfs/math.h        |   44 ++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/volumes.c     |   23 +----------------------
 3 files changed, 46 insertions(+), 40 deletions(-)
 create mode 100644 fs/btrfs/math.h
fs/btrfs/extent-tree.c +1 -18
index a010234..5f6bae1 100644
@@ -33,6 +33,7 @@
 #include "volumes.h"
 #include "locking.h"
 #include "free-space-cache.h"
+#include "math.h"
 
 #undef SCRAMBLE_DELAYED_REFS
 
@@ -648,24 +649,6 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
 	rcu_read_unlock();
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-	if (factor == 10)
-		return num;
-	num *= factor;
-	do_div(num, 10);
-	return num;
-}
-
-static u64 div_factor_fine(u64 num, int factor)
-{
-	if (factor == 100)
-		return num;
-	num *= factor;
-	do_div(num, 100);
-	return num;
-}
-
 u64 btrfs_find_block_group(struct btrfs_root *root,
 			   u64 search_start, u64 search_hint, int owner)
 {
fs/btrfs/math.h new file +44 -0

44 lines not on this page · raw message

fs/btrfs/volumes.c +1 -22
index 3f4e70e..2558fc0 100644
@@ -25,7 +25,6 @@
 #include <linux/capability.h>
 #include <linux/ratelimit.h>
 #include <linux/kthread.h>
-#include <asm/div64.h>
 #include "compat.h"
 #include "ctree.h"
 #include "extent_map.h"
@@ -36,6 +35,7 @@
 #include "async-thread.h"
 #include "check-integrity.h"
 #include "rcu-string.h"
+#include "math.h"
 
 static int init_first_rw_device(struct btrfs_trans_handle *trans,
 				struct btrfs_root *root,
@@ -2325,18 +2325,6 @@ static int chunk_profiles_filter(u64 chunk_type,
 	return 1;
 }
 
-static u64 div_factor_fine(u64 num, int factor)
-{
-	if (factor <= 0)
-		return 0;
-	if (factor >= 100)
-		return num;
-
-	num *= factor;
-	do_div(num, 100);
-	return num;
-}
-
 static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 			      struct btrfs_balance_args *bargs)
 {
@@ -2501,15 +2489,6 @@ static int should_balance_chunk(struct btrfs_root *root,
 	return 1;
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-	if (factor == 10)
-		return num;
-	num *= factor;
-	do_div(num, 10);
-	return num;
-}
-
 static int __btrfs_balance(struct btrfs_fs_info *fs_info)
 {
 	struct btrfs_balance_control *bctl = fs_info->balance_ctl;
Signature · 1 line
1.7.6.5
#1 lore raw
Quoted 3 lines · Miao Xie

div_factor{_fine} has been implemented for two times, cleanup it. And I move them into a independent file named math.h because they are common math functions.

You removed the sanity checks:

- if (factor <= 0)
- return 0;
- if (factor >= 100)
- return num;

in new version. And I don't think it's necessary to add an extra include with a rather generic name and trivial code. A separate .h/.c with non-filesystem related support code like this looks more suitable.

Do you intend to use the functions out of extent-tree.c ?

david

author
#2 lore raw

fs/btrfs/volumes.c static int chunk_profiles_filter(u64 chunk_type, · line 2333

Quoted 11 lines · David Sterba
Quoted 3 lines · Miao Xie

div_factor{_fine} has been implemented for two times, cleanup it. And I move them into a independent file named math.h because they are common math functions.

You removed the sanity checks:

fs/btrfs/volumes.c +0 -4
-       if (factor <= 0)
-               return 0;
-       if (factor >= 100)
-               return num;

As inline functions, they should not contain complex checks, the caller should make sure the parameters are right. I think.

Quoted 5 lines

in new version. And I don't think it's necessary to add an extra include with a rather generic name and trivial code. A separate .h/.c with non-filesystem related support code like this looks more suitable.

Do you intend to use the functions out of extent-tree.c ?

They are used in both extent-tree.c and volumes.c from the outset, but they were implemented in these two files severally.

#3 lore raw
Quoted 8 lines · Miao Xie
Quoted 7 lines · David Sterba
Quoted 3 lines · Miao Xie

div_factor{_fine} has been implemented for two times, cleanup it. And I move them into a independent file named math.h because they are common math functions.

You removed the sanity checks:

Quoted 7 lines

fs/btrfs/volumes.c static int chunk_profiles_filter(u64 chunk_type, · line 2333

Quoted 4 lines
fs/btrfs/volumes.c +0 -4
-       if (factor <= 0)
-               return 0;
-       if (factor >= 100)
-               return num;

As inline functions, they should not contain complex checks, the caller should make sure the parameters are right. I think.

div_factor_fine() in volumes.c is not inline, and is called from chunk_usage_filter() on unvalidated user input. If you think the caller should do those checks, you should move them to the caller as part of your patch.

Thanks,

Ilya

#4 lore raw
In reply to Miao Xie
Quoted 8 lines · Miao Xie
Quoted 7 lines · David Sterba
Quoted 3 lines · Miao Xie

div_factor{_fine} has been implemented for two times, cleanup it. And I move them into a independent file named math.h because they are common math functions.

You removed the sanity checks:

Quoted 7 lines

fs/btrfs/volumes.c static int chunk_profiles_filter(u64 chunk_type, · line 2333

Quoted 4 lines
fs/btrfs/volumes.c +0 -4
-       if (factor <= 0)
-               return 0;
-       if (factor >= 100)
-               return num;

As inline functions, they should not contain complex checks, the caller should make sure the parameters are right. I think.

It's compiler's job to decide whether a function should be inlined or not. The keyword/function attribute 'inline' is only a hint, unless always_inline is used and the author should be sure that it really has the expected outcome and that compiler is wrong here.

I don't agree that each caller should do the checks, it only makes code harder to read and forces the authors to check for conditions that may not be apparent or are just ommitted.

If we need a function that does not check the boundaries, then of course go for it, but I don't see such case yet.

Quoted 8 lines
Quoted 5 lines

in new version. And I don't think it's necessary to add an extra include with a rather generic name and trivial code. A separate .h/.c with non-filesystem related support code like this looks more suitable.

Do you intend to use the functions out of extent-tree.c ?

They are used in both extent-tree.c and volumes.c from the outset, but they were implemented in these two files severally.

Ah, I see.

david

author
#5 lore raw
Quoted 14 lines · David Sterba
Quoted 13 lines · Miao Xie
Quoted 11 lines · David Sterba
Quoted 3 lines · Miao Xie

div_factor{_fine} has been implemented for two times, cleanup it. And I move them into a independent file named math.h because they are common math functions.

You removed the sanity checks:

fs/btrfs/volumes.c +0 -4
-       if (factor <= 0)
-               return 0;
-       if (factor >= 100)
-               return num;
Quoted 7 lines
Quoted 2 lines

As inline functions, they should not contain complex checks, the caller should make sure the parameters are right. I think.

It's compiler's job to decide whether a function should be inlined or not. The keyword/function attribute 'inline' is only a hint, unless always_inline is used and the author should be sure that it really has the expected outcome and that compiler is wrong here.

Right, but I think we should make the functions as simple as possible since they are marked as inline, because the simple function is more likely to be inlined than the complex one.

Quoted 3 lines

I don't agree that each caller should do the checks, it only makes code harder to read and forces the authors to check for conditions that may not be apparent or are just ommitted.

Right. But for these functions, we are sure the value of the parameters is in the right range in the most place, and all the place that we are sure the value is right is in the hot path. The only place that we need check the parameters is in slow path, this is also the reason why we make them inline. so doing those checks just wastes time. We just need modify the caller.

Thanks
Miao

Quoted 16 lines

If we need a function that does not check the boundaries, then of course go for it, but I don't see such case yet.

Quoted 8 lines
Quoted 5 lines

in new version. And I don't think it's necessary to add an extra include with a rather generic name and trivial code. A separate .h/.c with non-filesystem related support code like this looks more suitable.

Do you intend to use the functions out of extent-tree.c ?

They are used in both extent-tree.c and volumes.c from the outset, but they were implemented in these two files severally.

Ah, I see.

david

author
#6 lore raw

PATCH v2 1/2 Btrfs: cleanup duplicated division functions

In reply to Miao Xie

div_factor{_fine} has been implemented for two times, cleanup it. And I move them into a independent file named math.h because they are common math functions.

Because those functions are mostly used on the hot path, and we are sure the parameters are right in the most cases, we don't add complex checks for the parameters. But in the other place, we must check and make sure the parameters are right. So besides the code cleanup, this patch also add a check for the usage of the space balance, it is the only place that we need add check to make sure the parameters of div_factor{_fine} are right till now.

---
Changelog v1 -> v2:
- add missing check

---
 fs/btrfs/extent-tree.c |   19 +------------------
 fs/btrfs/ioctl.c       |   18 ++++++++++++++++++
 fs/btrfs/math.h        |   44 ++++++++++++++++++++++++++++++++++++++++++++
 fs/btrfs/volumes.c     |   23 +----------------------
 4 files changed, 64 insertions(+), 40 deletions(-)
 create mode 100644 fs/btrfs/math.h
fs/btrfs/extent-tree.c +1 -18
index a010234..5f6bae1 100644
@@ -33,6 +33,7 @@
 #include "volumes.h"
 #include "locking.h"
 #include "free-space-cache.h"
+#include "math.h"
 
 #undef SCRAMBLE_DELAYED_REFS
 
@@ -648,24 +649,6 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
 	rcu_read_unlock();
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-	if (factor == 10)
-		return num;
-	num *= factor;
-	do_div(num, 10);
-	return num;
-}
-
-static u64 div_factor_fine(u64 num, int factor)
-{
-	if (factor == 100)
-		return num;
-	num *= factor;
-	do_div(num, 100);
-	return num;
-}
-
 u64 btrfs_find_block_group(struct btrfs_root *root,
 			   u64 search_start, u64 search_hint, int owner)
 {
fs/btrfs/ioctl.c +18 -0
index 9384a2a..d8d53f7 100644
@@ -3335,6 +3335,24 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 
 			goto do_balance;
 		}
+
+		if ((bargs->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->data.usage < 0 || bargs->data.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->meta.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->meta.usage < 0 || bargs->meta.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->sys.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->sys.usage < 0 || bargs->sys.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
 	} else {
 		bargs = NULL;
 	}
fs/btrfs/math.h new file +44 -0

44 lines not on this page · raw message

fs/btrfs/volumes.c +1 -22
index 3f4e70e..2558fc0 100644
@@ -25,7 +25,6 @@
 #include <linux/capability.h>
 #include <linux/ratelimit.h>
 #include <linux/kthread.h>
-#include <asm/div64.h>
 #include "compat.h"
 #include "ctree.h"
 #include "extent_map.h"
@@ -36,6 +35,7 @@
 #include "async-thread.h"
 #include "check-integrity.h"
 #include "rcu-string.h"
+#include "math.h"
 
 static int init_first_rw_device(struct btrfs_trans_handle *trans,
 				struct btrfs_root *root,
@@ -2325,18 +2325,6 @@ static int chunk_profiles_filter(u64 chunk_type,
 	return 1;
 }
 
-static u64 div_factor_fine(u64 num, int factor)
-{
-	if (factor <= 0)
-		return 0;
-	if (factor >= 100)
-		return num;
-
-	num *= factor;
-	do_div(num, 100);
-	return num;
-}
-
 static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 			      struct btrfs_balance_args *bargs)
 {
@@ -2501,15 +2489,6 @@ static int should_balance_chunk(struct btrfs_root *root,
 	return 1;
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-	if (factor == 10)
-		return num;
-	num *= factor;
-	do_div(num, 10);
-	return num;
-}
-
 static int __btrfs_balance(struct btrfs_fs_info *fs_info)
 {
 	struct btrfs_balance_control *bctl = fs_info->balance_ctl;
Signature · 1 line
1.7.6.5
#7 lore raw
Quoted 7 lines · Miao Xie

Because those functions are mostly used on the hot path, and we are sure the parameters are right in the most cases, we don't add complex checks for the parameters. But in the other place, we must check and make sure the parameters are right. So besides the code cleanup, this patch also add a check for the usage of the space balance, it is the only place that we need add check to make sure the parameters of div_factor{_fine} are right till now.

I've reviewed the hotpaths, makes sense to optimize for speed. Adding the boundary checks to balance ioctl is ok.

A few suggestions:

* drop the version that does the /10 version and keep only /100 (naming it div_factor)
* drop the

+ if (factor == 10)
+ return num;

check, there's only one instance where we pass the maximum value (and it's not a frequent case), so there's the if() penalty, makes the function smaller and even more suitable for inlining.

fs/btrfs/ioctl.c static long btrfs_ioctl_balance(struct file *file, void __user *arg) · line 3340

Quoted 11 lines
fs/btrfs/ioctl.c +3 -0
index 9384a2a..d8d53f7 100644
@@ -3335,6 +3335,24 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 
 			goto do_balance;
 		}
+
+		if ((bargs->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->data.usage < 0 || bargs->data.usage > 100)) {

data.usage <= 0

otherwise you'd divide by 0 in chunk_usage_filter()

(in current version the check is done in the _fine version, so -dusage=0 does not crash kernel)

fs/btrfs/ioctl.c static long btrfs_ioctl_balance(struct file *file, void __user *arg) · line 3346

Quoted 6 lines
fs/btrfs/ioctl.c +6 -0
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->meta.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->meta.usage < 0 || bargs->meta.usage > 100)) {

same here

fs/btrfs/ioctl.c static long btrfs_ioctl_balance(struct file *file, void __user *arg) · line 3352

Quoted 6 lines
fs/btrfs/ioctl.c +6 -0
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->sys.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->sys.usage < 0 || bargs->sys.usage > 100)) {

same here

fs/btrfs/math.h

Quoted 11 lines
fs/btrfs/ioctl.c +3 -0
+			ret = -EINVAL;
+			goto out_bargs;
+		}
 	} else {
 		bargs = NULL;
 	}
fs/btrfs/math.h new file +0 -0
new file mode 100644
index 0000000..b7816ce

I think we don't need single file to hold one trivial function then :)

fs/btrfs/math.h line 8

Quoted 9 lines
fs/btrfs/math.h new file +8 -0
@@ -0,0 +1,44 @@
+#include <asm/div64.h>
+
+static inline u64 div_factor(u64 num, int factor)
+{
+	num *= factor;
+	do_div(num, 100);
+	return num;
+}

david

author
#8 lore raw
Quoted 21 lines · David Sterba
Quoted 7 lines · Miao Xie

Because those functions are mostly used on the hot path, and we are sure the parameters are right in the most cases, we don't add complex checks for the parameters. But in the other place, we must check and make sure the parameters are right. So besides the code cleanup, this patch also add a check for the usage of the space balance, it is the only place that we need add check to make sure the parameters of div_factor{_fine} are right till now.

I've reviewed the hotpaths, makes sense to optimize for speed. Adding the boundary checks to balance ioctl is ok.

A few suggestions:

* drop the version that does the /10 version and keep only /100 (naming it div_factor)
* drop the

(quoted diff) +2 -0
+	if (factor == 10)
+		return num;
Quoted 3 lines

check, there's only one instance where we pass the maximum value (and it's not a frequent case), so there's the if() penalty, makes the function smaller and even more suitable for inlining.

OK.

Quoted 15 lines

fs/btrfs/ioctl.c static long btrfs_ioctl_balance(struct file *file, void __user *arg) · line 3340

Quoted 12 lines
fs/btrfs/ioctl.c +3 -0
index 9384a2a..d8d53f7 100644
@@ -3335,6 +3335,24 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 
 			goto do_balance;
 		}
+
+		if ((bargs->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->data.usage < 0 || bargs->data.usage > 100)) {

data.usage <= 0

Quoted 1 line

otherwise you'd divide by 0 in chunk_usage_filter()

The divisor always is 100 or 10, so...

Quoted 8 lines

fs/btrfs/math.h

Quoted 5 lines
fs/btrfs/math.h new file +0 -0
new file mode 100644
index 0000000..b7816ce

I think we don't need single file to hold one trivial function then :)

Quoted 9 lines

fs/btrfs/math.h line 8

Quoted 9 lines
fs/btrfs/math.h new file +8 -0
@@ -0,0 +1,44 @@
+#include <asm/div64.h>
+
+static inline u64 div_factor(u64 num, int factor)
+{
+	num *= factor;
+	do_div(num, 100);
+	return num;
+}

I don't find a suitable file to put it down. Maybe we can stuff it into ctree.h, but I prefer a single file to a unrelated file.

Thanks
Miao

author
#9 lore raw

PATCH v3 1/2 Btrfs: cleanup duplicated division functions

In reply to Miao Xie

div_factor{_fine} has been implemented for two times, and these two functions are very similar, so cleanup the reduplicate implement and drop the original div_factor(), and then rename div_factor_fine() to div_factor(). So the divisor of the new div_factor() is 100, not 10.

And I move div_factor into a independent file named math.h because it is a common math function, may be used by every composition of btrfs.

Because these functions are mostly used on the hot path, and we are sure the parameters are right in the most cases, we don't add complex checks for the parameters. But in the other place, we must check and make sure the parameters are right. So besides the code cleanup, this patch also add a check for the usage of the space balance, it is the only place that we need add check to make sure the parameters of div_factor are right till now.

---
Changelog v2 -> v3:
- drop the original div_factor and rename div_factor_fine to div_factor
- drop the check of the factor

Changelog v1 -> v2:
- add missing check

---
 fs/btrfs/extent-tree.c |   29 ++++++-----------------------
 fs/btrfs/ioctl.c       |   18 ++++++++++++++++++
 fs/btrfs/math.h        |   33 +++++++++++++++++++++++++++++++++
 fs/btrfs/relocation.c  |    2 +-
 fs/btrfs/transaction.c |    2 +-
 fs/btrfs/volumes.c     |   30 +++++-------------------------
 6 files changed, 64 insertions(+), 50 deletions(-)
 create mode 100644 fs/btrfs/math.h
fs/btrfs/extent-tree.c +6 -23
index a010234..bcb9ced 100644
@@ -33,6 +33,7 @@
 #include "volumes.h"
 #include "locking.h"
 #include "free-space-cache.h"
+#include "math.h"
 
 #undef SCRAMBLE_DELAYED_REFS
 
@@ -648,24 +649,6 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
 	rcu_read_unlock();
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-	if (factor == 10)
-		return num;
-	num *= factor;
-	do_div(num, 10);
-	return num;
-}
-
-static u64 div_factor_fine(u64 num, int factor)
-{
-	if (factor == 100)
-		return num;
-	num *= factor;
-	do_div(num, 100);
-	return num;
-}
-
 u64 btrfs_find_block_group(struct btrfs_root *root,
 			   u64 search_start, u64 search_hint, int owner)
 {
@@ -674,7 +657,7 @@ u64 btrfs_find_block_group(struct btrfs_root *root,
 	u64 last = max(search_hint, search_start);
 	u64 group_start = 0;
 	int full_search = 0;
-	int factor = 9;
+	int factor = 90;
 	int wrapped = 0;
 again:
 	while (1) {
@@ -708,7 +691,7 @@ again:
 	if (!full_search && factor < 10) {
 		last = search_start;
 		full_search = 1;
-		factor = 10;
+		factor = 100;
 		goto again;
 	}
 found:
@@ -3513,7 +3496,7 @@ static int should_alloc_chunk(struct btrfs_root *root,
 	if (force == CHUNK_ALLOC_LIMITED) {
 		thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
 		thresh = max_t(u64, 64 * 1024 * 1024,
-			       div_factor_fine(thresh, 1));
+			       div_factor(thresh, 1));
 
 		if (num_bytes - num_allocated < thresh)
 			return 1;
@@ -3521,12 +3504,12 @@ static int should_alloc_chunk(struct btrfs_root *root,
 	thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
 
 	/* 256MB or 2% of the FS */
-	thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 2));
+	thresh = max_t(u64, 256 * 1024 * 1024, div_factor(thresh, 2));
 	/* system chunks need a much small threshold */
 	if (sinfo->flags & BTRFS_BLOCK_GROUP_SYSTEM)
 		thresh = 32 * 1024 * 1024;
 
-	if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 8))
+	if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 80))
 		return 0;
 	return 1;
 }
fs/btrfs/ioctl.c +18 -0
index 9384a2a..d8d53f7 100644
@@ -3335,6 +3335,24 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 
 			goto do_balance;
 		}
+
+		if ((bargs->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->data.usage < 0 || bargs->data.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->meta.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->meta.usage < 0 || bargs->meta.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->sys.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->sys.usage < 0 || bargs->sys.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
 	} else {
 		bargs = NULL;
 	}
fs/btrfs/math.h new file +33 -0
new file mode 100644
index 0000000..a157665
@@ -0,0 +1,33 @@
+
+/*
+ * Copyright (C) 2012 Fujitsu.  All rights reserved.
+ * Written by Miao Xie <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __BTRFS_MATH_H
+#define __BTRFS_MATH_H
+
+#include <asm/div64.h>
+
+static inline u64 div_factor(u64 num, int factor)
+{
+	num *= factor;
+	do_div(num, 100);
+	return num;
+}
+
+#endif
fs/btrfs/relocation.c +1 -1
index f193096..2254478 100644
@@ -3813,7 +3813,7 @@ restart:
 			}
 		}
 
-		ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 5);
+		ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 50);
 		if (ret < 0) {
 			if (ret != -ENOSPC) {
 				err = ret;
fs/btrfs/transaction.c +1 -1
index cf98dbc..115f054 100644
@@ -489,7 +489,7 @@ static int should_end_transaction(struct btrfs_trans_handle *trans,
 {
 	int ret;
 
-	ret = btrfs_block_rsv_check(root, &root->fs_info->global_block_rsv, 5);
+	ret = btrfs_block_rsv_check(root, &root->fs_info->global_block_rsv, 50);
 	return ret ? 1 : 0;
 }
 
fs/btrfs/volumes.c +5 -25
index 3f4e70e..1fd43a4 100644
@@ -25,7 +25,6 @@
 #include <linux/capability.h>
 #include <linux/ratelimit.h>
 #include <linux/kthread.h>
-#include <asm/div64.h>
 #include "compat.h"
 #include "ctree.h"
 #include "extent_map.h"
@@ -36,6 +35,7 @@
 #include "async-thread.h"
 #include "check-integrity.h"
 #include "rcu-string.h"
+#include "math.h"
 
 static int init_first_rw_device(struct btrfs_trans_handle *trans,
 				struct btrfs_root *root,
@@ -2325,18 +2325,6 @@ static int chunk_profiles_filter(u64 chunk_type,
 	return 1;
 }
 
-static u64 div_factor_fine(u64 num, int factor)
-{
-	if (factor <= 0)
-		return 0;
-	if (factor >= 100)
-		return num;
-
-	num *= factor;
-	do_div(num, 100);
-	return num;
-}
-
 static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 			      struct btrfs_balance_args *bargs)
 {
@@ -2347,7 +2335,8 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 	cache = btrfs_lookup_block_group(fs_info, chunk_offset);
 	chunk_used = btrfs_block_group_used(&cache->item);
 
-	user_thresh = div_factor_fine(cache->key.offset, bargs->usage);
+	BUG_ON(bargs->usage < 0 || bargs->usage > 100);
+	user_thresh = div_factor(cache->key.offset, bargs->usage);
 	if (chunk_used < user_thresh)
 		ret = 0;
 
@@ -2501,15 +2490,6 @@ static int should_balance_chunk(struct btrfs_root *root,
 	return 1;
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-	if (factor == 10)
-		return num;
-	num *= factor;
-	do_div(num, 10);
-	return num;
-}
-
 static int __btrfs_balance(struct btrfs_fs_info *fs_info)
 {
 	struct btrfs_balance_control *bctl = fs_info->balance_ctl;
@@ -2534,7 +2514,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
 	devices = &fs_info->fs_devices->devices;
 	list_for_each_entry(device, devices, dev_list) {
 		old_size = device->total_bytes;
-		size_to_free = div_factor(old_size, 1);
+		size_to_free = div_factor(old_size, 10);
 		size_to_free = min(size_to_free, (u64)1 * 1024 * 1024);
 		if (!device->writeable ||
 		    device->total_bytes - device->bytes_used > size_to_free)
@@ -3284,7 +3264,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 	}
 
 	/* we don't want a chunk larger than 10% of writeable space */
-	max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 1),
+	max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 10),
 			     max_chunk_size);
 
 	devices_info = kzalloc(sizeof(*devices_info) * fs_devices->rw_devices,
Signature · 1 line
1.7.6.5
#10 lore raw

fs/btrfs/ioctl.c static long btrfs_ioctl_balance(struct file *file, void __user *arg) · line 3340

Quoted 9 lines · Miao Xie
fs/btrfs/ioctl.c +3 -0
@@ -3335,6 +3335,24 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 
 			goto do_balance;
 		}
+
+		if ((bargs->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->data.usage < 0 || bargs->data.usage > 100)) {

the 0 checks belong here

Quoted 19 lines
fs/btrfs/ioctl.c +15 -0
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->meta.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->meta.usage < 0 || bargs->meta.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->sys.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->sys.usage < 0 || bargs->sys.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
 	} else {
 		bargs = NULL;
 	}

fs/btrfs/ioctl.c static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, · line 2338

Quoted 5 lines
fs/btrfs/ioctl.c +1 -1
@@ -2347,7 +2335,8 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 	cache = btrfs_lookup_block_group(fs_info, chunk_offset);
 	chunk_used = btrfs_block_group_used(&cache->item);
 
-	user_thresh = div_factor_fine(cache->key.offset, bargs->usage);
+	BUG_ON(bargs->usage < 0 || bargs->usage > 100);

otherwise it reliably crashes here

fs/btrfs/ioctl.c static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, · line 2342

Quoted 4 lines
fs/btrfs/ioctl.c +1 -0
+	user_thresh = div_factor(cache->key.offset, bargs->usage);
 	if (chunk_used < user_thresh)
 		ret = 0;
 

other than that, patch looks good tome,

thanks,
david

author
#11 lore raw
Quoted 35 lines · David Sterba

fs/btrfs/ioctl.c static long btrfs_ioctl_balance(struct file *file, void __user *arg) · line 3340

Quoted 9 lines · Miao Xie
fs/btrfs/ioctl.c +3 -0
@@ -3335,6 +3335,24 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 
 			goto do_balance;
 		}
+
+		if ((bargs->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->data.usage < 0 || bargs->data.usage > 100)) {

the 0 checks belong here

Quoted 22 lines
fs/btrfs/ioctl.c +15 -0
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->meta.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->meta.usage < 0 || bargs->meta.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->sys.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->sys.usage < 0 || bargs->sys.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
 	} else {
 		bargs = NULL;
 	}
@@ -2347,7 +2335,8 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 	cache = btrfs_lookup_block_group(fs_info, chunk_offset);
 	chunk_used = btrfs_block_group_used(&cache->item);
 
Quoted 4 lines

fs/btrfs/ioctl.c static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, · line 2338

Quoted 2 lines
fs/btrfs/ioctl.c +1 -1
-	user_thresh = div_factor_fine(cache->key.offset, bargs->usage);
+	BUG_ON(bargs->usage < 0 || bargs->usage > 100);

otherwise it reliably crashes here

Sorry, I don't know why it will crash here if we input 0. I tried to input 0, and it worked well.

I think the only case we must take into account is the users might input the wrong value (>100 or <0) on the old kernel, and it can be stored into the filesystem. If we mount this filesystem on the new kernel, some problems may happen.

Thanks
Miao

#12 lore raw
Quoted 11 lines · Miao Xie
Quoted 8 lines

fs/btrfs/volumes.c static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, · line 2338

Quoted 6 lines
fs/btrfs/volumes.c +1 -1
@@ -2347,7 +2335,8 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 	cache = btrfs_lookup_block_group(fs_info, chunk_offset);
 	chunk_used = btrfs_block_group_used(&cache->item);
 
-	user_thresh = div_factor_fine(cache->key.offset, bargs->usage);
+	BUG_ON(bargs->usage < 0 || bargs->usage > 100);

otherwise it reliably crashes here

Sorry, I don't know why it will crash here if we input 0. I tried to input 0, and it worked well.

My oversight, sorry.

Quoted 3 lines

I think the only case we must take into account is the users might input the wrong value (>100 or <0) on the old kernel, and it can be stored into the filesystem. If we mount this filesystem on the new kernel, some problems may happen.

So better avoid a BUG_ON.

#13 lore raw
In reply to Miao Xie
Quoted 131 lines · Miao Xie

div_factor{_fine} has been implemented for two times, and these two functions are very similar, so cleanup the reduplicate implement and drop the original div_factor(), and then rename div_factor_fine() to div_factor(). So the divisor of the new div_factor() is 100, not 10.

And I move div_factor into a independent file named math.h because it is a common math function, may be used by every composition of btrfs.

Because these functions are mostly used on the hot path, and we are sure the parameters are right in the most cases, we don't add complex checks for the parameters. But in the other place, we must check and make sure the parameters are right. So besides the code cleanup, this patch also add a check for the usage of the space balance, it is the only place that we need add check to make sure the parameters of div_factor are right till now.

---
Changelog v2 -> v3:
- drop the original div_factor and rename div_factor_fine to div_factor
- drop the check of the factor

Changelog v1 -> v2:
- add missing check

---
 fs/btrfs/extent-tree.c |   29 ++++++-----------------------
 fs/btrfs/ioctl.c       |   18 ++++++++++++++++++
 fs/btrfs/math.h        |   33 +++++++++++++++++++++++++++++++++
 fs/btrfs/relocation.c  |    2 +-
 fs/btrfs/transaction.c |    2 +-
 fs/btrfs/volumes.c     |   30 +++++-------------------------
 6 files changed, 64 insertions(+), 50 deletions(-)
 create mode 100644 fs/btrfs/math.h
fs/btrfs/extent-tree.c +6 -23
index a010234..bcb9ced 100644
@@ -33,6 +33,7 @@
 #include "volumes.h"
 #include "locking.h"
 #include "free-space-cache.h"
+#include "math.h"
 
 #undef SCRAMBLE_DELAYED_REFS
 
@@ -648,24 +649,6 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
 	rcu_read_unlock();
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-	if (factor == 10)
-		return num;
-	num *= factor;
-	do_div(num, 10);
-	return num;
-}
-
-static u64 div_factor_fine(u64 num, int factor)
-{
-	if (factor == 100)
-		return num;
-	num *= factor;
-	do_div(num, 100);
-	return num;
-}
-
 u64 btrfs_find_block_group(struct btrfs_root *root,
 			   u64 search_start, u64 search_hint, int owner)
 {
@@ -674,7 +657,7 @@ u64 btrfs_find_block_group(struct btrfs_root *root,
 	u64 last = max(search_hint, search_start);
 	u64 group_start = 0;
 	int full_search = 0;
-	int factor = 9;
+	int factor = 90;
 	int wrapped = 0;
 again:
 	while (1) {
@@ -708,7 +691,7 @@ again:
 	if (!full_search && factor < 10) {
 		last = search_start;
 		full_search = 1;
-		factor = 10;
+		factor = 100;
 		goto again;
 	}
 found:
@@ -3513,7 +3496,7 @@ static int should_alloc_chunk(struct btrfs_root *root,
 	if (force == CHUNK_ALLOC_LIMITED) {
 		thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
 		thresh = max_t(u64, 64 * 1024 * 1024,
-			       div_factor_fine(thresh, 1));
+			       div_factor(thresh, 1));
 
 		if (num_bytes - num_allocated < thresh)
 			return 1;
@@ -3521,12 +3504,12 @@ static int should_alloc_chunk(struct btrfs_root *root,
 	thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
 
 	/* 256MB or 2% of the FS */
-	thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 2));
+	thresh = max_t(u64, 256 * 1024 * 1024, div_factor(thresh, 2));
 	/* system chunks need a much small threshold */
 	if (sinfo->flags & BTRFS_BLOCK_GROUP_SYSTEM)
 		thresh = 32 * 1024 * 1024;
 
-	if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 8))
+	if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 80))
 		return 0;
 	return 1;
 }
fs/btrfs/ioctl.c +11 -0
index 9384a2a..d8d53f7 100644
@@ -3335,6 +3335,24 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 
 			goto do_balance;
 		}
+
+		if ((bargs->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->data.usage < 0 || bargs->data.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->meta.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->meta.usage < 0 || bargs->meta.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;

fs/btrfs/ioctl.c static long btrfs_ioctl_balance(struct file *file, void __user *arg) · line 3358

Quoted 10 lines
fs/btrfs/ioctl.c +7 -0
+		}
+
+		if ((bargs->sys.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->sys.usage < 0 || bargs->sys.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
 	} else {
 		bargs = NULL;
 	}

Why not drop this hunk ...

Quoted 105 lines
fs/btrfs/math.h new file +33 -0
new file mode 100644
index 0000000..a157665
@@ -0,0 +1,33 @@
+
+/*
+ * Copyright (C) 2012 Fujitsu.  All rights reserved.
+ * Written by Miao Xie <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __BTRFS_MATH_H
+#define __BTRFS_MATH_H
+
+#include <asm/div64.h>
+
+static inline u64 div_factor(u64 num, int factor)
+{
+	num *= factor;
+	do_div(num, 100);
+	return num;
+}
+
+#endif
fs/btrfs/relocation.c +1 -1
index f193096..2254478 100644
@@ -3813,7 +3813,7 @@ restart:
 			}
 		}
 
-		ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 5);
+		ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 50);
 		if (ret < 0) {
 			if (ret != -ENOSPC) {
 				err = ret;
fs/btrfs/transaction.c +1 -1
index cf98dbc..115f054 100644
@@ -489,7 +489,7 @@ static int should_end_transaction(struct btrfs_trans_handle *trans,
 {
 	int ret;
 
-	ret = btrfs_block_rsv_check(root, &root->fs_info->global_block_rsv, 5);
+	ret = btrfs_block_rsv_check(root, &root->fs_info->global_block_rsv, 50);
 	return ret ? 1 : 0;
 }
 
fs/btrfs/volumes.c +1 -13
index 3f4e70e..1fd43a4 100644
@@ -25,7 +25,6 @@
 #include <linux/capability.h>
 #include <linux/ratelimit.h>
 #include <linux/kthread.h>
-#include <asm/div64.h>
 #include "compat.h"
 #include "ctree.h"
 #include "extent_map.h"
@@ -36,6 +35,7 @@
 #include "async-thread.h"
 #include "check-integrity.h"
 #include "rcu-string.h"
+#include "math.h"
 
 static int init_first_rw_device(struct btrfs_trans_handle *trans,
 				struct btrfs_root *root,
@@ -2325,18 +2325,6 @@ static int chunk_profiles_filter(u64 chunk_type,
 	return 1;
 }
 
-static u64 div_factor_fine(u64 num, int factor)
-{
-	if (factor <= 0)
-		return 0;
-	if (factor >= 100)
-		return num;
-
-	num *= factor;
-	do_div(num, 100);
-	return num;
-}
-
 static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 			      struct btrfs_balance_args *bargs)
 {

fs/btrfs/volumes.c static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, · line 2341

Quoted 8 lines
fs/btrfs/volumes.c +2 -1
@@ -2347,7 +2335,8 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 	cache = btrfs_lookup_block_group(fs_info, chunk_offset);
 	chunk_used = btrfs_block_group_used(&cache->item);
 
-	user_thresh = div_factor_fine(cache->key.offset, bargs->usage);
+	BUG_ON(bargs->usage < 0 || bargs->usage > 100);
+	user_thresh = div_factor(cache->key.offset, bargs->usage);
 	if (chunk_used < user_thresh)
 		ret = 0;

... and leave the check where it was before?

fs/btrfs/volumes.c +7 -2
index 6019fb2..ff86f91 100644
@@ -2334,8 +2334,13 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 	cache = btrfs_lookup_block_group(fs_info, chunk_offset);
 	chunk_used = btrfs_block_group_used(&cache->item);
 
-	BUG_ON(bargs->usage < 0 || bargs->usage > 100);
-	user_thresh = div_factor(cache->key.offset, bargs->usage);
+	if (bargs->usage == 0)
+		user_thresh = 0;
+	else if (bargs->usage >= 100)
+		user_thresh = cache->key.offset;
+	else
+		user_thresh = div_factor(cache->key.offset, bargs->usage);
+
 	if (chunk_used < user_thresh)
 		ret = 0;
 

(diff is on top of the patch in question)

This is the most straightforward transformation I can think of. It doesn't result in an unnecessary BUG_ON, keeps churn to a minimum and doesn't change the "style" of the balance ioctl. (If I were to check every filter argument that way, btrfs_balance_ioctl() would be very long and complicated.)

Thanks,

Ilya

author
#14 lore raw
Quoted 23 lines · Ilya Dryomov
Quoted 23 lines
fs/btrfs/ioctl.c +15 -0
index 9384a2a..d8d53f7 100644
@@ -3335,6 +3335,24 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 
 			goto do_balance;
 		}
+
+		if ((bargs->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->data.usage < 0 || bargs->data.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->meta.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->meta.usage < 0 || bargs->meta.usage > 100)) {
+			ret = -EINVAL;
+			goto out_bargs;
+		}
+
+		if ((bargs->sys.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+		    (bargs->sys.usage < 0 || bargs->sys.usage > 100)) {
Quoted 8 lines

fs/btrfs/ioctl.c static long btrfs_ioctl_balance(struct file *file, void __user *arg) · line 3358

Quoted 6 lines
fs/btrfs/ioctl.c +3 -0
+			ret = -EINVAL;
+			goto out_bargs;
+		}
 	} else {
 		bargs = NULL;
 	}

Why not drop this hunk ...

Generally, we should check the value when it is input. If not, we might run our program with the wrong value, and it is possible to cause unknown problems. So I think the above chunk is necessary.

Quoted 22 lines
fs/btrfs/volumes.c +7 -2
index 6019fb2..ff86f91 100644
@@ -2334,8 +2334,13 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 	cache = btrfs_lookup_block_group(fs_info, chunk_offset);
 	chunk_used = btrfs_block_group_used(&cache->item);
 
-	BUG_ON(bargs->usage < 0 || bargs->usage > 100);
-	user_thresh = div_factor(cache->key.offset, bargs->usage);
+	if (bargs->usage == 0)
+		user_thresh = 0;
+	else if (bargs->usage >= 100)
+		user_thresh = cache->key.offset;
+	else
+		user_thresh = div_factor(cache->key.offset, bargs->usage);
+
 	if (chunk_used < user_thresh)
 		ret = 0;
 

(diff is on top of the patch in question)

Quoted 2 lines

This is the most straightforward transformation I can think of. It doesn't result in an unnecessary BUG_ON, keeps churn to a minimum and

agree with you.

Quoted 3 lines

doesn't change the "style" of the balance ioctl. (If I were to check every filter argument that way, btrfs_balance_ioctl() would be very long and complicated.)

I think the check in btrfs_balance_ioctl() is necessary, the reason is above.

Thanks
Miao

#15 lore raw
Quoted 3 lines · Miao Xie

Generally, we should check the value when it is input. If not, we might run our program with the wrong value, and it is possible to cause unknown problems. So I think the above chunk is necessary.

The difference is that giving an invalid value will exit early (your version), while Ilya's version will clamp the 'usage' to the allowed range during processing. From usability POV, I'd prefer to let the command fail early with a verbose error eg. that the range is invalid.

Quoted 5 lines
Quoted 4 lines

(diff is on top of the patch in question)

This is the most straightforward transformation I can think of. It doesn't result in an unnecessary BUG_ON, keeps churn to a minimum and

Quoted 7 lines

agree with you.

Quoted 3 lines

doesn't change the "style" of the balance ioctl. (If I were to check every filter argument that way, btrfs_balance_ioctl() would be very long and complicated.)

I think the check in btrfs_balance_ioctl() is necessary, the reason is above.

btrfs_balance_ioctl does not seem as the right place, it does the processing related to the state of balance (resume/cancel etc). Look at btrfs_balance() itself, it does lot more sanity checks of the parameters. We can put the extra checks into helpers (and not only this one) if clarity and readability of the function becomes a concern.

david

#16 lore raw
Quoted 9 lines · David Sterba
Quoted 3 lines · Miao Xie

Generally, we should check the value when it is input. If not, we might run our program with the wrong value, and it is possible to cause unknown problems. So I think the above chunk is necessary.

The difference is that giving an invalid value will exit early (your version), while Ilya's version will clamp the 'usage' to the allowed range during processing. From usability POV, I'd prefer to let the command fail early with a verbose error eg. that the range is invalid.

I think that's the job for progs, and that's where this and a few other checks are currently implemented.

There is no possibility for "unknown problems", that's exactly how it's been implemented before the cleanup. The purpose of balance filters (and the usage filter in particular) is to lower the number of chunks we have to relocate. If someone decides to use raw ioctls, and supplies us with the invalid value, we just cut it down to a 100 and proceed. usage=100 is the equivalent of not using the usage filter at all, so the raw ioctl user will get what he deserves.

This is very similar to what we currently do with other filters. For example, "soft" can only be used with "convert", and this is checked by progs. But, if somebody were to set a "soft" flag without setting "convert" we would simply ignore that "soft". Same goes for "drange" and "devid", invalid ranges, invalid devids, etc. Pulling all these checks into the kernel is questionable at best, and, if enough people insist on it, should be discussed separately.

Thanks,

Ilya

author
#17 lore raw
Quoted 22 lines · Ilya Dryomov
Quoted 9 lines · David Sterba
Quoted 3 lines · Miao Xie

Generally, we should check the value when it is input. If not, we might run our program with the wrong value, and it is possible to cause unknown problems. So I think the above chunk is necessary.

The difference is that giving an invalid value will exit early (your version), while Ilya's version will clamp the 'usage' to the allowed range during processing. From usability POV, I'd prefer to let the command fail early with a verbose error eg. that the range is invalid.

I think that's the job for progs, and that's where this and a few other checks are currently implemented.

There is no possibility for "unknown problems", that's exactly how it's been implemented before the cleanup. The purpose of balance filters (and the usage filter in particular) is to lower the number of chunks we have to relocate. If someone decides to use raw ioctls, and supplies us with the invalid value, we just cut it down to a 100 and proceed. usage=100 is the equivalent of not using the usage filter at all, so the raw ioctl user will get what he deserves.

Quoted 7 lines

This is very similar to what we currently do with other filters. For example, "soft" can only be used with "convert", and this is checked by progs. But, if somebody were to set a "soft" flag without setting "convert" we would simply ignore that "soft". Same goes for "drange" and "devid", invalid ranges, invalid devids, etc. Pulling all these checks into the kernel is questionable at best, and, if enough people insist on it, should be discussed separately.

I think the usage is a special case that doesn't cause critical problem and are not used everywhere. But if there is a variant which is referenced at several places and the kernel would crash if it is invalid, in this case, we would add the check everywhere and make the code more complex and ugly if we don't check it when it is passed in. Besides that if we have done lots of work before the check, we must roll back when we find the variant is invalid, it wastes time. So I think doing the check and returning the error number as early as possible is a rule we should follow.

Thanks
Miao

author
#18 lore raw
In reply to David Sterba

Sorry to reply late.

Quoted 9 lines · David Sterba
Quoted 9 lines
Quoted 2 lines

This is the most straightforward transformation I can think of. It doesn't result in an unnecessary BUG_ON, keeps churn to a minimum and

agree with you.

Quoted 3 lines

doesn't change the "style" of the balance ioctl. (If I were to check every filter argument that way, btrfs_balance_ioctl() would be very long and complicated.)

Quoted 5 lines
Quoted 1 line

I think the check in btrfs_balance_ioctl() is necessary, the reason is above.

btrfs_balance_ioctl does not seem as the right place, it does the processing related to the state of balance (resume/cancel etc). Look at btrfs_balance() itself, it does lot more sanity checks of the parameters

I think we should not put the check in btrfs_balance(), because the arguments are valid forever if they pass the check when they are input, if we put the check in btrfs_balance(), the check will be done every time we resume the balance. it is unnecessary.

Quoted 2 lines

We can put the extra checks into helpers (and not only this one) if clarity and readability of the function becomes a concern.

Agree. I will put this check into a helper in the next version of this patch. And I will make a separate patch to move the current check in btrfs_balance from btrfs_balance to the above helper after this patch is received.

Thanks
Miao

author
#19 lore raw

PATCH v4 1/2 Btrfs: cleanup duplicated division functions

In reply to Miao Xie

div_factor{_fine} has been implemented for two times, and these two functions are very similar, so cleanup the reduplicate implement and drop the original div_factor(), and then rename div_factor_fine() to div_factor(). So the factor of the new div_factor() is 100, not 10.

And I move div_factor into a independent file named math.h because it is a common math function, may be used by every composition of btrfs.

Because these functions are mostly used on the hot path, and we are sure the parameters are right in the most cases, we don't add complex checks for the parameters. But in the other place, we must check and make sure the parameters are right. So besides the code cleanup, this patch also add a check for the usage of the space balance, it is the only place that we need add check to make sure the parameters of div_factor are right till now. Besides that, the old kernel may hold the wrong usage value, so we must rectify it.

---
Changelog v3 -> v4:
- deal with the wrong usage that was input on the old kernel

Changelog v2 -> v3:
- drop the original div_factor and rename div_factor_fine to div_factor
- drop the check of the factor

Changelog v1 -> v2:
- add missing check

---
 fs/btrfs/extent-tree.c |   29 +++++--------------------
 fs/btrfs/ioctl.c       |   21 ++++++++++++++++++
 fs/btrfs/math.h        |   35 ++++++++++++++++++++++++++++++
 fs/btrfs/relocation.c  |    2 +-
 fs/btrfs/transaction.c |    2 +-
 fs/btrfs/volumes.c     |   55 ++++++++++++++++++++++++++---------------------
 6 files changed, 94 insertions(+), 50 deletions(-)
 create mode 100644 fs/btrfs/math.h
fs/btrfs/extent-tree.c +6 -23
index a010234..bcb9ced 100644
@@ -33,6 +33,7 @@
 #include "volumes.h"
 #include "locking.h"
 #include "free-space-cache.h"
+#include "math.h"
 
 #undef SCRAMBLE_DELAYED_REFS
 
@@ -648,24 +649,6 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
 	rcu_read_unlock();
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-	if (factor == 10)
-		return num;
-	num *= factor;
-	do_div(num, 10);
-	return num;
-}
-
-static u64 div_factor_fine(u64 num, int factor)
-{
-	if (factor == 100)
-		return num;
-	num *= factor;
-	do_div(num, 100);
-	return num;
-}
-
 u64 btrfs_find_block_group(struct btrfs_root *root,
 			   u64 search_start, u64 search_hint, int owner)
 {
@@ -674,7 +657,7 @@ u64 btrfs_find_block_group(struct btrfs_root *root,
 	u64 last = max(search_hint, search_start);
 	u64 group_start = 0;
 	int full_search = 0;
-	int factor = 9;
+	int factor = 90;
 	int wrapped = 0;
 again:
 	while (1) {
@@ -708,7 +691,7 @@ again:
 	if (!full_search && factor < 10) {
 		last = search_start;
 		full_search = 1;
-		factor = 10;
+		factor = 100;
 		goto again;
 	}
 found:
@@ -3513,7 +3496,7 @@ static int should_alloc_chunk(struct btrfs_root *root,
 	if (force == CHUNK_ALLOC_LIMITED) {
 		thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
 		thresh = max_t(u64, 64 * 1024 * 1024,
-			       div_factor_fine(thresh, 1));
+			       div_factor(thresh, 1));
 
 		if (num_bytes - num_allocated < thresh)
 			return 1;
@@ -3521,12 +3504,12 @@ static int should_alloc_chunk(struct btrfs_root *root,
 	thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
 
 	/* 256MB or 2% of the FS */
-	thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 2));
+	thresh = max_t(u64, 256 * 1024 * 1024, div_factor(thresh, 2));
 	/* system chunks need a much small threshold */
 	if (sinfo->flags & BTRFS_BLOCK_GROUP_SYSTEM)
 		thresh = 32 * 1024 * 1024;
 
-	if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 8))
+	if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 80))
 		return 0;
 	return 1;
 }
fs/btrfs/ioctl.c +21 -0
index 9384a2a..121339c 100644
@@ -3297,6 +3297,23 @@ void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,
 	}
 }
 
+static int btrfs_check_balance_args(struct btrfs_ioctl_balance_args *bargs)
+{
+	if ((bargs->data.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+	    (bargs->data.usage < 0 || bargs->data.usage > 100))
+		return -EINVAL;
+
+	if ((bargs->meta.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+	    (bargs->meta.usage < 0 || bargs->meta.usage > 100))
+		return -EINVAL;
+
+	if ((bargs->sys.flags & BTRFS_BALANCE_ARGS_USAGE) &&
+	    (bargs->sys.usage < 0 || bargs->sys.usage > 100))
+		return -EINVAL;
+
+	return 0;
+}
+
 static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 {
 	struct btrfs_root *root = BTRFS_I(fdentry(file)->d_inode)->root;
@@ -3335,6 +3352,10 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
 
 			goto do_balance;
 		}
+
+		ret = btrfs_check_balance_args(bargs);
+		if (ret)
+			goto out_bargs;
 	} else {
 		bargs = NULL;
 	}
fs/btrfs/math.h new file +35 -0
new file mode 100644
index 0000000..4fef49f
@@ -0,0 +1,35 @@
+
+/*
+ * Copyright (C) 2012 Fujitsu.  All rights reserved.
+ * Written by Miao Xie <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __BTRFS_MATH_H
+#define __BTRFS_MATH_H
+
+#include <asm/div64.h>
+
+static inline u64 div_factor(u64 num, int factor)
+{
+	WARN_ON(factor > 100 || factor < 0);
+
+	num *= factor;
+	do_div(num, 100);
+	return num;
+}
+
+#endif
fs/btrfs/relocation.c +1 -1
index f193096..2254478 100644
@@ -3813,7 +3813,7 @@ restart:
 			}
 		}
 
-		ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 5);
+		ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 50);
 		if (ret < 0) {
 			if (ret != -ENOSPC) {
 				err = ret;
fs/btrfs/transaction.c +1 -1
index cf98dbc..115f054 100644
@@ -489,7 +489,7 @@ static int should_end_transaction(struct btrfs_trans_handle *trans,
 {
 	int ret;
 
-	ret = btrfs_block_rsv_check(root, &root->fs_info->global_block_rsv, 5);
+	ret = btrfs_block_rsv_check(root, &root->fs_info->global_block_rsv, 50);
 	return ret ? 1 : 0;
 }
 
fs/btrfs/volumes.c +30 -25

103 lines not on this page · raw message

Signature · 1 line
1.7.6.5
#20 lore raw

Hi Miao,

You haven't addressed any of my concerns with v3.

On Thu, Sep 27, 2012 at 06:19:58PM +0800, Miao Xie wrote:

(snipped)

Quoted 5 lines

the parameters are right. So besides the code cleanup, this patch also add a check for the usage of the space balance, it is the only place that we need add check to make sure the parameters of div_factor are right till now. Besides that, the old kernel may hold the wrong usage value, so we must rectify it.

Cleaning up/unifying duplicated functions and changing the existing logic are two very different things. If you, in the course of writing this patch, became unhappy with the way balancing ioctl deals with "invalid" input, please send a separate patch.

Before your patch, volumes.c had its own copy of div_factor_fine():

static u64 div_factor_fine(u64 num, int factor)

{
	if (factor <= 0)
		return 0;
	if (factor >= 100)
		return num;

	num *= factor;
	do_div(num, 100);
	return num;
}

which was called from chunk_usage_filter() on unvalidated user input. As far as the cleanup part of your patch goes, you've dropped factor <= 0 / factor >= 100 logic, merged volumes.c's copy with extent-tree.c's copy and renamed div_factor_fine() to div_factor(). To make chunk_usage_filter() happy again, it's enough to move the dropped logic directly to the call site:

static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
struct btrfs_balance_args *bargs)

{
	...

- user_thresh = div_factor_fine(cache->key.offset, bargs->usage);
+ if (bargs->usage == 0)
+ user_thresh = 0;
+ else if (bargs->usage >= 100)
+ user_thresh = cache->key.offset;
+ else
+ user_thresh = div_factor(cache->key.offset, bargs->usage);

	...
}

So I would suggest you drop all hunks related to changing the way balancing ioctl works and make the above change to chunk_usage_filter() instead. Once again, if you are unhappy with usage filter argument handling, send a separate patch.

Thanks,

Ilya

author
#21 lore raw
Quoted 48 lines · Ilya Dryomov
Quoted 5 lines

the parameters are right. So besides the code cleanup, this patch also add a check for the usage of the space balance, it is the only place that we need add check to make sure the parameters of div_factor are right till now. Besides that, the old kernel may hold the wrong usage value, so we must rectify it.

Cleaning up/unifying duplicated functions and changing the existing logic are two very different things. If you, in the course of writing this patch, became unhappy with the way balancing ioctl deals with "invalid" input, please send a separate patch.

Before your patch, volumes.c had its own copy of div_factor_fine():

static u64 div_factor_fine(u64 num, int factor)

{
	if (factor <= 0)
		return 0;
	if (factor >= 100)
		return num;

	num *= factor;
	do_div(num, 100);
	return num;
}

which was called from chunk_usage_filter() on unvalidated user input. As far as the cleanup part of your patch goes, you've dropped factor <= 0 / factor >= 100 logic, merged volumes.c's copy with extent-tree.c's copy and renamed div_factor_fine() to div_factor(). To make chunk_usage_filter() happy again, it's enough to move the dropped logic directly to the call site:

static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
struct btrfs_balance_args *bargs)

{
	...
(quoted diff) +6 -1
-	user_thresh = div_factor_fine(cache->key.offset, bargs->usage);
+	if (bargs->usage == 0)
+		user_thresh = 0;
+	else if (bargs->usage >= 100)
+		user_thresh = cache->key.offset;
+	else
+		user_thresh = div_factor(cache->key.offset, bargs->usage);
 
...

}

Quoted 4 lines

So I would suggest you drop all hunks related to changing the way balancing ioctl works and make the above change to chunk_usage_filter() instead. Once again, if you are unhappy with usage filter argument handling, send a separate patch.

Fine.
(I forget the rule that one patch just do one thing)

Thanks
Miao

author
#22 lore raw

PATCH v5 1/2 Btrfs: cleanup duplicated division functions

In reply to Miao Xie

div_factor{_fine} has been implemented for two times, and these two functions are very similar, so cleanup the reduplicate implement and drop the original div_factor(), and then rename div_factor_fine() to div_factor(). So the factor of the new div_factor() is 100, not 10.

And I move div_factor into a independent file named math.h because it is a common math function, may be used by every composition of btrfs.

Because these functions are mostly used on the hot path, and we are sure the parameters are right in the most cases, we don't add complex checks for the parameters. But in the other place, we must check and make sure the parameters are right. So besides the code cleanup, this patch also add a check for the usage of the space balance, it is the only place that we need add check to make sure the parameters of div_factor are right till now.

---
Changelog v4 -> v5:
- drop the check in the space balance, and make the churn to a minimum

Changelog v3 -> v4:
- deal with the wrong usage that was input on the old kernel

Changelog v2 -> v3:
- drop the original div_factor and rename div_factor_fine to div_factor
- drop the check of the factor

Changelog v1 -> v2:
- add missing check

---
 fs/btrfs/extent-tree.c |   29 ++++++-----------------------
 fs/btrfs/math.h        |   35 +++++++++++++++++++++++++++++++++++
 fs/btrfs/relocation.c  |    2 +-
 fs/btrfs/transaction.c |    2 +-
 fs/btrfs/volumes.c     |   35 ++++++++++-------------------------
 5 files changed, 53 insertions(+), 50 deletions(-)
 create mode 100644 fs/btrfs/math.h
fs/btrfs/extent-tree.c +6 -23
index a010234..bcb9ced 100644
@@ -33,6 +33,7 @@
 #include "volumes.h"
 #include "locking.h"
 #include "free-space-cache.h"
+#include "math.h"
 
 #undef SCRAMBLE_DELAYED_REFS
 
@@ -648,24 +649,6 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
 	rcu_read_unlock();
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-	if (factor == 10)
-		return num;
-	num *= factor;
-	do_div(num, 10);
-	return num;
-}
-
-static u64 div_factor_fine(u64 num, int factor)
-{
-	if (factor == 100)
-		return num;
-	num *= factor;
-	do_div(num, 100);
-	return num;
-}
-
 u64 btrfs_find_block_group(struct btrfs_root *root,
 			   u64 search_start, u64 search_hint, int owner)
 {
@@ -674,7 +657,7 @@ u64 btrfs_find_block_group(struct btrfs_root *root,
 	u64 last = max(search_hint, search_start);
 	u64 group_start = 0;
 	int full_search = 0;
-	int factor = 9;
+	int factor = 90;
 	int wrapped = 0;
 again:
 	while (1) {
@@ -708,7 +691,7 @@ again:
 	if (!full_search && factor < 10) {
 		last = search_start;
 		full_search = 1;
-		factor = 10;
+		factor = 100;
 		goto again;
 	}
 found:
@@ -3513,7 +3496,7 @@ static int should_alloc_chunk(struct btrfs_root *root,
 	if (force == CHUNK_ALLOC_LIMITED) {
 		thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
 		thresh = max_t(u64, 64 * 1024 * 1024,
-			       div_factor_fine(thresh, 1));
+			       div_factor(thresh, 1));
 
 		if (num_bytes - num_allocated < thresh)
 			return 1;
@@ -3521,12 +3504,12 @@ static int should_alloc_chunk(struct btrfs_root *root,
 	thresh = btrfs_super_total_bytes(root->fs_info->super_copy);
 
 	/* 256MB or 2% of the FS */
-	thresh = max_t(u64, 256 * 1024 * 1024, div_factor_fine(thresh, 2));
+	thresh = max_t(u64, 256 * 1024 * 1024, div_factor(thresh, 2));
 	/* system chunks need a much small threshold */
 	if (sinfo->flags & BTRFS_BLOCK_GROUP_SYSTEM)
 		thresh = 32 * 1024 * 1024;
 
-	if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 8))
+	if (num_bytes > thresh && sinfo->bytes_used < div_factor(num_bytes, 80))
 		return 0;
 	return 1;
 }
fs/btrfs/math.h new file +35 -0
new file mode 100644
index 0000000..4fef49f
@@ -0,0 +1,35 @@
+
+/*
+ * Copyright (C) 2012 Fujitsu.  All rights reserved.
+ * Written by Miao Xie <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __BTRFS_MATH_H
+#define __BTRFS_MATH_H
+
+#include <asm/div64.h>
+
+static inline u64 div_factor(u64 num, int factor)
+{
+	WARN_ON(factor > 100 || factor < 0);
+
+	num *= factor;
+	do_div(num, 100);
+	return num;
+}
+
+#endif
fs/btrfs/relocation.c +1 -1
index f193096..2254478 100644
@@ -3813,7 +3813,7 @@ restart:
 			}
 		}
 
-		ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 5);
+		ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 50);
 		if (ret < 0) {
 			if (ret != -ENOSPC) {
 				err = ret;
fs/btrfs/transaction.c +1 -1
index cf98dbc..115f054 100644
@@ -489,7 +489,7 @@ static int should_end_transaction(struct btrfs_trans_handle *trans,
 {
 	int ret;
 
-	ret = btrfs_block_rsv_check(root, &root->fs_info->global_block_rsv, 5);
+	ret = btrfs_block_rsv_check(root, &root->fs_info->global_block_rsv, 50);
 	return ret ? 1 : 0;
 }
 
fs/btrfs/volumes.c +10 -25
index 3f4e70e..763edc4 100644
@@ -25,7 +25,6 @@
 #include <linux/capability.h>
 #include <linux/ratelimit.h>
 #include <linux/kthread.h>
-#include <asm/div64.h>
 #include "compat.h"
 #include "ctree.h"
 #include "extent_map.h"
@@ -36,6 +35,7 @@
 #include "async-thread.h"
 #include "check-integrity.h"
 #include "rcu-string.h"
+#include "math.h"
 
 static int init_first_rw_device(struct btrfs_trans_handle *trans,
 				struct btrfs_root *root,
@@ -2325,18 +2325,6 @@ static int chunk_profiles_filter(u64 chunk_type,
 	return 1;
 }
 
-static u64 div_factor_fine(u64 num, int factor)
-{
-	if (factor <= 0)
-		return 0;
-	if (factor >= 100)
-		return num;
-
-	num *= factor;
-	do_div(num, 100);
-	return num;
-}
-
 static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 			      struct btrfs_balance_args *bargs)
 {
@@ -2347,7 +2335,13 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
 	cache = btrfs_lookup_block_group(fs_info, chunk_offset);
 	chunk_used = btrfs_block_group_used(&cache->item);
 
-	user_thresh = div_factor_fine(cache->key.offset, bargs->usage);
+	if (bargs->usage <= 0)
+		user_thresh = 0;
+	else if (bargs->usage >= 100)
+		user_thresh = cache->key.offset;
+	else
+		user_thresh = div_factor(cache->key.offset, bargs->usage);
+
 	if (chunk_used < user_thresh)
 		ret = 0;
 
@@ -2501,15 +2495,6 @@ static int should_balance_chunk(struct btrfs_root *root,
 	return 1;
 }
 
-static u64 div_factor(u64 num, int factor)
-{
-	if (factor == 10)
-		return num;
-	num *= factor;
-	do_div(num, 10);
-	return num;
-}
-
 static int __btrfs_balance(struct btrfs_fs_info *fs_info)
 {
 	struct btrfs_balance_control *bctl = fs_info->balance_ctl;
@@ -2534,7 +2519,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
 	devices = &fs_info->fs_devices->devices;
 	list_for_each_entry(device, devices, dev_list) {
 		old_size = device->total_bytes;
-		size_to_free = div_factor(old_size, 1);
+		size_to_free = div_factor(old_size, 10);
 		size_to_free = min(size_to_free, (u64)1 * 1024 * 1024);
 		if (!device->writeable ||
 		    device->total_bytes - device->bytes_used > size_to_free)
@@ -3284,7 +3269,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 	}
 
 	/* we don't want a chunk larger than 10% of writeable space */
-	max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 1),
+	max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 10),
 			     max_chunk_size);
 
 	devices_info = kzalloc(sizeof(*devices_info) * fs_devices->rw_devices,
Signature · 1 line
1.7.6.5
#23 lore raw
Quoted 31 lines · Miao Xie
fs/btrfs/math.h new file +25 -0
new file mode 100644
index 0000000..4fef49f
@@ -0,0 +1,35 @@
+
+/*
+ * Copyright (C) 2012 Fujitsu.  All rights reserved.
+ * Written by Miao Xie <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __BTRFS_MATH_H
+#define __BTRFS_MATH_H
+
+#include <asm/div64.h>
+

fs/btrfs/math.h line 35

Quoted 10 lines
fs/btrfs/math.h new file +10 -0
+static inline u64 div_factor(u64 num, int factor)
+{
+	WARN_ON(factor > 100 || factor < 0);
+
+	num *= factor;
+	do_div(num, 100);
+	return num;
+}
+
+#endif

Sorry no, a 4 line function does not deserve a separate file.

david