Specifications

This is the Title of the Book, eMatter Edition
Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
Performing Direct I/O
|
435
Performing Direct I/O
Most I/O operations are buffered through the kernel. The use of a kernel-space
buffer allows a degree of separation between user space and the actual device; this
separation can make programming easier and can also yield performance benefits in
many situations. There are cases, however, where it can be beneficial to perform I/O
directly to or from a user-space buffer. If the amount of data being transferred is
large, transferring data directly without an extra copy through kernel space can
speed things up.
One example of direct I/O use in the 2.6 kernel is the SCSI tape driver. Streaming
tapes can pass a lot of data through the system, and tape transfers are usually record-
oriented, so there is little benefit to buffering data in the kernel. So, when the condi-
tions are right (the user-space buffer is page-aligned, for example), the SCSI tape
driver performs its I/O without copying the data.
That said, it is important to recognize that direct I/O does not always provide the
performance boost that one might expect. The overhead of setting up direct I/O
(which involves faulting in and pinning down the relevant user pages) can be signifi-
cant, and the benefits of buffered I/O are lost. For example, the use of direct I/O
requires that the write system call operate synchronously; otherwise the application
does not know when it can reuse its I/O buffer. Stopping the application until each
write completes can slow things down, which is why applications that use direct I/O
often use asynchronous I/O operations as well.
The real moral of the story, in any case, is that implementing direct I/O in a char
driver is usually unnecessary and can be hurtful. You should take that step only if
you are sure that the overhead of buffered I/O is truly slowing things down. Note
also that block and network drivers need not worry about implementing direct I/O at
all; in both cases, higher-level code in the kernel sets up and makes use of direct I/O
when it is indicated, and driver-level code need not even know that direct I/O is
being performed.
The key to implementing direct I/O in the 2.6 kernel is a function called get_user_pages,
which is declared in <linux/mm.h> with the following prototype:
int get_user_pages(struct task_struct *tsk,
struct mm_struct *mm,
unsigned long start,
int len,
int write,
int force,
struct page **pages,
struct vm_area_struct **vmas);
,ch15.13676 Page 435 Friday, January 21, 2005 11:04 AM