5.3.1 Pipes
Pipes allow the transfer of data in a FIFO manner. The pipe() system call creates unnamed pipes.
Unnamed pipes are only accessible to the creating process and its descendants through file descriptors. Once
a pipe is created, a process may use the read() and write() VFS system calls to access it.
In order to allow access from the VFS layer, the kernel creates an inode object and two file objects for each
pipe. One file object is used for reading (reader) and the other for writing (writer). It is the responsibility of
the process to use the appropriate file descriptor for reading and writing. Processes access unnamed pipes
through their VFS file descriptors. Hence, access control is performed at the VFS layer in the same manner
as for regular files, as described in Sections 5.1.5.
The internal implementation of pipes has changed with the 2.6 kernel. Before, a pipe used a single page to
buffer data between the file object reader and writer. For a process writing more than a single page, it became
blocked until the file object reader consumed the amount of data necessary to allow the rest to be fit in the
buffer. In the new implementation, known as circular pipes, a circular buffer is used.
In a simple scenario, a curbuf pointer indicates the first buffer that contains data in the array, and nrbufs
indicates the number of buffers that contain data. The page structures are allocated and used as necessary. In
order to serialize access, the pipe semaphore is used, since file object writers and readers are able to
manipulate nrbufs. Length and offset fields compose the pipe buffer structure in order for each entry in the
circular buffer to be able to contain less than a full page of data.
This circular implementation improves pipe bandwidth from 30% to 90%, with a small increase in latency
because pages are allocated when data passes through the pipe. The better results in performance are
attributable to the large buffering, since file object readers and writers block less often when passing data
through the pipe.
This new functionality implemented in circular pipes is intended to become a general mechanism for
transmitting data streams through the kernel.
5.3.1.1 Data structures and algorithms
The inode object refers to a pipe with its i_pipe field, which points to a pipe_inode_info structure.
The pipe() system call invokes do_pipe() to create a pipe. The read() and write() operations
performed on the appropriate pipe file descriptors invoke, through the file operations vector f_op of the file
object, the pipe_read() and pipe_write() routines, respectively.
62
Figure 5-15: Pipes Implementation