It looks like d_strtoi_h was replaced by sysfs_strtoul_clamp in February of 2019 ([09/19] bcache: fix input overflow to sequential_cutoff - Patchwork).
Following the call stack of sysfs_strtoul_clamp appears to lead to _parse_integer:
_parse_integer has the comment “Don’t you dare use this function” and appears to stop parsing at any value outside of the range 0-f. It doesn’t appear to handle “M”.
/*
* Convert non-negative integer string representation in explicitly given radix
* to an integer.
* Return number of characters consumed maybe or-ed with overflow bit.
* If overflow occurs, result integer (incorrect) is still returned.
*
* Don't you dare use this function.
*/
unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *p)
{
unsigned long long res;
unsigned int rv;
res = 0;
rv = 0;
while (1) {
unsigned int c = *s;
unsigned int lc = c | 0x20; /* don't tolower() this line */
unsigned int val;
if ('0' <= c && c <= '9')
val = c - '0';
else if ('a' <= lc && lc <= 'f')
val = lc - 'a' + 10;
else
break;
if (val >= base)
break;
/*
* Check for overflow only if we are within range of
* it in the max base we support (16)
*/
if (unlikely(res & (~0ull << 60))) {
if (res > div_u64(ULLONG_MAX - val, base))
rv |= KSTRTOX_OVERFLOW;
}
res = res * base + val;
rv++;
s++;
}
*p = res;
return rv;
}
Since “M” is unparsed, The calling function (_kstrtoull) sees that there is still data in the string (*s) and returns “EINVAL”:
static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res)
{
unsigned long long _res;
unsigned int rv;
s = _parse_integer_fixup_radix(s, &base);
rv = _parse_integer(s, base, &_res);
if (rv & KSTRTOX_OVERFLOW)
return -ERANGE;
if (rv == 0)
return -EINVAL;
s += rv;
if (*s == '\n')
s++;
if (*s)
return -EINVAL;
*res = _res;
return 0;
}
P.S. As a workaround, it looks like there is a numfmt command that will do the conversion for you:
[/home/gregory]$ numfmt --from=iec 64M
67108864