exterror —
provide extended error information to
userspace
#define EXTERR_CATEGORY EXTERR_CAT_MYCATEGORY
#include
<sys/exterrvar.h>
struct kexterr;
void
exterr_clear(struct
kexterr *ke);
int
exterr_set_from(const
struct kexterr *ke);
int
EXTERROR(int
error, const char
*msg, ...);
void
EXTERROR_KE(struct
kexterr *ke, int
error, const char
*msg, ...);
The exterror framework allows the kernel
to return additional information about an error along with the standard
errno(3) error code, which is terse and often lacking
context.
The terseness is especially visible with commonly overloaded error
codes like EINVAL or EIO,
which occur at many places for a given syscall, or even outside the context
of the current kernel call. Identifying the specific cause for the returned
error using only the errno value requires searching
for all instances that the error is returned in the kernel and trying to
guess which is the most likely code path to have returned the error.
exterror attaches additional data to the error
itself and records the error category and the kernel source code file line
number. The intent of exterror is to make it easier
for a user to identify the cause of the error.
Before exterror can be used in the given
source .c file, the category of extended errors should be allocated in the
<sys/exterr_cat.h> file. The
category is the unique integer, that, together with the source line number,
uniquely identifies the extended error occurrence. Then, the
EXTERR_CATEGORY symbol should be defined as an alias
for the allocated category, as shown in the summary.
A typical code fragment to report an error is just
return (EINVAL);
An extended error can augment the error code with additional information:
return (EXTERROR(EINVAL, "Invalid
length"));
The error data and metadata is saved in the current thread storage. The metadata
includes the category and the source file line number.
Arguments to the
EXTERROR()
macro:
The strings passed as the second argument are only retained in the
kernel text if the option EXTERR_STRINGS was enabled
in the kernel config. Otherwise they are stripped at compile time and are
not available to userspace at runtime.
The
EXTERROR()
macro can be used in any context where the current thread is defined.
Specifically, EXTERROR() cannot be used in interrupt
contexts and context switch code. Additionally, use of
EXTERROR() in kernel threads is not sensible as
there is no userspace to retrieve the extended error data.
The
EXTERROR_KE()
macro is similar to EXTERROR(), but it takes an
explicit pointer kep to the struct
kexterr to fill with the extended error information. The macro
expression value is void. See below for description of
the asynchronous i/o error facilities.
The
exterr_clear()
function clears the content of the struct kexterr
pointed to by the argument ke.
The
exterr_set_from()
function sets the current thread extended error data from the
struct kexterr pointed to by the argument
ke.
There is no syscall overhead for using
exterror in the non-error case. When an error occurs
that has supplied extended information, the kernel copies out that
information into the userspace per-thread area that was registered with the
kernel, typically on image activation, or later at thread startup. The area
is controlled by the
exterrctl(2) internal syscall, normally done by the userspace
C runtime.
Userspace programs do not need to access the extended information
area directly. There is no field that is stable for the specific error
condition. Instead, the base library
“c” functions
err(3) and
warn(3) were modified to print the extended information if it
is available in addition to the usual errno
decoding.
Due to the nature of the FreeBSD i/o
subsystem, most input/output requests, presented as buffers (as in
struct buf) and geom bio's ( struct
bio) are processed asynchronously in filesystem- and geom-private
threads. This makes it challenging to pass any extended error information
from the geom providers and drivers, where an error typically occurs, back
to the thread that initiated the request, and is the consumer of the
result.
To alleviate the mismatch, both
struct buf and struct bio have
member of the struct kexterr type. For buffers, the
b_exterr for struct buf, and
bio_exterr for struct bio.
Asynchronous i/o code can use the
EXTERROR_KE()
macro, passing the pointer to the current request's embedded
struct kexterr, to record the extended error. In both
cases, the BIO_EXTERR flag should be set to indicate
that whole extended error is valid, not only the
b_error or bio_error values.
Both VFS and geom generic layers, and several geom providers that
generate subordinate bio's from the original request, are aware of the
extended errors. They pass kexterr from the failed
request back to the thread that create the request.
The exterror facility was introduced in
FreeBSD 15.0.