Revision 80ef4464d5e27408685e609d389663aad46644b9 authored by Robert Richter on 20 March 2019, 18:57:23 UTC, committed by Joerg Roedel on 22 March 2019, 11:01:58 UTC
If a 32 bit allocation request is too big to possibly succeed, it
early exits with a failure and then should never update max32_alloc_
size. This patch fixes current code, now the size is only updated if
the slow path failed while walking the tree. Without the fix the
allocation may enter the slow path again even if there was a failure
before of a request with the same or a smaller size.

Cc: <stable@vger.kernel.org> # 4.20+
Fixes: bee60e94a1e2 ("iommu/iova: Optimise attempts to allocate iova from 32bit address range")
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Robert Richter <rrichter@marvell.com>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
1 parent 4e50ce0
Raw File
utprint.c
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
/******************************************************************************
 *
 * Module Name: utprint - Formatted printing routines
 *
 * Copyright (C) 2000 - 2019, Intel Corp.
 *
 *****************************************************************************/

#include <acpi/acpi.h>
#include "accommon.h"

#define _COMPONENT          ACPI_UTILITIES
ACPI_MODULE_NAME("utprint")

#define ACPI_FORMAT_SIGN            0x01
#define ACPI_FORMAT_SIGN_PLUS       0x02
#define ACPI_FORMAT_SIGN_PLUS_SPACE 0x04
#define ACPI_FORMAT_ZERO            0x08
#define ACPI_FORMAT_LEFT            0x10
#define ACPI_FORMAT_UPPER           0x20
#define ACPI_FORMAT_PREFIX          0x40
/* Local prototypes */
static acpi_size
acpi_ut_bound_string_length(const char *string, acpi_size count);

static char *acpi_ut_bound_string_output(char *string, const char *end, char c);

static char *acpi_ut_format_number(char *string,
				   char *end,
				   u64 number,
				   u8 base, s32 width, s32 precision, u8 type);

static char *acpi_ut_put_number(char *string, u64 number, u8 base, u8 upper);

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_bound_string_length
 *
 * PARAMETERS:  string              - String with boundary
 *              count               - Boundary of the string
 *
 * RETURN:      Length of the string. Less than or equal to Count.
 *
 * DESCRIPTION: Calculate the length of a string with boundary.
 *
 ******************************************************************************/

