Kernel APIs, Part 1: Invoking user-space applications from the kernel
2013-07-03 00:34
489 查看
Kernel APIs, Part 1: Invoking user-space applications from the kernel
Implementation and use of the usermode-helper APISummary: The Linux® system call interface permits user-space applications to invoke functionality in the kernel, but what about invoking user-space applications from the kernel? Explore the usermode-helper
API, and learn how to invoke user-space applications and manipulate their output.
View
more content in this series
Invoking specific kernel functions (system calls) is a natural part of application development on GNU/Linux. But what about going in the other direction, kernel space calling user space? It turns out that there are a number of applications for this feature
that you likely use every day. For example, when the kernel finds a device for which a module needs to be loaded, how does this process occur? Dynamic module loading occurs from the kernel through the usermode-helperprocess.
Let's begin with an exploration of usermode-helper, its application programming interface (API), and some of the examples of where this feature is used in the kernel. Then, using the API, you'll build a sample application to better understand how it works and
its limitations.
The usermode-helper API
The usermode-helper API is a simple API with a well-known set of options. For example, to create a process from user space, you commonly provide the name of the executable, the options for the executable, and a set of environment variables (refer to the man
page for
execve). The same applies for creating a process from the kernel. But because you're starting the process from kernel space, a few additional options are available.
Kernel version
This article explores the usermode-helper API from the 2.6.27 kernel.Table 1 shows the core set of kernel functions available in the usermode-helper API.
Table 1. Core functions in the usermode-helper API
API function | Description |
---|---|
call_usermodehelper_setup | Prepare a handler for a user-land call |
call_usermodehelper_setkeys | Set the session keys for a helper |
call_usermodehelper_setcleanup | Set a cleanup function for the helper |
call_usermodehelper_stdinpipe | Create a stdinpipe for a helper |
call_usermodehelper_exec | Invoke the user-land call |
possible.
Table 2. Simplifications of the usermode-helper API
API function | Description |
---|---|
call_usermodehelper | Make a user-land call |
call_usermodehelper_pipe | Make a user-land call with a pipe stdin |
call_usermodehelper_keys | Make a user-land call with session keys |
subprocess_infostructure.
This structure (which can be found in ./kernel/kmod.c) aggregates all of the necessary elements for a given usermode-helper instance. The structure reference is returned from a call to
call_usermodehelper_setup.
The structure (and subsequent calls) is further configured through calls to
call_usermodehelper_setkeys(for credentials storage),
call_usermodehelper_setcleanup,
and
call_usermodehelper_stdinpipe. Finally, once configuration is complete, you can invoke the configured user-mode application through a call to
call_usermodehelper_exec.
Disclaimer
This method provides a necessary function for invoking user-space applications from the kernel. Although there are legitimate uses for this functionality, you should strongly consider whether other implementations are needed. This is one approach, but otherapproaches are better suited.
The core functions provide you with the greatest amount of control, where the helper functions do more of the work for you in a single call. The pipe-related calls (
call_usermodehelper_stdinpipeand
the helper function
call_usermodehelper_pipe) create an associated pipe for use by the helper. Specifically, a pipe is created (a file structure in the kernel). The pipe is
readable by the user-space application and writable by the kernel side. As of this writing, core dumps are the only application that can use a pipe with a usermode-helper. In this application (./fs/exec.c
do_coredump()),
the core dump is written through the pipe from kernel space to user space.
The relationship between these functions and the
sub_processinfoalong with the details of the
subprocess_infostructure
is shown in Figure 1.
Figure 1. Usermode-helper API relationships
The simplification functions in Table 2 perform the
call_usermodehelper_setupfunction
and
call_usermodehelper_execfunction internally. The last two calls in Table
2 invoke the
call_usermodehelper_setkeysand
call_usermodehelper_stdinpipe,
respectively. You can find the source to
call_usermodehelper_pipein ./kernel/kmod.c and to
call_usermodehelperand
call_usermodhelper_keysin
./include/linux/kmod.h.
Back
to top
Why invoke a user-space application from the kernel?
Let's now look at some of the places in the kernel where the usermode-helper API is put to use. Table 3 doesn't provide an exclusive list of applications but represents a cross-section of interesting uses.
Table 3. Applications of the usermode-helper API in the kernel
Application | Source location |
---|---|
Kernel module loading | ./kernel/kmod.c |
Power management | ./kernel/sys.c |
Control groups | ./kernel/cgroup.c |
Security key generation | ./security/keys/request_key.c |
Kernel event delivery | ./lib/kobject_uevent.c |
request_moduleencapsulates the
functionality of the usermode-helper API and provides a simple interface. In a common usage model, the kernel identifies a device or needed service and makes a call to
request_moduleto
have the module loaded. Through the usermode-helper API, the module is loaded into the kernel via
modprobe(the application invoked in user space via
request_module).
A similar application to module loading is device hot-plugging (to add or remove devices at run time). This feature is implemented with the usermode-helper API, invoking the /sbin/hotplug utility in user space.
An interesting application of the usermode-helper API (via
request_module) is the textsearch API (./lib/textsearch.c). This application provides a configurable text searching
infrastructure in the kernel. This application uses the usermode-helper API through the dynamic loading of search algorithms as loadable modules. In the 2.6.30 kernel release, three algorithms are supported, including Boyer-Moore (./lib/ts_bm.c), a naive finite-state
machine approach (./lib/ts_fsm.c), and finally the Knuth-Morris-Pratt algorithm (./lib/ts_kmp.c).
The usermode-helper API also supports Linux in an orderly system shutdown. When a system power-off is necessary, the kernel invokes the /sbin/poweroff command in user space to accomplish it. Other applications are listed in Table
3, with the accompanying source location.
Back
to top
Usermode-helper API internals
You'll find the source and API for the usermode-helper API in kernel/kmod.c (illustrating its primary use as the kernel-space kernel module loader). The implementation uses
kernel_execvefor
the dirty work. Note that
kernel_execveis the function used to start the
initprocess
at boot time and does not use the usermode-helper API.
The implementation of the usermode-helper API is quite simple and straightforward (see Figure 2). The work of the usermode-helper begins with the call to
call_usermodehelper_exec(which
is used to kick off the user-space application from a preconfigured
subprocess_infostructure). This function accepts two arguments: the
subprocess_infostructure
reference and an enumeration type (whether to not wait, wait for the process to be kicked of, or wait for the entire process to be completed). The
subprocess_info(or rather,
the
work_structelement of this structure) is then enqueued onto a work structure (
khelper_wq),
which asynchronously performs the invocation.
Figure 2. Internal implementation of the usermode-helper API
When an element is placed onto the
khelper_wq, the handler function for the work queue is invoked (in this case,
__call_usermodehelper),
which is run through the
khelperthread. This function begins by dequeuing the
subprocess_infostructure,
which contains all of the necessary information for the user-space invocation. The path next depends upon the
waitvariable enumeration. If the requester wants to wait for the
entire process to finish, including user-space invocation (
UMH_WAIT_PROC) or not wait at all (
UMH_NO_WAIT), then a kernel
thread is created from the function
wait_for_helper. Otherwise, the requester simply wants to wait for the user-space application to be invoked (
UMH_WAIT_EXEC)
but not complete. In this case, a kernel thread is created for
____call_usermodehelper().
In the
wait_for_helperthread, a SIGCHLD signal handler is installed, and another kernel thread is created for
____call_usermodehelper.
But in the
wait_for_helperthread, a call is made to
sys_wait4to
await termination of the
____call_usermodehelperkernel thread (indicated by a SIGCHLD signal). The thread then performs any necessary cleanup (either freeing the structures
for
UMH_NO_WAITor simply sending a completion notification back to
call_usermodehelper_exec().
The function
____call_usermodehelperis where the real work happens for getting the application started in user space. This function begins by unblocking all signals
and setting the session key ring. It also installs the
stdinpipe (if requested). After a bit more initialization, the user-space application is invoked through
a call to
kernel_execve(from kernel/syscall.c), which includes the previously defined
path,
argvlist
(including the user-space application name), and environment. When this process is complete, the thread exits through a call to
do_exit().
This process also uses Linux completions, which is a semaphore-like operation. When the
call_usermodehelper_execfunction is invoked, a completion is declared. After
the
subprocess_infostructure is placed on the
khelper_wq, a call is made to
wait_for_completion(using
the completion variable as its only argument). Note that this variable is also stored in the
subprocess_infostructure as the
completefield.
When the child threads want to wake up the
call_usermodehelper_execfunction, they call the kernel method
complete,
noting the completion variable from the
subprocess_infostructure. This call unlocks the function so that it can continue. You can find the implementation of this
API in include/linux/completion.h.
You'll find more information on the usermode-helper API by following the links in the Resources section.
Back
to top
Sample application
Now, let's look at a simple use of the usermode-helper API. You'll first look at the standard API, then learn how to simplify things further using the helper functions.
For this demonstration, you develop a simple loadable kernel module that invokes the API. Listing 1 presents the boilerplate module functions, defining the module entry and exit functions. These two functions are invoked on
modprobeor
insmodof
the module (module entry function) and
rmmodof the module (module exit).
Listing 1. Module boilerplate functions
#include <linux/module.h> #include <linux/init.h> #include <linux/kmod.h> MODULE_LICENSE( "GPL" ); static int __init mod_entry_func( void ) { return umh_test(); } static void __exit mod_exit_func( void ) { return; } module_init( mod_entry_func ); module_exit( mod_exit_func ); |
a variety of needed variables and structures. Start with the
subprocess_infostructure, which contains all of the information necessary to perform the user-space
invocation. This invocation is initialized when you call
call_usermodehelper_setup. Next, define your argument list, called
argv.
This list is similar to the
argvlist used in common
Cprograms
and defines the application (first element of the array) and argument list. A NULL terminator is required to indicate the end of the list. Note here that the
argcvariable (argument
count) is implicit, because the length of the
argvlist is known. In this example, the application name is /usr/bin/logger, and its argument is
help!,
which is followed by your terminating NULL. The next required variable is the environment array (
envp). This array is a list of parameters that define the execution environment for the user-space
application. In this example, you define a few typical parameters that are defined for the shell and end with a terminating NULL entry.
Listing 2. Simple usermode_helper API test
static int umh_test( void ) { struct subprocess_info *sub_info; char *argv[] = { "/usr/bin/logger", "help!", NULL }; static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL }; sub_info = call_usermodehelper_setup( argv[0], argv, envp, GFP_ATOMIC ); if (sub_info == NULL) return -ENOMEM; return call_usermodehelper_exec( sub_info, UMH_WAIT_PROC ); } |
call_usermodehelper_setupto create your initialized
subprocess_infostructure.
Note that you use your previously initialized variables along with a fourth parameter that indicates the GFP mask for memory initialization. Internal to the setup function, there's a call to
kzalloc(which
allocates kernel memory and zeroes it). This function requires either
GFP_ATOMICor the
GFP_KERNELflag
(where the former defines that the call should not sleep and the latter that sleep is possible). After a quick test of your new structure (namely, it's not NULL), continue to make the call using the
call_usermodehelper_execfunction.
This function takes your
subprocess_infostructure and an enumeration defining whether to wait (described in the internals section). And that's it! Once the module
is loaded, you should see the message in your /var/log/messages file.
You can simplify this process further by using the
call_usermodehelperAPI function, which performs the
call_usermodehelper_setupand
call_usermodehelper_execfunctions
together. As shown in Listing 3, this not only removes a function but also removes the need for the caller to manage the
subprocess_infostructure.
Listing 3. An even simpler usermode-helper API test
static int umh_test( void ) { char *argv[] = { "/usr/bin/logger", "help!", NULL }; static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL }; return call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC ); } |
argvand
envparrays).
The only difference here is that the helper function performs the
setupand
execfunctions.
Back
to top
Going further
The usermode-helper API is an important aspect to the kernel, given its wide and varying use (from kernel module loading, device hot-plugging, and event distribution for udev). Although it's important to validate genuine applications of the API, it's an important
aspect of the kernel to understand and therefore a useful addition to your Linux kernel toolkit.
Resources
Learn
Little information exists about the usermode-helper API, but the implementation is quite clean and simple to follow. You can review the implementation through LXR (the Linux Cross Referencer—source browser for all source revisions). The two primary files of
interest are kmod.c and kmod.h.
The /proc file system provides a method for communicating between the kernel and user space—namely, though a virtual file system. You can learn more about the /proc file system in "Access
the Linux kernel using the /proc filesystem" (developerworks, March 2006).
The Linux system call interface provides the means for user-space applications to invoke kernel functionality. For more details on Linux system calls, including how to add new system calls, see "Kernel
command using system calls" (developerworks, March 2007).
To illustrate the usermode-helper API, this article uses loadable kernel modules to install test applications into the kernel. To learn more about loadable kernel modules and their implementation, check out "Anatomy
of Linux loadable kernel modules" (developerworks, July 2008).
To learn more about the 2.6 kernel work queue interface, check out this older Linux Journal article from 2003, which provides a good introduction to the API and
operation of kernel work queues.
In the developerWorks Linux zone, find more resources for Linux developers.
Stay current with developerWorks technical events and Webcasts.
Follow developerWorks on Twitter.
Get products and technologies
With IBM trial software, available for download directly from developerWorks, build your next development project on Linux.
Discuss
Get involved in the My developerWorks community. Connect with other developerWorks users while exploring the developer-driven blogs, forums, groups, and wikis.
相关文章推荐
- Three Steps Down the Stairs: From Win32 User-Land through Native API to Kernel
- How to modify the uboot environment from userspace
- How to modify the uboot environment from userspace
- Along with all the above benefits, you cannot overlook the space efficiency and performance gains in using DataFrames and Dataset APIs for two reasons.
- Whole House Audio from the Palm of Your Hand - Part 2 of 3 @ JDJ
- user space to kernel space
- use WinRT APIs from desktop applications
- 在Django块标签中遇到的Error:Could not parse the remainder:'>' from 'user.age>'
- Debugging the kernel using Ftrace - part 2
- How to customise the TWebBrowser user interface (part 4 of 6)
- linux内存操作----kernel 3.5.X copy_from_user()和copy_to_user()
- Visual Studio cannot debug managed applications because a kernel debugger is enabled on the system
- Kernel APIs Timers and lists in the 2.6 kernel
- 102.You want to import schema objects of the HR user using Oracle Data Pump from the development dat
- Entering the kernel without a driver and getting interrupt information from APIC
- 142.The user SCOTT owns the CUST table that is placed in the SALES tablespace. The user SCOTT opens
- Debugging the kernel using Ftrace - part 3
- Unreachable catch block for UserExistException. This exception is never thrown from the try statemen
- Inside the Windows Vista Kernel: Part 1
- The path "fos_user.from_email.address" cannot contain an empty value, but got null.