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 | |
| 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>
| -rw-r--r-- | drivers/md/md.c | 64 | ||||
| -rw-r--r-- | drivers/md/md.h | 3 |
2 files changed, 44 insertions, 23 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 { |
diff --git a/drivers/md/md.h b/drivers/md/md.h index df692953a12f..b5c306925d94 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h | |||
| @@ -463,6 +463,7 @@ extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev); | |||
| 463 | extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors); | 463 | extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors); |
| 464 | extern int md_check_no_bitmap(mddev_t *mddev); | 464 | extern int md_check_no_bitmap(mddev_t *mddev); |
| 465 | extern int md_integrity_register(mddev_t *mddev); | 465 | extern int md_integrity_register(mddev_t *mddev); |
| 466 | void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev); | 466 | extern void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev); |
| 467 | extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); | ||
| 467 | 468 | ||
| 468 | #endif /* _MD_MD_H */ | 469 | #endif /* _MD_MD_H */ |
