DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 

buf(D4)


buf -- non-STREAMS I/O data transfer structure

Syntax

   #include <sys/types.h>
   #include <sys/proc.h>
   #include <sys/buf.h>
   #include <sys/scgth.h>
   #include <sys/ddi.h>

Description

The buf structure, also called a buffer header, is the basic data structure for I/O transfers.

Usage

Each I/O transfer has an associated buffer header structure. This structure contains control and status information for the transfer. Buffer headers are passed to drivers' biostart(D2) routines. They may also be allocated by the driver itself using getrbuf(D3), ngeteblk(D3), or geteblk(D3).

A data buffer that holds the data for the I/O operation is associated with each buffer header. The data buffer may be in kernel data space, or it may be simply a list of physical memory pages. It may also be a set of unlocked user address ranges that are represented by a uio(D4) structure.

Do not depend on the size of the buf structure when writing a driver (or any other module that needs binary compatibility). In particular, this means you must only allocate buf structures using DDI functions such as getrbuf(D3). Static allocations are not allowed.

It is important to note that a buffer header may be linked onto multiple lists simultaneously, and is also passed back to the system when the driver is done with it. Because of this, most of the members in the buffer header cannot be changed by the driver, even when the buffer header is in one of the driver's work lists.

To understand the rules for using various members of the buf structure, it is necessary to first understand the various agents that handle a buffer, and how control of the buffer is passed among these agents.


creator agent
acquires the buffer (through functions such as geteblk(D3), getrbuf(D3), and ngeteblk(D3)) and initializes it. Some of the initialization is done inside the allocating interface; some is done by the caller. The creator is often part of a filesystem module or a kernel filter routine, but it may also be a driver routine that calls getrbuf( ), geteblk( ), or ngeteblk( ).

I/O handler
the part of a device driver, starting from its biostart( ) entry point, that receives a buffer as an I/O request, handles the transfer of data and/or errors, and indicates I/O completion by calling the biodone(D3) function.

kernel filter routine
receives a buffer that either has already been passed to an I/O handler or is about to be, performs some transformations on either the buffer itself or newly created buffer(s) based on the original buffer, then passes the transformed buffer(s) on to (or back to) the I/O handler or the next filter.

controlling agent
Control of a buffer is handed off from one agent to another over the life of the buffer. At any given time, exactly one agent has control of the buffer. Only the controlling agent may do anything with the buffer besides waiting for I/O completion with biowait(D3) or biowait_sig(D3).

The creator controls the buffer initially. When the driver's biostart( ) routine is called, control transfers to the I/O handler. Control remains with the I/O handler until it calls the biodone( ) function. For synchronous I/O operations, the creator calls the biowait( ) or biowait_sig( ) function; when the biowait( ) function returns, control returns to the creator. If a filter routine is called, control transfers to the filter routine until it calls the next-level biostart( ) routine. During I/O completion processing, if an iodone( ) function is called (b_iodone was non-NULL), control transfers to that routine, which is considered to be part of the agent that set the b_iodone member in the first place.

Many buffer members are only allowed to be modified by certain agents. These and other restrictions are listed below, in the descriptions of the individual structure members. References to the driver refer to the whole driver, no matter which agent. Where a member is described as being preserved by an agent, this means that either the agent does not change the members, or that before giving up control of the buffer, the agent restores the members's value to the value it had when the agent first acquired control.

Structure definitions

The buf structure, buf_t, contains the following members that may be accessed by drivers. Note that some structure members may not be present in all DDI versions.
   uint_t      b_flags;
   buf_t       *b_forw;
   buf_t       *b_back;
   buf_t       *av_forw;
   buf_t       *av_back;
   long        b_bufsize;
   uint_t      b_bcount;
   daddr_t     b_blkno;
   ushort_t    b_blkoff;
   uchar_t     b_addrtype;
   

union { caddr_t b_addr; uio_t *b_uio; } b_un;

uint_t b_resid; clock_t b_start; void (*b_iodone)(); void *b_misc;

union { void *un_ptr; int un_int; } b_priv;

union { void *un_ptr; int un_int; long un_long; daddr_t un_daddr; } b_priv2;

Buffer members

Drivers are only allowed to access certain buffer members. Accesses by a driver to any other members are illegal and may not continue to work in subsequent releases of the UNIX System.

The following members may be accessed by the driver:


b_flags
This is a bitmask of flag bits which reflect buffer status and control flags. This members may not be directly assigned by any agent; it is only legal to set or clear specific bits.

The driver may only access some of these flag bits. The following flags may be accessed by the driver:


B_READ
Indicates that data are to be transferred from the peripheral device into main memory. This flag may only be changed by the creator agent.

B_WRITE
Indicates that data are to be transferred from main memory to the peripheral device. B_WRITE is a pseudo-flag that occupies the same bit location as B_READ. B_WRITE cannot be directly tested; it is only detected as the absence of B_READ ((bp->b_flags&B_READ), for example); it can only be ``set'' by clearing B_READ.

