From: James Simmons Date: Fri, 3 Jan 2020 02:47:07 +0000 (-0500) Subject: LU-9091 sysfs: use string helper like functions for sysfs X-Git-Tag: 2.13.51~15 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=d9e0c9f346d0f0cccfa37737807d6f9d08255ab7 LU-9091 sysfs: use string helper like functions for sysfs For a very long time the Linux kernel has supported the function memparse() that allowed the passing in of memory sizes with the suffix set of K, M, G, T, P, E. Lustre adopted this approach with its proc / sysfs implmentation. The difference being that lustre expanded this functionality to allow sizes with a fractional component, such as 1.5G for example. The code used to parse for the numerical value is heavily tied into the debugfs seq_file handling and stomps on the passed in buffer which you can't do with sysfs files. Similar functionality to what Lustre does today exist in newer linux kernels in the form of string helpers. Currently the string helpers only convert a numerical value to human readable format. A new function, string_to_size(), was created that takes a string and turns it into a numerical value. This enables the use of string helper suffixes i.e MiB, kB etc with the lustre tunables and we can now support 10 base numbers i.e MB, kB as well. Already string helper suffixes are used for debugfs files so I expect this to be adopted over time so it should be encouraged to use string_to_size() for newer lustre sysfs files. At the same time we want to perserve the original behavior of using the suffix set of K, M, G, T, P, E. To do this we create the function sysfs_memparse() that supports the new string helper suffixes as well as the older set of suffixes. This new code is also way simpler than what is currently done with the current code. Change-Id: Ia437db44f2a987aa11ab4ff3e9df23e9aeba04d7 Signed-off-by: James Simmons Reviewed-on: https://review.whamcloud.com/35658 Tested-by: jenkins Reviewed-by: Shaun Tancheff Reviewed-by: Andreas Dilger Tested-by: Maloo Reviewed-by: Oleg Drokin --- diff --git a/contrib/scripts/spelling.txt b/contrib/scripts/spelling.txt index 6883eb6..595d8d2 100644 --- a/contrib/scripts/spelling.txt +++ b/contrib/scripts/spelling.txt @@ -134,6 +134,8 @@ LPLX||%#lx LPO64||%#llo LPPID||%d lprocfs_str_to_s64||kstrtoxxx_from_user +lprocfs_str_with_units_to_s64||sysfs_memparse +lu_str_to_s64|sysfs_memparse LPROC_SEQ_FOPS||LUSTRE_RW_ATTR LPROC_SEQ_FOPS_RO_TYPE||LUSTRE_RO_ATTR LPROC_SEQ_FOPS_RO||LUSTRE_RO_ATTR diff --git a/lustre/include/lprocfs_status.h b/lustre/include/lprocfs_status.h index 1ff0926..0853a51 100644 --- a/lustre/include/lprocfs_status.h +++ b/lustre/include/lprocfs_status.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -621,7 +622,9 @@ extern int lprocfs_str_with_units_to_s64(const char __user *buffer, extern int lprocfs_str_with_units_to_u64(const char __user *buffer, unsigned long count, __u64 *val, char defunit); - +int string_to_size(u64 *size, const char *buffer, size_t count); +int sysfs_memparse(const char *buffer, size_t count, u64 *val, + const char *defunit); char *lprocfs_strnstr(const char *s1, const char *s2, size_t len); char *lprocfs_find_named_value(const char *buffer, const char *name, size_t *count); diff --git a/lustre/ldlm/ldlm_resource.c b/lustre/ldlm/ldlm_resource.c index d5f93fd..735ea3d 100644 --- a/lustre/ldlm/ldlm_resource.c +++ b/lustre/ldlm/ldlm_resource.c @@ -111,14 +111,22 @@ static ssize_t seq_watermark_write(struct file *file, const char __user *buffer, size_t count, loff_t *off) { - __s64 value; + u64 value; __u64 watermark; __u64 *data = ((struct seq_file *)file->private_data)->private; bool wm_low = (data == &ldlm_reclaim_threshold_mb) ? true : false; + char kernbuf[22] = ""; int rc; - rc = lprocfs_str_with_units_to_s64(buffer, count, &value, 'M'); - if (rc) { + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &value, "MiB"); + if (rc < 0) { CERROR("Failed to set %s, rc = %d.\n", wm_low ? "lock_reclaim_threshold_mb" : "lock_limit_mb", rc); diff --git a/lustre/lod/lproc_lod.c b/lustre/lod/lproc_lod.c index f89b0dc..d41c7cf 100644 --- a/lustre/lod/lproc_lod.c +++ b/lustre/lod/lproc_lod.c @@ -68,22 +68,13 @@ static ssize_t dom_stripesize_store(struct kobject *kobj, struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct lod_device *lod = dt2lod_dev(dt); - char tbuf[22] = ""; - s64 val; + u64 val; int rc; - if (count > (sizeof(tbuf) - 1)) - return -EINVAL; - - memcpy(tbuf, buffer, count); - - rc = lu_str_to_s64(tbuf, count, &val, '1'); - if (rc) + rc = sysfs_memparse(buffer, count, &val, "B"); + if (rc < 0) return rc; - if (val < 0) - return -ERANGE; - /* 1GB is the limit */ if (val > (1ULL << 30)) return -ERANGE; @@ -126,22 +117,13 @@ static ssize_t stripesize_store(struct kobject *kobj, struct attribute *attr, struct dt_device *dt = container_of(kobj, struct dt_device, dd_kobj); struct lod_device *lod = dt2lod_dev(dt); - char tbuf[22] = ""; - s64 val; + u64 val; int rc; - if (count > (sizeof(tbuf) - 1)) - return -EINVAL; - - memcpy(tbuf, buffer, count); - - rc = lu_str_to_s64(tbuf, count, &val, '1'); - if (rc) + rc = sysfs_memparse(buffer, count, &val, "B"); + if (rc < 0) return rc; - if (val < 0) - return -ERANGE; - lod_fix_desc_stripe_size(&val); lod->lod_ost_descs.ltd_lov_desc.ld_default_stripe_size = val; diff --git a/lustre/lov/lproc_lov.c b/lustre/lov/lproc_lov.c index bce82d2..a65b250 100644 --- a/lustre/lov/lproc_lov.c +++ b/lustre/lov/lproc_lov.c @@ -56,16 +56,23 @@ static ssize_t lov_stripesize_seq_write(struct file *file, { struct obd_device *dev = ((struct seq_file *)file->private_data)->private; struct lov_desc *desc; - s64 val; + char kernbuf[22] = ""; + u64 val; int rc; LASSERT(dev != NULL); desc = &dev->u.lov.desc; - rc = lprocfs_str_with_units_to_s64(buffer, count, &val, '1'); - if (rc) + + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &val, "B"); + if (rc < 0) return rc; - if (val < 0) - return -ERANGE; lov_fix_desc_stripe_size(&val); desc->ld_default_stripe_size = val; diff --git a/lustre/mdc/lproc_mdc.c b/lustre/mdc/lproc_mdc.c index 0c2e79a..c6a7e99 100644 --- a/lustre/mdc/lproc_mdc.c +++ b/lustre/mdc/lproc_mdc.c @@ -166,11 +166,19 @@ static ssize_t mdc_max_dirty_mb_seq_write(struct file *file, struct seq_file *sfl = file->private_data; struct obd_device *dev = sfl->private; struct client_obd *cli = &dev->u.cli; - s64 pages_number; + char kernbuf[22] = ""; + u64 pages_number; int rc; - rc = lprocfs_str_with_units_to_s64(buffer, count, &pages_number, 'M'); - if (rc) + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &pages_number, "MiB"); + if (rc < 0) return rc; /* MB -> pages */ @@ -251,7 +259,8 @@ mdc_cached_mb_seq_write(struct file *file, const char __user *buffer, struct seq_file *sfl = file->private_data; struct obd_device *dev = sfl->private; struct client_obd *cli = &dev->u.cli; - __s64 pages_number; + u64 pages_number; + const char *tmp; long rc; char kernbuf[128]; @@ -262,17 +271,13 @@ mdc_cached_mb_seq_write(struct file *file, const char __user *buffer, return -EFAULT; kernbuf[count] = 0; - buffer += lprocfs_find_named_value(kernbuf, "used_mb:", &count) - - kernbuf; - rc = lprocfs_str_with_units_to_s64(buffer, count, &pages_number, 'M'); - if (rc) + tmp = lprocfs_find_named_value(kernbuf, "used_mb:", &count); + rc = sysfs_memparse(tmp, count, &pages_number, "MiB"); + if (rc < 0) return rc; pages_number >>= PAGE_SHIFT; - if (pages_number < 0) - return -ERANGE; - rc = atomic_long_read(&cli->cl_lru_in_list) - pages_number; if (rc > 0) { struct lu_env *env; diff --git a/lustre/obdclass/class_obd.c b/lustre/obdclass/class_obd.c index 1759845..438e142 100644 --- a/lustre/obdclass/class_obd.c +++ b/lustre/obdclass/class_obd.c @@ -524,6 +524,20 @@ struct miscdevice obd_psdev = { .fops = &obd_psdev_fops, }; +#define test_string_to_size_one(value, result, def_unit) \ +({ \ + u64 __size; \ + int __ret; \ + \ + BUILD_BUG_ON(strlen(value) >= 23); \ + __ret = sysfs_memparse((value), (result), &__size, \ + (def_unit)); \ + if (__ret == 0 && (u64)result != __size) \ + CERROR("string_helper: size %llu != result %llu\n",\ + __size, (u64)result); \ + __ret; \ +}) + static int obd_init_checks(void) { __u64 u64val, div64val; @@ -587,6 +601,53 @@ static int obd_init_checks(void) ret = -EINVAL; } + /* invalid string */ + ret = test_string_to_size_one("256B34", 256, "B"); + if (ret == 0) + CERROR("string_helpers: format should be number then units\n"); + ret = test_string_to_size_one("132OpQ", 132, "B"); + if (ret == 0) + CERROR("string_helpers: invalid units should be rejected\n"); + ret = 0; + + /* small values */ + test_string_to_size_one("0B", 0, "B"); + ret = test_string_to_size_one("1.82B", 1, "B"); + if (ret == 0) + CERROR("string_helpers: number string with 'B' and '.' should be invalid\n"); + ret = 0; + test_string_to_size_one("512B", 512, "B"); + test_string_to_size_one("1.067kB", 1067, "B"); + test_string_to_size_one("1.042KiB", 1067, "B"); + + /* Lustre special handling */ + test_string_to_size_one("16", 16777216, "MiB"); + test_string_to_size_one("65536", 65536, "B"); + test_string_to_size_one("128K", 131072, "B"); + test_string_to_size_one("1M", 1048576, "B"); + test_string_to_size_one("256.5G", 275414777856ULL, "GiB"); + + /* normal values */ + test_string_to_size_one("8.39MB", 8390000, "MiB"); + test_string_to_size_one("8.00MiB", 8388608, "MiB"); + test_string_to_size_one("256GB", 256000000, "GiB"); + test_string_to_size_one("238.731 GiB", 256335459385ULL, "GiB"); + + /* huge values */ + test_string_to_size_one("0.4TB", 400000000000ULL, "TiB"); + test_string_to_size_one("12.5TiB", 13743895347200ULL, "TiB"); + test_string_to_size_one("2PB", 2000000000000000ULL, "PiB"); + test_string_to_size_one("16PiB", 18014398509481984ULL, "PiB"); + + /* huge values should overflow */ + ret = test_string_to_size_one("1000EiB", 0, "EiB"); + if (ret != -EOVERFLOW) + CERROR("string_helpers: Failed to detect overflow\n"); + ret = test_string_to_size_one("1000EB", 0, "EiB"); + if (ret != -EOVERFLOW) + CERROR("string_helpers: Failed to detect overflow\n"); + ret = 0; + return ret; } diff --git a/lustre/obdclass/lprocfs_status.c b/lustre/obdclass/lprocfs_status.c index 1bd4b72..391858e 100644 --- a/lustre/obdclass/lprocfs_status.c +++ b/lustre/obdclass/lprocfs_status.c @@ -1758,6 +1758,185 @@ __s64 lprocfs_read_helper(struct lprocfs_counter *lc, } EXPORT_SYMBOL(lprocfs_read_helper); +/** + * string_to_size - convert ASCII string representing a numerical + * value with optional units to 64-bit binary value + * + * @size: The numerical value extract out of @buffer + * @buffer: passed in string to parse + * @count: length of the @buffer + * + * This function returns a 64-bit binary value if @buffer contains a valid + * numerical string. The string is parsed to 3 significant figures after + * the decimal point. Support the string containing an optional units at + * the end which can be base 2 or base 10 in value. If no units are given + * the string is assumed to just a numerical value. + * + * Returns: @count if the string is successfully parsed, + * -errno on invalid input strings. Error values: + * + * - ``-EINVAL``: @buffer is not a proper numerical string + * - ``-EOVERFLOW``: results does not fit into 64 bits. + * - ``-E2BIG ``: @buffer is not large + */ +int string_to_size(u64 *size, const char *buffer, size_t count) +{ + /* For string_get_size() it can support values above exabytes, + * (ZiB, YiB) due to breaking the return value into a size and + * bulk size to avoid 64 bit overflow. We don't break the size + * up into block size units so we don't support ZiB or YiB. + */ + static const char *const units_10[] = { + "kB", "MB", "GB", "TB", "PB", "EB" + }; + static const char *const units_2[] = { + "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" + }; + static const char *const *const units_str[] = { + [STRING_UNITS_2] = units_2, + [STRING_UNITS_10] = units_10, + }; + static const unsigned int coeff[] = { + [STRING_UNITS_10] = 1000, + [STRING_UNITS_2] = 1024, + }; + enum string_size_units unit; + u64 whole, blk_size = 1; + char kernbuf[22], *end; + size_t len = count; + int rc; + int i; + + if (count >= sizeof(kernbuf)) + return -E2BIG; + + *size = 0; + /* 'iB' is used for based 2 numbers. If @buffer contains only a 'B' + * or only numbers then we treat it as a direct number which doesn't + * matter if its STRING_UNITS_2 or STRING_UNIT_10. + */ + unit = strstr(buffer, "iB") ? STRING_UNITS_2 : STRING_UNITS_10; + i = unit == STRING_UNITS_2 ? ARRAY_SIZE(units_2) - 1 : + ARRAY_SIZE(units_10) - 1; + do { + end = strstr(buffer, units_str[unit][i]); + if (end) { + for (; i >= 0; i--) + blk_size *= coeff[unit]; + len -= strlen(end); + break; + } + } while (i--); + + /* as 'B' is a substring of all units, we need to handle it + * separately. + */ + if (!end) { + /* 'B' is only acceptable letter at this point */ + end = strchr(buffer, 'B'); + if (end) { + len -= strlen(end); + + if (count - len > 2 || + (count - len == 2 && strcmp(end, "B\n") != 0)) + return -EINVAL; + } + /* kstrtoull will error out if it has non digits */ + goto numbers_only; + } + + end = strchr(buffer, '.'); + if (end) { + /* need to limit 3 decimal places */ + char rem[4] = "000"; + u64 frac = 0; + size_t off; + + len = end - buffer; + end++; + + /* limit to 3 decimal points */ + off = min_t(size_t, 3, strspn(end, "0123456789")); + /* need to limit frac_d to a u32 */ + memcpy(rem, end, off); + rc = kstrtoull(rem, 10, &frac); + if (rc) + return rc; + + if (fls64(frac) + fls64(blk_size) - 1 > 64) + return -EOVERFLOW; + + frac *= blk_size; + do_div(frac, 1000); + *size += frac; + } +numbers_only: + snprintf(kernbuf, sizeof(kernbuf), "%.*s", (int)len, buffer); + rc = kstrtoull(kernbuf, 10, &whole); + if (rc) + return rc; + + if (whole != 0 && fls64(whole) + fls64(blk_size) - 1 > 64) + return -EOVERFLOW; + + *size += whole * blk_size; + + return count; +} +EXPORT_SYMBOL(string_to_size); + +/** + * sysfs_memparse - parse a ASCII string to 64-bit binary value, + * with optional units + * + * @buffer: kernel pointer to input string + * @count: number of bytes in the input @buffer + * @val: (output) binary value returned to caller + * @defunit: default unit suffix to use if none is provided + * + * Parses a string into a number. The number stored at @buffer is + * potentially suffixed with K, M, G, T, P, E. Besides these other + * valid suffix units are shown in the string_to_size() function. + * If the string lacks a suffix then the defunit is used. The defunit + * should be given as a binary unit (e.g. MiB) as that is the standard + * for tunables in Lustre. If no unit suffix is given (e.g. 'G'), then + * it is assumed to be in binary units. + * + * Returns: 0 on success or -errno on failure. + */ +int sysfs_memparse(const char *buffer, size_t count, u64 *val, + const char *defunit) +{ + char param[23]; + int rc; + + if (count >= sizeof(param)) + return -E2BIG; + + count = strlen(buffer); + if (count && buffer[count - 1] == '\n') + count--; + + if (!count) + return -EINVAL; + + if (isalpha(buffer[count - 1])) { + if (buffer[count - 1] != 'B') { + scnprintf(param, sizeof(param), "%.*siB", + (int)count, buffer); + } else { + memcpy(param, buffer, sizeof(param)); + } + } else { + scnprintf(param, sizeof(param), "%.*s%s", (int)count, + buffer, defunit); + } + + rc = string_to_size(val, param, strlen(param)); + return rc < 0 ? rc : 0; +} +EXPORT_SYMBOL(sysfs_memparse); + /* Obtains the conversion factor for the unit specified */ static int get_mult(char unit, __u64 *mult) { diff --git a/lustre/ofd/lproc_ofd.c b/lustre/ofd/lproc_ofd.c index 22946c5..9593c3d 100644 --- a/lustre/ofd/lproc_ofd.c +++ b/lustre/ofd/lproc_ofd.c @@ -389,14 +389,22 @@ ofd_brw_size_seq_write(struct file *file, const char __user *buffer, struct seq_file *m = file->private_data; struct obd_device *obd = m->private; struct ofd_device *ofd = ofd_dev(obd->obd_lu_dev); - __s64 val; + char kernbuf[22] = ""; + u64 val; int rc; - rc = lprocfs_str_with_units_to_s64(buffer, count, &val, 'M'); - if (rc) + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &val, "MiB"); + if (rc < 0) return rc; - if (val <= 0) + if (val == 0) return -EINVAL; if (val > DT_MAX_BRW_SIZE || diff --git a/lustre/osc/lproc_osc.c b/lustre/osc/lproc_osc.c index 575e6bc..5f7638f 100644 --- a/lustre/osc/lproc_osc.c +++ b/lustre/osc/lproc_osc.c @@ -212,7 +212,8 @@ static ssize_t osc_cached_mb_seq_write(struct file *file, { struct obd_device *dev = ((struct seq_file *)file->private_data)->private; struct client_obd *cli = &dev->u.cli; - __s64 pages_number; + u64 pages_number; + const char *tmp; long rc; char kernbuf[128]; @@ -223,17 +224,13 @@ static ssize_t osc_cached_mb_seq_write(struct file *file, return -EFAULT; kernbuf[count] = 0; - buffer += lprocfs_find_named_value(kernbuf, "used_mb:", &count) - - kernbuf; - rc = lprocfs_str_with_units_to_s64(buffer, count, &pages_number, 'M'); - if (rc) + tmp = lprocfs_find_named_value(kernbuf, "used_mb:", &count); + rc = sysfs_memparse(tmp, count, &pages_number, "MiB"); + if (rc < 0) return rc; pages_number >>= PAGE_SHIFT; - if (pages_number < 0) - return -ERANGE; - rc = atomic_long_read(&cli->cl_lru_in_list) - pages_number; if (rc > 0) { struct lu_env *env; @@ -285,17 +282,23 @@ static ssize_t osc_cur_grant_bytes_seq_write(struct file *file, { struct obd_device *obd = ((struct seq_file *)file->private_data)->private; struct client_obd *cli = &obd->u.cli; - s64 val; + char kernbuf[22] = ""; + u64 val; int rc; if (obd == NULL) return 0; - rc = lprocfs_str_with_units_to_s64(buffer, count, &val, '1'); - if (rc) + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &val, "MiB"); + if (rc < 0) return rc; - if (val < 0) - return val; /* this is only for shrinking grant */ spin_lock(&cli->cl_loi_list_lock); diff --git a/lustre/osd-ldiskfs/osd_lproc.c b/lustre/osd-ldiskfs/osd_lproc.c index b264b75..082816b 100644 --- a/lustre/osd-ldiskfs/osd_lproc.c +++ b/lustre/osd-ldiskfs/osd_lproc.c @@ -561,6 +561,7 @@ ldiskfs_osd_readcache_seq_write(struct file *file, const char __user *buffer, struct seq_file *m = file->private_data; struct dt_device *dt = m->private; struct osd_device *osd = osd_dt_dev(dt); + char kernbuf[22] = ""; u64 val; int rc; @@ -568,8 +569,15 @@ ldiskfs_osd_readcache_seq_write(struct file *file, const char __user *buffer, if (unlikely(osd->od_mnt == NULL)) return -EINPROGRESS; - rc = lprocfs_str_with_units_to_u64(buffer, count, &val, '1'); - if (rc) + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &val, "B"); + if (rc < 0) return rc; osd->od_readcache_max_filesize = val > OSD_MAX_CACHE_SIZE ? @@ -599,18 +607,24 @@ ldiskfs_osd_readcache_max_io_seq_write(struct file *file, struct seq_file *m = file->private_data; struct dt_device *dt = m->private; struct osd_device *osd = osd_dt_dev(dt); - s64 val; + char kernbuf[22] = ""; + u64 val; int rc; LASSERT(osd != NULL); if (unlikely(osd->od_mnt == NULL)) return -EINPROGRESS; - rc = lprocfs_str_with_units_to_s64(buffer, count, &val, 'M'); - if (rc) + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &val, "MiB"); + if (rc < 0) return rc; - if (val < 0) - return -ERANGE; if (val > PTLRPC_MAX_BRW_SIZE) return -ERANGE; @@ -641,18 +655,24 @@ ldiskfs_osd_writethrough_max_io_seq_write(struct file *file, struct seq_file *m = file->private_data; struct dt_device *dt = m->private; struct osd_device *osd = osd_dt_dev(dt); - s64 val; + char kernbuf[22] = ""; + u64 val; int rc; LASSERT(osd != NULL); if (unlikely(osd->od_mnt == NULL)) return -EINPROGRESS; - rc = lprocfs_str_with_units_to_s64(buffer, count, &val, 'M'); - if (rc) + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &val, "MiB"); + if (rc < 0) return rc; - if (val < 0) - return -ERANGE; if (val > PTLRPC_MAX_BRW_SIZE) return -ERANGE; diff --git a/lustre/osd-zfs/osd_lproc.c b/lustre/osd-zfs/osd_lproc.c index 1516e58..7e742fd 100644 --- a/lustre/osd-zfs/osd_lproc.c +++ b/lustre/osd-zfs/osd_lproc.c @@ -387,6 +387,7 @@ zfs_osd_readcache_seq_write(struct file *file, const char __user *buffer, struct seq_file *m = file->private_data; struct dt_device *dt = m->private; struct osd_device *osd = osd_dt_dev(dt); + char kernbuf[22] = ""; u64 val; int rc; @@ -394,8 +395,15 @@ zfs_osd_readcache_seq_write(struct file *file, const char __user *buffer, if (unlikely(osd->od_os == NULL)) return -EINPROGRESS; - rc = lprocfs_str_with_units_to_u64(buffer, count, &val, '1'); - if (rc) + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &val, "B"); + if (rc < 0) return rc; osd->od_readcache_max_filesize = val > OSD_MAX_CACHE_SIZE ? diff --git a/lustre/osp/lproc_osp.c b/lustre/osp/lproc_osp.c index 01f122b..2aa77f5 100644 --- a/lustre/osp/lproc_osp.c +++ b/lustre/osp/lproc_osp.c @@ -835,14 +835,22 @@ osp_reserved_mb_high_seq_write(struct file *file, const char __user *buffer, struct seq_file *m = file->private_data; struct obd_device *dev = m->private; struct osp_device *osp = lu2osp_dev(dev->obd_lu_dev); - __s64 val; + char kernbuf[22] = ""; + u64 val; int rc; if (osp == NULL || osp->opd_pre == NULL) return -EINVAL; - rc = lprocfs_str_with_units_to_s64(buffer, count, &val, 'M'); - if (rc) + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &val, "MiB"); + if (rc < 0) return rc; val >>= 20; if (val < 1) @@ -896,14 +904,22 @@ osp_reserved_mb_low_seq_write(struct file *file, const char __user *buffer, struct seq_file *m = file->private_data; struct obd_device *dev = m->private; struct osp_device *osp = lu2osp_dev(dev->obd_lu_dev); - __s64 val; + char kernbuf[22] = ""; + u64 val; int rc; if (osp == NULL || osp->opd_pre == NULL) return -EINVAL; - rc = lprocfs_str_with_units_to_s64(buffer, count, &val, 'M'); - if (rc) + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &val, "MiB"); + if (rc < 0) return rc; val >>= 20;