summaryrefslogblamecommitdiffstats
path: root/cpukit/libblock/include/rtems/bdbuf.h
blob: 56dc9b44cb3ee99f8d524fd5d2d8e3f36ec74fe4 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                      
  
                                 


   


                                                        



                                                                    
                                                  

   

                      
 

                        
                        
 

                           
 




                  

                                  
   

            







                                                                                  
                        
 




                                                                               
   


                                                                           
 

                             



                                                                         
        
 

                                                                 
 

                                                                            
                                                                     
 
                                                                    
 
                                                                         
                                             
                                                                                  
                                              
 
                                                                       

                                                                          
 





                                                                            

                                                                                 
 
                                                                   
 
                                                                              
                                                       
                                                                       
                                                                         

                                                                   
 
                                                                             
                                                  



                                                                                
 
                                                                                 
                                                           

                                                                                 
                                                             

                                                                                  
                                                                 
                                                                         
 
                                                                                  
                                                                             
                                                                   
                   
 


                                                                              
   
                                        


                                                                               






                                                                               
   





                                                                               

                                   

                                                                                      


                                                                                     

                     




                                                                             
 








                                                                             
 





                                                                               
  

                                                                     

                 
                        
 












                                                                               
  

                                                                             
  


                                                                             
  

                                                                           
   
















                                                                                 
  


                                                                             
  

                                                                           
   









                                                                                  
  
                                                
  

                                                                     
   











                                                                             
  
                                                
  

                                                                     
   







                                                                               
  



                                                                         
  

                                                                     
   

                                          
 




                                                                            
  


                                                                              
  



                                                                     
   

                                
 



                                                                           
  

                                                           
  





                                                                              
   
                 
                                                                   
 

                                                               
  



                                                                            

           


                                                                            
  
                                                              
   

                                                                               





                  
/**
 * @file rtems/bdbuf.h
 *
 * Block Device Buffer Management
 */
 
/*
 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
 * Author: Victor V. Vengerov <vvv@oktet.ru>
 *
 * Copyright (C) 2008 Chris Johns <chrisj@rtems.org>
 *    Rewritten to remove score mutex access. Fixes many performance
 *    issues.
 *
 * @(#) bdbuf.h,v 1.9 2005/02/02 00:06:18 joel Exp
 */

#ifndef _RTEMS_BDBUF_H
#define _RTEMS_BDBUF_H

#include <rtems.h>
#include <rtems/libio.h>
#include <rtems/chain.h>

#include <rtems/blkdev.h>
#include <rtems/diskdevs.h>