B_ASYNC
Indiates an asynchronous data transfer. The b_iodone member must also be set. This flag may only be changed by the creator agent.

b_forw/b_back
These members can be used to link the buffer onto a doubly-linked list. They may only be used by the creator agent (or, if the creator is in a driver, by the whole driver), and only if the buffer was created by getrbuf.

av_forw/av_back
These members can be used to link the buffer onto a doubly-linked list. The driver may change these any time it controls the buffer. These members must be preserved by any filters.

b_bufsize
This member contains the size in bytes of the allocated buffer. The b_bufsize member may not be changed except by kernel functions that create buffers, or by the creator agent if the buffer was created with the getrbuf(D3) function.

b_bcount
This member specifies the number of bytes to be transferred. It will be set to the total byte count (which should always be a multiple of NBPSCTR) upon initial entry to the I/O handler or a filter. This member may be changed by the creator or the I/O handler.

b_blkno
This member specifies the first logical block on the device that is to be accessed. One block equals NBPSCTR bytes. The driver may have to convert this logical block number to a physical location such as a cylinder, track, and sector of a disk. Any agent may change this member, but it must restore the previous value before calling the biodone(D3) function.

b_blkoff
This member specifies the byte offset within the block given by b_blkno of the beginning of the transfer. This will always be less than NBPSCTR. Only the creator may change this member. Unless the driver indicates that it understands b_blkoff by setting D_BLKOFF in its Any agent may change this member, but it must restore the previous value before calling the biodone(D3) function. drvinfo(D4) structure (or, for DDI version 7 and earlier, its devflag(D1)), this member is always zero and may be ignored.

b_addrtype
This member specifies the type of address used to reference the buffer data. Valid values are:


BA_KVIRT
contiguous kernel virtual

BA_UVIRT
contiguous user virtual

BA_PAGELIST
a list of physical pages

BA_UIO
use uio(D4) structure

BA_SCGTH
physical scatter/gather list

This member may not be changed except by kernel functions. It is always set in the current DDI version.


b_un.b_addr
This member indicates the start of the data buffer for all address types except BA_SCGTH. It is either a virtual address or an offset into the first page of a page list (see B_PAGEIO, B_PHYS, and b_addrtype for more details). The creator or the I/O handler may change this member.

b_resid
This member indicates the number of bytes not transferred, usually because of an error. A value of zero indicates a successful complete transfer. The I/O handler must set this member before it calls the biodone(D3) function.

b_start
This member is used to hold the time the I/O request was started. This time is obtained by calling the drv_getparm(D3) function with the LBOLT parameter. The I/O handler may set it and use it upon I/O completion to compute response time metrics.

b_iodone
This member identifies a specific routine to be called when the I/O operation has completed. If it is non-NULL, the biodone(D3) function calls the *b_iodone member instead of doing the normal completion processing. Any agent may change this member, but it must restore the previous value before calling the biodone( ) function, and thus relinquish control of the buffer. For the creator, the previous value is always NULL. This protocol allows for ``stacking'' of iodone routines (particularly useful for filters). Each agent saves the old value, sets b_iodone to its iodone routine, and hands off the buffer to the next filter or the I/O handler. On completion, the I/O handler calls biodone, and each iodone function performs its final processing, restores b_iodone to the saved value, and calls the biodone( ) function again, thus invoking the next iodone routine.

b_misc
This is a miscellaneous member for use by the controlling agent. One common use is in conjunction with b_iodone, to help in saving the previous b_iodone value. Typically, the previous values of b_iodone and b_misc are saved in a structure, b_misc set to point to this structure, and b_iodone set to point to the new iodone routine. This member may only be used by the controlling agent. If the controlling agent is the creator, it may modify b_misc directly; otherwise it must preserve the original value before returning the buffer to another agent.

b_priv/b_priv2
These members are private members for use by the driver. No other agents interpret or change them.

Warnings

Buffers are a shared resource within the kernel. Drivers should only read or write the members listed in this section in accordance with the rules given above. Drivers that attempt to use undocumented members of the buf structure risk corrupting data in the kernel and on the device.

DDI-conforming drivers may only use buffer headers that have been allocated using the geteblk(D3), ngeteblk(D3), or getrbuf(D3) functions, or have been passed to the driver biostart(D2) entry-point routine.

Applicable hardware

All

Version applicability

ddi: 1, 2, 3, 4, 5, 5mp, 6, 6mp, 7, 7mp, 7.1, 7.1mp, 8, 8mp
Some members of the buf structure are not supported in all DDI versions:

b_edev
ddi: 1, 2, 3, 4, 5, 5mp, 6, 6mp, 7, 7mp, 7.1, 7.1mp

*b_proc
ddi: 1, 2, 3, 4, 5, 5mp, 6, 6mp, 7, 7mp, 7.1, 7.1mp

b_addrtype
ddi: 5, 5mp, 6, 6mp, 7, 7mp, 7.1, 7.1mp, 8, 8mp

