In Linux user space programming, functions often return integers with the convention that a return value of 0 indicates success of a call to the function and that different (usually negative) non-zero values are used to indicate different errors. In kernel programming, however, many functions may return pointers instead of integers, which complicates this approach since a pointer may use non-zero values to encode valid memory addresses that are returned as the result of a successful call to a function.
Linux addresses this challenge by exploiting the facts that (1) the upper portions of
the range of valid (virtual) addresses are unused, and (2) the use of negative values to indicate errors will make their higher order bits non-zero whether they're returned as pointers or integers, and then (3) providing a useful macro and inline functions in the
include/linux/err.h
file that can handle different combinations of pointer, integer, and Boolean types, in a
portable manner that works across different hardware architectures:
The
IS_ERR_VALUE
macro checks whether the upper range of a (pointer or integer) value is non-empty (i.e., contains an error value).
The
ERR_PTR
function converts a (long
) integer value into a (void *
) pointer value.
The
PTR_ERR
function converts a (const void *
) pointer value into a (long
) integer value.
The
IS_ERR
function converts a (const void *
) pointer value into an (unsigned long
) integer value, uses the
IS_ERR_VALUE
macro to check whether the upper range of the value is non-empty (i.e., contains an error value), and returns a bool
value accordingly.
The
IS_ERR_OR_NULL
function returns a bool
value that is true
if (1) the passed (const void *
) pointer value is 0 or (2) the result of converting it into an (unsigned long
) integer value and then using the
IS_ERR_VALUE
macro on it indicates that the upper range of the value is non-empty (i.e., contains an error value).
The
ERR_CAST
function converts a (const void *
) pointer into a
(void *
) pointer (casting away constness).
The
PTR_ERR_OR_ZERO
function uses the
IS_ERR
function to check whether the passed (const void *
) pointer value contains an error, and returns an (int
) integer value that is 0 if it does not, or is the error value obtained by calling the
PTR_ERR
function with it if it does.