+ /* 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.
+ */
+static int str_to_s64_internal(const char __user *buffer, unsigned long count,
+ __s64 *val, __u64 def_mult, bool allow_units)
+{
+ char kernbuf[22];
+ __u64 tmp;
+ unsigned int offset = 0;
+ int signed sign = 1;
+ __u64 max = LLONG_MAX;
+ int rc = 0;
+
+ if (count > (sizeof(kernbuf) - 1))
+ return -EINVAL;
+
+ if (copy_from_user(kernbuf, buffer, count))
+ return -EFAULT;
+
+ kernbuf[count] = '\0';
+
+ /* keep track of our sign */
+ if (*kernbuf == '-') {
+ sign = -1;
+ offset++;
+ /* equivalent to max = -LLONG_MIN, avoids overflow */
+ max++;
+ }
+
+ rc = str_to_u64_parse(kernbuf + offset, count - offset,
+ &tmp, def_mult, allow_units);
+ if (rc)
+ return rc;
+
+ /* check for overflow/underflow */
+ if (max < tmp)
+ return -ERANGE;
+
+ *val = (__s64)tmp * sign;
+
+ return 0;
+}
+
+/**
+ * Convert a user string into a signed 64 bit number. This function produces
+ * an error when the value parsed from the string underflows or
+ * overflows. This function accepts strings which contain digits and
+ * optionally a decimal or hex strings which are prefixed with "0x".
+ *
+ * \param[in] buffer string consisting of numbers and optionally a decimal
+ * \param[in] count buffer length
+ * \param[in] val if successful, the value represented by the string
+ *
+ * \retval 0 on success
+ * \retval negative number on error
+ */
+int lprocfs_str_to_s64(const char __user *buffer, unsigned long count,
+ __s64 *val)
+{
+ return str_to_s64_internal(buffer, count, val, 1, false);
+}
+EXPORT_SYMBOL(lprocfs_str_to_s64);
+
+/**
+ * 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)
+{
+ __u64 mult;
+ int rc;
+
+ rc = get_mult(defunit, &mult);
+ if (rc)
+ return rc;
+
+ return str_to_s64_internal(buffer, count, val, mult, true);