diff options
author | NeilBrown <neilb@suse.de> | 2009-12-13 20:49:55 -0500 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2009-12-13 20:51:41 -0500 |
commit | 72e02075a33f739e21430262f71da8e82db9dbb3 (patch) | |
tree | 04a87a16751b714fe0fb41f28ccc54af9f820de1 /drivers/md/md.c | |
parent | f6af949c5672115313cc3c976d85b0533f607d7e (diff) |
md: factor out parsing of fixed-point numbers
safe_delay_store can parse fixed point numbers (for fractions
of a second). We will want to do that for another sysfs
file soon, so factor out the code.
Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r-- | drivers/md/md.c | 64 |
1 files changed, 42 insertions, 22 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index c56c64d13075..93287f88f1f4 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -2763,6 +2763,47 @@ static void analyze_sbs(mddev_t * mddev) | |||
2763 | } | 2763 | } |
2764 | } | 2764 | } |
2765 | 2765 | ||
2766 | /* Read a fixed-point number. | ||
2767 | * Numbers in sysfs attributes should be in "standard" units where | ||
2768 | * possible, so time should be in seconds. | ||
2769 | * However we internally use a a much smaller unit such as | ||
2770 | * milliseconds or jiffies. | ||
2771 | * This function takes a decimal number with a possible fractional | ||
2772 | * component, and produces an integer which is the result of | ||
2773 | * multiplying that number by 10^'scale'. | ||
2774 | * all without any floating-point arithmetic. | ||
2775 | */ | ||
2776 | int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale) | ||
2777 | { | ||
2778 | unsigned long result = 0; | ||
2779 | long decimals = -1; | ||
2780 | while (isdigit(*cp) || (*cp == '.' && decimals < 0)) { | ||
2781 | if (*cp == '.') | ||
2782 | decimals = 0; | ||
2783 | else if (decimals < scale) { | ||
2784 | unsigned int value; | ||
2785 | value = *cp - '0'; | ||
2786 | result = result * 10 + value; | ||
2787 | if (decimals >= 0) | ||
2788 | decimals++; | ||
2789 | } | ||
2790 | cp++; | ||
2791 | } | ||
2792 | if (*cp == '\n') | ||
2793 | cp++; | ||
2794 | if (*cp) | ||
2795 | return -EINVAL; | ||
2796 | if (decimals < 0) | ||
2797 | decimals = 0; | ||
2798 | while (decimals < scale) { | ||
2799 | result *= 10; | ||
2800 | decimals ++; | ||
2801 | } | ||
2802 | *res = result; | ||
2803 | return 0; | ||
2804 | } | ||
2805 | |||
2806 | |||
2766 | static void md_safemode_timeout(unsigned long data); | 2807 | static void md_safemode_timeout(unsigned long data); |
2767 | 2808 | ||
2768 | static ssize_t | 2809 | static ssize_t |
@@ -2774,31 +2815,10 @@ safe_delay_show(mddev_t *mddev, char *page) | |||
2774 | static ssize_t | 2815 | static ssize_t |
2775 | safe_delay_store(mddev_t *mddev, const char *cbuf, size_t len) | 2816 | safe_delay_store(mddev_t *mddev, const char *cbuf, size_t len) |
2776 | { | 2817 | { |
2777 | int scale=1; | ||
2778 | int dot=0; | ||
2779 | int i; | ||
2780 | unsigned long msec; | 2818 | unsigned long msec; |
2781 | char buf[30]; | ||
2782 | 2819 | ||
2783 | /* remove a period, and count digits after it */ | 2820 | if (strict_strtoul_scaled(cbuf, &msec, 3) < 0) |
2784 | if (len >= sizeof(buf)) | ||
2785 | return -EINVAL; | ||
2786 | strlcpy(buf, cbuf, sizeof(buf)); | ||
2787 | for (i=0; i<len; i++) { | ||
2788 | if (dot) { | ||
2789 | if (isdigit(buf[i])) { | ||
2790 | buf[i-1] = buf[i]; | ||
2791 | scale *= 10; | ||
2792 | } | ||
2793 | buf[i] = 0; | ||
2794 | } else if (buf[i] == '.') { | ||
2795 | dot=1; | ||
2796 | buf[i] = 0; | ||
2797 | } | ||
2798 | } | ||
2799 | if (strict_strtoul(buf, 10, &msec) < 0) | ||
2800 | return -EINVAL; | 2821 | return -EINVAL; |
2801 | msec = (msec * 1000) / scale; | ||
2802 | if (msec == 0) | 2822 | if (msec == 0) |
2803 | mddev->safemode_delay = 0; | 2823 | mddev->safemode_delay = 0; |
2804 | else { | 2824 | else { |