diff options
author | NeilBrown <neilb@suse.de> | 2009-12-14 12:49:55 +1100 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2009-12-14 12:51:41 +1100 |
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) } } +/* Read a fixed-point number. + * Numbers in sysfs attributes should be in "standard" units where + * possible, so time should be in seconds. + * However we internally use a a much smaller unit such as + * milliseconds or jiffies. + * This function takes a decimal number with a possible fractional + * component, and produces an integer which is the result of + * multiplying that number by 10^'scale'. + * all without any floating-point arithmetic. + */ +int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale) +{ + unsigned long result = 0; + long decimals = -1; + while (isdigit(*cp) || (*cp == '.' && decimals < 0)) { + if (*cp == '.') + decimals = 0; + else if (decimals < scale) { + unsigned int value; + value = *cp - '0'; + result = result * 10 + value; + if (decimals >= 0) + decimals++; + } + cp++; + } + if (*cp == '\n') + cp++; + if (*cp) + return -EINVAL; + if (decimals < 0) + decimals = 0; + while (decimals < scale) { + result *= 10; + decimals ++; + } + *res = result; + return 0; +} + + static void md_safemode_timeout(unsigned long data); static ssize_t @@ -2774,31 +2815,10 @@ safe_delay_show(mddev_t *mddev, char *page) static ssize_t safe_delay_store(mddev_t *mddev, const char *cbuf, size_t len) { - int scale=1; - int dot=0; - int i; unsigned long msec; - char buf[30]; - /* remove a period, and count digits after it */ - if (len >= sizeof(buf)) - return -EINVAL; - strlcpy(buf, cbuf, sizeof(buf)); - for (i=0; i<len; i++) { - if (dot) { - if (isdigit(buf[i])) { - buf[i-1] = buf[i]; - scale *= 10; - } - buf[i] = 0; - } else if (buf[i] == '.') { - dot=1; - buf[i] = 0; - } - } - if (strict_strtoul(buf, 10, &msec) < 0) + if (strict_strtoul_scaled(cbuf, &msec, 3) < 0) return -EINVAL; - msec = (msec * 1000) / scale; if (msec == 0) mddev->safemode_delay = 0; 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); extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors); extern int md_check_no_bitmap(mddev_t *mddev); extern int md_integrity_register(mddev_t *mddev); -void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev); +extern void md_integrity_add_rdev(mdk_rdev_t *rdev, mddev_t *mddev); +extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale); #endif /* _MD_MD_H */ |