*b_misc
ddi: 5, 5mp, 6, 6mp, 7, 7mp, 7.1, 7.1mp, 8, 8mp

b_priv
ddi: 5, 5mp, 6, 6mp, 7, 7mp, 7.1, 7.1mp, 8, 8mp

b_priv2
ddi: 5, 5mp, 6, 6mp, 7, 7mp, 7.1, 7.1mp, 8, 8mp

b_private
ddi: 3

b_error
ddi: 1, 2, 4

The following values for the b_flags member are not supported in all DDI versions:


B_PAGEIO
ddi: 1, 2, 3, 4, 5, 5mp, 6, 6mp, 7, 7mp, 7.1, 7.1mp

B_PHYS
ddi: 1, 2, 3, 4, 5, 5mp, 6, 6mp, 7, 7mp, 7.1, 7.1mp

B_ASYNC
ddi: 8, 8mp

B_ERROR
ddi: 1, 2, 4

Difference between versions

In DDI versions before version 8, the buf structure is used only for block I/O drivers and is passed to the strategy(D2) entry point routine or, for physical I/O, to the physiock(D3) routine. The following header file is also required:
   #include <sys/proc.h>
In DDI versions prior to version 8, the following b_flags flags are also supported:

B_PAGEIO
If set, the data buffer is represented as a page list. This means that b_un.b_addr is not a virtual address but is instead the offset into the first page of a list of one or more physical pages. This list of pages is accessible through the getnextpg(D3) function. The pages will be in contiguous device block order, starting from the first block, given by b_blkno. If B_PAGEIO is not set, b_un.b_addr is a virtual address; it is a global kernel virtual address if B_PHYS is not set, or a user virtual address if B_PHYS is set. This flag may not be changed except by kernel utility routines which create, map, or unmap the buffer. If a driver does not have D_NOBRKUP set in its devflag(D1) information it will never see a buffer with B_PAGEIO set.

B_PHYS
Indicates that the data buffer is in user virtual space. b_un.b_addr contains the starting user virtual address of the data buffer. The data buffer and its virtual addresses are locked in memory so that accesses are guaranteed to succeed. The user virtual address may not be directly accessed; it must be mapped into a kernel virtual address using bp_mapin(D3), converted to physical addresses using vtop(D3) and b_proc, or copied to/from kernel space using copyin(D3) and copyout(D3) (the copyin/copyout functions may only be used initiator context.) B_PHYS and B_PAGEIO are never set simultaneously. This flag may not be changed except by kernel utility routines which create, map, or unmap the buffer. If a driver does not call physiock(D3) or does not have D_NOBRKUP set in its devflag(D1), it will never see a buffer with B_PHYS set.

In DDI versions prior to version 5, the following b_flags flag is also supported:


B_ERROR
The driver sets B_ERROR to indicate an error occurred during an I/O transfer. On systems where the bioerror(D3) function is available, drivers should not access this flag directly.

In DDI versions prior to version 8, the following b_addrtype value is not supported:


BA_PHYS
contiguous physical

The following buf structure members are supported only in DDI versions prior to version 8:

   dev_t       b_edev;
   proc_t      *b_proc;
   void        *b_private;
   int         b_error;

b_edev
This member contains the external device number of the device. Only the creator may change this member.

b_proc
When B_PHYS is set, the b_proc member identifies the process that contains the data buffer pointed to by the user virtual address in b_un.b_addr. When B_PHYS is not set, b_proc is NULL. This member can thus be used as the second argument to vtop(D3) to convert user virtual addresses from b_un.b_addr into physical addresses. When B_PAGEIO is set, b_proc is undefined and should be ignored. This member may not be changed except by kernel functions that create buffers.

b_private
This member is a private member for use by the driver. No other agents interpret or change it. In DDI versions that do not support this member, it is reserved for use by the kernel, or may not exist at all, so drivers should not used it.

b_error
If B_ERROR is set, this member holds the errnos(D5) that indicates the type of error that occurred. The functionality of this member is provided through the bioerror(D3) function in later DDI versions.

Note also the following differences about accessing specific members:


b_blkno
In older DDI versions, only the creator may change this member.

b_addrtype
In DDI versions before version 8, this member is valid only for strategy( ) routines that are called by the buf_breakup(D3) functions. It is always set in DDI 8.

References

biodone(D3), bioerror(D3), bioreset(D3), biowait(D3), biowait_sig(D3), brelse(D3), clrbuf(D3), freerbuf(D3), geteblk(D3), geterror(D3), getrbuf(D3), iovec(D4), ngeteblk(D3), physiock(D3), strategy(D2), uio(D4)

sdi_buf_store(D3sdi), sdi_buf_restore(D3sdi)

``Large device support'' in HDK Technical Reference


19 June 2005
© 2005 The SCO Group, Inc. All rights reserved.
OpenServer 6 and UnixWare (SVR5) HDK - June 2005