*nix Documentation Project
·  Home
 +   man pages
·  Linux HOWTOs
·  FreeBSD Tips
·  *niX Forums

  man pages->OpenBSD man pages -> disk_unbusy (9)              
Title
Content
Arch
Section
 

DISK(9)

Contents


NAME    [Toc]    [Back]

     disk - generic disk framework

SYNOPSIS    [Toc]    [Back]

     #include <sys/types.h>
     #include <sys/disklabel.h>
     #include <sys/disk.h>

     void
     disk_init(void);

     void
     disk_attach(struct disk *);

     void
     disk_detach(struct disk *);

     void
     disk_busy(struct disk *);

     void
     disk_unbusy(struct disk *, long bcount, int read);

     void
     disk_resetstat(struct disk *);

     struct disk *
     disk_find(char *);

DESCRIPTION    [Toc]    [Back]

     The OpenBSD generic disk framework is  designed  to  provide
flexible, scalable,
  and consistent handling of disk state and metrics information.  The
     fundamental component of this framework is the  disk  structure, which is
     defined as follows:

     struct disk {
             TAILQ_ENTRY(disk)  dk_link;       /*  link in global
disklist */
             char     *dk_name;      /* disk name */
             int      dk_bopenmask;  /* block devices open */
             int      dk_copenmask;  /* character devices open */
             int       dk_openmask;    /* composite (bopen|copen)
*/
             int      dk_state;      /* label state */
             int       dk_blkshift;     /*   shift   to   convert
DEV_BSIZE to blks */
             int      dk_byteshift;  /* shift to convert bytes to
blks */

             /*
              * Metrics data; note that some metrics may have  no
meaning
              * on certain types of disks.
              */
             int       dk_busy;      /* busy counter */
             u_int64_t dk_xfer;      /* total number of transfers
*/
             u_int64_t dk_seek;      /*  total  independent  seek
operations */
             u_int64_t  dk_bytes;      /* total bytes transferred
*/
             struct timeval  dk_attachtime;  /* time disk was attached */
             struct timeval  dk_timestamp;   /* timestamp of last
unbusy */
             struct timeval  dk_time;        /* total time  spent
busy */

             struct  dkdriver *dk_driver;    /* pointer to driver
*/

             /*
              * Disk label information.  Storage for the  in-core
disk label
              * must be dynamically allocated, otherwise the size
of this
              * structure becomes machine-dependent.
              */
             daddr_t  dk_labelsector;        /* sector containing
label */
             struct disklabel *dk_label;     /* label */
             struct cpu_disklabel *dk_cpulabel;
     };

     The  system  maintains a global linked-list of all disks attached to the
     system.  This list, called disklist, may grow or shrink over
time as
     disks  are  dynamically  added  and removed from the system.
Drivers which
     currently make use  of  the  detachment  capability  of  the
framework are the
     ccd(4) and vnd(4) pseudo-device drivers.

     The following is a brief description of each function in the
framework:

     disk_init()       Initialize the  disklist  and  other  data
structures used
                       by the framework.  Called by main() before
autoconfiguration.


     disk_attach()     Attach a disk; allocate  storage  for  the
disklabel, set
                       the  ``attached  time''  timestamp, insert
the disk into
                       the disklist,  and  increment  the  system
disk count.

     disk_detach()      Detach  a  disk;  free  storage  for  the
disklabel, remove
                       the disk from the disklist, and  decrement
the system
                       disk  count.  If the count drops below zero, panic.

     disk_busy()       Increment the disk's ``busy counter''.  If
this counter
                       goes from 0 to 1, set the timestamp corresponding to
                       this transfer.

     disk_unbusy()     Decrement a disk's busy counter.   If  the
count drops
                       below  zero, print a warning message.  Get
the current
                       time, subtract it from the  disk's  timestamp, and add
                       the  difference  to the disk's running total.  Set the
                       disk's timestamp to the current time.   If
the provided
                       byte  count  is  greater than 0, add it to
the disk's running
 total and  increment  the  number  of
transfers performed
  by  the  disk.  The third argument
read specifies
                       the direction of I/O; if non-zero it means
reading from
                       the  disk,  otherwise  it means writing to
the disk.

     disk_resetstat()  Reset the running byte, transfer, and time
totals.

     disk_find()        Return  a  pointer  to the disk structure
corresponding to
                       the name provided, or  NULL  if  the  disk
does not exist.

     The   functions  typically  called  by  device  drivers  are
disk_attach(),
     disk_detach(),     disk_busy(),      disk_unbusy(),      and
disk_resetstat().  The
     function disk_find() is provided as a utility function.

USING THE FRAMEWORK    [Toc]    [Back]

     This  section  includes  a  description  on basic use of the
framework and example
 usage of its functions.  Actual  implementation  of  a
device driver
     which utilizes the framework may vary.

     A special routine, disk_init(), is provided to perform basic
initialization
 of data structures used by the framework.  It is called
exactly once
     by the system, in main(), before device autoconfiguration.

     Each  device  in the system uses a ``softc'' structure which
contains autoconfiguration
 and state information for that device.  In the
case of
     disks,  the  softc  should  also contain one instance of the
disk structure,
     e.g.:

     struct foo_softc {
             struct  device *sc_dev;          /*  generic  device
information */
             struct   disk *sc_dk;            /* generic disk information */
             [ . . . more . . . ]
     };

     In order for the system to gather metrics data about a disk,
the disk
     must  be registered with the system.  The disk_attach() routine performs
     all of the functions currently required to register  a  disk