#ifdef __cplusplus
extern "C" {
#endif


/**
 * State of a buffer in the cache.
 */
typedef enum
{
  RTEMS_BDBUF_STATE_EMPTY = 0,            /*< Not in use. */
  RTEMS_BDBUF_STATE_READ_AHEAD = 1,       /*< Holds read ahead data only */
  RTEMS_BDBUF_STATE_CACHED = 2,           /*< In the cache and available */
  RTEMS_BDBUF_STATE_ACCESS = 3,           /*< The user has the buffer */
  RTEMS_BDBUF_STATE_MODIFIED = 4,         /*< In the cache but modified */
  RTEMS_BDBUF_STATE_ACCESS_MODIFIED = 5,  /*< With the user but modified */
  RTEMS_BDBUF_STATE_SYNC = 6,             /*< Requested to be sync'ed */
  RTEMS_BDBUF_STATE_TRANSFER = 7          /*< Being transferred to or from disk */
} rtems_bdbuf_buf_state;

/**
 * To manage buffers we using buffer descriptors (BD). A BD holds a buffer plus
 * a range of other information related to managing the buffer in the cache. To
 * speed-up buffer lookup descriptors are organized in AVL-Tree.  The fields
 * 'dev' and 'block' are search keys.
 */
typedef struct rtems_bdbuf_buffer
{
  rtems_chain_node link;       /* Link in the BD onto a number of lists. */

  struct rtems_bdbuf_avl_node
  {
    signed char                cache;  /*< Cache */
    struct rtems_bdbuf_buffer* left;   /*< Left Child */
    struct rtems_bdbuf_buffer* right;  /*< Right Child */
    signed char                bal;    /*< The balance of the sub-tree */
  } avl;

  dev_t             dev;        /*< device number */
  rtems_blkdev_bnum block;      /*< block number on the device */

  unsigned char*    buffer;     /*< Pointer to the buffer memory area */
  int               error;      /*< If not 0 indicate an error value (errno)
                                 * which can be used by user later */

  volatile rtems_bdbuf_buf_state state;  /*< State of the buffer. */

  volatile uint32_t waiters;    /*< The number of threads waiting on this
                                 * buffer. */
  rtems_bdpool_id pool;         /*< Identifier of buffer pool to which this buffer
                                    belongs */

  volatile uint32_t hold_timer; /*< Timer to indicate how long a buffer
                                 * has been held in the cache modified. */
} rtems_bdbuf_buffer;

/**
 * The groups of the blocks with the same size are collected in a pool. Note
 * that a several of the buffer's groups with the same size can exists.
 */
typedef struct rtems_bdbuf_pool
{
  uint32_t            blksize;           /*< The size of the blocks (in bytes) */
  uint32_t            nblks;             /*< Number of blocks in this pool */

  uint32_t            flags;             /*< Configuration flags */

  rtems_id            lock;              /*< The pool lock. Lock this data and
                                          * all BDs. */
  rtems_id            sync_lock;         /*< Sync calls lock writes. */
  bool                sync_active;       /*< True if a sync is active. */
  rtems_id            sync_requester;    /*< The sync requester. */
  dev_t               sync_device;       /*< The device to sync */

  rtems_bdbuf_buffer* tree;             /*< Buffer descriptor lookup AVL tree
                                         * root */
  rtems_chain_control ready;            /*< Free buffers list (or read-ahead) */
  rtems_chain_control lru;              /*< Last recently used list */
  rtems_chain_control modified;         /*< Modified buffers list */
  rtems_chain_control sync;             /*< Buffers to sync list */

  rtems_id            access;           /*< Obtain if waiting for a buffer in the
                                         * ACCESS state. */
  volatile uint32_t   access_waiters;   /*< Count of access blockers. */
  rtems_id            transfer;         /*< Obtain if waiting for a buffer in the
                                         * TRANSFER state. */
  volatile uint32_t   transfer_waiters; /*< Count of transfer blockers. */
  rtems_id            waiting;          /*< Obtain if waiting for a buffer and the
                                         * none are available. */
  volatile uint32_t   wait_waiters;     /*< Count of waiting blockers. */

  rtems_bdbuf_buffer* bds;              /*< Pointer to table of buffer descriptors
                                         * allocated for this buffer pool. */
  void*               buffers;          /*< The buffer's memory. */
} rtems_bdbuf_pool;

/**
 * Configuration structure describes block configuration (size, amount, memory
 * location) for buffering layer pool.
 */
typedef struct rtems_bdbuf_pool_config {
  int            size;      /*< Size of block */
  int            num;       /*< Number of blocks of appropriate size */
  unsigned char* mem_area;  /*< Pointer to the blocks location or NULL, in this
                             * case memory for blocks will be allocated by
                             * Buffering Layer with the help of RTEMS partition
                             * manager */
} rtems_bdbuf_pool_config;

/**
 * External references provided by the user for each pool in the system.
 */
extern rtems_bdbuf_pool_config rtems_bdbuf_pool_configuration[];
extern int                     rtems_bdbuf_pool_configuration_size;

/**
 * Buffering configuration definition. See confdefs.h for support on using this
 * structure.
 */
typedef struct rtems_bdbuf_config {
  uint32_t            max_read_ahead_blocks; /*< Number of blocks to read ahead. */
  uint32_t            max_write_blocks;      /*< Number of blocks to write at once. */
  rtems_task_priority swapout_priority;      /*< Priority of the swap out task. */
  uint32_t            swapout_period;        /*< Period swapout checks buf timers. */
  uint32_t            swap_block_hold;       /*< Period a buffer is held. */
} rtems_bdbuf_config;

/**
 * External referernce to the configuration. The configuration is provided by
 * the user.
 */
extern rtems_bdbuf_config rtems_bdbuf_configuration;

/**
 * The max_read_ahead_blocks value is altered if there are fewer buffers
 * than this defined max. This stops thrashing in the cache.
 */
#define RTEMS_BDBUF_MAX_READ_AHEAD_BLOCKS_DEFAULT    32
#define RTEMS_BDBUF_MAX_WRITE_BLOCKS_DEFAULT         16
#define RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT    15
#define RTEMS_BDBUF_SWAPOUT_TASK_SWAP_PERIOD_DEFAULT 250  /* milli-seconds */
#define RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT  1000 /* milli-seconds */

/**
 * Prepare buffering layer to work - initialize buffer descritors and (if it is
 * neccessary) buffers. Buffers will be allocated accoriding to the
 * configuration table, each entry describes the size of block and the size of
 * the pool. After initialization all blocks is placed into the ready state.
 * lists.
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_init (void);

/**
 * Get block buffer for data to be written into. The buffers is set to the
 * access or modifed access state. If the buffer is in the cache and modified
 * the state is access modified else the state is access. This buffer contents
 * are not initialised if the buffer is not already in the cache. If the block
 * is already resident in memory it is returned how-ever if not in memory the
 * buffer is not read from disk. This call is used when writing the whole block
 * on a disk rather than just changing a part of it. If there is no buffers
 * available this call will block. A buffer obtained with this call will not be
 * involved in a transfer request and will not be returned to another user
 * until released. If the buffer is already with a user when this call is made
 * the call is blocked until the buffer is returned. The highest priority
 * waiter will obtain the buffer first.
 *
 * The block number is the linear block number. This is relative to the start
 * of the partition on the media.
 *
 * @param device Device number (constructed of major and minor device number)
 * @param block  Linear media block number
 * @param bd     Reference to the buffer descriptor pointer.
 *
 * @return       RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *               successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_get (dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd);

/**
 * Get the block buffer and if not already in the cache read from the disk. If
 * specified block already cached return. The buffer is set to the access or
 * modifed access state. If the buffer is in the cache and modified the state
 * is access modified else the state is access. If block is already being read
 * from disk for being written to disk this call blocks. If the buffer is
 * waiting to be written it is removed from modified queue and returned to the
 * user. If the buffer is not in the cache a new buffer is obtained and the
 * data read from disk. The call may block until these operations complete. A
 * buffer obtained with this call will not be involved in a transfer request
 * and will not be returned to another user until released. If the buffer is
 * already with a user when this call is made the call is blocked until the
 * buffer is returned. The highest priority waiter will obtain the buffer
 * first. 
 *
 * @param device Device number (constructed of major and minor device number)
 * @param block  Linear media block number
 * @param bd     Reference to the buffer descriptor pointer.
 *
 * @return       RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *               successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_read (dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd);

/**
 * Release the buffer obtained by a read call back to the cache. If the buffer
 * was obtained by a get call and was not already in the cache the release
 * modified call should be used. A buffer released with this call obtained by a
 * get call may not be in sync with the contents on disk. If the buffer was in
 * the cache and modified before this call it will be returned to the modified
 * queue. The buffers is returned to the end of the LRU list.
 *
 * @param bd Reference to the buffer descriptor.
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_release (rtems_bdbuf_buffer* bd);

/**
 * Release the buffer allocated with a get or read call placing it on the
 * modidied list.  If the buffer was not released modified before the hold
 * timer is set to the configuration value. If the buffer had been released
 * modified before but not written to disk the hold timer is not updated. The
 * buffer will be written to disk when the hold timer has expired, there are
 * not more buffers available in the cache and a get or read buffer needs one
 * or a sync call has been made. If the buffer is obtained with a get or read
 * before the hold timer has expired the buffer will be returned to the user.
 *
 * @param bd Reference to the buffer descriptor.
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd);

/**
 * Release the buffer as modified and wait until it has been synchronized with
 * the disk by writing it. This buffer will be the first to be transfer to disk
 * and other buffers may also be written if the maximum number of blocks in a
 * requests allows it.
 *
 * @note This code does not lock the sync mutex and stop additions to the
 *       modified queue.

 * @param bd Reference to the buffer descriptor.
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_sync (rtems_bdbuf_buffer* bd);

/**
 * Synchronize all modified buffers for this device with the disk and wait
 * until the transfers have completed. The sync mutex for the pool is locked
 * stopping the addition of any further modifed buffers. It is only the
 * currently modified buffers that are written.
 *
 * @note Nesting calls to sync multiple devices attached to a single pool will
 * be handled sequentially. A nested call will be blocked until the first sync
 * request has complete. This is only true for device using the same pool.
 *
 * @param dev Block device number
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 */
rtems_status_code
rtems_bdbuf_syncdev (dev_t dev);

/**
 * Find first appropriate buffer pool. This primitive returns the index of
 * first buffer pool which block size is greater than or equal to specified
 * size.
 *
 * @param block_size Requested block size
 * @param pool The pool to use for the requested pool size.
 *
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 * @retval RTEMS_INVALID_SIZE The specified block size is invalid (not a power
 *         of 2)
 * @retval RTEMS_NOT_DEFINED The buffer pool for this or greater block size
 *         is not configured.
 */
rtems_status_code
rtems_bdbuf_find_pool (uint32_t block_size, rtems_bdpool_id *pool);

/**
 * Obtain characteristics of buffer pool with specified number.
 *
 * @param pool Buffer pool number
 * @param block_size Block size for which buffer pool is configured returned
 *                   there
 * @param blocks Number of buffers in buffer pool.
 *
 * RETURNS:
 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed
 *         successfully or error code if error is occured)
 * @retval RTEMS_INVALID_SIZE The appropriate buffer pool is not configured.
 *
 * @note Buffer pools enumerated continuously starting from 0.
 */
rtems_status_code
rtems_bdbuf_get_pool_info (rtems_bdpool_id pool, int *block_size, int *blocks);

#ifdef __cplusplus
}
#endif

#endif