From: Andreas Dilger Date: Tue, 24 Mar 2020 13:57:39 +0000 (-0400) Subject: LU-9091 procfs: remove old string parsing routines X-Git-Tag: 2.13.53~15 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=48242f98c3add59d9e084d73057e64265230a19f LU-9091 procfs: remove old string parsing routines Remove the llprocfs_str_with_units_to_s64(), lu_str_to_s64(), llprocfs_str_with_units_to_u64(), and lu_str_to_u64() functions. All new code should use sysfs_memparse() to parse sizes from userspace. Mark patch forbuildonly so that it does not land before we have a chance to remove any patches with users of these functions. Test-Parameters: trivial Signed-off-by: Andreas Dilger Change-Id: I6dc321e60eb587ef25652f4b5ae8fa478d3ebbe5 Reviewed-on: https://review.whamcloud.com/37275 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Neil Brown Reviewed-by: Shaun Tancheff Reviewed-by: James Simmons Reviewed-by: Oleg Drokin --- diff --git a/lustre/include/lprocfs_status.h b/lustre/include/lprocfs_status.h index 89b914b..55f6391 100644 --- a/lustre/include/lprocfs_status.h +++ b/lustre/include/lprocfs_status.h @@ -587,14 +587,6 @@ extern ssize_t lprocfs_pinger_recov_seq_write(struct file *file, const char __user *buffer, size_t count, loff_t *off); -int lu_str_to_s64(char *buffer, unsigned long count, __s64 *val, char defunit); -extern int lprocfs_str_with_units_to_s64(const char __user *buffer, - unsigned long count, __s64 *val, - char defunit); - -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); diff --git a/lustre/obdclass/lprocfs_status.c b/lustre/obdclass/lprocfs_status.c index 71d1edd..c97936a 100644 --- a/lustre/obdclass/lprocfs_status.c +++ b/lustre/obdclass/lprocfs_status.c @@ -1818,335 +1818,6 @@ int sysfs_memparse(const char *buffer, size_t count, u64 *val, } EXPORT_SYMBOL(sysfs_memparse); -/* Obtains the conversion factor for the unit specified */ -static int get_mult(char unit, __u64 *mult) -{ - __u64 units = 1; - - switch (unit) { - /* peta, tera, giga, mega, and kilo */ - case 'p': - case 'P': - units <<= 10; - /* fallthrough */ - case 't': - case 'T': - units <<= 10; - /* fallthrough */ - case 'g': - case 'G': - units <<= 10; - /* fallthrough */ - case 'm': - case 'M': - units <<= 10; - /* fallthrough */ - case 'k': - case 'K': - units <<= 10; - break; - /* some tests expect % to be accepted */ - case '%': - units = 1; - break; - default: - return -EINVAL; - } - - *mult = units; - - return 0; -} - -/* - * Ensures the numeric string is valid. The function provides the final - * multiplier in the case a unit exists at the end of the string. It also - * locates the start of the whole and fractional parts (if any). This - * function modifies the string so kstrtoull can be used to parse both - * the whole and fraction portions. This function also figures out - * the base of the number. - */ -static int preprocess_numeric_str(char *buffer, __u64 *mult, __u64 def_mult, - bool allow_units, char **whole, char **frac, - unsigned int *base) -{ - bool hit_decimal = false; - bool hit_unit = false; - int rc = 0; - char *start; - *mult = def_mult; - *whole = NULL; - *frac = NULL; - *base = 10; - - /* a hex string if it starts with "0x" */ - if (buffer[0] == '0' && tolower(buffer[1]) == 'x') { - *base = 16; - buffer += 2; - } - - start = buffer; - - while (*buffer) { - /* allow for a single new line before the null terminator */ - if (*buffer == '\n') { - *buffer = '\0'; - buffer++; - - if (*buffer) - return -EINVAL; - - break; - } - - /* any chars after our unit indicates a malformed string */ - if (hit_unit) - return -EINVAL; - - /* ensure we only hit one decimal */ - if (*buffer == '.') { - if (hit_decimal) - return -EINVAL; - - /* if past start, there's a whole part */ - if (start != buffer) - *whole = start; - - *buffer = '\0'; - start = buffer + 1; - hit_decimal = true; - } else if (!isdigit(*buffer) && - !(*base == 16 && isxdigit(*buffer))) { - if (allow_units) { - /* if we allow units, attempt to get mult */ - hit_unit = true; - rc = get_mult(*buffer, mult); - if (rc) - return rc; - - /* string stops here, but keep processing */ - *buffer = '\0'; - } else { - /* bad string */ - return -EINVAL; - } - } - - buffer++; - } - - if (hit_decimal) { - /* hit a decimal, make sure there's a fractional part */ - if (!*start) - return -EINVAL; - - *frac = start; - } else { - /* didn't hit a decimal, but may have a whole part */ - if (start != buffer && *start) - *whole = start; - } - - /* malformed string if we didn't get anything */ - if (!*frac && !*whole) - return -EINVAL; - - return 0; -} - -/* - * Parses a numeric string which can contain a whole and fraction portion - * into a __u64. Accepts a multiplier to apply to the value parsed. Also - * allows the string to have a unit at the end. The function handles - * wrapping of the final unsigned value. - */ -static int str_to_u64_parse(char *buffer, unsigned long count, - __u64 *val, __u64 def_mult, bool allow_units) -{ - __u64 whole = 0; - __u64 frac = 0; - unsigned int frac_d = 1; - __u64 wrap_indicator = ULLONG_MAX; - int rc = 0; - __u64 mult; - char *strwhole; - char *strfrac; - unsigned int base = 10; - - rc = preprocess_numeric_str(buffer, &mult, def_mult, allow_units, - &strwhole, &strfrac, &base); - - if (rc) - return rc; - - if (mult == 0) { - *val = 0; - return 0; - } - - /* the multiplier limits how large the value can be */ - wrap_indicator = div64_u64(wrap_indicator, mult); - - if (strwhole) { - rc = kstrtoull(strwhole, base, &whole); - if (rc) - return rc; - - if (whole > wrap_indicator) - return -ERANGE; - - whole *= mult; - } - - if (strfrac) { - if (strlen(strfrac) > 10) - strfrac[10] = '\0'; - - rc = kstrtoull(strfrac, base, &frac); - if (rc) - return rc; - - /* determine power of fractional portion */ - while (*strfrac) { - frac_d *= base; - strfrac++; - } - - /* fractional portion is too large to perform calculation */ - if (frac > wrap_indicator) - return -ERANGE; - - frac *= mult; - do_div(frac, frac_d); - } - - /* check that the sum of whole and fraction fits in u64 */ - if (whole > (ULLONG_MAX - frac)) - return -ERANGE; - - *val = whole + frac; - - return 0; -} - -/* - * This function parses numeric/hex strings into __s64. It accepts a multiplier - * which will apply to the value parsed. It also can allow the string to - * have a unit as the last character. The function handles overflow/underflow - * of the signed integer. - */ -int lu_str_to_s64(char *buffer, unsigned long count, __s64 *val, char defunit) -{ - __u64 mult = 1; - __u64 tmp; - unsigned int offset = 0; - int signed sign = 1; - __u64 max = LLONG_MAX; - int rc = 0; - - if (defunit != '1') { - rc = get_mult(defunit, &mult); - if (rc) - return rc; - } - - /* keep track of our sign */ - if (*buffer == '-') { - sign = -1; - offset++; - /* equivalent to max = -LLONG_MIN, avoids overflow */ - max++; - } - - rc = str_to_u64_parse(buffer + offset, count - offset, - &tmp, mult, true); - if (rc) - return rc; - - /* check for overflow/underflow */ - if (max < tmp) - return -ERANGE; - - *val = (__s64)tmp * sign; - - return 0; -} -EXPORT_SYMBOL(lu_str_to_s64); - -/* identical to s64 version, but does not handle overflow */ -static int str_to_u64_internal(const char __user *buffer, unsigned long count, - __u64 *val, __u64 def_mult, bool allow_units) -{ - char kernbuf[22]; - unsigned int offset = 0; - int rc = 0; - - if (count > (sizeof(kernbuf) - 1)) - return -EINVAL; - - if (copy_from_user(kernbuf, buffer, count)) - return -EFAULT; - - kernbuf[count] = '\0'; - - rc = str_to_u64_parse(kernbuf + offset, count - offset, - val, def_mult, allow_units); - if (rc) - return rc; - - return 0; -} -/** - * Convert a user string into a signed 64 bit number. This function produces - * an error when the value parsed from the string times multiplier underflows or - * overflows. This function only accepts strings that contains digits, an - * optional decimal, and a char representing a unit at the end. If a unit is - * specified in the string, the multiplier provided by the caller is ignored. - * This function can also accept hexadecimal strings which are prefixed with - * "0x". - * - * \param[in] buffer string consisting of numbers, a decimal, and a unit - * \param[in] count buffer length - * \param[in] val if successful, the value represented by the string - * \param[in] defunit default unit if string doesn't contain one - * - * \retval 0 on success - * \retval negative number on error - */ -int lprocfs_str_with_units_to_s64(const char __user *buffer, - unsigned long count, __s64 *val, char defunit) -{ - char kernbuf[22]; - - if (count > (sizeof(kernbuf) - 1)) - return -EINVAL; - - if (copy_from_user(kernbuf, buffer, count)) - return -EFAULT; - - kernbuf[count] = '\0'; - - return lu_str_to_s64(kernbuf, count, val, defunit); -} -EXPORT_SYMBOL(lprocfs_str_with_units_to_s64); - -/* identical to s64 version above, but does not handle overflow */ -int lprocfs_str_with_units_to_u64(const char __user *buffer, - unsigned long count, __u64 *val, char defunit) -{ - __u64 mult = 1; - int rc; - - if (defunit != '1') { - rc = get_mult(defunit, &mult); - if (rc) - return rc; - } - - return str_to_u64_internal(buffer, count, val, mult, true); -} -EXPORT_SYMBOL(lprocfs_str_with_units_to_u64); - char *lprocfs_strnstr(const char *s1, const char *s2, size_t len) { size_t l2;