with the system
 including allocation of disklabel storage space, recording of the
     time since boot that the disk was  attached,  and  insertion
into the
     disklist.   Note  that since this function allocates storage
space for the
     disklabel, it must be called before the  disklabel  is  read
from the media
     or used in any other way.  Before disk_attach() is called, a
portion of
     the disk structure must be initialized with data specific to
that disk.
     For example, in the ``foo'' disk driver, the following would
be performed
     in the autoconfiguration ``attach'' routine:

     void
     fooattach(parent, self, aux)
             struct device *parent, *self;
             void *aux;
     {
             struct foo_softc *sc = (struct foo_softc *)self;
             [ . . . ]

             /* Initialize and attach the disk structure. */
             sc->sc_dk.dk_driver = &foodkdriver;
             sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
             disk_attach(&sc->sc_dk);

             /* Read geometry and  fill  in  pertinent  parts  of
disklabel. */
             [ . . . ]
     }

     The foodkdriver above is the disk's ``driver'' switch.  This
switch currently
 includes a pointer to the  disk's  ``strategy''  routine.  This
     switch  needs to have global scope and should be initialized
as follows:

     void    foostrategy(struct buf *);
     struct  dkdriver foodkdriver = { foostrategy };

     Once the disk is attached, metrics may be gathered  on  that
disk.  In order
  to gather metrics data, the driver must tell the framework when the
     disk starts and stops  operations.   This  functionality  is
provided by the
     disk_busy()  and  disk_unbusy()  routines.   The disk_busy()
routine should
     be called immediately before a command to the disk is  sent,
e.g.:

     void
     foostart(sc)
             struct foo_softc *sc;
     {
             [ . . . ]

             /* Get buffer from drive's transfer queue. */
             [ . . . ]

             /* Build command to send to drive. */
             [ . . . ]

             /* Tell the disk framework we're going busy. */
             disk_busy(&sc->sc_dk);

             /* Send command to the drive. */
             [ . . . ]
     }

     When  disk_busy()  is  called,  a  timestamp is taken if the
disk's busy
     counter moves from 0 to 1, indicating the disk has gone from
an idle to
     non-idle  state.   Note  that  disk_busy() must be called at
splbio().  At
     the end of a transaction, the disk_unbusy()  routine  should
be called.
     This  routine  performs some consistency checks, such as ensuring that the
     calls to disk_busy() and disk_unbusy() are  balanced.   This
routine also
     performs  the  actual  metrics  calculation.  A timestamp is
taken, and the
     difference from the timestamp taken in disk_busy() is  added
to the disk's
     total running time.  The disk's timestamp is then updated in
case there
     is more than one pending transfer on the disk.  A byte count
is also
     added to the disk's running total, and if greater than zero,
the number
     of transfers the disk has performed is incremented.

     void
     foodone(xfer)
             struct foo_xfer *xfer;
     {
             struct     foo_softc     =     (struct     foo_softc
*)xfer->xf_softc;
             struct buf *bp = xfer->xf_buf;
             long nbytes;
             [ . . . ]

             /*
              *  Get number of bytes transferred.  If there is no
buf
              * associated with the xfer, we are being called  at
the
              * end of a non-I/O command.
              */
             if (bp == NULL)
                     nbytes = 0;
             else
                     nbytes = bp->b_bcount - bp->b_resid;

             [ . . . ]

             /*  Notify  the  disk framework that we've completed
the transfer. */
             disk_unbusy(&sc->sc_dk, nbytes);

             [ . . . ]
     }

     Like disk_busy(), disk_unbusy() must be called at  splbio().

     At  some  point  a driver may wish to reset the metrics data
gathered on a
     particular disk.  For this  function,  the  disk_resetstat()
routine is provided.

CODE REFERENCES    [Toc]    [Back]

     The disk framework itself is implemented within the file
     sys/kern/subr_disk.c.   Data  structures and function prototypes for the
     framework are located in sys/sys/disk.h.

     The OpenBSD machine-independent SCSI disk and CD-ROM drivers
utilize the
     disk  framework.   They  are  located  in  sys/scsi/sd.c and
sys/scsi/cd.c.

     The OpenBSD ccd(4), raid(4) and vnd(4) drivers  utilize  the
detachment capability
   of   the   framework.    They   are   located  in
sys/dev/ccd.c,
     sys/dev/raidframe/, and sys/dev/vnd.c.

SEE ALSO    [Toc]    [Back]

      
      
     ccd(4), raid(4), vnd(4), spl(9)

HISTORY    [Toc]    [Back]

     The OpenBSD generic disk framework first appeared in  NetBSD
1.2.

AUTHORS    [Toc]    [Back]

     The  OpenBSD  generic disk framework was architected and implemented within
     NetBSD by Jason R. Thorpe <thorpej@NetBSD.ORG>.

OpenBSD     3.6                         January      7,      1996
[ Back ]
 Similar pages
Name OS Title
evcnt NetBSD generic event counter framework
evcnt_detach NetBSD generic event counter framework
evcnt_attach_dynamic NetBSD generic event counter framework
mbuf_tags OpenBSD a framework for generic packet attributes
evcnt_attach_static NetBSD generic event counter framework
geom FreeBSD modular disk I/O request transformation framework.
GEOM FreeBSD modular disk I/O request transformation framework.
getdiskbyname NetBSD get generic disk description by its name
getdiskbyname OpenBSD get generic disk description by its name
setdisktab NetBSD get generic disk description by its name
Copyright © 2004-2005 DeniX Solutions SRL
newsletter delivery service