13c9f3681SJames Bottomley /* 23c9f3681SJames Bottomley * Helpers for formatting and printing strings 33c9f3681SJames Bottomley * 43c9f3681SJames Bottomley * Copyright 31 August 2008 James Bottomley 53c9f3681SJames Bottomley */ 63c9f3681SJames Bottomley #include <linux/kernel.h> 73c9f3681SJames Bottomley #include <linux/math64.h> 83c9f3681SJames Bottomley #include <linux/module.h> 93c9f3681SJames Bottomley #include <linux/string_helpers.h> 103c9f3681SJames Bottomley 113c9f3681SJames Bottomley /** 123c9f3681SJames Bottomley * string_get_size - get the size in the specified units 133c9f3681SJames Bottomley * @size: The size to be converted 143c9f3681SJames Bottomley * @units: units to use (powers of 1000 or 1024) 153c9f3681SJames Bottomley * @buf: buffer to format to 163c9f3681SJames Bottomley * @len: length of buffer 173c9f3681SJames Bottomley * 183c9f3681SJames Bottomley * This function returns a string formatted to 3 significant figures 193c9f3681SJames Bottomley * giving the size in the required units. Returns 0 on success or 203c9f3681SJames Bottomley * error on failure. @buf is always zero terminated. 213c9f3681SJames Bottomley * 223c9f3681SJames Bottomley */ 233c9f3681SJames Bottomley int string_get_size(u64 size, const enum string_size_units units, 243c9f3681SJames Bottomley char *buf, int len) 253c9f3681SJames Bottomley { 26*a8659597SH. Peter Anvin const char *units_10[] = { "B", "kB", "MB", "GB", "TB", "PB", 273c9f3681SJames Bottomley "EB", "ZB", "YB", NULL}; 283c9f3681SJames Bottomley const char *units_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", 293c9f3681SJames Bottomley "EiB", "ZiB", "YiB", NULL }; 303c9f3681SJames Bottomley const char **units_str[] = { 313c9f3681SJames Bottomley [STRING_UNITS_10] = units_10, 323c9f3681SJames Bottomley [STRING_UNITS_2] = units_2, 333c9f3681SJames Bottomley }; 34*a8659597SH. Peter Anvin const unsigned int divisor[] = { 353c9f3681SJames Bottomley [STRING_UNITS_10] = 1000, 363c9f3681SJames Bottomley [STRING_UNITS_2] = 1024, 373c9f3681SJames Bottomley }; 383c9f3681SJames Bottomley int i, j; 393c9f3681SJames Bottomley u64 remainder = 0, sf_cap; 403c9f3681SJames Bottomley char tmp[8]; 413c9f3681SJames Bottomley 423c9f3681SJames Bottomley tmp[0] = '\0'; 43*a8659597SH. Peter Anvin i = 0; 44*a8659597SH. Peter Anvin if (size >= divisor[units]) { 45*a8659597SH. Peter Anvin while (size >= divisor[units] && units_str[units][i]) { 463c9f3681SJames Bottomley remainder = do_div(size, divisor[units]); 47*a8659597SH. Peter Anvin i++; 48*a8659597SH. Peter Anvin } 493c9f3681SJames Bottomley 503c9f3681SJames Bottomley sf_cap = size; 513c9f3681SJames Bottomley for (j = 0; sf_cap*10 < 1000; j++) 523c9f3681SJames Bottomley sf_cap *= 10; 533c9f3681SJames Bottomley 543c9f3681SJames Bottomley if (j) { 553c9f3681SJames Bottomley remainder *= 1000; 563c9f3681SJames Bottomley do_div(remainder, divisor[units]); 573c9f3681SJames Bottomley snprintf(tmp, sizeof(tmp), ".%03lld", 583c9f3681SJames Bottomley (unsigned long long)remainder); 593c9f3681SJames Bottomley tmp[j+1] = '\0'; 603c9f3681SJames Bottomley } 61*a8659597SH. Peter Anvin } 623c9f3681SJames Bottomley 633c9f3681SJames Bottomley snprintf(buf, len, "%lld%s %s", (unsigned long long)size, 643c9f3681SJames Bottomley tmp, units_str[units][i]); 653c9f3681SJames Bottomley 663c9f3681SJames Bottomley return 0; 673c9f3681SJames Bottomley } 683c9f3681SJames Bottomley EXPORT_SYMBOL(string_get_size); 69