Btrfs: cleanup duplicated division functions
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
@@ -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
@@ -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
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.hbecause 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
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.hbecause 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.
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.hbecause 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
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.hbecause 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.candvolumes.cfrom the outset, but they were implemented in these two files severally.
Ah, I see.
david
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.hbecause 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_inlineis 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.candvolumes.cfrom the outset, but they were implemented in these two files severally.Ah, I see.
david
PATCH v2 1/2 Btrfs: cleanup duplicated division functions
In reply to Miao Xiediv_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
@@ -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
@@ -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
@@ -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
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@@ -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
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
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@@ -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
-0I 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
PATCH v3 1/2 Btrfs: cleanup duplicated division functions
In reply to Miao Xiediv_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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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
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
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.
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 renamediv_factor_fine()todiv_factor(). So the divisor of the newdiv_factor()is 100, not 10.And I move
div_factorinto a independent file namedmath.hbecause 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_factorare right till now.Signed-off-by Miao Xie <[email protected]>---
Changelog v2 -> v3:
- drop the originaldiv_factorand renamediv_factor_finetodiv_factor
- drop the check of the factorChangelog 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.hfs/btrfs/extent-tree.c +6
-23@@ -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@@ -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@@ -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@@ -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@@ -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@@ -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
@@ -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
Quoted 23 lines · Ilya Dryomov
Quoted 23 lines
fs/btrfs/ioctl.c +15
-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 )) { + 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@@ -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
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
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
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
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 andagree 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_ioctldoes not seem as the right place, it does the processing related to the state of balance (resume/cancel etc). Look atbtrfs_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
PATCH v4 1/2 Btrfs: cleanup duplicated division functions
In reply to Miao Xiediv_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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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_factorare 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
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_factorare 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.chad its own copy ofdiv_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 renameddiv_factor_fine()todiv_factor(). To makechunk_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, u64chunk_offset,
structbtrfs_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
PATCH v5 1/2 Btrfs: cleanup duplicated division functions
In reply to Miao Xiediv_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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Quoted 31 lines · Miao Xie
fs/btrfs/math.h new file +25
-0@@ -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