diff options
-rw-r--r-- | cpukit/ChangeLog | 15 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/bdbuf.h | 230 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/blkdev.h | 229 | ||||
-rw-r--r-- | cpukit/libblock/include/rtems/diskdevs.h | 340 | ||||
-rw-r--r-- | cpukit/libblock/src/bdbuf.c | 279 | ||||
-rw-r--r-- | cpukit/libblock/src/blkdev.c | 6 | ||||
-rw-r--r-- | cpukit/libblock/src/diskdevs.c | 318 | ||||
-rw-r--r-- | cpukit/sapi/include/confdefs.h | 2 |
8 files changed, 680 insertions, 739 deletions
diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog index 72d710303c..eaa3eae678 100644 --- a/cpukit/ChangeLog +++ b/cpukit/ChangeLog @@ -1,3 +1,18 @@ +2009-04-29 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * sapi/include/confdefs.h, libblock/include/rtems/bdbuf.h: Changed + type of rtems_bdbuf_pool_configuration_size to size_t. + + * libblock/include/rtems/bdbuf.h, libblock/include/rtems/blkdev.h, + libblock/include/rtems/diskdevs.h, libblock/src/bdbuf.c, + libblock/src/blkdev.c, libblock/src/diskdevs.c: Buffer pool + allocation is now cache aligned. The cache functions are + currently not available on all platforms so the cache line size is + fixed to 32 bytes for now. Changed various integer types which + refer to block sizes, numbers and indexes. Fixed logical block + indexes in buffer get and read function. It is now possible to + delete logical disks. Modified documentation + 2009-04-29 Chris Johns <chrisj@rtems.org> * libcsupport/include/rtems/libio.h: Add rtems_off64_t for diff --git a/cpukit/libblock/include/rtems/bdbuf.h b/cpukit/libblock/include/rtems/bdbuf.h index 56dc9b44cb..52ee557054 100644 --- a/cpukit/libblock/include/rtems/bdbuf.h +++ b/cpukit/libblock/include/rtems/bdbuf.h @@ -1,7 +1,7 @@ /** - * @file rtems/bdbuf.h + * @file * - * Block Device Buffer Management + * Block device buffer management. */ /* @@ -28,21 +28,101 @@ #ifdef __cplusplus extern "C" { #endif + +/** + * @defgroup rtems_libblock Block Device Library + */ +/** + * @defgroup rtems_bdbuf Block Device Buffer Management + * + * @ingroup rtems_libblock + * + * The Block Device Buffer Management implements a cache between the disk + * devices and file systems. The code provides read ahead and write queuing to + * the drivers and fast cache look up using an AVL tree. + * + * The buffers are held in pools based on size. Each pool has buffers and the + * buffers follow this state machine: + * + * @dot + * digraph g { + * ready [label="Ready\nRead Ahead"]; + * transfer [label="Transfer"]; + * accessed [label="Accessed\nAccessed Modified"]; + * modified [label="Modified\nSynchronized"]; + * cached [label="Cached"]; + * ready -> transfer [label="Read\nRead Ahead"]; + * transfer -> ready [label="Read Ahead Complete"]; + * ready -> accessed [label="Get"]; + * transfer -> accessed [label="Read or Write\nComplete"]; + * transfer -> cached [label="Read or Write\nComplete"]; + * accessed -> cached [label="Release"]; + * cached -> accessed [label="Get"]; + * modified -> accessed [label="Get"]; + * accessed -> modified [label="Modified"]; + * accessed -> transfer [label="Swap"]; + * } + * @enddot + * + * Empty buffers are added to the ready list and removed from this queue when a + * caller requests a buffer. This is referred to as getting a buffer in the + * code and the event get in the state diagram. The buffer is assigned to a + * block and inserted to the AVL based on the block/device key. If the block is + * to be read by the user and not in the cache (ready) it is transfered from + * the disk into memory. If no ready buffers exist the buffer is taken from the + * LRU list. If no buffers are on the LRU list the modified list is check. If + * no buffers are on the modified list the request blocks. If buffers are on + * the modified list the buffers hold timer is expired and the swap out task + * woken. + * + * A block being accessed is given to the file system layer and not accessable + * to another requester until released back to the cache. The same goes to a + * buffer in the transfer state. The transfer state means being read or + * written. If the file system has modifed the block and releases it as + * modified it placed on the pool's modified list and a hold timer + * initialised. The buffer is held for the hold time before being written to + * disk. Buffers are held for a configurable period of time on the modified + * list as a write sets the state to transfer and this locks the buffer out + * from the file system until the write complete. Buffers are often repeatable + * accessed and modified in a series of small updates so if sent to the disk + * when released as modified the user would have to block waiting until it had + * been written. This would be a performance problem. + * + * The code performs mulitple block reads and writes. Multiple block reads or + * read ahead increases performance with hardware that supports it. It also + * helps with a large cache as the disk head movement is reduced. It how-ever + * is a speculative operation so excessive use can remove valuable and needed + * blocks from the cache. The get call knows if a read is a for the file system + * or if it is a read ahead get. If the get is for a read ahead block and the + * block is already in the cache or no ready buffers are available the read + * ahead is stopped. The transfer occurs with the blocks so far. If a buffer is + * in the read ahead state and release it is placed on the ready list rather + * than the LRU list. This means these buffers are used before buffers used by + * the file system. + * + * The pool has the following lists of buffers: + * - @c ready: Empty buffers created when the pool is initialised. + * - @c modified: Buffers waiting to be written to disk. + * - @c sync: Buffers to be synced to disk. + * - @c lru: Accessed buffers released in least recently used order. + * + * @{ + */ /** * 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_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; /** @@ -57,27 +137,27 @@ typedef struct rtems_bdbuf_buffer 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 */ + 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 */ + 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) + 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 rtems_bdbuf_buf_state state; /**< State of the buffer. */ - volatile uint32_t waiters; /*< The number of threads waiting on this + volatile uint32_t waiters; /**< The number of threads waiting on this * buffer. */ - rtems_bdpool_id pool; /*< Identifier of buffer pool to which 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 + volatile uint32_t hold_timer; /**< Timer to indicate how long a buffer * has been held in the cache modified. */ } rtems_bdbuf_buffer; @@ -87,38 +167,38 @@ typedef struct rtems_bdbuf_buffer */ 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 blksize; /**< The size of the blocks (in bytes) */ + uint32_t nblks; /**< Number of blocks in this pool */ - uint32_t flags; /*< Configuration flags */ + uint32_t flags; /**< Configuration flags */ - rtems_id lock; /*< The pool lock. Lock this data and + 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_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 + 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_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 + 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 + 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 + 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. */ + volatile uint32_t wait_waiters; /**< Count of waiting blockers. */ - rtems_bdbuf_buffer* bds; /*< Pointer to table of buffer descriptors + rtems_bdbuf_buffer* bds; /**< Pointer to table of buffer descriptors * allocated for this buffer pool. */ - void* buffers; /*< The buffer's memory. */ + void* buffers; /**< The buffer's memory. */ } rtems_bdbuf_pool; /** @@ -126,35 +206,46 @@ typedef struct rtems_bdbuf_pool * 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 + 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. + * External reference to the pool configuration table describing each pool in + * the system. + * + * The configuration table is provided by the application. */ extern rtems_bdbuf_pool_config rtems_bdbuf_pool_configuration[]; -extern int rtems_bdbuf_pool_configuration_size; + +/** + * External reference the size of the pool configuration table + * @ref rtems_bdbuf_pool_configuration. + * + * The configuration table size is provided by the application. + */ +extern size_t 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. */ + 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. + * External reference to the configuration. + * + * The configuration is provided by the application. */ extern rtems_bdbuf_config rtems_bdbuf_configuration; @@ -163,10 +254,26 @@ extern rtems_bdbuf_config rtems_bdbuf_configuration; * than this defined max. This stops thrashing in the cache. */ #define RTEMS_BDBUF_MAX_READ_AHEAD_BLOCKS_DEFAULT 32 + +/** + * Default maximum number of blocks to write at once. + */ #define RTEMS_BDBUF_MAX_WRITE_BLOCKS_DEFAULT 16 + +/** + * Default swap-out task priority. + */ #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 */ + +/** + * Default swap-out task swap period in milli seconds. + */ +#define RTEMS_BDBUF_SWAPOUT_TASK_SWAP_PERIOD_DEFAULT 250 + +/** + * Default swap-out task block hold time in milli seconds. + */ +#define RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT 1000 /** * Prepare buffering layer to work - initialize buffer descritors and (if it is @@ -335,8 +442,13 @@ rtems_bdbuf_find_pool (uint32_t block_size, rtems_bdpool_id *pool); * * @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); +rtems_status_code rtems_bdbuf_get_pool_info( + rtems_bdpool_id pool, + uint32_t *block_size, + uint32_t *blocks +); + +/** @} */ #ifdef __cplusplus } diff --git a/cpukit/libblock/include/rtems/blkdev.h b/cpukit/libblock/include/rtems/blkdev.h index 57cbb6e47c..d5ec9f46cb 100644 --- a/cpukit/libblock/include/rtems/blkdev.h +++ b/cpukit/libblock/include/rtems/blkdev.h @@ -1,6 +1,7 @@ /** - * @file rtems/blkdev.h - * block device driver interface definitions + * @file + * + * Block device management. */ /* @@ -20,109 +21,168 @@ extern "C" { #endif -/* - * Interface with device drivers Block device looks, initialized and behaves - * like traditional RTEMS device driver. Heart of the block device driver is in - * BIOREQUEST ioctl. This call puts I/O request to the block device queue, in - * priority order, for asynchronous processing. When driver executes request, - * req_done function invoked, so callee knows about it. Look for details below. +/** + * @defgroup rtems_blkdev Block Device Management + * + * @ingroup rtems_libblock + * + * Interface between device drivers and the block device library. + * + * The heart of the block device driver is the @ref RTEMS_BLKIO_REQUEST IO + * control. This call puts IO @ref rtems_blkdev_request "requests" to the block + * device for asynchronous processing. When a driver executes a request, it + * invokes the request done callback function to finish the request. + * + * @{ */ -/* - * Block device block number datatype +/** + * Block device block index type. */ typedef uint32_t rtems_blkdev_bnum; -/* Block device request type */ +/** + * Block device request type. + */ typedef enum rtems_blkdev_request_op { - RTEMS_BLKDEV_REQ_READ, /* Read operation */ - RTEMS_BLKDEV_REQ_WRITE, /* Write operation */ - RTEMS_BLKDEV_CAPABILITIES /* Capabilities request */ + RTEMS_BLKDEV_REQ_READ, + RTEMS_BLKDEV_REQ_WRITE, + RTEMS_BLKDEV_CAPABILITIES } rtems_blkdev_request_op; /** - * ATA multi-sector buffer requests only supported. This option - * means the cache will only supply multiple buffers that are - * inorder so the ATA multi-sector command can be used. This is a + * Only consecutive multi-sector buffer requests are supported. + * + * This option means the cache will only supply multiple buffers that are + * inorder so the ATA multi-sector command for example can be used. This is a * hack to work around the current ATA driver. */ #define RTEMS_BLKDEV_CAP_MULTISECTOR_CONT (1 << 0) -/* - * @typedef rtems_blkdev_request_cb - * +/** * Type for block device request done callback function. * - * @param arg Argument supplied in blkdev_request - * @param status RTEMS status code for this operation - * @param errno errno value to be passed to the user when - * status != RTEMS_SUCCESSFUL + * @param arg Argument supplied in @ref rtems_blkdev_request. + * @param status Status code for this operation. + * @param errno The @c errno value to be passed to the user when status is not + * equal to @c RTEMS_SUCCESSFUL. */ typedef void (* rtems_blkdev_request_cb)(void *arg, rtems_status_code status, int error); /** - * @struct rtems_blkdev_sg_buffer - * Block device scatter/gather buffer structure + * Block device scatter or gather buffer structure. */ typedef struct rtems_blkdev_sg_buffer { - uint32_t block; /* The block number */ - uint32_t length; /* Buffer length */ - void *buffer; /* Buffer pointer */ - void *user; /* User pointer */ + /** + * Block index. + */ + rtems_blkdev_bnum block; + + /** + * Buffer length. + */ + uint32_t length; + + /** + * Buffer pointer. + */ + void *buffer; + + /** + * User pointer. + */ + void *user; } rtems_blkdev_sg_buffer; -/* blkdev_request (Block Device Request) structure is - * used to read/write a number of blocks from/to device. +/** + * The block device dequest structure is used to read or write a number of + * blocks from or to the device. */ typedef struct rtems_blkdev_request { - /* Block device operation (read or write) */ - rtems_blkdev_request_op req; - /* Callback function */ - rtems_blkdev_request_cb req_done; - /* Argument to be passed to callback function*/ - void *done_arg; - /* Last I/O operation completion status */ - rtems_status_code status; - /* If status != RTEMS_SUCCESSFUL, this field contains error code */ - int error; - /* Number of blocks for this request. */ - uint32_t bufnum; - - /* The task requesting the IO operation. */ - rtems_id io_task; - - /* List of scatter/gather buffers */ - rtems_blkdev_sg_buffer bufs[0]; + /** + * Block device operation (read or write). + */ + rtems_blkdev_request_op req; + + /** + * Request done callback function. + */ + rtems_blkdev_request_cb req_done; + + /** + * Argument to be passed to callback function. + */ + void *done_arg; + + /** + * Last IO operation completion status. + */ + rtems_status_code status; + + /** + * If @c status is not equal to @c RTEMS_SUCCESSFUL, this field contains the + * error number. + */ + int error; + + /** + * Number of blocks for this request. + */ + uint32_t bufnum; + + /** + * The task requesting the IO operation. + */ + rtems_id io_task; + + /** + * List of scatter or gather buffers. + */ + rtems_blkdev_sg_buffer bufs[0]; } rtems_blkdev_request; -/* The start block in a request. Only valid if the driver has returned the - * RTEMS_BLKDEV_CAPABILITIES of RTEMS_BLKDEV_CAP_MULTISECTOR_CONT */ -#define RTEMS_BLKDEV_START_BLOCK(_r) (_r->bufs[0].block) - -/* Block device IOCTL request codes */ -#define RTEMS_BLKIO_REQUEST _IOWR('B', 1, rtems_blkdev_request) -#define RTEMS_BLKIO_GETBLKSIZE _IO('B', 2) -#define RTEMS_BLKIO_GETSIZE _IO('B', 3) -#define RTEMS_BLKIO_SYNCDEV _IO('B', 4) +/** + * The start block in a request. + * + * Only valid if the driver has returned the @ref RTEMS_BLKDEV_CAPABILITIES of + * @ref RTEMS_BLKDEV_CAP_MULTISECTOR_CONT. + */ +#define RTEMS_BLKDEV_START_BLOCK(req) (req->bufs[0].block) -/* Device driver interface conventions suppose that driver may - * contain initialize/open/close/read/write/ioctl entry points. These - * primitives (except initialize) can be implemented in generic fashion, - * based upon supplied block device driver ioctl handler. Every block - * device driver should provide initialize entry point, which is register - * all block devices and appropriate ioctl handlers. +/** + * @name IO Control Request Codes + * + * @{ */ +#define RTEMS_BLKIO_REQUEST _IOWR('B', 1, rtems_blkdev_request) +#define RTEMS_BLKIO_GETBLKSIZE _IO('B', 2) +#define RTEMS_BLKIO_GETSIZE _IO('B', 3) +#define RTEMS_BLKIO_SYNCDEV _IO('B', 4) + +/** @} */ + +/** + * The device driver interface conventions suppose that a driver may contain an + * initialize, open, close, read, write and IO control entry points. These + * primitives (except initialize) can be implemented in a generic fashion based + * upon the supplied block device driver IO control handler. Every block device + * driver should provide an initialize entry point, which registers the + * appropriate IO control handler. + */ #define RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES \ - rtems_blkdev_generic_open, rtems_blkdev_generic_close, \ - rtems_blkdev_generic_read, rtems_blkdev_generic_write, \ - rtems_blkdev_generic_ioctl + .open_entry = rtems_blkdev_generic_open, \ + .close_entry = rtems_blkdev_generic_close, \ + .read_entry = rtems_blkdev_generic_read, \ + .write_entry = rtems_blkdev_generic_write, \ + .control_entry = rtems_blkdev_generic_ioctl -/* blkdev_generic_read -- - * Generic block device read primitive. Implemented using block device - * buffer management primitives. +/** + * Generic block device read primitive. + * + * Implemented using block device buffer management primitives. */ rtems_device_driver rtems_blkdev_generic_read( @@ -131,9 +191,10 @@ rtems_blkdev_generic_read( void * arg ); -/* blkdev_generic_write -- - * Generic block device driver write primitive. Implemented using block - * device buffer management primitives. +/** + * Generic block device write primitive. + * + * Implemented using block device buffer management primitives. */ rtems_device_driver rtems_blkdev_generic_write( @@ -142,8 +203,10 @@ rtems_blkdev_generic_write( void * arg ); -/* blkdev_generic_open -- - * Generic block device open primitive. +/** + * Generic block device open primitive. + * + * Implemented using block device buffer management primitives. */ rtems_device_driver rtems_blkdev_generic_open( @@ -152,8 +215,10 @@ rtems_blkdev_generic_open( void * arg ); -/* blkdev_generic_close -- - * Generic block device close primitive. +/** + * Generic block device close primitive. + * + * Implemented using block device buffer management primitives. */ rtems_device_driver rtems_blkdev_generic_close( @@ -162,8 +227,10 @@ rtems_blkdev_generic_close( void * arg ); -/* blkdev_generic_ioctl -- - * Generic block device ioctl primitive. +/** + * Generic block device IO control primitive. + * + * Implemented using block device buffer management primitives. */ rtems_device_driver rtems_blkdev_generic_ioctl( @@ -172,6 +239,8 @@ rtems_blkdev_generic_ioctl( void * arg ); +/** @} */ + #ifdef __cplusplus } #endif diff --git a/cpukit/libblock/include/rtems/diskdevs.h b/cpukit/libblock/include/rtems/diskdevs.h index af56f720a0..da5c32ec13 100644 --- a/cpukit/libblock/include/rtems/diskdevs.h +++ b/cpukit/libblock/include/rtems/diskdevs.h @@ -1,6 +1,7 @@ /** - * @file rtems/diskdevs.h - * Physical and logical block devices (disks) support + * @file + * + * Block device disk management. */ /* @@ -13,197 +14,212 @@ #ifndef _RTEMS_DISKDEVS_H #define _RTEMS_DISKDEVS_H -#ifdef __cplusplus -extern "C" { -#endif - #include <rtems.h> #include <rtems/libio.h> #include <stdlib.h> -/* Buffer pool identifier */ +/** + * @ingroup rtems_bdbuf + * + * Buffer pool identifier. + */ typedef int rtems_bdpool_id; #include <rtems/blkdev.h> -/* Driver capabilities. */ +#ifdef __cplusplus +extern "C" { +#endif -/* Block device ioctl handler */ -typedef int (* rtems_block_device_ioctl) (dev_t dev, uint32_t req, void *argp); +/** + * @defgroup rtems_disk Block Device Disk Management + * + * @ingroup rtems_libblock + * + * This module provides functions to manage disk devices. The disk devices are + * accessed via the RTEMS block device library. A disk is a set of blocks + * which are identified by a consecutive set of non-negative integers starting + * at zero. There are also logical disks which contain a subset of consecutive + * disk blocks. The logical disks are used to represent the partitions of a + * disk. + * + * @{ + */ -/* rtems_disk_device: Entry of this type created for every disk device - * (both for logical and physical disks). - * Array of arrays of pointers to disk_device structures maintained. First - * table indexed by major number and second table indexed by minor number. - * Such data organization allow quick lookup using data structure of - * moderated size. +/** + * Block device IO control handler type. + */ +typedef int (*rtems_block_device_ioctl)( dev_t dev, uint32_t req, void *argp); + +/** + * Description of a disk device (logical and physical disks). + * + * An array of pointer tables to rtems_disk_device structures is maintained. + * The first table will be indexed by the major number and the second table + * will be indexed by the minor number. This allows quick lookup using a data + * structure of moderated size. */ typedef struct rtems_disk_device { - dev_t dev; /* Device ID (major + minor) */ - struct rtems_disk_device *phys_dev; /* Physical device ID (the same - as dev if this entry specifies - the physical device) */ - uint32_t capabilities; /* Driver capabilities. */ - char *name; /* Disk device name */ - int uses; /* Use counter. Device couldn't be - removed if it is in use. */ - uint32_t start; /* Starting block number (0 for - physical devices, block offset - on the related physical device - for logical device) */ - uint32_t size; /* Size of physical or logical disk - in disk blocks */ - uint32_t block_size; /* Size of device block (minimum - transfer unit) in bytes - (must be power of 2) */ - uint32_t block_size_log2; /* log2 of block_size */ - rtems_bdpool_id pool; /* Buffer pool assigned to this - device */ - rtems_block_device_ioctl ioctl; /* ioctl handler for this block - device */ + /** + * Device identifier (concatenation of major and minor number). + */ + dev_t dev; + + /** + * Physical device identifier (equals the @c dev entry if it specifies a + * physical device). + */ + struct rtems_disk_device *phys_dev; + + /** + * Driver capabilities. + */ + uint32_t capabilities; + + /** + * Disk device name. + */ + char *name; + + /** + * Usage counter. + * + * Devices cannot be removed if they are in use. + */ + unsigned uses; + + /** + * Start block number. + * + * Equals zero for physical devices. It is a block offset to the related + * physical device for logical device. + */ + rtems_blkdev_bnum start; + + /** + * Size of the physical or logical disk in blocks. + */ + rtems_blkdev_bnum size; + + /** + * Device block size in bytes. + * + * This is the minimum transfer unit and must be power of two. + */ + uint32_t block_size; + + /** + * Binary logarithm of the block size. + */ + uint32_t block_size_log2; + + /** + * Buffer pool assigned to this disk. + */ + rtems_bdpool_id pool; + + /** + * IO control handler for this disk. + */ + rtems_block_device_ioctl ioctl; } rtems_disk_device; -/* rtems_disk_create_phys -- - * Create physical disk entry. This function usually invoked from - * block device driver initialization code when physical device - * detected in the system. Device driver should provide ioctl handler - * to allow block device access operations. This primitive will register - * device in rtems (invoke rtems_io_register_name). - * - * PARAMETERS: - * dev - device identifier (major, minor numbers) - * block_size - size of disk block (minimum data transfer unit); must be - * power of 2 - * disk_size - number of blocks on device - * handler - IOCTL handler (function providing basic block input/output - * request handling BIOREQUEST and other device management - * operations) - * name - character name of device (e.g. /dev/hda) - * - * RETURNS: - * RTEMS_SUCCESSFUL if information about new physical disk added, or - * error code if error occured (device already registered, wrong block - * size value, no memory available). - */ -rtems_status_code -rtems_disk_create_phys(dev_t dev, int block_size, int disk_size, - rtems_block_device_ioctl handler, - const char *name); - -/* rtems_disk_create_log -- - * Create logical disk entry. Logical disk is contiguous area on physical - * disk. Disk may be splitted to several logical disks in several ways: - * manually or using information stored in blocks on physical disk - * (DOS-like partition table, BSD disk label, etc). This function usually - * invoked from application when application-specific splitting are in use, - * or from generic code which handle different logical disk organizations. - * This primitive will register device in rtems (invoke - * rtems_io_register_name). - * - * PARAMETERS: - * dev - logical device identifier (major, minor numbers) - * phys - physical device (block device which holds this logical disk) - * identifier - * start - starting block number on the physical device - * size - logical disk size in blocks - * name - logical disk name - * - * RETURNS: - * RTEMS_SUCCESSFUL if logical device successfully added, or error code - * if error occured (device already registered, no physical device - * exists, logical disk is out of physical disk boundaries, no memory - * available). +/** + * Creates a physical disk with device identifier @a dev. + * + * The block size @a block_size must be a power of two. The disk size @a + * disk_size is the number of blocks provided by this disk. The block index + * starts with zero. The associated disk device driver will be invoked via the + * IO control handler @a handler. A device node will be registered in the file + * system with absolute path @a name. This function is usually invoked from a + * block device driver during initialization when a physical device is detected + * in the system. The device driver provides an IO control handler to allow + * block device operations. */ -rtems_status_code -rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name); - -/* rtems_disk_delete -- - * Delete physical or logical disk device. Device may be deleted if its - * use counter (and use counters of all logical devices - if it is - * physical device) equal to 0. When physical device deleted, - * all logical devices deleted inherently. Appropriate devices removed - * from "/dev" filesystem. - * - * PARAMETERS: - * dev - device identifier (major, minor numbers) - * - * RETURNS: - * RTEMS_SUCCESSFUL if block device successfully deleted, or error code - * if error occured (device is not defined, device is in use). +rtems_status_code rtems_disk_create_phys( + dev_t dev, + uint32_t block_size, + rtems_blkdev_bnum disk_size, + rtems_block_device_ioctl handler, + const char *name +); + +/** + * Creates a logical disk with device identifier @a dev. + * + * A logical disk manages a subset of consecutive blocks containd in the + * physical disk with identifier @a phys. The start block index of the logical + * disk device is @a start. The block number of the logcal disk will be @a + * size. The blocks must be within the range of blocks managed by the + * associated physical disk device. A device node will be registered in the + * file system with absolute path @a name. The block size and IO control + * handler are inherited by the physical disk. */ -rtems_status_code -rtems_disk_delete(dev_t dev); +rtems_status_code rtems_disk_create_log( + dev_t dev, + dev_t phys, + rtems_blkdev_bnum start, + rtems_blkdev_bnum size, + const char *name +); -/* rtems_disk_obtain -- - * Find block device descriptor by its device identifier. This function - * increment usage counter to 1. User should release disk_device structure - * by invoking rtems_disk_release primitive. - * - * PARAMETERS: - * dev - device identifier (major, minor numbers) +/** + * Deletes a physical or logical disk device with identifier @a dev. * - * RETURNS: - * pointer to the block device descriptor, or NULL if no such device - * exists. + * Disk devices may be deleted if there usage counter (and the usage counters + * of all contained logical disks devices) equals zero. When a physical disk + * device is deleted, all logical disk devices will deleted too. The + * corresponding device nodes will be removed from the file system. */ -rtems_disk_device * -rtems_disk_obtain(dev_t dev); +rtems_status_code rtems_disk_delete(dev_t dev); -/* rtems_disk_release -- - * Release disk_device structure (decrement usage counter to 1). - * - * PARAMETERS: - * dd - pointer to disk device structure - * - * RETURNS: - * RTEMS_SUCCESSFUL +/** + * Returns the disk device descriptor for the device identifier @a dev. * - * NOTE: - * It should be implemented as inline function. + * Increments usage counter by one. You should release the disk device + * descriptor with rtems_disk_release(). Returns @c NULL if no corresponding + * disk exists. */ -rtems_status_code -rtems_disk_release(rtems_disk_device *dd); +rtems_disk_device *rtems_disk_obtain(dev_t dev); -/* rtems_disk_next -- - * Disk device enumerator. Looking for device having device number larger - * than dev and return disk device descriptor for it. If there are no - * such device, NULL value returned. - * - * PARAMETERS: - * dev - device number (use -1 to start search) +/** + * Releases the disk device description @a dd. * - * RETURNS: - * Pointer to the disk descriptor for next disk device, or NULL if all - * devices enumerated. */ -rtems_disk_device * -rtems_disk_next(dev_t dev); + * Decrements usage counter by one. + */ +rtems_status_code rtems_disk_release(rtems_disk_device *dd); -/* rtems_diskio_initialize -- - * Initialization of disk device library (initialize all data structures, - * etc.) +/** + * Disk device iterator. * - * PARAMETERS: - * none + * Returns the next disk device descriptor with a device identifier larger than + * @a dev. If there is no such device, @c NULL will be returned. Use minus + * one to start the search. * - * RETURNS: - * RTEMS_SUCCESSFUL if library initialized, or error code if error - * occured. + * @code + * rtems_disk_device *dd = rtems_disk_next((dev_t) -1); + * + * while (dd != NULL) { + * dd = rtems_disk_next(dd->dev); + * } + * @endcode */ -rtems_status_code -rtems_disk_io_initialize(void); +rtems_disk_device *rtems_disk_next(dev_t dev); -/* rtems_diskio_done -- - * Release all resources allocated for disk device interface. - * - * PARAMETERS: - * none +/** + * Initializes the disk device management. * - * RETURNS: - * RTEMS_SUCCESSFUL if all resources released, or error code if error - * occured. + * This functions returns successful if the disk device management is already + * initialized. There is no protection against concurrent access. */ -rtems_status_code -rtems_disk_io_done(void); +rtems_status_code rtems_disk_io_initialize(void); + +/** + * Releases all resources allocated for disk device management. + */ +rtems_status_code rtems_disk_io_done(void); + +/** @} */ #ifdef __cplusplus } diff --git a/cpukit/libblock/src/bdbuf.c b/cpukit/libblock/src/bdbuf.c index 3d57a3c3b8..6ae6c4dccc 100644 --- a/cpukit/libblock/src/bdbuf.c +++ b/cpukit/libblock/src/bdbuf.c @@ -1,3 +1,9 @@ +/** + * @file + * + * Block device buffer management. + */ + /* * Disk I/O buffering * Buffer managment @@ -15,81 +21,6 @@ */ /** - * @file - * - * The Buffer Descriptor Buffer code implements a cache between the disk - * devices and file systems. The code provides read ahead and write queuing to - * the drivers and fast cache look up using an AVL tree. - * - * The buffers are held in pools based on size. Each pool has buffers and the - * buffers follow this state machine: - * - * read/read ahead - * +-------------------------------+ - * | v - * +-----------+ read ahead +------------+ - * | READY, | complete | |---------+ - * | READ |<----------------| TRANSFER | | - * | AHEAD | +-------------| |<--+ | - * +-----------+ | read/write +------------+ | | - * | get v complete swap | | - * | +-----------+ modified +------------+ | - * +--->| ACCESSED, |---------->| MODIFIED, | | - * | ACCESSED |<----------| SYNC | | - * +----| MODIFIED |<--+ get | | | - * | +-----------+ | +------------+ | - * | release get | | - * | +-----------+ | | - * +--->| |---+ read complete | - * | CACHED | write complete | - * | |<-------------------------+ - * +-----------+ - * - * Empty buffers are added to the ready list and removed from this queue when a - * caller requests a buffer. This is referred to as getting a buffer in the - * code and the event get in the state diagram. The buffer is assigned to a - * block and inserted to the AVL based on the block/device key. If the block is - * to be read by the user and not in the cache (ready) it is transfered from - * the disk into memory. If no ready buffers exist the buffer is taken from the - * LRU list. If no buffers are on the LRU list the modified list is check. If - * no buffers are on the modified list the request blocks. If buffers are on - * the modified list the buffers hold timer is expired and the swap out task - * woken. - * - * A block being accessed is given to the file system layer and not accessable - * to another requester until released back to the cache. The same goes to a - * buffer in the transfer state. The transfer state means being read or - * written. If the file system has modifed the block and releases it as - * modified it placed on the pool's modified list and a hold timer - * initialised. The buffer is held for the hold time before being written to - * disk. Buffers are held for a configurable period of time on the modified - * list as a write sets the state to transfer and this locks the buffer out - * from the file system until the write complete. Buffers are often repeatable - * accessed and modified in a series of small updates so if sent to the disk - * when released as modified the user would have to block waiting until it had - * been written. This would be a performance problem. - * - * The code performs mulitple block reads and writes. Multiple block reads or - * read ahead increases performance with hardware that supports it. It also - * helps with a large cache as the disk head movement is reduced. It how-ever - * is a speculative operation so excessive use can remove valuable and needed - * blocks from the cache. The get call knows if a read is a for the file system - * or if it is a read ahead get. If the get is for a read ahead block and the - * block is already in the cache or no ready buffers are available the read - * ahead is stopped. The transfer occurs with the blocks so far. If a buffer is - * in the read ahead state and release it is placed on the ready list rather - * than the LRU list. This means these buffers are used before buffers used by - * the file system. - * - * The pool have the following lists of buffers: - * - * ready - Empty buffers created when the pool is initialised. - * modified - Buffers waiting to be written to disk. - * sync - Buffers to be synced to disk. - * lru - Accessed buffers released in least recently used order. - */ - -/** * Set to 1 to enable debug tracing. */ #define RTEMS_BDBUF_TRACE 0 @@ -100,6 +31,7 @@ #include <rtems.h> #include <rtems/error.h> +#include <rtems/malloc.h> #include <limits.h> #include <errno.h> #include <assert.h> @@ -430,7 +362,7 @@ rtems_bdbuf_avl_insert(rtems_bdbuf_buffer** root, /** * Removes the node from the tree. * - * @param root_addr Pointer to pointer to the root node + * @param root Pointer to pointer to the root node * @param node Pointer to the node to remove * @retval 0 Item removed * @retval -1 No such item found @@ -704,7 +636,7 @@ rtems_bdbuf_avl_remove(rtems_bdbuf_buffer** root, /** * Get the pool for the device. * - * @param pdd Physical disk device. + * @param pid Physical disk device. */ static rtems_bdbuf_pool* rtems_bdbuf_get_pool (const rtems_bdpool_id pid) @@ -923,11 +855,19 @@ static rtems_status_code rtems_bdbuf_initialize_pool (rtems_bdbuf_pool_config* config, rtems_bdpool_id pid) { + int rv = 0; unsigned char* buffer = config->mem_area; rtems_bdbuf_pool* pool; rtems_bdbuf_buffer* bd; rtems_status_code sc; uint32_t b; + int cache_aligment = 32 /* FIXME rtems_cache_get_data_line_size() */; + + /* For unspecified cache alignments we use the CPU alignment */ + if (cache_aligment <= 0) + { + cache_aligment = CPU_ALIGNMENT; + } pool = rtems_bdbuf_get_pool (pid); @@ -961,16 +901,21 @@ rtems_bdbuf_initialize_pool (rtems_bdbuf_pool_config* config, return RTEMS_NO_MEMORY; /* - * Allocate memory for buffers if required. + * Allocate memory for buffers if required. The pool memory will be cache + * aligned. It is possible to free the memory allocated by rtems_memalign() + * with free(). */ if (buffer == NULL) { - buffer = pool->buffers = malloc (config->num * config->size); - if (!pool->buffers) + rv = rtems_memalign ((void **) &buffer, + cache_aligment, + config->num * config->size); + if (rv != 0) { free (pool->bds); return RTEMS_NO_MEMORY; } + pool->buffers = buffer; } for (b = 0, bd = pool->bds; @@ -1079,16 +1024,6 @@ rtems_bdbuf_release_pool (rtems_bdpool_id pid) return RTEMS_SUCCESSFUL; } -/** - * 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) { @@ -1209,7 +1144,7 @@ rtems_bdbuf_init (void) * it will make sure the pool is locked when it returns. The pool will be * unlocked if the call could block. * - * @param device The physical disk device + * @param pdd The physical disk device * @param pool The pool reference * @param block Absolute media block number * @param read_ahead The get is for a read ahead buffer @@ -1401,30 +1336,6 @@ rtems_bdbuf_get_buffer (rtems_disk_device* pdd, return bd; } -/** - * 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, @@ -1447,17 +1358,16 @@ rtems_bdbuf_get (dev_t device, return RTEMS_INVALID_NUMBER; } - block += dd->start; - pool = rtems_bdbuf_get_pool (dd->phys_dev->pool); rtems_bdbuf_lock_pool (pool); #if RTEMS_BDBUF_TRACE - rtems_bdbuf_printf ("get: %d (dev = %08x)\n", block, device); + /* Print the block index relative to the physical disk */ + rtems_bdbuf_printf ("get: %d (dev = %08x)\n", block + dd->start, device); #endif - bd = rtems_bdbuf_get_buffer (dd->phys_dev, pool, block, false); + bd = rtems_bdbuf_get_buffer (dd->phys_dev, pool, block + dd->start, false); if (bd->state == RTEMS_BDBUF_STATE_MODIFIED) bd->state = RTEMS_BDBUF_STATE_ACCESS_MODIFIED; @@ -1494,31 +1404,6 @@ rtems_bdbuf_read_done (void* arg, rtems_status_code status, int error) rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC); } -/** - * 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. - * - * @note Read ahead always reads buffers in sequence. All multi-block reads - * read consecutive blocks. - * - * @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, @@ -1545,18 +1430,16 @@ rtems_bdbuf_read (dev_t device, dd = rtems_disk_obtain (device); if (dd == NULL) return RTEMS_INVALID_ID; - - block += dd->start; - -#if RTEMS_BDBUF_TRACE - rtems_bdbuf_printf ("read: %d (dev = %08x)\n", block, device); -#endif - if (block >= dd->size) - { + if (block >= dd->size) { rtems_disk_release(dd); return RTEMS_INVALID_NUMBER; } + +#if RTEMS_BDBUF_TRACE + /* Print the block index relative to the physical disk */ + rtems_bdbuf_printf ("read: %d (dev = %08x)\n", block + dd->start, device); +#endif req->bufnum = 0; @@ -1587,7 +1470,7 @@ rtems_bdbuf_read (dev_t device, * caller. */ bd = rtems_bdbuf_get_buffer (dd->phys_dev, pool, - block + req->bufnum, + block + dd->start + req->bufnum, req->bufnum == 0 ? false : true); /* @@ -1711,19 +1594,6 @@ rtems_bdbuf_read (dev_t device, return RTEMS_SUCCESSFUL; } -/** - * 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) { @@ -1785,21 +1655,6 @@ rtems_bdbuf_release (rtems_bdbuf_buffer* bd) return RTEMS_SUCCESSFUL; } -/** - * 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) { @@ -1828,20 +1683,6 @@ rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd) return RTEMS_SUCCESSFUL; } -/** - * 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) { @@ -1895,17 +1736,6 @@ rtems_bdbuf_sync (rtems_bdbuf_buffer* bd) return RTEMS_SUCCESSFUL; } -/** - * 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. - * - * @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) { @@ -2427,21 +2257,6 @@ rtems_bdbuf_swapout_task (rtems_task_argument arg) rtems_task_delete (RTEMS_SELF); } -/** - * 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) { @@ -2480,23 +2295,11 @@ 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) +rtems_status_code rtems_bdbuf_get_pool_info( + rtems_bdpool_id pool, + uint32_t *block_size, + uint32_t *blocks +) { if (pool >= rtems_bdbuf_ctx.npools) return RTEMS_INVALID_NUMBER; diff --git a/cpukit/libblock/src/blkdev.c b/cpukit/libblock/src/blkdev.c index 560ad224ec..fd5b7f09b0 100644 --- a/cpukit/libblock/src/blkdev.c +++ b/cpukit/libblock/src/blkdev.c @@ -1,3 +1,9 @@ +/** + * @file + * + * Block device management. + */ + /* * blkdev.h - block device driver generic support * diff --git a/cpukit/libblock/src/diskdevs.c b/cpukit/libblock/src/diskdevs.c index a371d1a9ba..f888246e36 100644 --- a/cpukit/libblock/src/diskdevs.c +++ b/cpukit/libblock/src/diskdevs.c @@ -1,3 +1,9 @@ +/** + * @file + * + * Block device disk management. + */ + /* * diskdevs.c - Physical and logical block devices (disks) support * @@ -212,32 +218,13 @@ create_disk(dev_t dev, const char *name, rtems_disk_device **diskdev) return RTEMS_SUCCESSFUL; } -/* rtems_disk_create_phys -- - * Create physical disk entry. This function usually invoked from - * block device driver initialization code when physical device - * detected in the system. Device driver should provide ioctl handler - * to allow block device access operations. This primitive will register - * device in rtems (invoke rtems_io_register_name). - * - * PARAMETERS: - * dev - device identifier (major, minor numbers) - * block_size - size of disk block (minimum data transfer unit); must be - * power of 2 - * disk_size - number of blocks on device - * handler - IOCTL handler (function providing basic block input/output - * request handling BIOREQUEST and other device management - * operations) - * name - character name of device (e.g. /dev/hda) - * - * RETURNS: - * RTEMS_SUCCESSFUL if information about new physical disk added, or - * error code if error occured (device already registered, wrong block - * size value, no memory available). - */ -rtems_status_code -rtems_disk_create_phys(dev_t dev, int block_size, int disk_size, - rtems_block_device_ioctl handler, - const char *name) +rtems_status_code rtems_disk_create_phys( + dev_t dev, + uint32_t block_size, + rtems_blkdev_bnum disk_size, + rtems_block_device_ioctl handler, + const char *name +) { int bs_log2; int i; @@ -297,163 +284,138 @@ rtems_disk_create_phys(dev_t dev, int block_size, int disk_size, return rc; } -/* rtems_disk_create_log -- - * Create logical disk entry. Logical disk is contiguous area on physical - * disk. Disk may be splitted to several logical disks in several ways: - * manually or using information stored in blocks on physical disk - * (DOS-like partition table, BSD disk label, etc). This function usually - * invoked from application when application-specific splitting are in use, - * or from generic code which handle different logical disk organizations. - * This primitive will register device in rtems (invoke - * rtems_io_register_name). - * - * PARAMETERS: - * dev - logical device identifier (major, minor numbers) - * phys - physical device (block device which holds this logical disk) - * identifier - * start - starting block number on the physical device - * size - logical disk size in blocks - * name - logical disk name - * - * RETURNS: - * RTEMS_SUCCESSFUL if logical device successfully added, or error code - * if error occured (device already registered, no physical device - * exists, logical disk is out of physical disk boundaries, no memory - * available). - */ -rtems_status_code -rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name) +rtems_status_code rtems_disk_create_log( + dev_t dev, + dev_t phys, + rtems_blkdev_bnum start, + rtems_blkdev_bnum size, + const char *name +) { - rtems_disk_device *dd; - rtems_disk_device *pdd; - rtems_status_code rc; - rtems_device_major_number major; - rtems_device_minor_number minor; - - rtems_filesystem_split_dev_t (dev, major, minor); + rtems_disk_device *dd = NULL; + rtems_disk_device *pdd = NULL; + rtems_status_code rc = RTEMS_SUCCESSFUL; + rtems_device_major_number major = 0; + rtems_device_minor_number minor = 0; + rtems_blkdev_bnum end = start + size; - rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - if (rc != RTEMS_SUCCESSFUL) - return rc; - diskdevs_protected = true; + rtems_filesystem_split_dev_t (dev, major, minor); - pdd = get_disk_entry(phys); - if (pdd == NULL) - { - diskdevs_protected = false; - rtems_semaphore_release(diskdevs_mutex); - return RTEMS_INVALID_NUMBER; - } + rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (rc != RTEMS_SUCCESSFUL) { + return rc; + } + + diskdevs_protected = true; + + pdd = get_disk_entry(phys); + if ( + pdd == NULL + || pdd != pdd->phys_dev + || start >= pdd->size + || end <= start + || end > pdd->size + ) { + diskdevs_protected = false; + rtems_semaphore_release(diskdevs_mutex); + return RTEMS_INVALID_NUMBER; + } - rc = create_disk(dev, name, &dd); - if (rc != RTEMS_SUCCESSFUL) - { - diskdevs_protected = false; - rtems_semaphore_release(diskdevs_mutex); - return rc; - } + rc = create_disk(dev, name, &dd); + if (rc != RTEMS_SUCCESSFUL) { + diskdevs_protected = false; + rtems_semaphore_release(diskdevs_mutex); + return rc; + } - dd->phys_dev = pdd; - dd->uses = 0; - dd->start = start; - dd->size = size; - dd->block_size = pdd->block_size; - dd->block_size_log2 = pdd->block_size_log2; - dd->ioctl = pdd->ioctl; + dd->phys_dev = pdd; + dd->uses = 0; + dd->start = start; + dd->size = size; + dd->block_size = pdd->block_size; + dd->block_size_log2 = pdd->block_size_log2; + dd->ioctl = pdd->ioctl; - rc = rtems_io_register_name(name, major, minor); + rc = rtems_io_register_name(name, major, minor); - diskdevs_protected = false; - rc = rtems_semaphore_release(diskdevs_mutex); + diskdevs_protected = false; + rc = rtems_semaphore_release(diskdevs_mutex); - return rc; + return rc; } -/* rtems_disk_delete -- - * Delete physical or logical disk device. Device may be deleted if its - * use counter (and use counters of all logical devices - if it is - * physical device) equal to 0. When physical device deleted, - * all logical devices deleted inherently. Appropriate devices removed - * from "/dev" filesystem. - * - * PARAMETERS: - * dev - device identifier (major, minor numbers) - * - * RETURNS: - * RTEMS_SUCCESSFUL if block device successfully deleted, or error code - * if error occured (device is not defined, device is in use). - */ rtems_status_code rtems_disk_delete(dev_t dev) { - rtems_status_code rc; - int used; - rtems_device_major_number maj; - rtems_device_minor_number min; + rtems_status_code rc = RTEMS_SUCCESSFUL; + rtems_device_major_number maj = 0; + rtems_device_minor_number min = 0; + rtems_disk_device *dd = NULL; + bool physical_disk = true; + + rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (rc != RTEMS_SUCCESSFUL) { + return rc; + } + diskdevs_protected = true; - rc = rtems_semaphore_obtain(diskdevs_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - if (rc != RTEMS_SUCCESSFUL) - return rc; - diskdevs_protected = true; + /* Check if we have a physical or logical disk */ + dd = get_disk_entry(dev); + if (dd == NULL) { + return RTEMS_INVALID_NUMBER; + } + physical_disk = dd->phys_dev == dd; + + if (physical_disk) { + unsigned used = 0; /* Check if this device is in use -- calculate usage counter */ - used = 0; - for (maj = 0; maj < disktab_size; maj++) - { - rtems_disk_device_table *dtab = disktab + maj; - if (dtab != NULL) - { - for (min = 0; min < dtab->size; min++) - { - rtems_disk_device *dd = dtab->minor[min]; - if ((dd != NULL) && (dd->phys_dev->dev == dev)) - used += dd->uses; - } + for (maj = 0; maj < disktab_size; maj++) { + rtems_disk_device_table *dtab = disktab + maj; + if (dtab != NULL) { + for (min = 0; min < dtab->size; min++) { + dd = dtab->minor[min]; + if ((dd != NULL) && (dd->phys_dev->dev == dev)) { + used += dd->uses; + } } + } } - if (used != 0) - { - diskdevs_protected = false; - rtems_semaphore_release(diskdevs_mutex); - return RTEMS_RESOURCE_IN_USE; + if (used != 0) { + diskdevs_protected = false; + rtems_semaphore_release(diskdevs_mutex); + return RTEMS_RESOURCE_IN_USE; } /* Delete this device and all of its logical devices */ - for (maj = 0; maj < disktab_size; maj++) - { - rtems_disk_device_table *dtab = disktab +maj; - if (dtab != NULL) - { - for (min = 0; min < dtab->size; min++) - { - rtems_disk_device *dd = dtab->minor[min]; - if ((dd != NULL) && (dd->phys_dev->dev == dev)) - { - unlink(dd->name); - free(dd->name); - free(dd); - dtab->minor[min] = NULL; - } - } + for (maj = 0; maj < disktab_size; maj++) { + rtems_disk_device_table *dtab = disktab + maj; + if (dtab != NULL) { + for (min = 0; min < dtab->size; min++) { + dd = dtab->minor[min]; + if ((dd != NULL) && (dd->phys_dev->dev == dev)) { + unlink(dd->name); + free(dd->name); + free(dd); + dtab->minor[min] = NULL; + } } + } } - - diskdevs_protected = false; - rc = rtems_semaphore_release(diskdevs_mutex); - return rc; + } else { + rtems_filesystem_split_dev_t(dev, maj, min); + disktab[maj].minor[min] = NULL; + unlink(dd->name); + free(dd->name); + free(dd); + } + + diskdevs_protected = false; + rc = rtems_semaphore_release(diskdevs_mutex); + return rc; } -/* rtems_disk_obtain -- - * Find block device descriptor by its device identifier. - * - * PARAMETERS: - * dev - device identifier (major, minor numbers) - * - * RETURNS: - * pointer to the block device descriptor, or NULL if no such device - * exists. - */ rtems_disk_device * rtems_disk_obtain(dev_t dev) { @@ -486,15 +448,6 @@ rtems_disk_obtain(dev_t dev) } } -/* rtems_disk_release -- - * Release rtems_disk_device structure (decrement usage counter to 1). - * - * PARAMETERS: - * dd - pointer to disk device structure - * - * RETURNS: - * RTEMS_SUCCESSFUL - */ rtems_status_code rtems_disk_release(rtems_disk_device *dd) { @@ -505,18 +458,6 @@ rtems_disk_release(rtems_disk_device *dd) return RTEMS_SUCCESSFUL; } -/* rtems_disk_next -- - * Disk device enumerator. Looking for device having device number larger - * than dev and return disk device descriptor for it. If there are no - * such device, NULL value returned. - * - * PARAMETERS: - * dev - device number (use -1 to start search) - * - * RETURNS: - * Pointer to the disk descriptor for next disk device, or NULL if all - * devices enumerated. - */ rtems_disk_device * rtems_disk_next(dev_t dev) { @@ -549,17 +490,6 @@ rtems_disk_next(dev_t dev) } } -/* rtems_disk_initialize -- - * Initialization of disk device library (initialize all data structures, - * etc.) - * - * PARAMETERS: - * none - * - * RETURNS: - * RTEMS_SUCCESSFUL if library initialized, or error code if error - * occured. - */ rtems_status_code rtems_disk_io_initialize(void) { @@ -598,16 +528,6 @@ rtems_disk_io_initialize(void) return RTEMS_SUCCESSFUL; } -/* rtems_disk_io_done -- - * Release all resources allocated for disk device interface. - * - * PARAMETERS: - * none - * - * RETURNS: - * RTEMS_SUCCESSFUL if all resources released, or error code if error - * occured. - */ rtems_status_code rtems_disk_io_done(void) { diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h index b50ff01107..52a611b5f0 100644 --- a/cpukit/sapi/include/confdefs.h +++ b/cpukit/sapi/include/confdefs.h @@ -740,7 +740,7 @@ rtems_fs_init_functions_t rtems_fs_init_helper = rtems_bdbuf_pool_config rtems_bdbuf_pool_configuration[] = { {CONFIGURE_BDBUF_BUFFER_SIZE, CONFIGURE_BDBUF_BUFFER_COUNT, NULL} }; - int rtems_bdbuf_pool_configuration_size = + size_t rtems_bdbuf_pool_configuration_size = (sizeof(rtems_bdbuf_pool_configuration) / sizeof(rtems_bdbuf_pool_configuration[0])); #endif /* CONFIGURE_INIT */ |