Microdrivers: a New Architecture for Device Drivers
Total Page:16
File Type:pdf, Size:1020Kb
Microdrivers: A New Architecture for Device Drivers Vinod Ganapathy, Arini Balakrishnan, Michael M. Swift and Somesh Jha Computer Sciences Department, University of Wisconsin-Madison Abstract Microdrivers Commodity operating systems achieve good perfor- Driver 1 Driver 2 Applications user−mode user−mode mance by running device drivers in-kernel. Unfortu- component component nately, this architecture offers poor fault isolation. This paper introduces microdrivers, which reduce the amount of driver code running in the kernel by splitting driver Driver 1 Driver 2 Rest of the functionality between a small kernel-mode component kernel−mode kernel−mode Operating System Kernel component component and a larger user-mode component. This paper presents the microdriver architecture and techniques to refactor existing device drivers into microdrivers, achieving most Device 1 Device 2 of the benefits of user-mode driverswith the performance of kernel-mode drivers. Experiments on a network driver Figure 1: Microdrivers split device driver func- show that 75% of its code can be removed from the ker- tionality between a kernel-mode component and a nel without affecting common-case performance. user-mode component. 1 Introduction Bugs in device drivers are a major source of reliabil- ifications and rewriting device drivers [7, 14]. Second, ity problems in commodity operating systems. For in- switching between the kernel and a user-mode device stance, a recent Microsoft report indicates that as many driver involves the costly overhead of changing protec- as 85% of failures in Windows XP stem from buggy de- tion domains. For devices such as high-throughput net- vice drivers [19]. work cards, this can result in significant latencies and The root of the problemis the architectureof commod- performance penalties [22, 23]. A common escape hatch ity operating systems. They are designed as monolithic employed in such cases is to implement drivers within kernels with all device drivers (and other kernel exten- the kernel, which defeats the benefit afforded by micro- sions), residing in the same address space as the kernel. kernels. This architecture results in good performancebecause in- This paper presents a new architecture for device voking driver functionality is as easy and efficient as a drivers called microdrivers. Microdrivers seek the mid- function call. Unfortunately, this also results in bloated dle ground between monolithic kernels and microker- operating systems and poor fault isolation. For exam- nels, and improve reliability while maximizing perfor- ple, kernel extensions constitute over 70% of Linux ker- mance. In a microdriver, the functionality of a device nel code [6] (a large fraction of these are device drivers), driver is split between a kernel-mode component and a while over 35, 000 drivers exist on Windows XP desk- user-mode component(Figure 1). The kernel-modecom- tops [18]. A single bug exercised in any one of these ponent contains critical and frequently used functional- extensions suffices to crash the entire operating system. ity, such as interrupt handling and performance-critical Several architectures have been proposed to isolate operations (e.g., sending and receiving network packets faults in device drivers [1, 9, 10, 16, 17, 22, 25]. For and processing SCSI commands), while the user-mode example, microkernels run device drivers as user-mode component contains non-critical and infrequently used processes. A bug exercised in a device driver only re- functionality (e.g., startup/shutdown and error-handling). sults in the failure of the user-mode process running that The user-mode component is implemented as a stan- driver. This approach, however, has two key problems. dalone process that is called from the kernel-mode com- First, this architecture is not compatible with commodity ponent. Together, they provide the functionality of a tra- operating systems, which are designed as monolithic ker- ditional device driver. nels. Providing support for user-mode device drivers in Microdrivers are motivated by a simple mantra: re- commodity operating systems thus requires kernel mod- duce the amount of code running in the kernel to improve its reliability. As discussed in Section 2, more than 70% Driver family Drivers analyzed Critical funcs of device driver code contains non-critical functionality. Network 134 27.8% By relegating this code to a user-mode process, a micro- SCSI 49 26.1% driver reduces the amount of code running in the kernel Sound 272 7.8% and improves the reliability of the system as a whole. In addition, because the kernel-mode component of a Figure 2: Classification of functions in different microdriver is much smaller than the entire driver, it is families of Linux device drivers. amenable to verification and code audits. Perhaps the most important aspect of microdrivers is taken, and whose type signature matches that of the is compatibility with commodity operating system function pointer. architectures—device drivers written for monolithic ker- We then identified a set of critical root functions that nels can be refactored nearly automatically into micro- are driver entrypoints that must execute in the kernel drivers. This provides a path to execute device drivers for high performance. Critical root functions are those written for commodity operating systems in user-mode that handle interrupts or execute at other high-priority without sacrificing performance. Prior efforts at user- levels (e.g., tasklets, bottom-halves), and functions that mode device drivers have either required rewriting the supply data to or receive data from a device. We de- driver completely [7, 14] or impose significant perfor- fine performance-critical functions to be critical root mance penalty [23]. We show that program analy- functions plus the functions that they transitively call. sis techniques can automatically identify critical func- Given a template of the entrypoints, critical root func- tions in a device driver, following which a semantics- tions can be identified automatically for each family of preserving transformation can split the driver into a user- drivers: e.g., functions that transmit network packets are mode and a kernel-mode component. We discuss the critical for network drivers, while functions that process design and implementation of such a refactoring tool in SCSI commands are critical for SCSI device drivers. We Section 4. We used this tool to refactor the e1000 device wrote a tool to automatically identify critical root func- driver for the Intel PRO/1000 gigabit network adapter tions (based upon their type signatures) and the functions into a microdriver. The kernel-mode component of this that they transitively call. microdriver contains just 25% of the code of the entire Figure 2 shows the results of our study. We found microdriver. Our preliminary experience with this mi- that fewer than 30% of the functions in a driver are per- crodriver indicates that overheads for common-case per- formance critical. The remaining functions are called formance and CPU utilization are negligible. only occasionally, e.g., during device startup/shutdown, 2 The case for microdrivers to configure device parameters, and to obtain diagnostic information. Consider, for example, the e1000 driver for / Because device drivers communicate with I O devices, the Intel PRO/1000 gigabit network adapter, one of the / their performance is critical to ensure fast I O. Con- drivers considered in our study. Critical root functions ventional wisdom holds that performance-critical func- for this driver include the interrupt handler, the function tionality must be implemented in the kernel. Even un- to transmit network packets, and callback functions reg- / dergraduate texts preach that I O algorithms must be istered with the kernel to poll the device. This driver implemented in the kernel for good performance [21, contains 274 functions containing approximately 15, 100 page 427]. Unfortunately, a popular interpretation of this lines of source code. Of these, just 25 functions contain- tenet is that device drivers must reside in the kernel. This ing approximately 1, 550 lines of source code were clas- has lead to the monolithic and unreliable operating sys- sified as critical. It suffices to execute just these func- tems that we see today. tions in the kernel for good performance. Relegating Surely, the entire driver does not reside on the the remaining functions, which handle startup/shutdown performance-critical path? To answer this question, we and get/set device parameters, to a user-mode process conducted a study of 455 device drivers, comprising net- will greatly reduce the amount of code running in kernel work, SCSI and sound drivers from the Linux 2.6.18 ker- space without adversely impacting common-case perfor- nel, and identified performance-critical functions in each mance. Note that our estimate of critical device driver of them. To do so, we extracted the static call-graph code is conservative, because we only identify critical → of each driver—this graph has an edge f g if func- functions. It is likely that a finer-grained approach will tion f can potentially call function g. We resolved calls show that even less code is on the critical path. via function pointers using a simple pointer analysis that Three factors lead us to believe that implementing is conservative in the absence of type-casts—each func- non-critical functionality as a user-mode process will tion pointer can resolve to any function whose address also improve system reliability