BIOCLONE(9F)            Kernel Functions for Drivers            BIOCLONE(9F)
NAME
       bioclone - clone another buffer
SYNOPSIS
       #include <sys/ddi.h>
       #include <sys/sunddi.h>       
struct buf *bioclone(
struct buf *bp, 
off_t off, 
size_t len, 
dev_t dev,            
daddr_t blkno, 
int (*iodone) (struct buf 
*), 
struct buf *bp_mem,            
int sleepflag);
INTERFACE LEVEL
       illumos DDI specific (illumos DDI).
PARAMETERS
       bp                    Pointer to the 
buf(9S) structure describing the original                    
I/O request.       
off                    Offset within original 
I/O request where new 
I/O request
                    should start.       
len                    Length of the 
I/O request.       
dev                    Device number.       
blkno                    Block number on device.       
iodone                    Specific 
biodone(9F) routine.       
bp_mem                    Pointer to a buffer structure to be filled in or 
NULL.       sleepflag                    Determines whether caller can sleep for memory. Possible
                    flags are 
KM_SLEEP to allow sleeping until memory is
                    available, or 
KM_NOSLEEP to return 
NULL immediately if
                    memory is not available.
DESCRIPTION
       The 
bioclone() function returns an initialized buffer to perform 
I/O       to a portion of another buffer. The new buffer will be set up to
       perform 
I/O to the range within the original 
I/O request specified by
       the parameters 
off and 
len. An offset 
0 starts the new 
I/O request at
       the same address as the original request. 
off + 
len must not exceed       
b_bcount, the length of the original request.  The device number 
dev       specifies the device to which the buffer is to perform 
I/O. 
blkno is
       the block number on device. It will be assigned to the 
b_blkno field
       of the cloned buffer structure.  
iodone lets the driver identify a
       specific 
biodone(9F) routine to be called by the driver when the 
I/O       is complete. 
bp_mem determines from where the space for the buffer
       should be allocated. If 
bp_mem is 
NULL, 
bioclone() will allocate a
       new buffer using 
getrbuf(9F). If 
sleepflag is set to 
KM_SLEEP, the
       driver may sleep until space is freed up. If 
sleepflag is set to       
KM_NOSLEEP, the driver will not sleep. In either case, a pointer to
       the allocated space is returned or 
NULL to indicate that no space was
       available. After the transfer is completed, the buffer has to be
       freed using 
freerbuf(9F). If 
bp_mem is not 
NULL, it will be used as
       the space for the buffer structure. The driver has to ensure that       
bp_mem is initialized properly either using 
getrbuf(9F) or       
bioinit(9F).
       If the original buffer is mapped into the kernel virtual address
       space using 
bp_mapin(9F) before calling 
bioclone(), a clone buffer
       will share the kernel mapping of the original buffer. An additional       
bp_mapin() to get a kernel mapping for the clone buffer is not
       necessary.
       The driver has to ensure that the original buffer is not freed while
       any of the clone buffers is still performing 
I/O. The 
biodone()       function has to be called on all clone buffers 
before it is called on
       the original buffer.
RETURN VALUES
       The 
bioclone() function returns a pointer to the initialized buffer
       header, or 
NULL if no space is available.
CONTEXT
       The 
bioclone() function can be called from user, interrupt, or kernel
       context. Drivers must not allow 
bioclone() to sleep if called from an
       interrupt routine.
EXAMPLES
       Example 1: Using bioclone() for Disk Striping
       A device driver can use 
bioclone() for disk striping. For each disk
       in the stripe, a clone buffer is created which performs 
I/O to a
       portion of the original buffer.
         static int
         stripe_strategy(struct buf *bp)
         {
                ...
                bp_orig = bp;
                bp_1 = bioclone(bp_orig, 0, size_1, dev_1, blkno_1,
                                stripe_done, NULL, KM_SLEEP);
                fragment++;
                ...
                bp_n = bioclone(bp_orig, offset_n, size_n, dev_n,
                              blkno_n, stripe_done, NULL, KM_SLEEP);
                fragment++;
                /* submit bp_1 ... bp_n to device */
                xxstrategy(bp_x);
                return (0);
         }
         static uint_t
         xxintr(caddr_t arg)
         {
                ...
                /*
                * get bp of completed subrequest. 
biodone(9F) will
                * call stripe_done()
                */
                biodone(bp);
                return (0);
         }
         static int
         stripe_done(struct buf *bp)
         {
                ...
                freerbuf(bp);
                fragment--;
                if (fragment == 0) {
                        /* get bp_orig */
                        biodone(bp_orig);
                }
                return (0);
         }
SEE ALSO
       biodone(9F), 
bp_mapin(9F), 
freerbuf(9F), 
getrbuf(9F), 
buf(9S)       Writing Device Drivers                               August 22, 2023                  BIOCLONE(9F)