static acpi_size
acpi_ut_bound_string_length(const char *string, acpi_size count)
{
	u32 length = 0;

	while (*string && count) {
		length++;
		string++;
		count--;
	}

	return (length);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_bound_string_output
 *
 * PARAMETERS:  string              - String with boundary
 *              end                 - Boundary of the string
 *              c                   - Character to be output to the string
 *
 * RETURN:      Updated position for next valid character
 *
 * DESCRIPTION: Output a character into a string with boundary check.
 *
 ******************************************************************************/

static char *acpi_ut_bound_string_output(char *string, const char *end, char c)
{

	if (string < end) {
		*string = c;
	}

	++string;
	return (string);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_put_number
 *
 * PARAMETERS:  string              - Buffer to hold reverse-ordered string
 *              number              - Integer to be converted
 *              base                - Base of the integer
 *              upper               - Whether or not using upper cased digits
 *
 * RETURN:      Updated position for next valid character
 *
 * DESCRIPTION: Convert an integer into a string, note that, the string holds a
 *              reversed ordered number without the trailing zero.
 *
 ******************************************************************************/

static char *acpi_ut_put_number(char *string, u64 number, u8 base, u8 upper)
{
	const char *digits;
	u64 digit_index;
	char *pos;

	pos = string;
	digits = upper ? acpi_gbl_upper_hex_digits : acpi_gbl_lower_hex_digits;

	if (number == 0) {
		*(pos++) = '0';
	} else {
		while (number) {
			(void)acpi_ut_divide(number, base, &number,
					     &digit_index);
			*(pos++) = digits[digit_index];
		}
	}

	/* *(Pos++) = '0'; */
	return (pos);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_scan_number
 *
 * PARAMETERS:  string              - String buffer
 *              number_ptr          - Where the number is returned
 *
 * RETURN:      Updated position for next valid character
 *
 * DESCRIPTION: Scan a string for a decimal integer.
 *
 ******************************************************************************/

const char *acpi_ut_scan_number(const char *string, u64 *number_ptr)
{
	u64 number = 0;

	while (isdigit((int)*string)) {
		acpi_ut_short_multiply(number, 10, &number);
		number += *(string++) - '0';
	}

	*number_ptr = number;
	return (string);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_print_number
 *
 * PARAMETERS:  string              - String buffer
 *              number              - The number to be converted
 *
 * RETURN:      Updated position for next valid character
 *
 * DESCRIPTION: Print a decimal integer into a string.
 *
 ******************************************************************************/

const char *acpi_ut_print_number(char *string, u64 number)
{
	char ascii_string[20];
	const char *pos1;
	char *pos2;

	pos1 = acpi_ut_put_number(ascii_string, number, 10, FALSE);
	pos2 = string;

	while (pos1 != ascii_string) {
		*(pos2++) = *(--pos1);
	}

	*pos2 = 0;
	return (string);
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ut_format_number
 *
 * PARAMETERS:  string              - String buffer with boundary
 *              end                 - Boundary of the string
 *              number              - The number to be converted
 *              base                - Base of the integer
 *              width               - Field width
 *              precision           - Precision of the integer
 *              type                - Special printing flags
 *
 * RETURN:      Updated position for next valid character
 *
 * DESCRIPTION: Print an integer into a string with any base and any precision.
 *
 ******************************************************************************/

static char *acpi_ut_format_number(char *string,
				   char *end,
				   u64 number,
				   u8 base, s32 width, s32 precision, u8 type)
{
	char *pos;
	char sign;
	char zero;
	u8 need_prefix;
	u8 upper;
	s32 i;
	char reversed_string[66];

	/* Parameter validation */

	if (base < 2 || base > 16) {
		return (NULL);
	}

	if (type & ACPI_FORMAT_LEFT) {
		type &= ~ACPI_FORMAT_ZERO;
	}

	need_prefix = ((type & ACPI_FORMAT_PREFIX)
		       && base != 10) ? TRUE : FALSE;
	upper = (type & ACPI_FORMAT_UPPER) ? TRUE : FALSE;
	zero = (type & ACPI_FORMAT_ZERO) ? '0' : ' ';

	/* Calculate size according to sign and prefix */

	sign = '\0';
	if (type & ACPI_FORMAT_SIGN) {
		if ((s64)number < 0) {
			sign = '-';
			number = -(s64)number;
			width--;
		} else if (type & ACPI_FORMAT_SIGN_PLUS) {
			sign = '+';
			width--;
		} else if (type & ACPI_FORMAT_SIGN_PLUS_SPACE) {
			sign = ' ';
			width--;
		}
	}
	if (need_prefix) {
		width--;
		if (base == 16) {
			width--;
		}
	}

	/* Generate full string in reverse order */

	pos = acpi_ut_put_number(reversed_string, number, base, upper);
	i = (s32)ACPI_PTR_DIFF(pos, reversed_string);

	/* Printing 100 using %2d gives "100", not "00" */

	if (i > precision) {
		precision = i;
	}

	width -= precision;

	/* Output the string */

	if (!(type & (ACPI_FORMAT_ZERO | ACPI_FORMAT_LEFT))) {
		while (--width >= 0) {
			string = acpi_ut_bound_string_output(string, end, ' ');
		}
	}
	if (sign) {
		string = acpi_ut_bound_string_output(string, end, sign);
	}
	if (need_prefix) {
		string = acpi_ut_bound_string_output(string, end, '0');
		if (base == 16) {
			string =
			    acpi_ut_bound_string_output(string, end,
							upper ? 'X' : 'x');
		}
	}
	if (!(type & ACPI_FORMAT_LEFT)) {
		while (--width >= 0) {
			string = acpi_ut_bound_string_output(string, end, zero);
		}
	}

	while (i <= --precision) {
		string = acpi_ut_bound_string_output(string, end, '0');
	}
	while (--i >= 0) {
		string = acpi_ut_bound_string_output(string, end,
						     reversed_string[i]);
	}
	while (--width >= 0) {
		string = acpi_ut_bound_string_output(string, end, ' ');
	}

	return (string);
}

/*******************************************************************************
 *
 * FUNCTION:    vsnprintf
 *
 * PARAMETERS:  string              - String with boundary
 *              size                - Boundary of the string
 *              format              - Standard printf format
 *              args                - Argument list
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to a string using argument list pointer.
 *
 ******************************************************************************/

int vsnprintf(char *string, acpi_size size, const char *format, va_list args)
{
	u8 base;
	u8 type;
	s32 width;
	s32 precision;
	char qualifier;
	u64 number;
	char *pos;
	char *end;
	char c;
	const char *s;
	const void *p;
	s32 length;
	int i;

	pos = string;
	end = string + size;

	for (; *format; ++format) {
		if (*format != '%') {
			pos = acpi_ut_bound_string_output(pos, end, *format);
			continue;
		}

		type = 0;
		base = 10;

		/* Process sign */

		do {
			++format;
			if (*format == '#') {
				type |= ACPI_FORMAT_PREFIX;
			} else if (*format == '0') {
				type |= ACPI_FORMAT_ZERO;
			} else if (*format == '+') {
				type |= ACPI_FORMAT_SIGN_PLUS;
			} else if (*format == ' ') {
				type |= ACPI_FORMAT_SIGN_PLUS_SPACE;
			} else if (*format == '-') {
				type |= ACPI_FORMAT_LEFT;
			} else {
				break;
			}

		} while (1);

		/* Process width */

		width = -1;
		if (isdigit((int)*format)) {
			format = acpi_ut_scan_number(format, &number);
			width = (s32)number;
		} else if (*format == '*') {
			++format;
			width = va_arg(args, int);
			if (width < 0) {
				width = -width;
				type |= ACPI_FORMAT_LEFT;
			}
		}

		/* Process precision */

		precision = -1;
		if (*format == '.') {
			++format;
			if (isdigit((int)*format)) {
				format = acpi_ut_scan_number(format, &number);
				precision = (s32)number;
			} else if (*format == '*') {
				++format;
				precision = va_arg(args, int);
			}

			if (precision < 0) {
				precision = 0;
			}
		}

		/* Process qualifier */

		qualifier = -1;
		if (*format == 'h' || *format == 'l' || *format == 'L') {
			qualifier = *format;
			++format;

			if (qualifier == 'l' && *format == 'l') {
				qualifier = 'L';
				++format;
			}
		}

		switch (*format) {
		case '%':

			pos = acpi_ut_bound_string_output(pos, end, '%');
			continue;

		case 'c':

			if (!(type & ACPI_FORMAT_LEFT)) {
				while (--width > 0) {
					pos =
					    acpi_ut_bound_string_output(pos,
									end,
									' ');
				}
			}

			c = (char)va_arg(args, int);
			pos = acpi_ut_bound_string_output(pos, end, c);

			while (--width > 0) {
				pos =
				    acpi_ut_bound_string_output(pos, end, ' ');
			}
			continue;

		case 's':

			s = va_arg(args, char *);
			if (!s) {
				s = "<NULL>";
			}
			length = (s32)acpi_ut_bound_string_length(s, precision);
			if (!(type & ACPI_FORMAT_LEFT)) {
				while (length < width--) {
					pos =
					    acpi_ut_bound_string_output(pos,
									end,
									' ');
				}
			}

			for (i = 0; i < length; ++i) {
				pos = acpi_ut_bound_string_output(pos, end, *s);
				++s;
			}

			while (length < width--) {
				pos =
				    acpi_ut_bound_string_output(pos, end, ' ');
			}
			continue;

		case 'o':

			base = 8;
			break;

		case 'X':

			type |= ACPI_FORMAT_UPPER;
			/* FALLTHROUGH */

		case 'x':

			base = 16;
			break;

		case 'd':
		case 'i':

			type |= ACPI_FORMAT_SIGN;

		case 'u':

			break;

		case 'p':

			if (width == -1) {
				width = 2 * sizeof(void *);
				type |= ACPI_FORMAT_ZERO;
			}

			p = va_arg(args, void *);
			pos =
			    acpi_ut_format_number(pos, end, ACPI_TO_INTEGER(p),
						  16, width, precision, type);
			continue;

		default:

			pos = acpi_ut_bound_string_output(pos, end, '%');
			if (*format) {
				pos =
				    acpi_ut_bound_string_output(pos, end,
								*format);
			} else {
				--format;
			}
			continue;
		}

		if (qualifier == 'L') {
			number = va_arg(args, u64);
			if (type & ACPI_FORMAT_SIGN) {
				number = (s64)number;
			}
		} else if (qualifier == 'l') {
			number = va_arg(args, unsigned long);
			if (type & ACPI_FORMAT_SIGN) {
				number = (s32)number;
			}
		} else if (qualifier == 'h') {
			number = (u16)va_arg(args, int);
			if (type & ACPI_FORMAT_SIGN) {
				number = (s16)number;
			}
		} else {
			number = va_arg(args, unsigned int);
			if (type & ACPI_FORMAT_SIGN) {
				number = (signed int)number;
			}
		}

		pos = acpi_ut_format_number(pos, end, number, base,
					    width, precision, type);
	}

	if (size > 0) {
		if (pos < end) {
			*pos = '\0';
		} else {
			end[-1] = '\0';
		}
	}

	return ((int)ACPI_PTR_DIFF(pos, string));
}

/*******************************************************************************
 *
 * FUNCTION:    snprintf
 *
 * PARAMETERS:  string              - String with boundary
 *              size                - Boundary of the string
 *              Format, ...         - Standard printf format
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to a string.
 *
 ******************************************************************************/

int snprintf(char *string, acpi_size size, const char *format, ...)
{
	va_list args;
	int length;

	va_start(args, format);
	length = vsnprintf(string, size, format, args);
	va_end(args);

	return (length);
}

/*******************************************************************************
 *
 * FUNCTION:    sprintf
 *
 * PARAMETERS:  string              - String with boundary
 *              Format, ...         - Standard printf format
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to a string.
 *
 ******************************************************************************/

int sprintf(char *string, const char *format, ...)
{
	va_list args;
	int length;

	va_start(args, format);
	length = vsnprintf(string, ACPI_UINT32_MAX, format, args);
	va_end(args);

	return (length);
}

#ifdef ACPI_APPLICATION
/*******************************************************************************
 *
 * FUNCTION:    vprintf
 *
 * PARAMETERS:  format              - Standard printf format
 *              args                - Argument list
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to stdout using argument list pointer.
 *
 ******************************************************************************/

int vprintf(const char *format, va_list args)
{
	acpi_cpu_flags flags;
	int length;

	flags = acpi_os_acquire_lock(acpi_gbl_print_lock);
	length = vsnprintf(acpi_gbl_print_buffer,
			   sizeof(acpi_gbl_print_buffer), format, args);

	(void)fwrite(acpi_gbl_print_buffer, length, 1, ACPI_FILE_OUT);
	acpi_os_release_lock(acpi_gbl_print_lock, flags);

	return (length);
}

/*******************************************************************************
 *
 * FUNCTION:    printf
 *
 * PARAMETERS:  Format, ...         - Standard printf format
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to stdout.
 *
 ******************************************************************************/

int printf(const char *format, ...)
{
	va_list args;
	int length;

	va_start(args, format);
	length = vprintf(format, args);
	va_end(args);

	return (length);
}

/*******************************************************************************
 *
 * FUNCTION:    vfprintf
 *
 * PARAMETERS:  file                - File descriptor
 *              format              - Standard printf format
 *              args                - Argument list
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to a file using argument list pointer.
 *
 ******************************************************************************/

int vfprintf(FILE * file, const char *format, va_list args)
{
	acpi_cpu_flags flags;
	int length;

	flags = acpi_os_acquire_lock(acpi_gbl_print_lock);
	length = vsnprintf(acpi_gbl_print_buffer,
			   sizeof(acpi_gbl_print_buffer), format, args);

	(void)fwrite(acpi_gbl_print_buffer, length, 1, file);
	acpi_os_release_lock(acpi_gbl_print_lock, flags);

	return (length);
}

/*******************************************************************************
 *
 * FUNCTION:    fprintf
 *
 * PARAMETERS:  file                - File descriptor
 *              Format, ...         - Standard printf format
 *
 * RETURN:      Number of bytes actually written.
 *
 * DESCRIPTION: Formatted output to a file.
 *
 ******************************************************************************/

int fprintf(FILE * file, const char *format, ...)
{
	va_list args;
	int length;

	va_start(args, format);
	length = vfprintf(file, format, args);
	va_end(args);

	return (length);
}
#endif
back to top