Changeset 3899a537 in rtems for cpukit/libblock
- Timestamp:
- 07/29/08 02:21:15 (16 years ago)
- Branches:
- 4.10, 4.11, 4.9, 5, master
- Children:
- c4bd98c
- Parents:
- 1b39f18
- Location:
- cpukit/libblock
- Files:
-
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
cpukit/libblock/Makefile.am
r1b39f18 r3899a537 9 9 noinst_LIBRARIES = libblock.a 10 10 libblock_a_SOURCES = src/bdbuf.c src/blkdev.c src/diskdevs.c src/flashdisk.c \ 11 src/ramdisk.c src/ide_part_table.c src/ show_bdbuf.c src/nvdisk.c \11 src/ramdisk.c src/ide_part_table.c src/nvdisk.c \ 12 12 src/nvdisk-sram.c \ 13 13 include/rtems/bdbuf.h include/rtems/blkdev.h \ -
cpukit/libblock/include/rtems/bdbuf.h
r1b39f18 r3899a537 26 26 #include "rtems/diskdevs.h" 27 27 28 29 /* 30 * To manage buffers we using Buffer Descriptors. 31 * To speed-up buffer lookup descriptors are organized in AVL-Tree. 32 * The fields 'dev' and 'block' are search key. 33 */ 34 35 /* Buffer descriptors 36 * Descriptors organized in AVL-tree to speedup buffer lookup. 37 * dev and block fields are search key in AVL-tree. 38 * Modified buffers, free buffers and used buffers linked in 'mod', 'free' and 39 * 'lru' chains appropriately. 40 */ 41 42 typedef struct bdbuf_buffer { 43 Chain_Node link; /* Link in the lru, mod or free chains */ 44 45 struct bdbuf_avl_node { 46 signed char cache; /* Cache */ 47 48 struct bdbuf_buffer* left; /* Left Child */ 49 struct bdbuf_buffer* right; /* Right Child */ 50 51 signed char bal; /* The balance of the sub-tree */ 52 } avl; 53 54 dev_t dev; /* device number */ 55 blkdev_bnum block; /* block number on the device */ 56 57 unsigned char *buffer; /* Pointer to the buffer memory area */ 58 rtems_status_code status; /* Last I/O operation completion status */ 59 int error; /* If status != RTEMS_SUCCESSFUL, this field contains 60 errno value which can be used by user later */ 61 boolean modified:1; /* =1 if buffer was modified */ 62 boolean in_progress:1; /* =1 if exchange with disk is in progress; 63 need to wait on semaphore */ 64 boolean actual:1; /* Buffer contains actual data */ 65 int use_count; /* Usage counter; incremented when somebody use 66 this buffer; decremented when buffer released 67 without modification or when buffer is flushed 68 by swapout task */ 69 70 rtems_bdpool_id pool; /* Identifier of buffer pool to which this buffer 71 belongs */ 72 CORE_mutex_Control transfer_sema; 73 /* Transfer operation semaphore */ 74 } bdbuf_buffer; 75 76 77 /* 78 * the following data structures are internal to the bdbuf layer, 79 * but it is convenient to have them visible from the outside for inspection 80 */ 81 /* 82 * The groups of the blocks with the same size are collected in the 83 * bd_pool. Note that a several of the buffer's groups with the 84 * same size can exists. 85 */ 86 typedef struct bdbuf_pool 28 /** 29 * State of a buffer in the cache. 30 */ 31 typedef enum 87 32 { 88 bdbuf_buffer *tree; /* Buffer descriptor lookup AVL tree root */ 89 90 Chain_Control free; /* Free buffers list */ 91 Chain_Control lru; /* Last recently used list */ 92 93 int blksize; /* The size of the blocks (in bytes) */ 94 int nblks; /* Number of blocks in this pool */ 95 rtems_id bufget_sema; /* Buffer obtain counting semaphore */ 96 void *mallocd_bufs; /* Pointer to the malloc'd buffer memory, 97 or NULL, if buffer memory provided in 98 buffer configuration */ 99 bdbuf_buffer *bdbufs; /* Pointer to table of buffer descriptors 100 allocated for this buffer pool. */ 101 } bdbuf_pool; 102 103 /* Buffering layer context definition */ 104 struct bdbuf_context { 105 bdbuf_pool *pool; /* Table of buffer pools */ 106 int npools; /* Number of entries in pool table */ 107 108 Chain_Control mod; /* Modified buffers list */ 109 rtems_id flush_sema; /* Buffer flush semaphore; counting 110 semaphore; incremented when buffer 111 flushed to the disk; decremented when 112 buffer modified */ 113 rtems_id swapout_task; /* Swapout task ID */ 114 }; 115 /* 116 * the context of the buffering layer, visible for inspection 117 */ 118 extern struct bdbuf_context rtems_bdbuf_ctx; 119 120 /* bdbuf_config structure describes block configuration (size, 121 * amount, memory location) for buffering layer 33 RTEMS_BDBUF_STATE_EMPTY = 0, /* Not in use. */ 34 RTEMS_BDBUF_STATE_READ_AHEAD = 1, /* Holds read ahead data only */ 35 RTEMS_BDBUF_STATE_CACHED = 2, /* In the cache and available */ 36 RTEMS_BDBUF_STATE_ACCESS = 3, /* The user has the buffer */ 37 RTEMS_BDBUF_STATE_MODIFIED = 4, /* In the cache but modified */ 38 RTEMS_BDBUF_STATE_ACCESS_MODIFIED = 5, /* With the user but modified */ 39 RTEMS_BDBUF_STATE_SYNC = 6, /* Requested to be sync'ed */ 40 RTEMS_BDBUF_STATE_TRANSFER = 7 /* Being transferred to or from disk */ 41 } rtems_bdbuf_buf_state; 42 43 /** 44 * To manage buffers we using buffer descriptors (BD). A BD holds a buffer plus 45 * a range of other information related to managing the buffer in the cache. To 46 * speed-up buffer lookup descriptors are organized in AVL-Tree. The fields 47 * 'dev' and 'block' are search keys. 48 */ 49 typedef struct rtems_bdbuf_buffer 50 { 51 rtems_chain_node link; /* Link in the BD onto a number of lists. */ 52 53 struct rtems_bdbuf_avl_node 54 { 55 signed char cache; /* Cache */ 56 struct rtems_bdbuf_buffer* left; /* Left Child */ 57 struct rtems_bdbuf_buffer* right; /* Right Child */ 58 signed char bal; /* The balance of the sub-tree */ 59 } avl; 60 61 dev_t dev; /* device number */ 62 rtems_blkdev_bnum block; /* block number on the device */ 63 64 unsigned char* buffer; /* Pointer to the buffer memory area */ 65 int error; /* If not 0 indicate an error value (errno) 66 * which can be used by user later */ 67 68 volatile rtems_bdbuf_buf_state state; /* State of the buffer. */ 69 70 volatile uint32_t waiters; /* The number of threads waiting on this 71 * buffer. */ 72 rtems_bdpool_id pool; /* Identifier of buffer pool to which this buffer 73 belongs */ 74 75 volatile uint32_t hold_timer; /* Timer to indicate how long a buffer 76 * has been held in the cache modified. */ 77 } rtems_bdbuf_buffer; 78 79 /** 80 * The groups of the blocks with the same size are collected in a pool. Note 81 * that a several of the buffer's groups with the same size can exists. 82 */ 83 typedef struct rtems_bdbuf_pool 84 { 85 int blksize; /* The size of the blocks (in bytes) */ 86 int nblks; /* Number of blocks in this pool */ 87 88 uint32_t flags; /* Configuration flags */ 89 90 rtems_id lock; /* The pool lock. Lock this data and 91 * all BDs. */ 92 rtems_id sync_lock; /* Sync calls lock writes. */ 93 boolean sync_active; /* True if a sync is active. */ 94 rtems_id sync_requester; /* The sync requester. */ 95 dev_t sync_device; /* The device to sync */ 96 97 rtems_bdbuf_buffer* tree; /* Buffer descriptor lookup AVL tree 98 * root */ 99 rtems_chain_control ready; /* Free buffers list (or read-ahead) */ 100 rtems_chain_control lru; /* Last recently used list */ 101 rtems_chain_control modified; /* Modified buffers list */ 102 rtems_chain_control sync; /* Buffers to sync list */ 103 104 rtems_id access; /* Obtain if waiting for a buffer in the 105 * ACCESS state. */ 106 volatile uint32_t access_waiters; /* Count of access blockers. */ 107 rtems_id transfer; /* Obtain if waiting for a buffer in the 108 * TRANSFER state. */ 109 volatile uint32_t transfer_waiters; /* Count of transfer blockers. */ 110 rtems_id waiting; /* Obtain if waiting for a buffer and the 111 * none are available. */ 112 volatile uint32_t wait_waiters; /* Count of waiting blockers. */ 113 114 rtems_bdbuf_buffer* bds; /* Pointer to table of buffer descriptors 115 * allocated for this buffer pool. */ 116 void* buffers; /* The buffer's memory. */ 117 } rtems_bdbuf_pool; 118 119 /** 120 * Configuration structure describes block configuration (size, amount, memory 121 * location) for buffering layer pool. 122 */ 123 typedef struct rtems_bdbuf_pool_config { 124 int size; /* Size of block */ 125 int num; /* Number of blocks of appropriate size */ 126 unsigned char* mem_area; /* Pointer to the blocks location or NULL, in this 127 * case memory for blocks will be allocated by 128 * Buffering Layer with the help of RTEMS partition 129 * manager */ 130 } rtems_bdbuf_pool_config; 131 132 /** 133 * External references provided by the user for each pool in the system. 134 */ 135 extern rtems_bdbuf_pool_config rtems_bdbuf_pool_configuration[]; 136 extern int rtems_bdbuf_pool_configuration_size; 137 138 /** 139 * Buffering configuration definition. See confdefs.h for support on using this 140 * structure. 122 141 */ 123 142 typedef struct rtems_bdbuf_config { 124 int size; /* Size of block */ 125 int num; /* Number of blocks of appropriate size */ 126 unsigned char *mem_area; 127 /* Pointer to the blocks location or NULL, in this 128 case memory for blocks will be allocated by 129 Buffering Layer with the help of RTEMS partition 130 manager */ 143 int max_read_ahead_blocks; /*<< Number of blocks to read ahead. */ 144 int max_write_blocks; /*<< Number of blocks to write at once. */ 145 rtems_task_priority swapout_priority; /*<< Priority of the swap out task. */ 146 uint32_t swapout_period; /*<< Period swapout checks buf timers. */ 147 uint32_t swap_block_hold; /*<< Period a buffer is held. */ 131 148 } rtems_bdbuf_config; 132 149 133 extern rtems_bdbuf_config rtems_bdbuf_configuration[]; 134 extern int rtems_bdbuf_configuration_size; 135 136 #define SWAPOUT_TASK_DEFAULT_PRIORITY 15 137 extern rtems_task_priority swapout_task_priority; 150 /** 151 * External referernce to the configuration. The configuration is provided by 152 * the user. 153 */ 154 extern rtems_bdbuf_config rtems_bdbuf_configuration; 155 156 /** 157 * The max_read_ahead_blocks value is altered if there are fewer buffers 158 * than this defined max. This stops thrashing in the cache. 159 */ 160 #define RTEMS_BDBUF_MAX_READ_AHEAD_BLOCKS_DEFAULT 32 161 #define RTEMS_BDBUF_MAX_WRITE_BLOCKS_DEFAULT 16 162 #define RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT 15 163 #define RTEMS_BDBUF_SWAPOUT_TASK_SWAP_PERIOD_DEFAULT 250 /* milli-seconds */ 164 #define RTEMS_BDBUF_SWAPOUT_TASK_BLOCK_HOLD_DEFAULT 1000 /* milli-seconds */ 138 165 139 166 /* rtems_bdbuf_init -- … … 144 171 * free elements lists. 145 172 * 146 * PARAMETERS:147 * conf_table - pointer to the buffers configuration table148 * size - number of entries in configuration table149 *150 173 * RETURNS: 151 174 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully … … 153 176 */ 154 177 rtems_status_code 155 rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size); 156 178 rtems_bdbuf_init (); 157 179 158 180 /* rtems_bdbuf_get -- … … 178 200 * bufget_sema semaphore obtained by this primitive. 179 201 */ 180 rtems_status_code181 rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr);202 rtems_status_code 203 rtems_bdbuf_get(dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd); 182 204 183 205 /* rtems_bdbuf_read -- … … 202 224 * bufget_sema and transfer_sema semaphores obtained by this primitive. 203 225 */ 204 rtems_status_code205 rtems_bdbuf_read(dev_t device, blkdev_bnum block, bdbuf_buffer **bdb_ptr);226 rtems_status_code 227 rtems_bdbuf_read(dev_t device, rtems_blkdev_bnum block, rtems_bdbuf_buffer** bd); 206 228 207 229 /* rtems_bdbuf_release -- … … 224 246 * flush_sema and bufget_sema semaphores may be released by this primitive. 225 247 */ 226 rtems_status_code227 rtems_bdbuf_release(bdbuf_buffer *bd_buf);248 rtems_status_code 249 rtems_bdbuf_release(rtems_bdbuf_buffer* bd); 228 250 229 251 /* rtems_bdbuf_release_modified -- … … 245 267 * flush_sema semaphore may be released by this primitive. 246 268 */ 247 rtems_status_code248 rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf);269 rtems_status_code 270 rtems_bdbuf_release_modified(rtems_bdbuf_buffer* bd); 249 271 250 272 /* rtems_bdbuf_sync -- … … 266 288 * Primitive may be blocked on transfer_sema semaphore. 267 289 */ 268 rtems_status_code269 rtems_bdbuf_sync(bdbuf_buffer *bd_buf);290 rtems_status_code 291 rtems_bdbuf_sync(rtems_bdbuf_buffer* bd); 270 292 271 293 /* rtems_bdbuf_syncdev -- … … 280 302 * or error code if error is occured) 281 303 */ 282 rtems_status_code283 rtems_bdbuf_syncdev(dev_t dev);304 rtems_status_code 305 rtems_bdbuf_syncdev(dev_t dev); 284 306 285 307 /* rtems_bdbuf_find_pool -- … … 298 320 * is not configured. 299 321 */ 300 rtems_status_code301 rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool);322 rtems_status_code 323 rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool); 302 324 303 325 /* rtems_bdbuf_get_pool_info -- … … 317 339 * Buffer pools enumerated contiguously starting from 0. 318 340 */ 319 rtems_status_code320 rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, int *blocks);341 rtems_status_code 342 rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, int *blocks); 321 343 322 344 #ifdef __cplusplus -
cpukit/libblock/include/rtems/blkdev.h
r1b39f18 r3899a537 21 21 #endif 22 22 23 /* Interface with device drivers24 * Block device looks, initialized and behaves like traditional RTEMS device25 * driver. Heart of the block device driver is in BIOREQUEST ioctl. This call26 * puts I/O request to the block device queue, in priority order, for27 * asynchronous processing. When driver executes request, req_done28 * function invoked, so callee knows about it. Look for details below.23 /* 24 * Interface with device drivers Block device looks, initialized and behaves 25 * like traditional RTEMS device driver. Heart of the block device driver is in 26 * BIOREQUEST ioctl. This call puts I/O request to the block device queue, in 27 * priority order, for asynchronous processing. When driver executes request, 28 * req_done function invoked, so callee knows about it. Look for details below. 29 29 */ 30 30 31 32 /* Block device block number datatype */ 33 typedef uint32_t blkdev_bnum; 31 /* 32 * Block device block number datatype 33 */ 34 typedef uint32_t rtems_blkdev_bnum; 34 35 35 36 /* Block device request type */ 36 typedef enum blkdev_request_op { 37 BLKDEV_REQ_READ, /* Read operation */ 38 BLKDEV_REQ_WRITE /* Write operation */ 39 } blkdev_request_op; 37 typedef enum rtems_blkdev_request_op { 38 RTEMS_BLKDEV_REQ_READ, /* Read operation */ 39 RTEMS_BLKDEV_REQ_WRITE, /* Write operation */ 40 RTEMS_BLKDEV_CAPABILITIES /* Capabilities request */ 41 } rtems_blkdev_request_op; 40 42 41 /* Type for block device request done callback function. 43 /** 44 * ATA multi-sector buffer requests only supported. This option 45 * means the cache will only supply multiple buffers that are 46 * inorder so the ATA multi-sector command can be used. This is a 47 * hack to work around the current ATA driver. 48 */ 49 #define RTEMS_BLKDEV_CAP_MULTISECTOR_CONT (1 << 0) 50 51 /* 52 * @typedef rtems_blkdev_request_cb 42 53 * 43 * PARAMETERS: 44 * arg - argument supplied in blkdev_request 45 * status - rtems status code for this operation 46 * errno - errno value to be passed to the user when 54 * Type for block device request done callback function. 55 * 56 * @param arg Argument supplied in blkdev_request 57 * @param status RTEMS status code for this operation 58 * @param errno errno value to be passed to the user when 47 59 * status != RTEMS_SUCCESSFUL 48 60 */ 49 typedef void (* blkdev_request_cb)(void *arg,50 rtems_status_code status,51 int error);61 typedef void (* rtems_blkdev_request_cb)(void *arg, 62 rtems_status_code status, 63 int error); 52 64 53 /* blkdev_sg_buffer 65 /** 66 * @struct rtems_blkdev_sg_buffer 54 67 * Block device scatter/gather buffer structure 55 68 */ 56 typedef struct blkdev_sg_buffer { 69 typedef struct rtems_blkdev_sg_buffer { 70 uint32_t block; /* The block number */ 57 71 uint32_t length; /* Buffer length */ 58 void *buffer; /* Buffer pointer */ 59 } blkdev_sg_buffer; 72 void *buffer; /* Buffer pointer */ 73 void *user; /* User pointer */ 74 } rtems_blkdev_sg_buffer; 60 75 61 76 /* blkdev_request (Block Device Request) structure is 62 77 * used to read/write a number of blocks from/to device. 63 78 */ 64 typedef struct blkdev_request { 65 blkdev_request_op req; /* Block device operation (read or write) */ 66 blkdev_request_cb req_done; /* Callback function */ 67 void *done_arg; /* Argument to be passed to callback function*/ 68 rtems_status_code status; /* Last I/O operation completion status */ 69 int error; /* If status != RTEMS_SUCCESSFUL, this field 70 * contains error code 71 */ 72 blkdev_bnum start; /* Start block number */ 73 uint32_t count; /* Number of blocks to be exchanged */ 74 uint32_t bufnum; /* Number of buffers provided */ 79 typedef struct rtems_blkdev_request { 80 /* Block device operation (read or write) */ 81 rtems_blkdev_request_op req; 82 /* Callback function */ 83 rtems_blkdev_request_cb req_done; 84 /* Argument to be passed to callback function*/ 85 void *done_arg; 86 /* Last I/O operation completion status */ 87 rtems_status_code status; 88 /* If status != RTEMS_SUCCESSFUL, this field contains error code */ 89 int error; 90 /* Start block number */ 91 rtems_blkdev_bnum start; 92 /* Number of blocks to be exchanged */ 93 uint32_t count; 94 /* Number of buffers provided */ 95 uint32_t bufnum; 75 96 76 blkdev_sg_buffer bufs[0];/* List of scatter/gather buffers */ 77 } blkdev_request; 97 /* The task requesting the IO operation. */ 98 rtems_id io_task; 99 100 /* List of scatter/gather buffers */ 101 rtems_blkdev_sg_buffer bufs[0]; 102 } rtems_blkdev_request; 78 103 79 104 /* Block device IOCTL request codes */ 80 #define BLKIO_REQUEST _IOWR('B', 1,blkdev_request)81 #define BLKIO_GETBLKSIZE _IO('B', 2)82 #define BLKIO_GETSIZE _IO('B', 3)83 #define BLKIO_SYNCDEV _IO('B', 4)105 #define RTEMS_BLKIO_REQUEST _IOWR('B', 1, rtems_blkdev_request) 106 #define RTEMS_BLKIO_GETBLKSIZE _IO('B', 2) 107 #define RTEMS_BLKIO_GETSIZE _IO('B', 3) 108 #define RTEMS_BLKIO_SYNCDEV _IO('B', 4) 84 109 85 110 /* Device driver interface conventions suppose that driver may … … 91 116 */ 92 117 93 #define GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES \118 #define RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES \ 94 119 rtems_blkdev_generic_open, rtems_blkdev_generic_close, \ 95 120 rtems_blkdev_generic_read, rtems_blkdev_generic_write, \ -
cpukit/libblock/include/rtems/diskdevs.h
r1b39f18 r3899a537 22 22 #include <stdlib.h> 23 23 24 #include "rtems/blkdev.h"25 26 24 /* Buffer pool identifier */ 27 25 typedef int rtems_bdpool_id; 28 26 27 #include "rtems/blkdev.h" 28 29 /* Driver capabilities. */ 30 29 31 /* Block device ioctl handler */ 30 typedef int (* block_device_ioctl) (dev_t dev, uint32_t req, void *argp);31 32 /* disk_device: Entry of this type created for every disk device (both for33 * logical and physical disks).32 typedef int (* rtems_block_device_ioctl) (dev_t dev, uint32_t req, void *argp); 33 34 /* rtems_disk_device: Entry of this type created for every disk device 35 * (both for logical and physical disks). 34 36 * Array of arrays of pointers to disk_device structures maintained. First 35 37 * table indexed by major number and second table indexed by minor number. … … 37 39 * moderated size. 38 40 */ 39 typedef struct disk_device { 40 dev_t dev; /* Device ID (major + minor) */ 41 struct disk_device *phys_dev; /* Physical device ID (the same 42 as dev if this entry specifies 43 the physical device) */ 44 char *name; /* Disk device name */ 45 int uses; /* Use counter. Device couldn't be 46 removed if it is in use. */ 47 int start; /* Starting block number (0 for 48 physical devices, block offset 49 on the related physical device 50 for logical device) */ 51 int size; /* Size of physical or logical disk 52 in disk blocks */ 53 int block_size; /* Size of device block (minimum 54 transfer unit) in bytes 55 (must be power of 2) */ 56 int block_size_log2; /* log2 of block_size */ 57 rtems_bdpool_id pool; /* Buffer pool assigned to this 58 device */ 59 block_device_ioctl ioctl; /* ioctl handler for this block 60 device */ 61 } disk_device; 41 typedef struct rtems_disk_device { 42 dev_t dev; /* Device ID (major + minor) */ 43 struct rtems_disk_device *phys_dev; /* Physical device ID (the same 44 as dev if this entry specifies 45 the physical device) */ 46 uint32_t capabilities; /* Driver capabilities. */ 47 char *name; /* Disk device name */ 48 int uses; /* Use counter. Device couldn't be 49 removed if it is in use. */ 50 int start; /* Starting block number (0 for 51 physical devices, block offset 52 on the related physical device 53 for logical device) */ 54 int size; /* Size of physical or logical disk 55 in disk blocks */ 56 int block_size; /* Size of device block (minimum 57 transfer unit) in bytes 58 (must be power of 2) */ 59 int block_size_log2; /* log2 of block_size */ 60 rtems_bdpool_id pool; /* Buffer pool assigned to this 61 device */ 62 rtems_block_device_ioctl ioctl; /* ioctl handler for this block 63 device */ 64 } rtems_disk_device; 62 65 63 66 /* rtems_disk_create_phys -- … … 85 88 rtems_status_code 86 89 rtems_disk_create_phys(dev_t dev, int block_size, int disk_size, 87 block_device_ioctl handler,90 rtems_block_device_ioctl handler, 88 91 const char *name); 89 92 … … 132 135 rtems_disk_delete(dev_t dev); 133 136 134 /* rtems_disk_ lookup--137 /* rtems_disk_obtain -- 135 138 * Find block device descriptor by its device identifier. This function 136 139 * increment usage counter to 1. User should release disk_device structure … … 144 147 * exists. 145 148 */ 146 disk_device *147 rtems_disk_ lookup(dev_t dev);149 rtems_disk_device * 150 rtems_disk_obtain(dev_t dev); 148 151 149 152 /* rtems_disk_release -- … … 160 163 */ 161 164 rtems_status_code 162 rtems_disk_release( disk_device *dd);165 rtems_disk_release(rtems_disk_device *dd); 163 166 164 167 /* rtems_disk_next -- … … 173 176 * Pointer to the disk descriptor for next disk device, or NULL if all 174 177 * devices enumerated. */ 175 disk_device *178 rtems_disk_device * 176 179 rtems_disk_next(dev_t dev); 177 180 -
cpukit/libblock/include/rtems/ide_part_table.h
r1b39f18 r3899a537 78 78 * corresponds to the sector on the device 79 79 */ 80 typedef struct sector_data_s80 typedef struct rtems_sector_data_s 81 81 { 82 82 uint32_t sector_num; /* sector number on the device */ 83 83 uint8_t data[0]; /* raw sector data */ 84 } sector_data_t;84 } rtems_sector_data_t; 85 85 86 86 … … 88 88 * Enum partition types 89 89 * see list at http://ata-atapi.com/hiwtab.htm 90 * 91 * @todo Should these have RTEMS before them. 90 92 */ 91 93 enum { … … 109 111 110 112 /* Forward declaration */ 111 struct disk_desc_s;113 struct rtems_disk_desc_s; 112 114 113 115 /* … … 115 117 * contains all neccessary information about partition 116 118 */ 117 typedef struct part_desc_s {119 typedef struct rtems_part_desc_s { 118 120 uint8_t bootable; /* is the partition active */ 119 121 uint8_t sys_type; /* type of partition */ 120 122 uint8_t log_id; /* logical number of partition */ 121 uint32_t start; /* first partition sector, in absolute numeration */ 123 uint32_t start; /* first partition sector, in absolute 124 * numeration */ 122 125 uint32_t size; /* size in sectors */ 123 126 uint32_t end; /* last partition sector, end = start + size - 1 */ 124 struct disk_desc_s *disk_desc; /* descriptor of disk, partition contains in */ 125 struct part_desc_s *ext_part; /* extended partition containing this one */ 127 struct rtems_disk_desc_s *disk_desc; /* descriptor of disk, partition 128 * contains in */ 129 struct rtems_part_desc_s *ext_part; /* extended partition containing this 130 * one */ 126 131 127 132 /* partitions, containing in this one */ 128 struct part_desc_s *sub_part[RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER];129 } part_desc_t;130 131 132 133 typedef struct disk_desc_s {133 struct rtems_part_desc_s *sub_part[RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER]; 134 } rtems_part_desc_t; 135 136 137 138 typedef struct rtems_disk_desc_s { 134 139 dev_t dev; /* device number */ 135 140 … … 143 148 144 149 /* primary partition descriptors */ 145 part_desc_t *partitions[RTEMS_IDE_PARTITION_MAX_PARTITION_NUMBER];146 } disk_desc_t;150 rtems_part_desc_t *partitions[RTEMS_IDE_PARTITION_MAX_PARTITION_NUMBER]; 151 } rtems_disk_desc_t; 147 152 148 153 #ifdef __cplusplus … … 161 166 */ 162 167 void 163 rtems_ide_part_table_free( disk_desc_t *disk_desc);168 rtems_ide_part_table_free(rtems_disk_desc_t *disk_desc); 164 169 165 170 … … 177 182 */ 178 183 rtems_status_code 179 rtems_ide_part_table_get(const char *dev_name, disk_desc_t *disk_desc);184 rtems_ide_part_table_get(const char *dev_name, rtems_disk_desc_t *disk_desc); 180 185 181 186 -
cpukit/libblock/include/rtems/nvdisk.h
r1b39f18 r3899a537 165 165 uint32_t flags; /**< Set of flags to control 166 166 driver. */ 167 uint32_t info_level; /**< Default info level. */167 uint32_t info_level; /**< Default info level. */ 168 168 } rtems_nvdisk_config; 169 169 -
cpukit/libblock/include/rtems/ramdisk.h
r1b39f18 r3899a537 48 48 49 49 #define RAMDISK_DRIVER_TABLE_ENTRY \ 50 { ramdisk_initialize, GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES }50 { ramdisk_initialize, RTEMS_GENERIC_BLOCK_DEVICE_DRIVER_ENTRIES } 51 51 52 52 #ifdef __cplusplus -
cpukit/libblock/src/bdbuf.c
r1b39f18 r3899a537 11 11 */ 12 12 13 /** 14 * @file 15 * 16 * The Buffer Descriptor Buffer code implement a cache between the disk 17 * devices and file systems. The code provides a read ahead and qrite queuing 18 * to the drivers and fast cache look up using an AVL tree. 19 * 20 * The buffers are held in pools based on size. Each pool has buffers and the 21 * buffers follow this state machine: 22 * 23 * read 24 * +-------------------------------+ 25 * | v 26 * +-----------+ read complete +------------+ 27 * | | write complete | |---------+ 28 * | EMPTY | +---------| TRANSFER | | 29 * | | | | |<--+ | 30 * +-----------+ | +------------+ | | 31 * ^ | get v swap | | 32 * | | +-----------+ modified +------------+ | 33 * | +--->| |---------->| | | 34 * | | ACCESSED |<----------| MODIFIED | | 35 * | +----| |<--+ get | | | 36 * | | +-----------+ | +------------+ | 37 * | | | | 38 * | | release get | | 39 * | | | | 40 * | | +-----------+ | | 41 * expire | +--->| |---+ read complete | 42 * | | CACHED | write complete | 43 * +--------| |<-------------------------+ 44 * +-----------+ 45 * 46 * Empty buffers are added to the empty list and removed from this queue when a 47 * caller wishes to access a buffer. This is referred to getting a buffer in 48 * the code and the event get in the state diagram. The buffer is assigned to a 49 * block and inserted to the AVL. If the block is to be read by the user and 50 * not in the cache (empty) it is transfered from the disk into memory. If no 51 * empty buffers exist the buffer is expired from the cache. Currently the 52 * least recently used block is expired first. A block being accessed is given 53 * to the file system layer and not accessable to another requester until 54 * released back to the cache. If the user has modifed the block it is 55 * transfered to disk then placed on the LRU list. 56 * 57 * The pool have the following lists of buffers: 58 * 59 * empty - Empty buffers created when the pool is initialised. 60 * modided - Buffers waiting to be written to disk. 61 * cached_lru - Accessed buffers released in least recently used order. 62 * cached_unsed - Read ahead buffers that have not been accessed. 63 * 64 */ 65 66 /** 67 * Set to 1 to enable debug tracing. 68 */ 69 #define RTEMS_BDBUF_TRACE 0 70 13 71 #if HAVE_CONFIG_H 14 72 #include "config.h" 15 73 #endif 16 74 17 #define __RTEMS_VIOLATE_KERNEL_VISIBILITY__18 75 #include <rtems.h> 76 #include <rtems/error.h> 19 77 #include <limits.h> 20 78 #include <errno.h> 21 79 #include <assert.h> 22 80 81 #if RTEMS_BDBUF_TRACE 82 #include <stdio.h> 83 #endif 84 23 85 #include "rtems/bdbuf.h" 24 86 25 /* Fatal errors: */ 26 #define BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) | ((uint32_t)(n) & (uint32_t)0x00FFFFFF)) 27 #define BLKDEV_FATAL_BDBUF_CONSISTENCY BLKDEV_FATAL_ERROR(1) 28 #define BLKDEV_FATAL_BDBUF_SWAPOUT BLKDEV_FATAL_ERROR(2) 29 30 31 #define SWAPOUT_TASK_STACK_SIZE (RTEMS_MINIMUM_STACK_SIZE * 2) 32 33 #define READ_MULTIPLE 34 35 #if defined(READ_MULTIPLE) 36 #define READ_AHEAD_MAX_BLK_CNT 32 37 typedef struct { 38 blkdev_request req; 39 blkdev_sg_buffer sg[READ_AHEAD_MAX_BLK_CNT]; 40 } blkdev_request_read_ahead; 87 /** 88 * The BD buffer context. 89 */ 90 /* Buffering layer context definition */ 91 typedef struct rtems_bdbuf_context { 92 rtems_bdbuf_pool* pool; /* Table of buffer pools */ 93 int npools; /* Number of entries in pool table */ 94 rtems_id swapout; /* Swapout task ID */ 95 boolean swapout_enabled; 96 } rtems_bdbuf_context; 97 98 /** 99 * Fatal errors 100 */ 101 #define RTEMS_BLKDEV_FATAL_ERROR(n) (((uint32_t)'B' << 24) | \ 102 ((uint32_t)(n) & (uint32_t)0x00FFFFFF)) 103 104 #define RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY RTEMS_BLKDEV_FATAL_ERROR(1) 105 #define RTEMS_BLKDEV_FATAL_BDBUF_SWAPOUT RTEMS_BLKDEV_FATAL_ERROR(2) 106 #define RTEMS_BLKDEV_FATAL_BDBUF_SYNC_LOCK RTEMS_BLKDEV_FATAL_ERROR(3) 107 #define RTEMS_BLKDEV_FATAL_BDBUF_SYNC_UNLOCK RTEMS_BLKDEV_FATAL_ERROR(4) 108 #define RTEMS_BLKDEV_FATAL_BDBUF_POOL_LOCK RTEMS_BLKDEV_FATAL_ERROR(5) 109 #define RTEMS_BLKDEV_FATAL_BDBUF_POOL_UNLOCK RTEMS_BLKDEV_FATAL_ERROR(6) 110 #define RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT RTEMS_BLKDEV_FATAL_ERROR(7) 111 #define RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAKE RTEMS_BLKDEV_FATAL_ERROR(8) 112 #define RTEMS_BLKDEV_FATAL_BDBUF_SO_WAKE RTEMS_BLKDEV_FATAL_ERROR(9) 113 #define RTEMS_BLKDEV_FATAL_BDBUF_SO_NOMEM RTEMS_BLKDEV_FATAL_ERROR(10) 114 #define BLKDEV_FATAL_BDBUF_SWAPOUT_RE RTEMS_BLKDEV_FATAL_ERROR(11) 115 #define BLKDEV_FATAL_BDBUF_SWAPOUT_TS RTEMS_BLKDEV_FATAL_ERROR(12) 116 117 #define RTEMS_BDBUF_TRANSFER_SYNC RTEMS_EVENT_1 118 #define RTEMS_BDBUF_SWAPOUT_SYNC RTEMS_EVENT_2 119 120 #define SWAPOUT_TASK_STACK_SIZE (8 * 1024) 121 122 /** 123 * Lock semaphore attributes. This is used for locking type mutexes. 124 */ 125 #define RTEMS_BDBUF_POOL_LOCK_ATTRIBS \ 126 (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \ 127 RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL) 128 129 /** 130 * Waiter semaphore attributes. 131 * 132 * @note Do not configure as inherit priority. If a driver is in the driver 133 * initialisation table this locked semaphore will have the IDLE task as 134 * the holder and a blocking task will raise the priority of the IDLE 135 * task which can cause unsual side effects. 136 */ 137 #define RTEMS_BDBUF_POOL_WAITER_ATTRIBS \ 138 (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | \ 139 RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL) 140 41 141 /* 42 * list of bd_bufs related to one transfer request 43 */ 44 typedef struct { 45 int cnt; 46 bdbuf_buffer *bd_bufs[READ_AHEAD_MAX_BLK_CNT]; 47 } read_ahead_bd_buf_group; 142 * The swap out task. 143 */ 144 static rtems_task rtems_bdbuf_swapout_task(rtems_task_argument arg); 145 146 /** 147 * The context of buffering layer. 148 */ 149 static rtems_bdbuf_context rtems_bdbuf_ctx; 150 151 /** 152 * Print a message to the bdbuf trace output and flush it. 153 * 154 * @param format The format string. See printf for details. 155 * @param ... The arguments for the format text. 156 * @return int The number of bytes written to the output. 157 */ 158 #if RTEMS_BDBUF_TRACE 159 boolean rtems_bdbuf_tracer; 160 static void 161 rtems_bdbuf_printf (const char *format, ...) 162 { 163 va_list args; 164 va_start (args, format); 165 if (rtems_bdbuf_tracer) 166 { 167 fprintf (stdout, "bdbuf:"); 168 vfprintf (stdout, format, args); 169 fflush (stdout); 170 } 171 } 48 172 #endif 49 173 50 typedef struct { 51 blkdev_request *req; 52 bdbuf_buffer **write_store; 53 } write_tfer_done_arg_t; 54 55 static rtems_task bdbuf_swapout_task(rtems_task_argument unused); 56 57 static rtems_status_code bdbuf_release(bdbuf_buffer *bd_buf); 58 /* 59 * maximum number of blocks that might be chained together to one 60 * write driver call 61 */ 62 #define SWAP_OUT_MAX_BLK_CNT 32 63 /*#define SWAP_OUT_MAX_BLK_CNT 1 */ 64 /* 65 * XXX: this is a global buffer. It is used in the swapout task 66 * and currently will be reused only after it is no longer in use 67 * 68 */ 69 static bdbuf_buffer *bd_buf_write_store[SWAP_OUT_MAX_BLK_CNT]; 70 71 /* Block device request with a single buffer provided */ 72 typedef struct blkdev_request1 { 73 blkdev_request req; 74 blkdev_sg_buffer sg[1]; 75 } blkdev_request1; 76 77 /* The context of buffering layer */ 78 struct bdbuf_context rtems_bdbuf_ctx; 79 80 #define SAFE 81 #ifdef SAFE 82 typedef rtems_mode preemption_key; 83 84 #define DISABLE_PREEMPTION(key) \ 85 do { \ 86 rtems_task_mode(RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &(key)); \ 87 } while (0) 88 89 #define ENABLE_PREEMPTION(key) \ 90 do { \ 91 rtems_mode temp; \ 92 rtems_task_mode((key), RTEMS_PREEMPT_MASK, &temp); \ 93 } while (0) 94 95 #else 96 97 typedef boolean preemption_key; 98 99 #define DISABLE_PREEMPTION(key) \ 100 do { \ 101 (key) = _Thread_Executing->is_preemptible; \ 102 _Thread_Executing->is_preemptible = 0; \ 103 } while (0) 104 105 #define ENABLE_PREEMPTION(key) \ 106 do { \ 107 _Thread_Executing->is_preemptible = (key); \ 108 if (_Thread_Evaluate_mode()) \ 109 _Thread_Dispatch(); \ 110 } while (0) 111 174 /** 175 * The default maximum height of 32 allows for AVL trees having between 176 * 5,704,880 and 4,294,967,295 nodes, depending on order of insertion. You may 177 * change this compile-time constant as you wish. 178 */ 179 #ifndef RTEMS_BDBUF_AVL_MAX_HEIGHT 180 #define RTEMS_BDBUF_AVL_MAX_HEIGHT (32) 112 181 #endif 113 182 114 115 /* The default maximum height of 32 allows for AVL trees having 116 between 5,704,880 and 4,294,967,295 nodes, depending on order of 117 insertion. You may change this compile-time constant as you 118 wish. */ 119 #ifndef AVL_MAX_HEIGHT 120 #define AVL_MAX_HEIGHT 32 183 /** 184 * Searches for the node with specified dev/block. 185 * 186 * @param root pointer to the root node of the AVL-Tree 187 * @param dev device search key 188 * @param block block search key 189 * @retval NULL node with the specified dev/block is not found 190 * @return pointer to the node with specified dev/block 191 */ 192 static rtems_bdbuf_buffer * 193 rtems_bdbuf_avl_search (rtems_bdbuf_buffer** root, 194 dev_t dev, 195 rtems_blkdev_bnum block) 196 { 197 rtems_bdbuf_buffer* p = *root; 198 199 while ((p != NULL) && ((p->dev != dev) || (p->block != block))) 200 { 201 if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) 202 { 203 p = p->avl.right; 204 } 205 else 206 { 207 p = p->avl.left; 208 } 209 } 210 211 return p; 212 } 213 214 #if CCJ_REMOVE_IN_IN_CVS 215 /** 216 * Search in AVL tree for first modified buffer belongs to specified 217 * disk device. 218 * 219 * @param root pointer to the root node of the AVL-Tree 220 * @param dd - disk device descriptor 221 * @retval NULL no modified blocks on the disk device 222 * @return pointer to the modified node 223 */ 224 static rtems_bdbuf_buffer * 225 rtems_bdbuf_avl_search_for_sync (rtems_bdbuf_buffer** root, 226 rtems_disk_device* dd) 227 { 228 dev_t dev = dd->phys_dev->dev; 229 rtems_blkdev_bnum block_start = dd->start; 230 rtems_blkdev_bnum block_end = dd->start + dd->size - 1; 231 rtems_bdbuf_buffer* buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT]; 232 rtems_bdbuf_buffer** buf_prev = buf_stack; 233 rtems_bdbuf_buffer* p = *root; 234 235 while (p != NULL) 236 { 237 if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start))) 238 { 239 p = p->avl.right; 240 } 241 else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end))) 242 { 243 p = p->avl.left; 244 } 245 else if (p->state == RTEMS_BDBUF_STATE_MODIFIED) 246 { 247 return p; 248 } 249 else 250 { 251 if (p->avl.right != NULL) 252 { 253 *buf_prev++ = p->avl.right; 254 } 255 p = p->avl.left; 256 } 257 258 if ((p == NULL) && (buf_prev > buf_stack)) 259 { 260 p = *--buf_prev; 261 } 262 } 263 264 return p; 265 } 121 266 #endif 122 267 123 /* 124 * avl_search -- 125 * Searches for the node with specified dev/block. 268 /** 269 * Inserts the specified node to the AVl-Tree. 270 * 271 * @param root pointer to the root node of the AVL-Tree 272 * @param node Pointer to the node to add. 273 * @retval 0 The node added successfully 274 * @retval -1 An error occured 275 */ 276 static int 277 rtems_bdbuf_avl_insert(rtems_bdbuf_buffer** root, 278 rtems_bdbuf_buffer* node) 279 { 280 dev_t dev = node->dev; 281 rtems_blkdev_bnum block = node->block; 282 283 rtems_bdbuf_buffer* p = *root; 284 rtems_bdbuf_buffer* q; 285 rtems_bdbuf_buffer* p1; 286 rtems_bdbuf_buffer* p2; 287 rtems_bdbuf_buffer* buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT]; 288 rtems_bdbuf_buffer** buf_prev = buf_stack; 289 290 boolean modified = FALSE; 291 292 if (p == NULL) 293 { 294 *root = node; 295 node->avl.left = NULL; 296 node->avl.right = NULL; 297 node->avl.bal = 0; 298 return 0; 299 } 300 301 while (p != NULL) 302 { 303 *buf_prev++ = p; 304 305 if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) 306 { 307 p->avl.cache = 1; 308 q = p->avl.right; 309 if (q == NULL) 310 { 311 q = node; 312 p->avl.right = q = node; 313 break; 314 } 315 } 316 else if ((p->dev != dev) || (p->block != block)) 317 { 318 p->avl.cache = -1; 319 q = p->avl.left; 320 if (q == NULL) 321 { 322 q = node; 323 p->avl.left = q; 324 break; 325 } 326 } 327 else 328 { 329 return -1; 330 } 331 332 p = q; 333 } 334 335 q->avl.left = q->avl.right = NULL; 336 q->avl.bal = 0; 337 modified = TRUE; 338 buf_prev--; 339 340 while (modified) 341 { 342 if (p->avl.cache == -1) 343 { 344 switch (p->avl.bal) 345 { 346 case 1: 347 p->avl.bal = 0; 348 modified = FALSE; 349 break; 350 351 case 0: 352 p->avl.bal = -1; 353 break; 354 355 case -1: 356 p1 = p->avl.left; 357 if (p1->avl.bal == -1) /* simple LL-turn */ 358 { 359 p->avl.left = p1->avl.right; 360 p1->avl.right = p; 361 p->avl.bal = 0; 362 p = p1; 363 } 364 else /* double LR-turn */ 365 { 366 p2 = p1->avl.right; 367 p1->avl.right = p2->avl.left; 368 p2->avl.left = p1; 369 p->avl.left = p2->avl.right; 370 p2->avl.right = p; 371 if (p2->avl.bal == -1) p->avl.bal = +1; else p->avl.bal = 0; 372 if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0; 373 p = p2; 374 } 375 p->avl.bal = 0; 376 modified = FALSE; 377 break; 378 379 default: 380 break; 381 } 382 } 383 else 384 { 385 switch (p->avl.bal) 386 { 387 case -1: 388 p->avl.bal = 0; 389 modified = FALSE; 390 break; 391 392 case 0: 393 p->avl.bal = 1; 394 break; 395 396 case 1: 397 p1 = p->avl.right; 398 if (p1->avl.bal == 1) /* simple RR-turn */ 399 { 400 p->avl.right = p1->avl.left; 401 p1->avl.left = p; 402 p->avl.bal = 0; 403 p = p1; 404 } 405 else /* double RL-turn */ 406 { 407 p2 = p1->avl.left; 408 p1->avl.left = p2->avl.right; 409 p2->avl.right = p1; 410 p->avl.right = p2->avl.left; 411 p2->avl.left = p; 412 if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0; 413 if (p2->avl.bal == -1) p1->avl.bal = +1; else p1->avl.bal = 0; 414 p = p2; 415 } 416 p->avl.bal = 0; 417 modified = FALSE; 418 break; 419 420 default: 421 break; 422 } 423 } 424 q = p; 425 if (buf_prev > buf_stack) 426 { 427 p = *--buf_prev; 428 429 if (p->avl.cache == -1) 430 { 431 p->avl.left = q; 432 } 433 else 434 { 435 p->avl.right = q; 436 } 437 } 438 else 439 { 440 *root = p; 441 break; 442 } 443 }; 444 445 return 0; 446 } 447 448 449 /** 450 * Removes the node from the tree. 451 * 452 * @param root_addr Pointer to pointer to the root node 453 * @param node Pointer to the node to remove 454 * @retval 0 Item removed 455 * @retval -1 No such item found 456 */ 457 static int 458 rtems_bdbuf_avl_remove(rtems_bdbuf_buffer** root, 459 const rtems_bdbuf_buffer* node) 460 { 461 dev_t dev = node->dev; 462 rtems_blkdev_bnum block = node->block; 463 464 rtems_bdbuf_buffer* p = *root; 465 rtems_bdbuf_buffer* q; 466 rtems_bdbuf_buffer* r; 467 rtems_bdbuf_buffer* s; 468 rtems_bdbuf_buffer* p1; 469 rtems_bdbuf_buffer* p2; 470 rtems_bdbuf_buffer* buf_stack[RTEMS_BDBUF_AVL_MAX_HEIGHT]; 471 rtems_bdbuf_buffer** buf_prev = buf_stack; 472 473 boolean modified = FALSE; 474 475 memset (buf_stack, 0, sizeof(buf_stack)); 476 477 while (p != NULL) 478 { 479 *buf_prev++ = p; 480 481 if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) 482 { 483 p->avl.cache = 1; 484 p = p->avl.right; 485 } 486 else if ((p->dev != dev) || (p->block != block)) 487 { 488 p->avl.cache = -1; 489 p = p->avl.left; 490 } 491 else 492 { 493 /* node found */ 494 break; 495 } 496 } 497 498 if (p == NULL) 499 { 500 /* there is no such node */ 501 return -1; 502 } 503 504 q = p; 505 506 buf_prev--; 507 if (buf_prev > buf_stack) 508 { 509 p = *(buf_prev - 1); 510 } 511 else 512 { 513 p = NULL; 514 } 515 516 /* at this moment q - is a node to delete, p is q's parent */ 517 if (q->avl.right == NULL) 518 { 519 r = q->avl.left; 520 if (r != NULL) 521 { 522 r->avl.bal = 0; 523 } 524 q = r; 525 } 526 else 527 { 528 rtems_bdbuf_buffer **t; 529 530 r = q->avl.right; 531 532 if (r->avl.left == NULL) 533 { 534 r->avl.left = q->avl.left; 535 r->avl.bal = q->avl.bal; 536 r->avl.cache = 1; 537 *buf_prev++ = q = r; 538 } 539 else 540 { 541 t = buf_prev++; 542 s = r; 543 544 while (s->avl.left != NULL) 545 { 546 *buf_prev++ = r = s; 547 s = r->avl.left; 548 r->avl.cache = -1; 549 } 550 551 s->avl.left = q->avl.left; 552 r->avl.left = s->avl.right; 553 s->avl.right = q->avl.right; 554 s->avl.bal = q->avl.bal; 555 s->avl.cache = 1; 556 557 *t = q = s; 558 } 559 } 560 561 if (p != NULL) 562 { 563 if (p->avl.cache == -1) 564 { 565 p->avl.left = q; 566 } 567 else 568 { 569 p->avl.right = q; 570 } 571 } 572 else 573 { 574 *root = q; 575 } 576 577 modified = TRUE; 578 579 while (modified) 580 { 581 if (buf_prev > buf_stack) 582 { 583 p = *--buf_prev; 584 } 585 else 586 { 587 break; 588 } 589 590 if (p->avl.cache == -1) 591 { 592 /* rebalance left branch */ 593 switch (p->avl.bal) 594 { 595 case -1: 596 p->avl.bal = 0; 597 break; 598 case 0: 599 p->avl.bal = 1; 600 modified = FALSE; 601 break; 602 603 case +1: 604 p1 = p->avl.right; 605 606 if (p1->avl.bal >= 0) /* simple RR-turn */ 607 { 608 p->avl.right = p1->avl.left; 609 p1->avl.left = p; 610 611 if (p1->avl.bal == 0) 612 { 613 p1->avl.bal = -1; 614 modified = FALSE; 615 } 616 else 617 { 618 p->avl.bal = 0; 619 p1->avl.bal = 0; 620 } 621 p = p1; 622 } 623 else /* double RL-turn */ 624 { 625 p2 = p1->avl.left; 626 627 p1->avl.left = p2->avl.right; 628 p2->avl.right = p1; 629 p->avl.right = p2->avl.left; 630 p2->avl.left = p; 631 632 if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0; 633 if (p2->avl.bal == -1) p1->avl.bal = 1; else p1->avl.bal = 0; 634 635 p = p2; 636 p2->avl.bal = 0; 637 } 638 break; 639 640 default: 641 break; 642 } 643 } 644 else 645 { 646 /* rebalance right branch */ 647 switch (p->avl.bal) 648 { 649 case +1: 650 p->avl.bal = 0; 651 break; 652 653 case 0: 654 p->avl.bal = -1; 655 modified = FALSE; 656 break; 657 658 case -1: 659 p1 = p->avl.left; 660 661 if (p1->avl.bal <= 0) /* simple LL-turn */ 662 { 663 p->avl.left = p1->avl.right; 664 p1->avl.right = p; 665 if (p1->avl.bal == 0) 666 { 667 p1->avl.bal = 1; 668 modified = FALSE; 669 } 670 else 671 { 672 p->avl.bal = 0; 673 p1->avl.bal = 0; 674 } 675 p = p1; 676 } 677 else /* double LR-turn */ 678 { 679 p2 = p1->avl.right; 680 681 p1->avl.right = p2->avl.left; 682 p2->avl.left = p1; 683 p->avl.left = p2->avl.right; 684 p2->avl.right = p; 685 686 if (p2->avl.bal == -1) p->avl.bal = 1; else p->avl.bal = 0; 687 if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0; 688 689 p = p2; 690 p2->avl.bal = 0; 691 } 692 break; 693 694 default: 695 break; 696 } 697 } 698 699 if (buf_prev > buf_stack) 700 { 701 q = *(buf_prev - 1); 702 703 if (q->avl.cache == -1) 704 { 705 q->avl.left = p; 706 } 707 else 708 { 709 q->avl.right = p; 710 } 711 } 712 else 713 { 714 *root = p; 715 break; 716 } 717 718 } 719 720 return 0; 721 } 722 723 /** 724 * Get the pool for the device. 725 * 726 * @param pdd Physical disk device. 727 */ 728 static rtems_bdbuf_pool* 729 rtems_bdbuf_get_pool (const rtems_bdpool_id pid) 730 { 731 return &rtems_bdbuf_ctx.pool[pid]; 732 } 733 734 /** 735 * Lock the pool. A single task can nest calls. 736 * 737 * @param pool The pool to lock. 738 */ 739 static void 740 rtems_bdbuf_lock_pool (rtems_bdbuf_pool* pool) 741 { 742 rtems_status_code sc = rtems_semaphore_obtain (pool->lock, 743 RTEMS_WAIT, 744 RTEMS_NO_TIMEOUT); 745 if (sc != RTEMS_SUCCESSFUL) 746 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_LOCK); 747 } 748 749 /** 750 * Unlock the pool. 751 * 752 * @param pool The pool to unlock. 753 */ 754 static void 755 rtems_bdbuf_unlock_pool (rtems_bdbuf_pool* pool) 756 { 757 rtems_status_code sc = rtems_semaphore_release (pool->lock); 758 if (sc != RTEMS_SUCCESSFUL) 759 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_UNLOCK); 760 } 761 762 /** 763 * Lock the pool's sync. A single task can nest calls. 764 * 765 * @param pool The pool's sync to lock. 766 */ 767 static void 768 rtems_bdbuf_lock_sync (rtems_bdbuf_pool* pool) 769 { 770 rtems_status_code sc = rtems_semaphore_obtain (pool->sync_lock, 771 RTEMS_WAIT, 772 RTEMS_NO_TIMEOUT); 773 if (sc != RTEMS_SUCCESSFUL) 774 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SYNC_LOCK); 775 } 776 777 /** 778 * Unlock the pool's sync. 779 * 780 * @param pool The pool's sync to unlock. 781 */ 782 static void 783 rtems_bdbuf_unlock_sync (rtems_bdbuf_pool* pool) 784 { 785 rtems_status_code sc = rtems_semaphore_release (pool->sync_lock); 786 if (sc != RTEMS_SUCCESSFUL) 787 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SYNC_UNLOCK); 788 } 789 790 /** 791 * Wait until woken. Semaphores are used so a number of tasks can wait and 792 * can be woken at once. Task events would require we maintain a list 793 * of tasks to be woken and this would require storgage and we do not 794 * know the number of tasks that could be waiting. 795 * 796 * While we have the pool locked we can try and claim the semaphore and 797 * therefore know when we release the lock to the pool we will block until the 798 * semaphore is released. This may even happen before we get to block. 799 * 800 * A counter is used to save the release call when no one is waiting. 801 * 802 * The function assumes the pool is locked on entry and it will have locked 803 * the pool on exit. 804 * 805 * @param pool The pool to wait for a buffer to return. 806 * @param sema The semaphore to block on and wait. 807 * @param waiters The wait counter for this semaphore. 808 */ 809 static void 810 rtems_bdbuf_wait (rtems_bdbuf_pool* pool, rtems_id* sema, 811 volatile uint32_t* waiters) 812 { 813 rtems_status_code sc; 814 rtems_mode prev_mode; 815 816 /* 817 * Indicate we are waiting. 818 */ 819 *waiters += 1; 820 821 /* 822 * Disable preemption then unlock the pool and block. 823 * There is no POSIX condition variable in the core API so 824 * this is a work around. 825 * 826 * The issue is a task could preempt after the pool is unlocked 827 * because it is blocking or just hits that window, and before 828 * this task has blocked on the semaphore. If the preempting task 829 * flushes the queue this task will not see the flush and may 830 * block for ever or until another transaction flushes this 831 * semaphore. 832 */ 833 sc = rtems_task_mode (RTEMS_NO_PREEMPT, RTEMS_PREEMPT_MASK, &prev_mode); 834 835 if (sc != RTEMS_SUCCESSFUL) 836 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT); 837 838 /* 839 * Unlock the pool, wait, and lock the pool when we return. 840 */ 841 rtems_bdbuf_unlock_pool (pool); 842 843 sc = rtems_semaphore_obtain (*sema, RTEMS_WAIT, RTEMS_NO_TIMEOUT); 844 845 if (sc != RTEMS_UNSATISFIED) 846 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT); 847 848 rtems_bdbuf_lock_pool (pool); 849 850 sc = rtems_task_mode (prev_mode, RTEMS_ALL_MODE_MASKS, &prev_mode); 851 852 if (sc != RTEMS_SUCCESSFUL) 853 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAIT); 854 855 *waiters -= 1; 856 } 857 858 /** 859 * Wake a blocked resource. The resource has a counter that lets us know if 860 * there are any waiters. 861 * 862 * @param sema The semaphore to release. 863 * @param waiters The wait counter for this semaphore. 864 */ 865 static void 866 rtems_bdbuf_wake (rtems_id sema, volatile uint32_t* waiters) 867 { 868 if (*waiters) 869 { 870 rtems_status_code sc; 871 872 sc = rtems_semaphore_flush (sema); 873 874 if (sc != RTEMS_SUCCESSFUL) 875 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_POOL_WAKE); 876 } 877 } 878 879 /** 880 * Add a buffer descriptor to the modified list. This modified list is treated 881 * a litte differently to the other lists. To access it you must have the pool 882 * locked and this is assumed to be the case on entry to this call and you must 883 * hold the sync lock. The sync lock is used to block writes while a sync is 884 * active. 885 * 886 * @param sema The semaphore to release. 887 * @param waiters The wait counter for this semaphore. 888 */ 889 static void 890 rtems_bdbuf_append_modified (rtems_bdbuf_pool* pool, rtems_bdbuf_buffer* bd) 891 { 892 /* 893 * Take a copy of the sync_active variable as it will change after 894 * we unlock the pool and wait for the sync to finish. 895 */ 896 int sync_active = pool->sync_active; 897 if (0 && sync_active) 898 { 899 rtems_bdbuf_unlock_pool (pool); 900 rtems_bdbuf_lock_sync (pool); 901 rtems_bdbuf_lock_pool (pool); 902 } 903 904 bd->state = RTEMS_BDBUF_STATE_MODIFIED; 905 906 rtems_chain_append (&pool->modified, &bd->link); 907 908 if (0 && sync_active) 909 rtems_bdbuf_unlock_sync (pool); 910 } 911 912 static void 913 rtems_bdbuf_wake_swapper () 914 { 915 rtems_status_code sc = rtems_event_send (rtems_bdbuf_ctx.swapout, 916 RTEMS_BDBUF_SWAPOUT_SYNC); 917 if (sc != RTEMS_SUCCESSFUL) 918 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SO_WAKE); 919 } 920 921 /* bdbuf_initialize_pool -- 922 * Initialize single buffer pool. 126 923 * 127 924 * PARAMETERS: 128 * root - pointer to the root node of the AVL-Tree.129 * dev, block - search key925 * config - buffer pool configuration 926 * pool - pool number 130 927 * 131 928 * RETURNS: 132 * NULL if node with specified dev/block not found 133 * non-NULL - pointer to the node with specified dev/block 134 */ 135 static bdbuf_buffer * 136 avl_search(bdbuf_buffer **root, dev_t dev, blkdev_bnum block) 137 { 138 bdbuf_buffer *p = *root; 139 140 while ((p != NULL) && ((p->dev != dev) || (p->block != block))) 141 { 142 if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) 929 * RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error 930 * code if error occured. 931 */ 932 static rtems_status_code 933 rtems_bdbuf_initialize_pool (rtems_bdbuf_pool_config* config, 934 rtems_bdpool_id pid) 935 { 936 unsigned char* buffer = config->mem_area; 937 rtems_bdbuf_pool* pool; 938 rtems_bdbuf_buffer* bd; 939 rtems_status_code sc; 940 int b; 941 942 pool = rtems_bdbuf_get_pool (pid); 943 944 pool->blksize = config->size; 945 pool->nblks = config->num; 946 pool->tree = NULL; 947 pool->buffers = NULL; 948 949 rtems_chain_initialize_empty (&pool->ready); 950 rtems_chain_initialize_empty (&pool->lru); 951 rtems_chain_initialize_empty (&pool->modified); 952 rtems_chain_initialize_empty (&pool->sync); 953 954 pool->access = 0; 955 pool->access_waiters = 0; 956 pool->transfer = 0; 957 pool->transfer_waiters = 0; 958 pool->waiting = 0; 959 pool->wait_waiters = 0; 960 961 /* 962 * Allocate memory for buffer descriptors 963 */ 964 pool->bds = calloc (config->num, sizeof (rtems_bdbuf_buffer)); 965 966 if (!pool->bds) 967 return RTEMS_NO_MEMORY; 968 969 /* 970 * Allocate memory for buffers if required. 971 */ 972 if (buffer == NULL) 973 { 974 buffer = pool->buffers = malloc (config->num * config->size); 975 if (!pool->buffers) 976 { 977 free (pool->bds); 978 return RTEMS_NO_MEMORY; 979 } 980 } 981 982 for (b = 0, bd = pool->bds; 983 b < pool->nblks; 984 b++, bd++, buffer += pool->blksize) 985 { 986 bd->dev = -1; 987 bd->block = 0; 988 bd->buffer = buffer; 989 bd->avl.left = NULL; 990 bd->avl.right = NULL; 991 bd->state = RTEMS_BDBUF_STATE_EMPTY; 992 bd->pool = pid; 993 bd->error = 0; 994 bd->waiters = 0; 995 bd->hold_timer = 0; 996 997 rtems_chain_append (&pool->ready, &bd->link); 998 } 999 1000 sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'L'), 1001 1, RTEMS_BDBUF_POOL_LOCK_ATTRIBS, 0, 1002 &pool->lock); 1003 if (sc != RTEMS_SUCCESSFUL) 1004 { 1005 free (pool->buffers); 1006 free (pool->bds); 1007 return sc; 1008 } 1009 1010 sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 's'), 1011 0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0, 1012 &pool->sync_lock); 1013 if (sc != RTEMS_SUCCESSFUL) 1014 { 1015 rtems_semaphore_delete (pool->lock); 1016 free (pool->buffers); 1017 free (pool->bds); 1018 return sc; 1019 } 1020 1021 sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'a'), 1022 0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0, 1023 &pool->access); 1024 if (sc != RTEMS_SUCCESSFUL) 1025 { 1026 rtems_semaphore_delete (pool->sync_lock); 1027 rtems_semaphore_delete (pool->lock); 1028 free (pool->buffers); 1029 free (pool->bds); 1030 return sc; 1031 } 1032 1033 sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 't'), 1034 0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0, 1035 &pool->transfer); 1036 if (sc != RTEMS_SUCCESSFUL) 1037 { 1038 rtems_semaphore_delete (pool->access); 1039 rtems_semaphore_delete (pool->sync_lock); 1040 rtems_semaphore_delete (pool->lock); 1041 free (pool->buffers); 1042 free (pool->bds); 1043 return sc; 1044 } 1045 1046 sc = rtems_semaphore_create (rtems_build_name ('B', 'P', '0' + pid, 'w'), 1047 0, RTEMS_BDBUF_POOL_WAITER_ATTRIBS, 0, 1048 &pool->waiting); 1049 if (sc != RTEMS_SUCCESSFUL) 1050 { 1051 rtems_semaphore_delete (pool->transfer); 1052 rtems_semaphore_delete (pool->access); 1053 rtems_semaphore_delete (pool->sync_lock); 1054 rtems_semaphore_delete (pool->lock); 1055 free (pool->buffers); 1056 free (pool->bds); 1057 return sc; 1058 } 1059 1060 return RTEMS_SUCCESSFUL; 1061 } 1062 1063 /* bdbuf_release_pool -- 1064 * Free resources allocated for buffer pool with specified number. 1065 * 1066 * PARAMETERS: 1067 * pool - buffer pool number 1068 * 1069 * RETURNS: 1070 * RTEMS_SUCCESSFUL 1071 */ 1072 static rtems_status_code 1073 rtems_bdbuf_release_pool (rtems_bdpool_id pid) 1074 { 1075 rtems_bdbuf_pool* pool = rtems_bdbuf_get_pool (pid); 1076 1077 rtems_bdbuf_lock_pool (pool); 1078 1079 rtems_semaphore_delete (pool->waiting); 1080 rtems_semaphore_delete (pool->transfer); 1081 rtems_semaphore_delete (pool->access); 1082 rtems_semaphore_delete (pool->lock); 1083 1084 free (pool->buffers); 1085 free (pool->bds); 1086 1087 return RTEMS_SUCCESSFUL; 1088 } 1089 1090 /* rtems_bdbuf_init -- 1091 * Prepare buffering layer to work - initialize buffer descritors 1092 * and (if it is neccessary) buffers. Buffers will be allocated according 1093 * to the configuration table, each entry describes kind of block and 1094 * amount requested. After initialization all blocks are placed onto 1095 * empty elements lists. 1096 * 1097 * PARAMETERS: 1098 * conf_table - pointer to the buffers configuration table 1099 * size - number of entries in configuration table 1100 * 1101 * RETURNS: 1102 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 1103 * or error code if error is occured) 1104 */ 1105 rtems_status_code 1106 rtems_bdbuf_init () 1107 { 1108 rtems_bdpool_id p; 1109 rtems_status_code sc; 1110 1111 #if RTEMS_BDBUF_TRACE 1112 rtems_bdbuf_printf ("init\n"); 1113 #endif 1114 1115 if (rtems_bdbuf_pool_configuration_size <= 0) 1116 return RTEMS_INVALID_SIZE; 1117 1118 if (rtems_bdbuf_ctx.npools) 1119 return RTEMS_RESOURCE_IN_USE; 1120 1121 rtems_bdbuf_ctx.npools = rtems_bdbuf_pool_configuration_size; 1122 1123 /* 1124 * Allocate memory for buffer pool descriptors 1125 */ 1126 rtems_bdbuf_ctx.pool = calloc (rtems_bdbuf_pool_configuration_size, 1127 sizeof (rtems_bdbuf_pool)); 1128 1129 if (rtems_bdbuf_ctx.pool == NULL) 1130 return RTEMS_NO_MEMORY; 1131 1132 /* 1133 * Initialize buffer pools and roll out if something failed, 1134 */ 1135 for (p = 0; p < rtems_bdbuf_ctx.npools; p++) 1136 { 1137 sc = rtems_bdbuf_initialize_pool (&rtems_bdbuf_pool_configuration[p], p); 1138 if (sc != RTEMS_SUCCESSFUL) 1139 { 1140 rtems_bdpool_id j; 1141 for (j = 0; j < p - 1; j++) 1142 rtems_bdbuf_release_pool (j); 1143 return sc; 1144 } 1145 } 1146 1147 /* 1148 * Create and start swapout task 1149 */ 1150 1151 rtems_bdbuf_ctx.swapout_enabled = TRUE; 1152 1153 sc = rtems_task_create (rtems_build_name('B', 'S', 'W', 'P'), 1154 (rtems_bdbuf_configuration.swapout_priority ? 1155 rtems_bdbuf_configuration.swapout_priority : 1156 RTEMS_BDBUF_SWAPOUT_TASK_PRIORITY_DEFAULT), 1157 SWAPOUT_TASK_STACK_SIZE, 1158 RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR, 1159 RTEMS_LOCAL | RTEMS_NO_FLOATING_POINT, 1160 &rtems_bdbuf_ctx.swapout); 1161 if (sc != RTEMS_SUCCESSFUL) 1162 { 1163 for (p = 0; p < rtems_bdbuf_ctx.npools; p++) 1164 rtems_bdbuf_release_pool (p); 1165 free (rtems_bdbuf_ctx.pool); 1166 return sc; 1167 } 1168 1169 sc = rtems_task_start (rtems_bdbuf_ctx.swapout, 1170 rtems_bdbuf_swapout_task, 1171 (rtems_task_argument) &rtems_bdbuf_ctx); 1172 if (sc != RTEMS_SUCCESSFUL) 1173 { 1174 rtems_task_delete (rtems_bdbuf_ctx.swapout); 1175 for (p = 0; p < rtems_bdbuf_ctx.npools; p++) 1176 rtems_bdbuf_release_pool (p); 1177 free (rtems_bdbuf_ctx.pool); 1178 return sc; 1179 } 1180 1181 return RTEMS_SUCCESSFUL; 1182 } 1183 1184 /** 1185 * Get a buffer for this device and block. This function returns a buffer once 1186 * placed into the AVL tree. If no buffer is available and it is not a read 1187 * ahead request wait until one is available. If the buffer is for a read ahead 1188 * transfer return NULL if there is not buffer or it is in the cache. 1189 * 1190 * The AVL tree of buffers for the pool is searched and if not located check 1191 * obtain a buffer and insert it into the AVL tree. Buffers are first obtained 1192 * from the ready list until all empty buffers are used. Once all buffers are 1193 * in use buffers are taken from the LRU list with the least recently used 1194 * buffer taken first. A buffer taken from the LRU list is removed from the AVL 1195 * tree. The empty list or LRU list buffer is initialised to this device and 1196 * block. If no buffers are available due to the empty and LRU lists being 1197 * empty the caller is blocked on the waiting semaphore and counter. When 1198 * buffers return from the upper layers (access) or lower driver (transfer) the 1199 * blocked caller task is woken and this procedure is repeated. The repeat 1200 * handles a case of a another thread pre-empting getting a buffer first and 1201 * adding it to the AVL tree. 1202 * 1203 * A buffer located in the AVL tree means it is already in the cache and maybe 1204 * in use somewhere. The buffer can be either: 1205 * 1206 * # Cached. Not being accessed or part of a media transfer. 1207 * # Access. Is with an upper layer being accessed. 1208 * # Transfer. Is with the driver and part of a media transfer. 1209 * 1210 * If cached we assign the state new state extract it from any list it maybe 1211 * part of and return to the user. The buffer could be part of the LRU list or 1212 * the modifed list waiting to be swapped out by the swap out task. 1213 * 1214 * This function assumes the pool the buffer is being taken from is locked and 1215 * it insure the pool is locked when it returns. 1216 * 1217 * @param device The physical disk device 1218 * @param block Linear media block number 1219 * @param 1220 * @param bd Address to store of found descriptor 1221 1222 * RETURNS: 1223 * RTEMS status code ( if operation completed successfully 1224 * or error code if error is occured) 1225 * 1226 * SIDE EFFEECTS: 1227 * bufget_sema may be obtained by this primitive 1228 * 1229 * NOTE: 1230 * It is assumed that primitive invoked when thread preemption is disabled. 1231 */ 1232 static rtems_bdbuf_buffer* 1233 rtems_bdbuf_get_buffer (rtems_disk_device* pdd, 1234 rtems_bdbuf_pool* pool, 1235 rtems_blkdev_bnum block, 1236 boolean read_ahead) 1237 { 1238 dev_t device = pdd->dev; 1239 rtems_bdbuf_buffer* bd; 1240 boolean available; 1241 1242 /* 1243 * Loop until we get a buffer. Under load we could find no buffers are 1244 * available so in the case of the required block this task needs to wait 1245 * until some return before proceeding. There is no timeout. If the buffer is 1246 * for a read ahead buffer return NULL. 1247 * 1248 * The search procedure is repeated as another thread could have pre-empted 1249 * us while we waited for a buffer, obtained an empty buffer and loaded the 1250 * AVL tree with it. 1251 */ 1252 do 1253 { 1254 /* 1255 * Search for buffer descriptor for this dev/block key. 1256 */ 1257 bd = rtems_bdbuf_avl_search (&pool->tree, device, block); 1258 1259 /* 1260 * No buffer in the cache for this block. We need to obtain a buffer and 1261 * this means take a buffer that is ready to use. If all buffers are in use 1262 * take the least recently used buffer. If there are none then the cache is 1263 * empty. All the buffers are either queued to be written to disk or with 1264 * the user. We cannot do much with the buffers with the user how-ever with 1265 * the modified buffers waiting to be written to disk flush the maximum 1266 * number transfered in a block to disk. After this all that be done is to 1267 * wait for a buffer to return to the cache. 1268 */ 1269 if (!bd) 1270 { 1271 /* 1272 * Assign new buffer descriptor from the empty list if one is present. If 1273 * the empty queue is empty get the oldest buffer from LRU list. If the 1274 * LRU list is empty there are no available buffers so we need to wait 1275 * until some are returned. 1276 */ 1277 if (rtems_chain_is_empty (&pool->ready)) 1278 { 1279 /* 1280 * No unsed or read-ahead buffers. 1281 * 1282 * If this is a read ahead buffer just return. No need to place 1283 * further pressure on the cache by reading something that may be 1284 * needed when we have data in the cache that was needed. 1285 */ 1286 if (read_ahead) 1287 return NULL; 1288 1289 /* 1290 * Check the LRU list. 1291 */ 1292 bd = (rtems_bdbuf_buffer *) rtems_chain_get (&pool->lru); 1293 1294 if (bd) 143 1295 { 144 p = p->avl.right; 1296 /* 1297 * Remove the buffer from the AVL tree. 1298 */ 1299 if (rtems_bdbuf_avl_remove (&pool->tree, bd) != 0) 1300 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); 145 1301 } 146 1302 else 147 1303 { 148 p = p->avl.left; 1304 /* 1305 * If there are buffers on the modified list expire the hold timer 1306 * and wake the swap out task. 1307 */ 1308 if (!rtems_chain_is_empty (&pool->modified)) 1309 { 1310 rtems_chain_node* node = rtems_chain_head (&pool->modified); 1311 int write_blocks = 0; 1312 1313 node = node->next; 1314 while ((write_blocks < rtems_bdbuf_configuration.max_write_blocks) && 1315 !rtems_chain_is_tail (&pool->modified, node)) 1316 { 1317 rtems_bdbuf_buffer* bd = (rtems_bdbuf_buffer*) node; 1318 bd->hold_timer = 0; 1319 write_blocks++; 1320 node = node->next; 1321 } 1322 1323 rtems_bdbuf_wake_swapper (); 1324 } 1325 1326 /* 1327 * Wait for a buffer to be returned to the pool. The buffer will be 1328 * placed on the LRU list. 1329 */ 1330 rtems_bdbuf_wait (pool, &pool->waiting, &pool->wait_waiters); 149 1331 } 150 } 151 152 return p; 153 } 154 155 156 /* avl_search_for_sync -- 157 * Search in AVL tree for first modified buffer belongs to specified 158 * disk device. 159 * 160 * PARAMETERS: 161 * root - pointer to tree root 162 * dd - disk device descriptor 163 * 164 * RETURNS: 165 * Block buffer, or NULL if no modified blocks on specified device 166 * exists. 167 */ 168 static bdbuf_buffer * 169 avl_search_for_sync(bdbuf_buffer **root, disk_device *dd) 170 { 171 dev_t dev = dd->phys_dev->dev; 172 blkdev_bnum block_start = dd->start; 173 blkdev_bnum block_end = dd->start + dd->size - 1; 174 175 bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT]; 176 bdbuf_buffer **buf_prev = buf_stack; 177 bdbuf_buffer *p = *root; 178 179 while (p != NULL) 180 { 181 if ((p->dev < dev) || ((p->dev == dev) && (p->block < block_start))) 1332 } 1333 else 1334 { 1335 bd = (rtems_bdbuf_buffer *) rtems_chain_get (&(pool->ready)); 1336 1337 if ((bd->state != RTEMS_BDBUF_STATE_EMPTY) && 1338 (bd->state != RTEMS_BDBUF_STATE_READ_AHEAD)) 1339 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); 1340 1341 if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD) 182 1342 { 183 p = p->avl.right; 1343 if (rtems_bdbuf_avl_remove (&pool->tree, bd) != 0) 1344 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); 184 1345 } 185 else if ((p->dev > dev) || ((p->dev == dev) && (p->block > block_end))) 186 { 187 p = p->avl.left; 188 } 189 else if (p->modified) 190 { 191 return p; 192 } 193 else 194 { 195 if (p->avl.right != NULL) 196 { 197 *buf_prev++ = p->avl.right; 198 } 199 p = p->avl.left; 200 } 201 202 if ((p == NULL) && (buf_prev > buf_stack)) 203 { 204 p = *--buf_prev; 205 } 206 } 207 208 return p; 209 } 210 211 212 /* 213 * avl_insert -- 214 * Inserts the specified node to the AVl-Tree. 215 * 216 * PARAMETERS: 217 * root - Pointer to pointer to the root node 218 * node - Pointer to the node to add. 219 * 220 * RETURNS: 221 * 0 - The node added successfully 222 * -1 - An error occured 223 */ 224 static int 225 avl_insert(bdbuf_buffer **root, bdbuf_buffer *node) 226 { 227 dev_t dev = node->dev; 228 blkdev_bnum block = node->block; 229 230 bdbuf_buffer *p = *root; 231 bdbuf_buffer *q, *p1, *p2; 232 bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT]; 233 bdbuf_buffer **buf_prev = buf_stack; 234 235 boolean modified = FALSE; 236 237 if (p == NULL) 238 { 239 *root = node; 240 node->avl.left = NULL; 241 node->avl.right = NULL; 242 node->avl.bal = 0; 243 return 0; 244 } 245 246 while (p != NULL) 247 { 248 *buf_prev++ = p; 249 250 if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) 251 { 252 p->avl.cache = 1; 253 q = p->avl.right; 254 if (q == NULL) 255 { 256 q = node; 257 p->avl.right = q = node; 258 break; 259 } 260 } 261 else if ((p->dev != dev) || (p->block != block)) 262 { 263 p->avl.cache = -1; 264 q = p->avl.left; 265 if (q == NULL) 266 { 267 q = node; 268 p->avl.left = q; 269 break; 270 } 271 } 272 else 273 { 274 return -1; 275 } 276 277 p = q; 278 } 279 280 q->avl.left = q->avl.right = NULL; 281 q->avl.bal = 0; 282 modified = TRUE; 283 buf_prev--; 284 285 while (modified) 286 { 287 if (p->avl.cache == -1) 288 { 289 switch (p->avl.bal) 290 { 291 case 1: 292 p->avl.bal = 0; 293 modified = FALSE; 294 break; 295 296 case 0: 297 p->avl.bal = -1; 298 break; 299 300 case -1: 301 p1 = p->avl.left; 302 if (p1->avl.bal == -1) /* simple LL-turn */ 303 { 304 p->avl.left = p1->avl.right; 305 p1->avl.right = p; 306 p->avl.bal = 0; 307 p = p1; 308 } 309 else /* double LR-turn */ 310 { 311 p2 = p1->avl.right; 312 p1->avl.right = p2->avl.left; 313 p2->avl.left = p1; 314 p->avl.left = p2->avl.right; 315 p2->avl.right = p; 316 if (p2->avl.bal == -1) p->avl.bal = +1; else p->avl.bal = 0; 317 if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0; 318 p = p2; 319 } 320 p->avl.bal = 0; 321 modified = FALSE; 322 break; 323 324 default: 325 break; 326 } 327 } 328 else 329 { 330 switch (p->avl.bal) 331 { 332 case -1: 333 p->avl.bal = 0; 334 modified = FALSE; 335 break; 336 337 case 0: 338 p->avl.bal = 1; 339 break; 340 341 case 1: 342 p1 = p->avl.right; 343 if (p1->avl.bal == 1) /* simple RR-turn */ 344 { 345 p->avl.right = p1->avl.left; 346 p1->avl.left = p; 347 p->avl.bal = 0; 348 p = p1; 349 } 350 else /* double RL-turn */ 351 { 352 p2 = p1->avl.left; 353 p1->avl.left = p2->avl.right; 354 p2->avl.right = p1; 355 p->avl.right = p2->avl.left; 356 p2->avl.left = p; 357 if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0; 358 if (p2->avl.bal == -1) p1->avl.bal = +1; else p1->avl.bal = 0; 359 p = p2; 360 } 361 p->avl.bal = 0; 362 modified = FALSE; 363 break; 364 365 default: 366 break; 367 } 368 } 369 q = p; 370 if (buf_prev > buf_stack) 371 { 372 p = *--buf_prev; 373 374 if (p->avl.cache == -1) 375 { 376 p->avl.left = q; 377 } 378 else 379 { 380 p->avl.right = q; 381 } 382 } 383 else 384 { 385 *root = p; 386 break; 387 } 388 }; 389 390 return 0; 391 } 392 393 394 /* avl_remove -- 395 * removes the node from the tree. 396 * 397 * PARAMETERS: 398 * root_addr - Pointer to pointer to the root node 399 * node - Pointer to the node to remove 400 * 401 * RETURNS: 402 * 0 - Item removed 403 * -1 - No such item found 404 */ 405 static int 406 avl_remove(bdbuf_buffer **root, const bdbuf_buffer *node) 407 { 408 dev_t dev = node->dev; 409 blkdev_bnum block = node->block; 410 411 bdbuf_buffer *p = *root; 412 bdbuf_buffer *q, *r, *s, *p1, *p2; 413 bdbuf_buffer *buf_stack[AVL_MAX_HEIGHT]; 414 bdbuf_buffer **buf_prev = buf_stack; 415 416 boolean modified = FALSE; 417 418 memset(buf_stack, 0, sizeof(buf_stack)); 419 420 while (p != NULL) 421 { 422 *buf_prev++ = p; 423 424 if ((p->dev < dev) || ((p->dev == dev) && (p->block < block))) 425 { 426 p->avl.cache = 1; 427 p = p->avl.right; 428 } 429 else if ((p->dev != dev) || (p->block != block)) 430 { 431 p->avl.cache = -1; 432 p = p->avl.left; 433 } 434 else 435 { 436 /* node found */ 437 break; 438 } 439 } 440 441 if (p == NULL) 442 { 443 /* there is no such node */ 444 return -1; 445 } 446 447 q = p; 448 449 buf_prev--; 450 if (buf_prev > buf_stack) 451 { 452 p = *(buf_prev - 1); 453 } 454 else 455 { 456 p = NULL; 457 } 458 459 /* at this moment q - is a node to delete, p is q's parent */ 460 if (q->avl.right == NULL) 461 { 462 r = q->avl.left; 463 if (r != NULL) 464 { 465 r->avl.bal = 0; 466 } 467 q = r; 468 } 469 else 470 { 471 bdbuf_buffer **t; 472 473 r = q->avl.right; 474 475 if (r->avl.left == NULL) 476 { 477 r->avl.left = q->avl.left; 478 r->avl.bal = q->avl.bal; 479 r->avl.cache = 1; 480 *buf_prev++ = q = r; 481 } 482 else 483 { 484 t = buf_prev++; 485 s = r; 486 487 while (s->avl.left != NULL) 488 { 489 *buf_prev++ = r = s; 490 s = r->avl.left; 491 r->avl.cache = -1; 492 } 493 494 s->avl.left = q->avl.left; 495 r->avl.left = s->avl.right; 496 s->avl.right = q->avl.right; 497 s->avl.bal = q->avl.bal; 498 s->avl.cache = 1; 499 500 *t = q = s; 501 } 502 } 503 504 if (p != NULL) 505 { 506 if (p->avl.cache == -1) 507 { 508 p->avl.left = q; 509 } 510 else 511 { 512 p->avl.right = q; 513 } 514 } 515 else 516 { 517 *root = q; 518 } 519 520 modified = TRUE; 521 522 while (modified) 523 { 524 if (buf_prev > buf_stack) 525 { 526 p = *--buf_prev; 527 } 528 else 529 { 530 break; 531 } 532 533 if (p->avl.cache == -1) 534 { 535 /* rebalance left branch */ 536 switch (p->avl.bal) 537 { 538 case -1: 539 p->avl.bal = 0; 540 break; 541 case 0: 542 p->avl.bal = 1; 543 modified = FALSE; 544 break; 545 546 case +1: 547 p1 = p->avl.right; 548 549 if (p1->avl.bal >= 0) /* simple RR-turn */ 550 { 551 p->avl.right = p1->avl.left; 552 p1->avl.left = p; 553 554 if (p1->avl.bal == 0) 555 { 556 p1->avl.bal = -1; 557 modified = FALSE; 558 } 559 else 560 { 561 p->avl.bal = 0; 562 p1->avl.bal = 0; 563 } 564 p = p1; 565 } 566 else /* double RL-turn */ 567 { 568 p2 = p1->avl.left; 569 570 p1->avl.left = p2->avl.right; 571 p2->avl.right = p1; 572 p->avl.right = p2->avl.left; 573 p2->avl.left = p; 574 575 if (p2->avl.bal == +1) p->avl.bal = -1; else p->avl.bal = 0; 576 if (p2->avl.bal == -1) p1->avl.bal = 1; else p1->avl.bal = 0; 577 578 p = p2; 579 p2->avl.bal = 0; 580 } 581 break; 582 583 default: 584 break; 585 } 586 } 587 else 588 { 589 /* rebalance right branch */ 590 switch (p->avl.bal) 591 { 592 case +1: 593 p->avl.bal = 0; 594 break; 595 596 case 0: 597 p->avl.bal = -1; 598 modified = FALSE; 599 break; 600 601 case -1: 602 p1 = p->avl.left; 603 604 if (p1->avl.bal <= 0) /* simple LL-turn */ 605 { 606 p->avl.left = p1->avl.right; 607 p1->avl.right = p; 608 if (p1->avl.bal == 0) 609 { 610 p1->avl.bal = 1; 611 modified = FALSE; 612 } 613 else 614 { 615 p->avl.bal = 0; 616 p1->avl.bal = 0; 617 } 618 p = p1; 619 } 620 else /* double LR-turn */ 621 { 622 p2 = p1->avl.right; 623 624 p1->avl.right = p2->avl.left; 625 p2->avl.left = p1; 626 p->avl.left = p2->avl.right; 627 p2->avl.right = p; 628 629 if (p2->avl.bal == -1) p->avl.bal = 1; else p->avl.bal = 0; 630 if (p2->avl.bal == +1) p1->avl.bal = -1; else p1->avl.bal = 0; 631 632 p = p2; 633 p2->avl.bal = 0; 634 } 635 break; 636 637 default: 638 break; 639 } 640 } 641 642 if (buf_prev > buf_stack) 643 { 644 q = *(buf_prev - 1); 645 646 if (q->avl.cache == -1) 647 { 648 q->avl.left = p; 649 } 650 else 651 { 652 q->avl.right = p; 653 } 654 } 655 else 656 { 657 *root = p; 658 break; 659 } 660 661 } 662 663 return 0; 664 } 665 666 /* bdbuf_initialize_pool -- 667 * Initialize single buffer pool. 668 * 669 * PARAMETERS: 670 * config - buffer pool configuration 671 * pool - pool number 672 * 673 * RETURNS: 674 * RTEMS_SUCCESSFUL, if buffer pool initialized successfully, or error 675 * code if error occured. 676 */ 677 static rtems_status_code 678 bdbuf_initialize_pool(rtems_bdbuf_config *config, int pool) 679 { 680 bdbuf_pool *p = rtems_bdbuf_ctx.pool + pool; 681 unsigned char *bufs; 682 bdbuf_buffer *b; 683 rtems_status_code rc; 684 int i; 685 686 p->blksize = config->size; 687 p->nblks = config->num; 688 p->tree = NULL; 689 690 rtems_chain_initialize_empty(&p->free); 691 rtems_chain_initialize_empty(&p->lru); 692 693 /* Allocate memory for buffer descriptors */ 694 p->bdbufs = calloc(config->num, sizeof(bdbuf_buffer)); 695 if (p->bdbufs == NULL) 696 { 697 return RTEMS_NO_MEMORY; 698 } 699 700 /* Allocate memory for buffers if required */ 701 if (config->mem_area == NULL) 702 { 703 bufs = p->mallocd_bufs = malloc(config->num * config->size); 704 if (bufs == NULL) 705 { 706 free(p->bdbufs); 707 return RTEMS_NO_MEMORY; 708 } 709 } 710 else 711 { 712 bufs = config->mem_area; 713 p->mallocd_bufs = NULL; 714 } 715 716 for (i = 0, b = p->bdbufs; i < p->nblks; i++, b++, bufs += p->blksize) 717 { 718 b->dev = -1; b->block = 0; 719 b->buffer = bufs; 720 b->actual = b->modified = b->in_progress = FALSE; 721 b->use_count = 0; 722 b->pool = pool; 723 rtems_chain_append(&p->free, &b->link); 724 } 725 726 rc = rtems_semaphore_create( 727 rtems_build_name('B', 'U', 'F', 'G'), 728 p->nblks, 729 RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | 730 RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 731 0, 732 &p->bufget_sema); 733 734 if (rc != RTEMS_SUCCESSFUL) 735 { 736 free(p->bdbufs); 737 free(p->mallocd_bufs); 738 return rc; 739 } 740 741 return RTEMS_SUCCESSFUL; 742 } 743 744 /* bdbuf_release_pool -- 745 * Free resources allocated for buffer pool with specified number. 746 * 747 * PARAMETERS: 748 * pool - buffer pool number 749 * 750 * RETURNS: 751 * RTEMS_SUCCESSFUL 752 */ 753 static rtems_status_code 754 bdbuf_release_pool(rtems_bdpool_id pool) 755 { 756 bdbuf_pool *p = rtems_bdbuf_ctx.pool + pool; 757 rtems_semaphore_delete(p->bufget_sema); 758 free(p->bdbufs); 759 free(p->mallocd_bufs); 760 return RTEMS_SUCCESSFUL; 761 } 762 763 /* rtems_bdbuf_init -- 764 * Prepare buffering layer to work - initialize buffer descritors 765 * and (if it is neccessary)buffers. Buffers will be allocated accoriding 766 * to the configuration table, each entry describes kind of block and 767 * amount requested. After initialization all blocks is placed into 768 * free elements lists. 769 * 770 * PARAMETERS: 771 * conf_table - pointer to the buffers configuration table 772 * size - number of entries in configuration table 773 * 774 * RETURNS: 775 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 776 * or error code if error is occured) 1346 } 1347 1348 if (bd) 1349 { 1350 bd->dev = device; 1351 bd->block = block; 1352 bd->avl.left = NULL; 1353 bd->avl.right = NULL; 1354 bd->state = RTEMS_BDBUF_STATE_EMPTY; 1355 bd->error = 0; 1356 bd->waiters = 0; 1357 1358 if (rtems_bdbuf_avl_insert (&pool->tree, bd) != 0) 1359 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); 1360 1361 return bd; 1362 } 1363 } 1364 } 1365 while (!bd); 1366 1367 /* 1368 * If the buffer is for read ahead and it exists in the AVL cache or is being 1369 * accessed or being transfered then return NULL. 1370 */ 1371 if (read_ahead) 1372 return NULL; 1373 1374 /* 1375 * Loop waiting for the buffer to enter the cached state. If the buffer 1376 * is in the access or transfer state then wait until it is not. 1377 */ 1378 available = FALSE; 1379 while (!available) 1380 { 1381 switch (bd->state) 1382 { 1383 case RTEMS_BDBUF_STATE_CACHED: 1384 case RTEMS_BDBUF_STATE_MODIFIED: 1385 case RTEMS_BDBUF_STATE_READ_AHEAD: 1386 available = TRUE; 1387 break; 1388 1389 case RTEMS_BDBUF_STATE_ACCESS: 1390 case RTEMS_BDBUF_STATE_ACCESS_MODIFIED: 1391 bd->waiters++; 1392 rtems_bdbuf_wait (pool, &pool->access, &pool->access_waiters); 1393 bd->waiters--; 1394 break; 1395 1396 case RTEMS_BDBUF_STATE_SYNC: 1397 case RTEMS_BDBUF_STATE_TRANSFER: 1398 bd->waiters++; 1399 rtems_bdbuf_wait (pool, &pool->transfer, &pool->transfer_waiters); 1400 bd->waiters--; 1401 break; 1402 1403 default: 1404 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); 1405 } 1406 } 1407 1408 /* 1409 * Buffer is linked to the LRU, modifed, or sync lists. Remove it from there. 1410 */ 1411 rtems_chain_extract (&bd->link); 1412 1413 return bd; 1414 } 1415 1416 /** 1417 * Obtain block buffer. If specified block already cached (i.e. there's block 1418 * in the _modified_, or _recently_used_), return address of appropriate buffer 1419 * descriptor. If block is not cached, allocate new buffer and return it. Data 1420 * shouldn't be read to the buffer from media; buffer may contains arbitrary 1421 * data. This primitive may be blocked if there are no free buffer descriptors 1422 * available and there are no unused non-modified (or synchronized with media) 1423 * buffers available. 1424 * 1425 * @param device device number (constructed of major and minor device number) 1426 * @param block linear media block number 1427 * @param bd address of variable to store pointer to the buffer descriptor 1428 * @return RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 1429 * or error code if error is occured) 777 1430 */ 778 1431 rtems_status_code 779 rtems_bdbuf_init(rtems_bdbuf_config *conf_table, int size) 780 { 781 rtems_bdpool_id i; 782 rtems_status_code rc; 783 784 if (size <= 0) 785 return RTEMS_INVALID_SIZE; 786 787 rtems_bdbuf_ctx.npools = size; 788 789 /* 790 * Allocate memory for buffer pool descriptors 791 */ 792 rtems_bdbuf_ctx.pool = calloc(size, sizeof(bdbuf_pool)); 793 if (rtems_bdbuf_ctx.pool == NULL) 794 { 795 return RTEMS_NO_MEMORY; 796 } 797 798 rtems_chain_initialize_empty(&rtems_bdbuf_ctx.mod); 799 800 /* Initialize buffer pools and roll out if something failed */ 801 for (i = 0; i < size; i++) 802 { 803 rc = bdbuf_initialize_pool(conf_table + i, i); 804 if (rc != RTEMS_SUCCESSFUL) 805 { 806 rtems_bdpool_id j; 807 for (j = 0; j < i - 1; j++) 808 { 809 bdbuf_release_pool(j); 810 } 811 return rc; 812 } 813 } 814 815 /* Create buffer flush semaphore */ 816 rc = rtems_semaphore_create( 817 rtems_build_name('B', 'F', 'L', 'U'), 0, 818 RTEMS_FIFO | RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | 819 RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, 820 &rtems_bdbuf_ctx.flush_sema); 821 if (rc != RTEMS_SUCCESSFUL) 822 { 823 for (i = 0; i < size; i++) 824 bdbuf_release_pool(i); 825 free(rtems_bdbuf_ctx.pool); 826 return rc; 827 } 828 829 /* Create and start swapout task */ 830 rc = rtems_task_create( 831 rtems_build_name('B', 'S', 'W', 'P'), 832 ((swapout_task_priority > 0) 833 ? swapout_task_priority 834 : SWAPOUT_TASK_DEFAULT_PRIORITY), 835 SWAPOUT_TASK_STACK_SIZE, 836 RTEMS_DEFAULT_MODES | RTEMS_NO_PREEMPT, 837 RTEMS_DEFAULT_ATTRIBUTES, 838 &rtems_bdbuf_ctx.swapout_task); 839 if (rc != RTEMS_SUCCESSFUL) 840 { 841 rtems_semaphore_delete(rtems_bdbuf_ctx.flush_sema); 842 for (i = 0; i < size; i++) 843 bdbuf_release_pool(i); 844 free(rtems_bdbuf_ctx.pool); 845 return rc; 846 } 847 848 rc = rtems_task_start(rtems_bdbuf_ctx.swapout_task, bdbuf_swapout_task, 0); 849 if (rc != RTEMS_SUCCESSFUL) 850 { 851 rtems_task_delete(rtems_bdbuf_ctx.swapout_task); 852 rtems_semaphore_delete(rtems_bdbuf_ctx.flush_sema); 853 for (i = 0; i < size; i++) 854 bdbuf_release_pool(i); 855 free(rtems_bdbuf_ctx.pool); 856 return rc; 857 } 858 859 return RTEMS_SUCCESSFUL; 860 } 861 862 /* find_or_assign_buffer -- 863 * Looks for buffer already assigned for this dev/block. If one is found 864 * obtain block buffer. If specified block already cached (i.e. there's 865 * block in the _modified_, or _recently_used_), return address 866 * of appropriate buffer descriptor and increment reference counter to 1. 867 * If block is not cached, allocate new buffer and return it. Data 868 * shouldn't be read to the buffer from media; buffer contains arbitrary 869 * data. This primitive may be blocked if there are no free buffer 870 * descriptors available and there are no unused non-modified (or 871 * synchronized with media) buffers available. 872 * 873 * PARAMETERS: 874 * device - device number (constructed of major and minor device number 875 * block - linear media block number 876 * ret_buf - address of the variable to store address of found descriptor 877 * 878 * RETURNS: 879 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 880 * or error code if error is occured) 881 * 882 * SIDE EFFEECTS: 883 * bufget_sema may be obtained by this primitive 884 * 885 * NOTE: 886 * It is assumed that primitive invoked when thread preemption is disabled. 887 */ 888 static rtems_status_code 889 find_or_assign_buffer(disk_device *dd, 890 blkdev_bnum block, 891 bdbuf_buffer **ret_buf) 892 { 893 bdbuf_buffer *bd_buf; 894 bdbuf_pool *bd_pool; 895 rtems_status_code rc; 896 dev_t device; 897 ISR_Level level; 898 899 int blksize; 900 901 device = dd->dev; 902 bd_pool = rtems_bdbuf_ctx.pool + dd->pool; 903 blksize = dd->block_size; 904 905 again: 906 /* Looking for buffer descriptor used for this dev/block. */ 907 bd_buf = avl_search(&bd_pool->tree, device, block); 908 909 if (bd_buf == NULL) 910 { 911 /* Try to obtain semaphore without waiting first. It is the most 912 frequent case when reasonable number of buffers configured. If 913 it is failed, obtain semaphore blocking on it. In this case 914 it should be checked that appropriate buffer hasn't been loaded 915 by another thread, because this thread is preempted */ 916 rc = rtems_semaphore_obtain(bd_pool->bufget_sema, RTEMS_NO_WAIT, 0); 917 if (rc == RTEMS_UNSATISFIED) 918 { 919 rc = rtems_semaphore_obtain(bd_pool->bufget_sema, 920 RTEMS_WAIT, RTEMS_NO_TIMEOUT); 921 bd_buf = avl_search(&bd_pool->tree, device, block); 922 if (bd_buf != NULL) 923 rtems_semaphore_release(bd_pool->bufget_sema); 924 } 925 } 926 927 if (bd_buf == NULL) 928 { 929 /* Assign new buffer descriptor */ 930 if (rtems_chain_is_empty(&bd_pool->free)) 931 { 932 bd_buf = (bdbuf_buffer *)rtems_chain_get(&bd_pool->lru); 933 if (bd_buf != NULL) 934 { 935 int avl_result; 936 avl_result = avl_remove(&bd_pool->tree, bd_buf); 937 if (avl_result != 0) 938 { 939 rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY); 940 return RTEMS_INTERNAL_ERROR; 941 } 942 } 943 } 944 else 945 { 946 bd_buf = (bdbuf_buffer *)rtems_chain_get(&(bd_pool->free)); 947 } 948 949 if (bd_buf == NULL) 950 { 951 goto again; 952 } 953 else 954 { 955 bd_buf->dev = device; 956 bd_buf->block = block; 957 #ifdef AVL_GPL 958 bd_buf->avl.link[0] = NULL; 959 bd_buf->avl.link[1] = NULL; 960 #else 961 bd_buf->avl.left = NULL; 962 bd_buf->avl.right = NULL; 1432 rtems_bdbuf_get (dev_t device, 1433 rtems_blkdev_bnum block, 1434 rtems_bdbuf_buffer** bdp) 1435 { 1436 rtems_disk_device* dd; 1437 rtems_bdbuf_pool* pool; 1438 rtems_bdbuf_buffer* bd; 1439 1440 /* 1441 * Do not hold the pool lock when obtaining the disk table. 1442 */ 1443 dd = rtems_disk_obtain (device); 1444 if (dd == NULL) 1445 return RTEMS_INVALID_ID; 1446 1447 if (block >= dd->size) 1448 { 1449 rtems_disk_release (dd); 1450 return RTEMS_INVALID_NUMBER; 1451 } 1452 1453 block += dd->start; 1454 1455 pool = rtems_bdbuf_get_pool (dd->phys_dev->pool); 1456 1457 rtems_disk_release(dd); 1458 1459 rtems_bdbuf_lock_pool (pool); 1460 1461 #if RTEMS_BDBUF_TRACE 1462 rtems_bdbuf_printf ("get: %d (dev = %08x)\n", block, device); 963 1463 #endif 964 bd_buf->use_count = 1; 965 bd_buf->modified = bd_buf->actual = bd_buf->in_progress = FALSE; 966 bd_buf->status = RTEMS_SUCCESSFUL; 967 968 if (avl_insert(&bd_pool->tree, bd_buf) != 0) 969 { 970 rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY); 971 return RTEMS_INTERNAL_ERROR; 972 } 973 974 *ret_buf = bd_buf; 975 976 return RTEMS_SUCCESSFUL; 977 } 978 } 979 else 980 { 981 /* Buffer descriptor already assigned for this dev/block */ 982 if (bd_buf->use_count == 0) 983 { 984 /* If we are removing from lru list, obtain the bufget_sema 985 * first. If we are removing from mod list, obtain flush sema. 986 * It should be obtained without blocking because we know 987 * that our buffer descriptor is in the list. */ 988 if (bd_buf->modified) 989 { 990 rc = rtems_semaphore_obtain(rtems_bdbuf_ctx.flush_sema, 991 RTEMS_NO_WAIT, 0); 992 } 993 else 994 { 995 rc = rtems_semaphore_obtain(bd_pool->bufget_sema, 996 RTEMS_NO_WAIT, 0); 997 } 998 /* It is possible that we couldn't obtain flush or bufget sema 999 * although buffer in the appropriate chain is available: 1000 * semaphore may be released to swapout task, but this task 1001 * actually did not start to process it. */ 1002 if (rc == RTEMS_UNSATISFIED) 1003 rc = RTEMS_SUCCESSFUL; 1004 if (rc != RTEMS_SUCCESSFUL) 1005 { 1006 rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_CONSISTENCY); 1007 return RTEMS_INTERNAL_ERROR; 1008 } 1009 1010 /* Buffer descriptor is linked to the lru or mod chain. Remove 1011 it from there. */ 1012 rtems_chain_extract(&bd_buf->link); 1013 } 1014 bd_buf->use_count++; 1015 while (bd_buf->in_progress != 0) 1016 { 1017 rtems_interrupt_disable(level); 1018 _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 1019 WATCHDOG_NO_TIMEOUT, level); 1020 } 1021 1022 *ret_buf = bd_buf; 1023 return RTEMS_SUCCESSFUL; 1024 } 1025 } 1026 1027 /* rtems_bdbuf_get -- 1028 * Obtain block buffer. If specified block already cached (i.e. there's 1029 * block in the _modified_, or _recently_used_), return address 1030 * of appropriate buffer descriptor and increment reference counter to 1. 1031 * If block is not cached, allocate new buffer and return it. Data 1032 * shouldn't be read to the buffer from media; buffer may contains 1033 * arbitrary data. This primitive may be blocked if there are no free 1034 * buffer descriptors available and there are no unused non-modified 1035 * (or synchronized with media) buffers available. 1036 * 1037 * PARAMETERS: 1038 * device - device number (constructed of major and minor device number) 1039 * block - linear media block number 1040 * bd - address of variable to store pointer to the buffer descriptor 1041 * 1042 * RETURNS: 1043 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 1044 * or error code if error is occured) 1045 * 1046 * SIDE EFFECTS: 1047 * bufget_sema semaphore obtained by this primitive. 1048 */ 1049 rtems_status_code 1050 rtems_bdbuf_get(dev_t device, blkdev_bnum block, bdbuf_buffer **bd) 1051 { 1052 rtems_status_code rc; 1053 disk_device *dd; 1054 disk_device *pdd; 1055 preemption_key key; 1056 1057 /* 1058 * Convert logical dev/block to physical one 1059 */ 1060 dd = rtems_disk_lookup(device); 1061 if (dd == NULL) 1062 return RTEMS_INVALID_ID; 1063 1064 if (block >= dd->size) 1065 { 1066 rtems_disk_release(dd); 1067 return RTEMS_INVALID_NUMBER; 1068 } 1069 1070 pdd = dd->phys_dev; 1071 block += dd->start; 1072 rtems_disk_release(dd); 1073 1074 DISABLE_PREEMPTION(key); 1075 rc = find_or_assign_buffer(pdd, block, bd); 1076 ENABLE_PREEMPTION(key); 1077 1078 if (rc != RTEMS_SUCCESSFUL) 1079 return rc; 1080 1081 return RTEMS_SUCCESSFUL; 1082 } 1083 1084 /* bdbuf_initialize_transfer_sema -- 1085 * Initialize transfer_sema mutex semaphore associated with buffer 1086 * descriptor. 1087 */ 1088 static inline void 1089 bdbuf_initialize_transfer_sema(bdbuf_buffer *bd_buf) 1090 { 1091 CORE_mutex_Attributes mutex_attr; 1092 mutex_attr.lock_nesting_behavior = CORE_MUTEX_NESTING_BLOCKS; 1093 mutex_attr.only_owner_release = FALSE; 1094 mutex_attr.discipline = CORE_MUTEX_DISCIPLINES_FIFO; 1095 mutex_attr.priority_ceiling = 0; 1096 1097 _CORE_mutex_Initialize(&bd_buf->transfer_sema, 1098 &mutex_attr, CORE_MUTEX_LOCKED); 1099 } 1100 1101 /* bdbuf_write_transfer_done -- 1464 1465 bd = rtems_bdbuf_get_buffer (dd->phys_dev, pool, block, FALSE); 1466 1467 if (bd->state == RTEMS_BDBUF_STATE_MODIFIED) 1468 bd->state = RTEMS_BDBUF_STATE_ACCESS_MODIFIED; 1469 else 1470 bd->state = RTEMS_BDBUF_STATE_ACCESS; 1471 1472 rtems_bdbuf_unlock_pool (pool); 1473 1474 *bdp = bd; 1475 1476 return RTEMS_SUCCESSFUL; 1477 } 1478 1479 /* bdbuf_read_transfer_done -- 1102 1480 * Callout function. Invoked by block device driver when data transfer 1103 * to device (write) is completed. This function may be invoked from1481 * from device (read) is completed. This function may be invoked from 1104 1482 * interrupt handler. 1105 1483 * … … 1115 1493 */ 1116 1494 static void 1117 bdbuf_write_transfer_done(void *arg, rtems_status_code status, int error) 1118 { 1119 int i; 1120 write_tfer_done_arg_t *wtd_arg = arg; 1121 blkdev_request *req = wtd_arg->req; 1122 bdbuf_buffer **bd_buf_write_store = wtd_arg->write_store; 1123 bdbuf_buffer *bd_buf; 1124 for (i = 0;i < req->count;i++) { 1125 bd_buf = bd_buf_write_store[i]; 1126 bd_buf->status = status; 1127 bd_buf->error = RTEMS_IO_ERROR; 1495 rtems_bdbuf_read_done (void* arg, rtems_status_code status, int error) 1496 { 1497 rtems_blkdev_request* req = (rtems_blkdev_request*) arg; 1498 1499 req->error = error; 1500 req->status = status; 1501 1502 rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC); 1503 } 1504 1505 /** 1506 * Read a block into memory. If the block is not is the cache it is read into 1507 * memory. The caller is blocked until the block is read and placed into the 1508 * cache. 1509 * 1510 * @param device The device number (consists of major and minor device number) 1511 * @param block Linear media block number 1512 * @param bd Pointer to the buffer BD address. 1513 * @retval RTEMS_SUCCESSFUL Operation completed successfully. 1514 * @return rtems_status_code An error code. Buffer still passed to caller. 1515 */ 1516 1517 rtems_status_code 1518 rtems_bdbuf_read (dev_t device, 1519 rtems_blkdev_bnum block, 1520 rtems_bdbuf_buffer** bdp) 1521 { 1522 rtems_disk_device* dd; 1523 rtems_bdbuf_pool* pool; 1524 rtems_bdbuf_buffer* bd = NULL; 1525 int read_ahead_count; 1526 rtems_blkdev_request* req; 1527 1528 /* 1529 * @todo This type of request structure is wrong and should be removed. 1530 */ 1531 #define bdbuf_alloc(size) __builtin_alloca (size) 1532 1533 req = bdbuf_alloc (sizeof (rtems_blkdev_request) + 1534 (sizeof ( rtems_blkdev_sg_buffer) * 1535 rtems_bdbuf_configuration.max_read_ahead_blocks)); 1536 1537 /* 1538 * Do not hold the pool lock when obtaining the disk table. 1539 */ 1540 dd = rtems_disk_obtain (device); 1541 if (dd == NULL) 1542 return RTEMS_INVALID_ID; 1543 1544 block += dd->start; 1545 1546 #if RTEMS_BDBUF_TRACE 1547 rtems_bdbuf_printf ("read: %d (dev = %08x)\n", block, device); 1548 #endif 1549 1550 if (block >= dd->size) 1551 { 1552 rtems_disk_release(dd); 1553 return RTEMS_INVALID_NUMBER; 1554 } 1555 1556 req->count = 0; 1557 req->bufnum = 0; 1558 1559 /* 1560 * Read the block plus the required number of blocks ahead. The number of 1561 * blocks to read ahead is configured by the user and limited by the size of 1562 * the disk or reaching a read ahead block that is also cached. 1563 * 1564 * Limit the blocks read by the size of the disk. 1565 */ 1566 if ((rtems_bdbuf_configuration.max_read_ahead_blocks + block) < dd->size) 1567 read_ahead_count = rtems_bdbuf_configuration.max_read_ahead_blocks; 1568 else 1569 read_ahead_count = dd->size - block; 1570 1571 pool = rtems_bdbuf_get_pool (dd->phys_dev->pool); 1572 1573 rtems_bdbuf_lock_pool (pool); 1574 1575 while (req->count < read_ahead_count) 1576 { 1577 /* 1578 * Get the buffer for the requested block. If the block is cached then 1579 * return it. If it is not cached transfer the block from the disk media 1580 * into memory. 1581 * 1582 * We need to clean up any buffers allocated and not passed back to the 1583 * caller. 1584 */ 1585 bd = rtems_bdbuf_get_buffer (dd->phys_dev, pool, 1586 block + req->count, 1587 req->count == 0 ? FALSE : TRUE); 1588 1589 /* 1590 * Read ahead buffer is in the cache or none available. Read what we 1591 * can. 1592 */ 1593 if (!bd) 1594 break; 1595 1596 /* 1597 * Is the block we are interested in the cache ? 1598 */ 1599 if ((bd->state == RTEMS_BDBUF_STATE_CACHED) || 1600 (bd->state == RTEMS_BDBUF_STATE_MODIFIED)) 1601 break; 1602 1603 bd->state = RTEMS_BDBUF_STATE_TRANSFER; 1604 bd->error = 0; 1605 1606 /* 1607 * @todo The use of these req blocks is not a great design. 1608 * The req is a struct with a single 'bufs' declared in the 1609 * req struct and the others are added in the outer level 1610 * struct. This relies on the structs joining as a single 1611 * array and that assumes the compiler packs the structs. 1612 * Why not just place on a list ? The BD has a node that 1613 * can be used. 1614 */ 1615 req->bufs[req->count].user = bd; 1616 req->bufs[req->count].block = bd->block; 1617 req->bufs[req->count].length = dd->block_size; 1618 req->bufs[req->count].buffer = bd->buffer; 1619 req->count++; 1620 req->bufnum++; 1621 } 1622 1623 /* 1624 * Transfer any requested buffers. If the request count is 0 we have found 1625 * the block in the cache so return it. 1626 */ 1627 if (req->count) 1628 { 1629 /* 1630 * Unlock the pool. We have the buffer for the block and it will be in the 1631 * access or transfer state. We may also have a number of read ahead blocks 1632 * if we need to transfer data. At this point any other threads can gain 1633 * access to the pool and if they are after any of the buffers we have they 1634 * will block and be woken when the buffer is returned to the pool. 1635 * 1636 * If a transfer is needed the I/O operation will occur with pre-emption 1637 * enabled and the pool unlocked. This is a change to the previous version 1638 * of the bdbuf code. 1639 */ 1640 int result; 1641 int b; 1642 1643 rtems_bdbuf_unlock_pool (pool); 1644 1645 req->req = RTEMS_BLKDEV_REQ_READ; 1646 req->req_done = rtems_bdbuf_read_done; 1647 req->done_arg = req; 1648 req->io_task = rtems_task_self (); 1649 req->status = RTEMS_RESOURCE_IN_USE; 1650 req->error = 0; 1651 req->start = dd->start; 1652 1653 result = dd->ioctl (dd->phys_dev->dev, RTEMS_BLKIO_REQUEST, req); 1654 1655 /* 1656 * Inspection of the DOS FS code shows the result from this function is 1657 * handled and a buffer must be returned. 1658 */ 1659 if (result < 0) 1660 { 1661 req->error = errno; 1662 req->status = RTEMS_IO_ERROR; 1663 } 1664 else 1665 { 1666 rtems_status_code sc; 1667 rtems_event_set out; 1668 sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC, 1669 RTEMS_EVENT_ALL | RTEMS_WAIT, 1670 0, &out); 1671 1672 if (sc != RTEMS_SUCCESSFUL) 1673 rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE); 1674 } 1675 1676 rtems_bdbuf_lock_pool (pool); 1677 1678 for (b = 1; b < req->count; b++) 1679 { 1680 bd = req->bufs[b].user; 1681 bd->error = req->error; 1682 bd->state = RTEMS_BDBUF_STATE_READ_AHEAD; 1683 rtems_bdbuf_release (bd); 1684 } 1685 1686 bd = req->bufs[0].user; 1687 } 1688 1689 /* 1690 * The data for this block is cached in the buffer. 1691 */ 1692 if (bd->state == RTEMS_BDBUF_STATE_MODIFIED) 1693 bd->state = RTEMS_BDBUF_STATE_ACCESS_MODIFIED; 1694 else 1695 bd->state = RTEMS_BDBUF_STATE_ACCESS; 1696 1697 rtems_bdbuf_unlock_pool (pool); 1698 rtems_disk_release (dd); 1699 1700 *bdp = bd; 1701 1702 return RTEMS_SUCCESSFUL; 1703 } 1704 1705 /** 1706 * Release buffer that has been in use. The buffer could have been in the 1707 * access state and so with a user of the cache or it was being transfered to 1708 * or from the disk media and so with a driver. Wake any waiters. If no one is 1709 * waiting and this is the only buffer on the LRU list see if anyone is 1710 * waiting. Wake them if they are. 1711 * 1712 * If the buffer has been modified use the modified release call. 1713 * 1714 * @param bd The buffer to return to the pool. 1715 * @retval RTEMS_SUCCESSFUL This operation always succeeds. 1716 */ 1717 1718 rtems_status_code 1719 rtems_bdbuf_release (rtems_bdbuf_buffer* bd) 1720 { 1721 rtems_bdbuf_pool* pool; 1722 1723 if (bd == NULL) 1724 return RTEMS_INVALID_ADDRESS; 1725 1726 pool = rtems_bdbuf_get_pool (bd->pool); 1727 1728 rtems_bdbuf_lock_pool (pool); 1729 1730 #if RTEMS_BDBUF_TRACE 1731 rtems_bdbuf_printf ("release: %d\n", bd->block); 1732 #endif 1733 1734 if (bd->state == RTEMS_BDBUF_STATE_ACCESS_MODIFIED) 1735 { 1736 rtems_bdbuf_append_modified (pool, bd); 1737 } 1738 else 1739 { 1740 /* 1741 * If this is a read ahead buffer place the ready queue. Buffers are 1742 * taken from here first. If we prepend then get from the queue the 1743 * buffers furthermost from the read buffer will be used. 1744 */ 1745 if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD) 1746 rtems_chain_prepend (&pool->ready, &bd->link); 1747 else 1748 { 1749 bd->state = RTEMS_BDBUF_STATE_CACHED; 1750 rtems_chain_append (&pool->lru, &bd->link); 1751 } 1752 } 1753 1754 /* 1755 * If there are threads waiting to access the buffer wake them. Wake any 1756 * waiters if this is the first buffer to placed back onto the queue. 1757 */ 1758 if (bd->waiters) 1759 rtems_bdbuf_wake (pool->access, &pool->access_waiters); 1760 else 1761 { 1762 if (bd->state == RTEMS_BDBUF_STATE_READ_AHEAD) 1763 { 1764 if (rtems_chain_has_only_one_node (&pool->ready)) 1765 rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters); 1766 } 1767 else 1768 { 1769 if (rtems_chain_has_only_one_node (&pool->lru)) 1770 rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters); 1771 } 1772 } 1773 1774 rtems_bdbuf_unlock_pool (pool); 1775 1776 return RTEMS_SUCCESSFUL; 1777 } 1778 1779 /** 1780 * Release buffer that has been in use and has been modified. The buffer could 1781 * have been in the access state and so with a user of the cache or it was 1782 * being transfered to or from the disk media and so with a driver. Wake any 1783 * waiters. If no one is waiting and this is the only buffer on the LRU list 1784 * see if anyone is waiting. Wake them if they are. 1785 * 1786 * If the buffer has been modified use the modified release call. 1787 * 1788 * @param bd The buffer to return to the pool. 1789 * @retval RTEMS_SUCCESSFUL This operation always succeeds. 1790 */ 1791 1792 rtems_status_code 1793 rtems_bdbuf_release_modified (rtems_bdbuf_buffer* bd) 1794 { 1795 rtems_bdbuf_pool* pool; 1796 1797 if (bd == NULL) 1798 return RTEMS_INVALID_ADDRESS; 1799 1800 pool = rtems_bdbuf_get_pool (bd->pool); 1801 1802 rtems_bdbuf_lock_pool (pool); 1803 1804 #if RTEMS_BDBUF_TRACE 1805 rtems_bdbuf_printf ("release modified: %d\n", bd->block); 1806 #endif 1807 1808 bd->hold_timer = rtems_bdbuf_configuration.swap_block_hold; 1809 1810 rtems_bdbuf_append_modified (pool, bd); 1811 1812 if (bd->waiters) 1813 rtems_bdbuf_wake (pool->access, &pool->access_waiters); 1814 1815 rtems_bdbuf_unlock_pool (pool); 1816 1817 return RTEMS_SUCCESSFUL; 1818 } 1819 1820 /** 1821 * Wait until specified buffer synchronized with disk. Invoked on exchanges 1822 * critical for data consistency on the media. The buffer is placed on the sync 1823 * list and the swapper is woken. No sync lock is taken as the buffers on the 1824 * sync list are taken first and passed to the driver before buffers on the 1825 * modified list. 1826 * 1827 * @note This code does not lock the sync mutex and stop additions to the 1828 * modified queue. This means the buffer could be written and then 1829 * returned to the modified list but will not happen as the buffer's 1830 * state is sync. 1831 * 1832 * @param bd Pointer to the bdbuf_buffer structure previously obtained using 1833 * get/read primitive. 1834 * @retval RTEMS_SUCCESSFUL Always returned. 1835 */ 1836 1837 rtems_status_code 1838 rtems_bdbuf_sync (rtems_bdbuf_buffer* bd) 1839 { 1840 rtems_bdbuf_pool* pool; 1841 boolean available; 1842 1843 #if RTEMS_BDBUF_TRACE 1844 rtems_bdbuf_printf ("sync: %d\n", bd->block); 1845 #endif 1846 1847 if (bd == NULL) 1848 return RTEMS_INVALID_ADDRESS; 1849 1850 pool = rtems_bdbuf_get_pool (bd->pool); 1851 1852 rtems_bdbuf_lock_pool (pool); 1853 1854 bd->state = RTEMS_BDBUF_STATE_SYNC; 1855 1856 rtems_chain_append (&pool->sync, &bd->link); 1857 1858 rtems_bdbuf_wake_swapper (); 1859 1860 available = FALSE; 1861 while (!available) 1862 { 1863 switch (bd->state) 1864 { 1865 case RTEMS_BDBUF_STATE_CACHED: 1866 case RTEMS_BDBUF_STATE_READ_AHEAD: 1867 case RTEMS_BDBUF_STATE_MODIFIED: 1868 case RTEMS_BDBUF_STATE_ACCESS: 1869 case RTEMS_BDBUF_STATE_ACCESS_MODIFIED: 1870 available = TRUE; 1871 break; 1872 1873 case RTEMS_BDBUF_STATE_SYNC: 1874 case RTEMS_BDBUF_STATE_TRANSFER: 1875 bd->waiters++; 1876 rtems_bdbuf_wait (pool, &pool->transfer, &pool->transfer_waiters); 1877 bd->waiters--; 1878 break; 1879 1880 default: 1881 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_CONSISTENCY); 1882 } 1883 } 1884 1885 rtems_bdbuf_unlock_pool (pool); 1886 1887 return RTEMS_SUCCESSFUL; 1888 } 1889 1890 /* rtems_bdbuf_syncdev -- 1891 * Synchronize with disk all buffers containing the blocks belonging to 1892 * specified device. 1893 * 1894 * PARAMETERS: 1895 * dev - block device number 1896 * 1897 * RETURNS: 1898 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 1899 * or error code if error is occured) 1900 */ 1901 rtems_status_code 1902 rtems_bdbuf_syncdev (dev_t dev) 1903 { 1904 rtems_disk_device* dd; 1905 rtems_bdbuf_pool* pool; 1906 rtems_status_code sc; 1907 rtems_event_set out; 1908 1909 #if RTEMS_BDBUF_TRACE 1910 rtems_bdbuf_printf ("syncdev: %08x\n", dev); 1911 #endif 1912 1913 /* 1914 * Do not hold the pool lock when obtaining the disk table. 1915 */ 1916 dd = rtems_disk_obtain (dev); 1917 if (dd == NULL) 1918 return RTEMS_INVALID_ID; 1919 1920 pool = rtems_bdbuf_get_pool (dd->pool); 1921 1922 /* 1923 * Take the sync lock before locking the pool. Once we have the sync lock 1924 * we can lock the pool. If another thread has the sync lock it will cause 1925 * this thread to block until it owns the sync lock then it can own the 1926 * pool. The sync lock can only be obtained with the pool unlocked. 1927 */ 1928 1929 rtems_bdbuf_lock_sync (pool); 1930 rtems_bdbuf_lock_pool (pool); 1931 1932 pool->sync_active = TRUE; 1933 pool->sync_requester = rtems_task_self (); 1934 pool->sync_device = dev; 1935 1936 rtems_bdbuf_wake_swapper (); 1937 rtems_bdbuf_unlock_pool (pool); 1938 1939 sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC, 1940 RTEMS_EVENT_ALL | RTEMS_WAIT, 1941 0, &out); 1942 1943 if (sc != RTEMS_SUCCESSFUL) 1944 rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE); 1128 1945 1129 bd_buf->in_progress = FALSE; 1130 _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL); 1131 _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL, 1132 CORE_MUTEX_STATUS_SUCCESSFUL); 1133 } 1134 } 1135 1136 /* bdbuf_read_transfer_done -- 1946 rtems_bdbuf_lock_pool (pool); 1947 1948 pool->sync_active = FALSE; 1949 1950 rtems_bdbuf_unlock_sync (pool); 1951 rtems_bdbuf_unlock_pool (pool); 1952 1953 return rtems_disk_release(dd); 1954 } 1955 1956 /* bdbuf_write_transfer_done -- 1137 1957 * Callout function. Invoked by block device driver when data transfer 1138 * from device (read) is completed. This function may be invoked from1958 * to device (write) is completed. This function may be invoked from 1139 1959 * interrupt handler. 1140 1960 * … … 1150 1970 */ 1151 1971 static void 1152 bdbuf_read_transfer_done(void *arg, rtems_status_code status, int error) 1153 { 1154 #if defined(READ_MULTIPLE) 1155 1156 read_ahead_bd_buf_group *bd_buf_group = arg; 1157 bdbuf_buffer *bd_buf; 1158 int i; 1159 for (i = 0;i < bd_buf_group->cnt;i++) { 1160 bd_buf = bd_buf_group->bd_bufs[i]; 1161 1162 bd_buf->status = status; 1163 bd_buf->error = RTEMS_IO_ERROR; 1164 _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL); 1165 _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL, 1166 CORE_MUTEX_STATUS_SUCCESSFUL); 1167 } 1168 #else 1169 bdbuf_buffer *bd_buf = arg; 1170 bd_buf->status = status; 1171 bd_buf->error = RTEMS_IO_ERROR; 1172 _CORE_mutex_Surrender(&bd_buf->transfer_sema, 0, NULL); 1173 _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL, 1174 CORE_MUTEX_STATUS_SUCCESSFUL); 1175 #endif 1176 } 1177 1178 /* rtems_bdbuf_read -- 1179 * (Similar to the rtems_bdbuf_get, except reading data from media) 1180 * Obtain block buffer. If specified block already cached, return address 1181 * of appropriate buffer and increment reference counter to 1. If block is 1182 * not cached, allocate new buffer and read data to it from the media. 1183 * This primitive may be blocked on waiting until data to be read from 1184 * media, if there are no free buffer descriptors available and there are 1185 * no unused non-modified (or synchronized with media) buffers available. 1186 * 1187 * PARAMETERS: 1188 * device - device number (consists of major and minor device number) 1189 * block - linear media block number 1190 * bd - address of variable to store pointer to the buffer descriptor 1191 * 1192 * RETURNS: 1193 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 1194 * or error code if error is occured) 1195 * 1196 * SIDE EFFECTS: 1197 * bufget_sema and transfer_sema semaphores obtained by this primitive. 1198 */ 1199 #if !defined(READ_MULTIPLE) 1200 rtems_status_code 1201 rtems_bdbuf_read(dev_t device, 1202 blkdev_bnum block, 1203 bdbuf_buffer **bd) 1204 { 1205 preemption_key key; 1206 ISR_Level level; 1207 1208 bdbuf_buffer *bd_buf; 1209 rtems_status_code rc; 1210 int result; 1211 disk_device *dd; 1212 disk_device *pdd; 1213 blkdev_request1 req; 1214 1215 dd = rtems_disk_lookup(device); 1216 if (dd == NULL) 1217 return RTEMS_INVALID_ID; 1218 1219 if (block >= dd->size) 1220 { 1221 rtems_disk_release(dd); 1222 return RTEMS_INVALID_NUMBER; 1223 } 1224 1225 pdd = dd->phys_dev; 1226 block += dd->start; 1227 1228 DISABLE_PREEMPTION(key); 1229 rc = find_or_assign_buffer(pdd, block, &bd_buf); 1230 1231 if (rc != RTEMS_SUCCESSFUL) 1232 { 1233 ENABLE_PREEMPTION(key); 1234 rtems_disk_release(dd); 1235 return rc; 1236 } 1237 1238 if (!bd_buf->actual) 1239 { 1240 bd_buf->in_progress = 1; 1241 1242 req.req.req = BLKDEV_REQ_READ; 1243 req.req.req_done = bdbuf_read_transfer_done; 1244 req.req.done_arg = bd_buf; 1245 req.req.start = block; 1246 req.req.count = 1; 1247 req.req.bufnum = 1; 1248 req.req.bufs[0].length = dd->block_size; 1249 req.req.bufs[0].buffer = bd_buf->buffer; 1250 1251 bdbuf_initialize_transfer_sema(bd_buf); 1252 result = dd->ioctl(pdd->dev, BLKIO_REQUEST, &req); 1253 if (result == -1) 1972 rtems_bdbuf_write_done(void *arg, rtems_status_code status, int error) 1973 { 1974 rtems_blkdev_request* req = (rtems_blkdev_request*) arg; 1975 1976 req->error = error; 1977 req->status = status; 1978 1979 rtems_event_send (req->io_task, RTEMS_BDBUF_TRANSFER_SYNC); 1980 } 1981 1982 /** 1983 * Process the modified list of buffers. We can have a sync or modified 1984 * list that needs to be handled. 1985 */ 1986 static void 1987 rtems_bdbuf_swapout_modified_processing (rtems_bdpool_id pid, 1988 dev_t* dev, 1989 rtems_chain_control* chain, 1990 rtems_chain_control* transfer, 1991 boolean sync_active, 1992 boolean update_timers, 1993 uint32_t timer_delta) 1994 { 1995 if (!rtems_chain_is_empty (chain)) 1996 { 1997 rtems_chain_node* node = rtems_chain_head (chain); 1998 node = node->next; 1999 2000 while (!rtems_chain_is_tail (chain, node)) 2001 { 2002 rtems_bdbuf_buffer* bd = (rtems_bdbuf_buffer*) node; 2003 2004 if (bd->pool == pid) 2005 { 2006 /* 2007 * Check if the buffer's hold timer has reached 0. If a sync 2008 * is active force all the timers to 0. 2009 * 2010 * @note Lots of sync requests will skew this timer. It should 2011 * be based on TOD to be accurate. Does it matter ? 2012 */ 2013 if (sync_active) 2014 bd->hold_timer = 0; 2015 2016 if (bd->hold_timer) 1254 2017 { 1255 bd_buf->status = RTEMS_IO_ERROR; 1256 bd_buf->error = errno; 1257 bd_buf->actual = FALSE; 2018 if (update_timers) 2019 { 2020 if (bd->hold_timer > timer_delta) 2021 bd->hold_timer -= timer_delta; 2022 else 2023 bd->hold_timer = 0; 2024 } 2025 2026 if (bd->hold_timer) 2027 { 2028 node = node->next; 2029 continue; 2030 } 2031 } 2032 2033 /* 2034 * This assumes we can set dev_t to -1 which is just an 2035 * assumption. Cannot use the transfer list being empty 2036 * the sync dev calls sets the dev to use. 2037 */ 2038 if (*dev == -1) 2039 *dev = bd->dev; 2040 2041 if (bd->dev == *dev) 2042 { 2043 rtems_chain_node* next_node = node->next; 2044 rtems_chain_extract (node); 2045 rtems_chain_append (transfer, node); 2046 node = next_node; 2047 bd->state = RTEMS_BDBUF_STATE_TRANSFER; 1258 2048 } 1259 2049 else 1260 2050 { 1261 rtems_interrupt_disable(level); 1262 _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 1263 WATCHDOG_NO_TIMEOUT, level); 1264 bd_buf->actual = TRUE; 2051 node = node->next; 1265 2052 } 1266 bd_buf->in_progress = FALSE; 1267 } 1268 rtems_disk_release(dd); 1269 1270 ENABLE_PREEMPTION(key); 1271 1272 *bd = bd_buf; 1273 1274 return RTEMS_SUCCESSFUL; 1275 } 1276 #else /* READ_MULTIPLE */ 1277 rtems_status_code 1278 rtems_bdbuf_read(dev_t device, 1279 blkdev_bnum block, 1280 bdbuf_buffer **bd) 1281 { 1282 preemption_key key; 1283 ISR_Level level; 1284 1285 bdbuf_buffer *bd_buf,*first_bd_buf; 1286 rtems_status_code rc; 1287 int result; 1288 disk_device *dd; 1289 disk_device *pdd; 1290 blkdev_request_read_ahead req; 1291 read_ahead_bd_buf_group bd_buf_group; 1292 boolean find_more_buffers; 1293 int i; 1294 1295 dd = rtems_disk_lookup(device); 2053 } 2054 } 2055 } 2056 } 2057 2058 /** 2059 * Process the pool. 2060 */ 2061 static boolean 2062 rtems_bdbuf_swapout_pool_processing (rtems_bdpool_id pid, 2063 unsigned long timer_delta, 2064 boolean update_timers, 2065 rtems_blkdev_request* write_req) 2066 { 2067 rtems_bdbuf_pool* pool = rtems_bdbuf_get_pool (pid); 2068 rtems_chain_control transfer; 2069 dev_t dev = -1; 2070 rtems_disk_device* dd; 2071 boolean result = TRUE; 2072 2073 rtems_chain_initialize_empty (&transfer); 2074 2075 rtems_bdbuf_lock_pool (pool); 2076 2077 if (pool->sync_active) 2078 dev = pool->sync_device; 2079 2080 #if 1 2081 /* 2082 * If we have any buffers in the sync queue move then to the 2083 * modified list. The first sync buffer will select the 2084 * device we use. 2085 */ 2086 rtems_bdbuf_swapout_modified_processing (pid, &dev, 2087 &pool->sync, &transfer, 2088 TRUE, FALSE, 2089 timer_delta); 2090 2091 /* 2092 * Process the pool's modified list. 2093 */ 2094 rtems_bdbuf_swapout_modified_processing (pid, &dev, 2095 &pool->modified, &transfer, 2096 pool->sync_active, 2097 update_timers, 2098 timer_delta); 2099 2100 /* 2101 * We have all the buffers that have been modified for this device so 2102 * the pool can be unlocked because the state is set to TRANSFER. 2103 */ 2104 #endif 2105 rtems_bdbuf_unlock_pool (pool); 2106 2107 /* 2108 * If there are buffers to transfer to the media tranfer them. 2109 */ 2110 if (rtems_chain_is_empty (&transfer)) 2111 result = FALSE; 2112 else 2113 { 2114 /* 2115 * Obtain the disk device. Release the pool mutex to avoid a dead 2116 * lock. 2117 */ 2118 dd = rtems_disk_obtain (dev); 1296 2119 if (dd == NULL) 1297 return RTEMS_INVALID_ID; 1298 1299 if (block >= dd->size) 1300 { 1301 rtems_disk_release(dd); 1302 return RTEMS_INVALID_NUMBER; 1303 } 1304 1305 pdd = dd->phys_dev; 1306 block += dd->start; 1307 1308 DISABLE_PREEMPTION(key); 1309 rc = find_or_assign_buffer(pdd, block, &first_bd_buf); 1310 1311 if (rc != RTEMS_SUCCESSFUL) 1312 { 1313 ENABLE_PREEMPTION(key); 1314 rtems_disk_release(dd); 1315 return rc; 1316 } 1317 if (!first_bd_buf->actual) 1318 { 1319 1320 bd_buf_group.bd_bufs[0] = first_bd_buf; 1321 bd_buf_group.cnt = 1; 1322 1323 first_bd_buf->in_progress = TRUE; 1324 1325 req.req.req = BLKDEV_REQ_READ; 1326 req.req.req_done = bdbuf_read_transfer_done; 1327 req.req.done_arg = &bd_buf_group; 1328 req.req.start = block; 1329 req.req.count = 1; 1330 req.req.bufnum = 1; 1331 req.req.bufs[0].length = dd->block_size; 1332 req.req.bufs[0].buffer = first_bd_buf->buffer; 2120 result = FALSE; 2121 else 2122 { 2123 /* 2124 * The last block number used when the driver only supports 2125 * continuous blocks in a single request. 2126 */ 2127 uint32_t last_block = 0; 2128 2129 /* 2130 * Take as many buffers are configured and pass to the driver. Note, 2131 * the API to the drivers has the array of buffers and if a chain was 2132 * passed we could have just passed the list. If the driver API is 2133 * updated it should be possible to make this change with little effect 2134 * in this code. The array that is passed is broken in design and 2135 * should be removed. Merging to members of a struct into the first 2136 * member is trouble waiting to happen. 2137 */ 2138 2139 write_req->status = RTEMS_RESOURCE_IN_USE; 2140 write_req->start = dd->start; 2141 write_req->error = 0; 2142 write_req->count = 0; 2143 write_req->bufnum = 0; 2144 2145 while (!rtems_chain_is_empty (&transfer)) 2146 { 2147 rtems_bdbuf_buffer* bd = 2148 (rtems_bdbuf_buffer*) rtems_chain_get (&transfer); 2149 2150 boolean write = FALSE; 1333 2151 1334 bdbuf_initialize_transfer_sema(first_bd_buf); 1335 /* 1336 * FIXME: check for following blocks to be: 1337 * - still in range of partition size 1338 * - not yet assigned 1339 * - buffer available 1340 * allocate for read call, if possible 1341 */ 1342 find_more_buffers = TRUE; 1343 while (find_more_buffers) { 1344 block++; 1345 /* 1346 * still bd_buf_group entries free and 1347 * still in range of this disk? 1348 */ 1349 if ((bd_buf_group.cnt >= READ_AHEAD_MAX_BLK_CNT) || 1350 (block >= dd->size)) { 1351 find_more_buffers = FALSE; 1352 } 1353 if (find_more_buffers) { 1354 rc = find_or_assign_buffer(pdd, block, &bd_buf); 1355 if (rc != RTEMS_SUCCESSFUL) { 1356 find_more_buffers = FALSE; 1357 } 1358 else if (bd_buf->actual) { 1359 find_more_buffers = FALSE; 1360 bdbuf_release(bd_buf); 1361 } 1362 } 1363 if (find_more_buffers) { 1364 bdbuf_initialize_transfer_sema(bd_buf); 1365 bd_buf->in_progress = TRUE; 1366 1367 req.req.bufs[req.req.count].length = dd->block_size; 1368 req.req.bufs[req.req.count].buffer = bd_buf->buffer; 1369 req.req.count++; 1370 req.req.bufnum++; 1371 bd_buf_group.bd_bufs[bd_buf_group.cnt] = bd_buf; 1372 bd_buf_group.cnt++; 1373 } 1374 } 1375 1376 /* do the actual read call here 1377 */ 1378 result = dd->ioctl(pdd->dev, BLKIO_REQUEST, &req); 1379 1380 /* 1381 * cleanup: 1382 * wait, until all bd_bufs are processed 1383 * set status in all bd_bufs 1384 */ 1385 for (i = 0;i < bd_buf_group.cnt;i++) { 1386 bd_buf = bd_buf_group.bd_bufs[i]; 1387 if (result == -1) 1388 { 1389 bd_buf->status = RTEMS_IO_ERROR; 1390 bd_buf->error = errno; 1391 bd_buf->actual = FALSE; 1392 } 1393 else 1394 { 1395 rtems_interrupt_disable(level); 1396 _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 1397 WATCHDOG_NO_TIMEOUT, level); 1398 bd_buf->actual = TRUE; 1399 } 1400 bd_buf->in_progress = FALSE; 1401 /* release any pre-read buffers */ 1402 if (i > 0) { 1403 bdbuf_release(bd_buf); 1404 } 1405 } 1406 } 1407 rtems_disk_release(dd); 1408 1409 ENABLE_PREEMPTION(key); 1410 1411 *bd = first_bd_buf; 1412 1413 return RTEMS_SUCCESSFUL; 1414 } 1415 #endif /* READ_MULTIPLE */ 1416 1417 1418 /* bdbuf_release -- 1419 * Release buffer. Decrease buffer usage counter. If it is zero, further 1420 * processing depends on modified attribute. If buffer was modified, it 1421 * is inserted into mod chain and swapout task waken up. If buffer was 1422 * not modified, it is returned to the end of lru chain making it available 1423 * for further use. 1424 * 1425 * PARAMETERS: 1426 * bd_buf - pointer to the released buffer descriptor. 1427 * 1428 * RETURNS: 1429 * RTEMS_SUCCESSFUL if buffer released successfully, or error code if 1430 * error occured. 1431 * 1432 * NOTE: 1433 * This is internal function. It is assumed that task made non-preemptive 1434 * before its invocation. 1435 */ 1436 static rtems_status_code 1437 bdbuf_release(bdbuf_buffer *bd_buf) 1438 { 1439 bdbuf_pool *bd_pool; 1440 rtems_status_code rc = RTEMS_SUCCESSFUL; 1441 1442 if (bd_buf->use_count <= 0) 1443 return RTEMS_INTERNAL_ERROR; 1444 1445 bd_pool = rtems_bdbuf_ctx.pool + bd_buf->pool; 1446 1447 bd_buf->use_count--; 1448 1449 if (bd_buf->use_count == 0) 1450 { 1451 if (bd_buf->modified) 2152 /* 2153 * If the device only accepts sequential buffers and 2154 * this is not the first buffer (the first is always 2155 * sequential, and the buffer is not sequential then 2156 * put the buffer back on the transfer chain and 2157 * write the committed buffers. 2158 */ 2159 2160 if ((dd->capabilities & RTEMS_BLKDEV_CAP_MULTISECTOR_CONT) && 2161 write_req->count && 2162 (bd->block != (last_block + 1))) 1452 2163 { 1453 1454 /* Buffer was modified. Insert buffer to the modified buffers 1455 * list and initiate flushing. */ 1456 rtems_chain_append(&rtems_bdbuf_ctx.mod, &bd_buf->link); 1457 1458 /* Release the flush_sema */ 1459 rc = rtems_semaphore_release(rtems_bdbuf_ctx.flush_sema); 2164 rtems_chain_prepend (&transfer, &bd->link); 2165 write = TRUE; 1460 2166 } 1461 2167 else 1462 2168 { 1463 /* Buffer was not modified. Add this descriptor to the 1464 * end of lru chain and make it available for reuse. */ 1465 rtems_chain_append(&bd_pool->lru, &bd_buf->link); 1466 rc = rtems_semaphore_release(bd_pool->bufget_sema); 2169 write_req->bufs[write_req->count].user = bd; 2170 write_req->bufs[write_req->count].block = bd->block; 2171 write_req->bufs[write_req->count].length = dd->block_size; 2172 write_req->bufs[write_req->count].buffer = bd->buffer; 2173 write_req->count++; 2174 write_req->bufnum++; 2175 last_block = bd->block; 1467 2176 } 1468 } 1469 return rc; 1470 } 1471 1472 1473 /* rtems_bdbuf_release -- 1474 * Release buffer allocated before. This primitive decrease the 1475 * usage counter. If it is zero, further destiny of buffer depends on 1476 * 'modified' status. If buffer was modified, it is placed to the end of 1477 * mod list and flush task waken up. If buffer was not modified, 1478 * it is placed to the end of lru list, and bufget_sema released, allowing 1479 * to reuse this buffer. 1480 * 1481 * PARAMETERS: 1482 * bd_buf - pointer to the bdbuf_buffer structure previously obtained using 1483 * get/read primitive. 1484 * 1485 * RETURNS: 1486 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 1487 * or error code if error is occured) 1488 * 1489 * SIDE EFFECTS: 1490 * flush_sema and bufget_sema semaphores may be released by this primitive. 1491 */ 1492 rtems_status_code 1493 rtems_bdbuf_release(bdbuf_buffer *bd_buf) 1494 { 1495 preemption_key key; 1496 rtems_status_code rc = RTEMS_SUCCESSFUL; 1497 1498 if (bd_buf == NULL) 1499 return RTEMS_INVALID_ADDRESS; 1500 1501 DISABLE_PREEMPTION(key); 1502 1503 rc = bdbuf_release(bd_buf); 1504 1505 ENABLE_PREEMPTION(key); 1506 1507 return rc; 1508 } 1509 1510 /* rtems_bdbuf_release_modified -- 1511 * Release buffer allocated before, assuming that it is _modified_ by 1512 * it's owner. This primitive decrease usage counter for buffer, mark 1513 * buffer descriptor as modified. If usage counter is 0, insert it at 1514 * end of mod chain and release flush_sema semaphore to activate the 1515 * flush task. 1516 * 1517 * PARAMETERS: 1518 * bd_buf - pointer to the bdbuf_buffer structure previously obtained using 1519 * get/read primitive. 1520 * 1521 * RETURNS: 1522 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 1523 * or error code if error is occured) 1524 * 1525 * SIDE EFFECTS: 1526 * flush_sema semaphore may be released by this primitive. 1527 */ 1528 rtems_status_code 1529 rtems_bdbuf_release_modified(bdbuf_buffer *bd_buf) 1530 { 1531 preemption_key key; 1532 rtems_status_code rc = RTEMS_SUCCESSFUL; 1533 1534 if (bd_buf == NULL) 1535 return RTEMS_INVALID_ADDRESS; 1536 1537 DISABLE_PREEMPTION(key); 1538 1539 if (!bd_buf->modified) 1540 { 1541 bdbuf_initialize_transfer_sema(bd_buf); 1542 } 1543 bd_buf->modified = TRUE; 1544 bd_buf->actual = TRUE; 1545 rc = bdbuf_release(bd_buf); 1546 1547 ENABLE_PREEMPTION(key); 1548 1549 return rc; 1550 } 1551 1552 /* rtems_bdbuf_sync -- 1553 * Wait until specified buffer synchronized with disk. Invoked on exchanges 1554 * critical for data consistency on the media. This primitive mark owned 1555 * block as modified, decrease usage counter. If usage counter is 0, 1556 * block inserted to the mod chain and flush_sema semaphore released. 1557 * Finally, primitives blocked on transfer_sema semaphore. 1558 * 1559 * PARAMETERS: 1560 * bd_buf - pointer to the bdbuf_buffer structure previously obtained using 1561 * get/read primitive. 1562 * 1563 * RETURNS: 1564 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 1565 * or error code if error is occured) 1566 * 1567 * SIDE EFFECTS: 1568 * Primitive may be blocked on transfer_sema semaphore. 1569 */ 1570 rtems_status_code 1571 rtems_bdbuf_sync(bdbuf_buffer *bd_buf) 1572 { 1573 preemption_key key; 1574 ISR_Level level; 1575 rtems_status_code rc = RTEMS_SUCCESSFUL; 1576 1577 if (bd_buf == NULL) 1578 return RTEMS_INVALID_ADDRESS; 1579 1580 DISABLE_PREEMPTION(key); 1581 1582 if (!bd_buf->modified) 1583 { 1584 bdbuf_initialize_transfer_sema(bd_buf); 1585 } 1586 bd_buf->modified = TRUE; 1587 bd_buf->actual = TRUE; 1588 1589 rc = bdbuf_release(bd_buf); 1590 1591 if (rc == RTEMS_SUCCESSFUL) 1592 { 1593 rtems_interrupt_disable(level); 1594 _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 1595 WATCHDOG_NO_TIMEOUT, level); 1596 } 1597 1598 ENABLE_PREEMPTION(key); 1599 1600 return rc; 1601 } 1602 1603 /* rtems_bdbuf_syncdev -- 1604 * Synchronize with disk all buffers containing the blocks belonging to 1605 * specified device. 1606 * 1607 * PARAMETERS: 1608 * dev - block device number 1609 * 1610 * RETURNS: 1611 * RTEMS status code (RTEMS_SUCCESSFUL if operation completed successfully 1612 * or error code if error is occured) 1613 */ 1614 rtems_status_code 1615 rtems_bdbuf_syncdev(dev_t dev) 1616 { 1617 preemption_key key; 1618 ISR_Level level; 1619 1620 bdbuf_buffer *bd_buf; 1621 disk_device *dd; 1622 bdbuf_pool *pool; 1623 1624 dd = rtems_disk_lookup(dev); 1625 if (dd == NULL) 1626 return RTEMS_INVALID_ID; 1627 1628 pool = rtems_bdbuf_ctx.pool + dd->pool; 1629 1630 DISABLE_PREEMPTION(key); 1631 do { 1632 bd_buf = avl_search_for_sync(&pool->tree, dd); 1633 if (bd_buf != NULL /* && bd_buf->modified */) 2177 2178 /* 2179 * Perform the transfer if there are no more buffers, or the 2180 * transfer size has reached the configured max. value. 2181 */ 2182 2183 if (rtems_chain_is_empty (&transfer) || 2184 (write_req->count >= rtems_bdbuf_configuration.max_write_blocks)) 2185 write = TRUE; 2186 2187 if (write) 1634 2188 { 1635 rtems_interrupt_disable(level); 1636 _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 1637 WATCHDOG_NO_TIMEOUT, level); 2189 int result; 2190 int b; 2191 2192 /* 2193 * Perform the transfer. No pool locks, no preemption, only the 2194 * disk device is being held. 2195 */ 2196 result = dd->ioctl (dd->phys_dev->dev, 2197 RTEMS_BLKIO_REQUEST, write_req); 2198 2199 if (result < 0) 2200 { 2201 rtems_bdbuf_lock_pool (pool); 2202 2203 for (b = 0; b < write_req->count; b++) 2204 { 2205 bd = write_req->bufs[b].user; 2206 bd->state = RTEMS_BDBUF_STATE_MODIFIED; 2207 bd->error = errno; 2208 2209 /* 2210 * Place back on the pools modified queue and try again. 2211 * 2212 * @warning Not sure this is the best option but I do 2213 * not know what else can be done. 2214 */ 2215 rtems_chain_append (&pool->modified, &bd->link); 2216 } 2217 } 2218 else 2219 { 2220 rtems_status_code sc = 0; 2221 rtems_event_set out; 2222 2223 sc = rtems_event_receive (RTEMS_BDBUF_TRANSFER_SYNC, 2224 RTEMS_EVENT_ALL | RTEMS_WAIT, 2225 0, &out); 2226 2227 if (sc != RTEMS_SUCCESSFUL) 2228 rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE); 2229 2230 rtems_bdbuf_lock_pool (pool); 2231 2232 for (b = 0; b < write_req->count; b++) 2233 { 2234 bd = write_req->bufs[b].user; 2235 bd->state = RTEMS_BDBUF_STATE_CACHED; 2236 bd->error = 0; 2237 2238 rtems_chain_append (&pool->lru, &bd->link); 2239 2240 if (bd->waiters) 2241 rtems_bdbuf_wake (pool->transfer, &pool->transfer_waiters); 2242 else 2243 { 2244 if (rtems_chain_has_only_one_node (&pool->lru)) 2245 rtems_bdbuf_wake (pool->waiting, &pool->wait_waiters); 2246 } 2247 } 2248 } 2249 2250 rtems_bdbuf_unlock_pool (pool); 2251 2252 write_req->status = RTEMS_RESOURCE_IN_USE; 2253 write_req->error = 0; 2254 write_req->count = 0; 2255 write_req->bufnum = 0; 1638 2256 } 1639 } while (bd_buf != NULL); 1640 ENABLE_PREEMPTION(key); 1641 return rtems_disk_release(dd); 1642 } 1643 1644 /* bdbuf_swapout_task -- 1645 * Body of task which take care on flushing modified buffers to the 1646 * disk. 2257 } 2258 2259 rtems_disk_release (dd); 2260 } 2261 } 2262 2263 if (pool->sync_active) 2264 rtems_event_send (pool->sync_requester, RTEMS_BDBUF_TRANSFER_SYNC); 2265 2266 return result; 2267 } 2268 2269 /** 2270 * Body of task which take care on flushing modified buffers to the disk. 1647 2271 */ 1648 2272 static rtems_task 1649 bdbuf_swapout_task(rtems_task_argument unused) 1650 { 1651 rtems_status_code rc; 1652 int result; 1653 int i; 1654 ISR_Level level; 1655 bdbuf_buffer *bd_buf; 1656 bdbuf_buffer *nxt_bd_buf; 1657 bdbuf_pool *bd_pool = NULL; 1658 disk_device *dd = NULL; 1659 struct { 1660 blkdev_request req; 1661 blkdev_sg_buffer sg[SWAP_OUT_MAX_BLK_CNT]; 1662 } req; 1663 write_tfer_done_arg_t write_tfer_done_arg; 2273 rtems_bdbuf_swapout_task (rtems_task_argument arg) 2274 { 2275 rtems_bdbuf_context* context = (rtems_bdbuf_context*) arg; 2276 rtems_blkdev_request* write_req; 2277 uint32_t period_in_ticks; 2278 const uint32_t period_in_msecs = rtems_bdbuf_configuration.swapout_period; 2279 uint32_t timer_delta; 2280 rtems_status_code sc; 2281 2282 /* 2283 * @note chrisj The rtems_blkdev_request and the array at the end is a hack. 2284 * I am disappointment at finding code like this in RTEMS. The request should 2285 * have been a rtems_chain_control. Simple, fast and less storage as the node 2286 * is already part of the buffer structure. 2287 */ 2288 write_req = 2289 malloc (sizeof (rtems_blkdev_request) + 2290 (rtems_bdbuf_configuration.max_write_blocks * 2291 sizeof (rtems_blkdev_sg_buffer))); 2292 2293 if (!write_req) 2294 rtems_fatal_error_occurred (RTEMS_BLKDEV_FATAL_BDBUF_SO_NOMEM); 2295 2296 write_req->req = RTEMS_BLKDEV_REQ_WRITE; 2297 write_req->req_done = rtems_bdbuf_write_done; 2298 write_req->done_arg = write_req; 2299 write_req->io_task = rtems_task_self (); 2300 2301 period_in_ticks = TOD_MICROSECONDS_TO_TICKS (period_in_msecs * 1000); 2302 2303 /* 2304 * This is temporary. Needs to be changed to use the real clock. 2305 */ 2306 timer_delta = period_in_msecs; 2307 2308 while (context->swapout_enabled) 2309 { 2310 rtems_event_set out; 1664 2311 1665 2312 /* 1666 * provide info needed for write_transfer_done function2313 * Only update the timers once in the processing cycle. 1667 2314 */ 1668 write_tfer_done_arg.req = (blkdev_request *)&req.req; 1669 write_tfer_done_arg.write_store = bd_buf_write_store; 1670 nxt_bd_buf = NULL; 1671 while (1) 1672 { 1673 req.req.req = BLKDEV_REQ_WRITE; 1674 req.req.req_done = bdbuf_write_transfer_done; 1675 req.req.done_arg = &write_tfer_done_arg; 1676 req.req.count = 0; 1677 req.req.bufnum = 0; 1678 bd_buf = NULL; 1679 do { 1680 /* 1681 * if a buffer was left over from last loop, then use this buffer 1682 * otherwise fetch new buffer from chain. 1683 * Wait for buffer, if this is the first one of the request, 1684 * otherwise do not wait, if no buffer available 1685 */ 1686 if (nxt_bd_buf == NULL) { 1687 rc = rtems_semaphore_obtain(rtems_bdbuf_ctx.flush_sema, 1688 (req.req.count == 0) 1689 ? RTEMS_WAIT 1690 : RTEMS_NO_WAIT, 1691 0); 1692 if (rc == RTEMS_SUCCESSFUL) { 1693 nxt_bd_buf = (bdbuf_buffer *)rtems_chain_get(&rtems_bdbuf_ctx.mod); 1694 if (nxt_bd_buf != NULL) { 1695 nxt_bd_buf->in_progress = TRUE; 1696 /* IMD try: clear "modified" bit early */ 1697 /* (and not in bdbuf_write_transfer_done) to allow */ 1698 /* another modification during write processing */ 1699 nxt_bd_buf->modified = FALSE; 1700 1701 nxt_bd_buf->use_count++; 1702 } 1703 } 1704 else if ((rc != RTEMS_UNSATISFIED) && 1705 (rc != RTEMS_TIMEOUT)) { 1706 rtems_fatal_error_occurred(BLKDEV_FATAL_BDBUF_SWAPOUT); 1707 } 1708 } 1709 /* 1710 * It is possible that flush_sema semaphore will be released, but 1711 * buffer to be removed from mod chain before swapout task start 1712 * its processing. 1713 */ 1714 if ((req.req.count == 0) || /* first bd_buf for this request */ 1715 ((nxt_bd_buf != NULL) && 1716 (nxt_bd_buf->dev == bd_buf->dev) && /* same device */ 1717 (nxt_bd_buf->block == bd_buf->block+1))) {/* next block */ 1718 bd_buf = nxt_bd_buf; 1719 nxt_bd_buf = NULL; 1720 } 1721 else { 1722 bd_buf = NULL; 1723 } 1724 /* 1725 * here we have three possible states: 1726 * bd_buf == NULL, nxt_bd_buf == NULL: no further block available 1727 * bd_buf != NULL, nxt_bd_buf == NULL: append bd_buf to request 1728 * bd_buf == NULL, nxt_bd_buf != NULL: nxt_bd_buf canot be appended 1729 * to current request, keep it 1730 * for next main loop 1731 */ 1732 if (bd_buf != NULL) { 1733 bd_pool = rtems_bdbuf_ctx.pool + bd_buf->pool; 1734 if (req.req.count == 0) { 1735 /* 1736 * this is the first block, so use its address 1737 */ 1738 dd = rtems_disk_lookup(bd_buf->dev); 1739 req.req.start = bd_buf->block + dd->start; 1740 } 1741 req.req.bufs[req.req.bufnum].length = dd->block_size; 1742 req.req.bufs[req.req.bufnum].buffer = bd_buf->buffer; 1743 /* 1744 * keep bd_buf for postprocessing 1745 */ 1746 bd_buf_write_store[req.req.bufnum] = bd_buf; 1747 req.req.count++; 1748 req.req.bufnum++; 1749 } 1750 } while ((bd_buf != NULL) && 1751 (req.req.count < SWAP_OUT_MAX_BLK_CNT)); 1752 1753 /* transfer_sema initialized when bd_buf inserted in the mod chain 1754 first time */ 1755 result = dd->ioctl(dd->phys_dev->dev, BLKIO_REQUEST, &req); 1756 1757 rtems_disk_release(dd); 1758 1759 for (i = 0;i < req.req.count;i++) { 1760 bd_buf = bd_buf_write_store[i]; 1761 if (result == -1) 1762 { 1763 1764 bd_buf->status = RTEMS_IO_ERROR; 1765 bd_buf->error = errno; 1766 /* Release tasks waiting on syncing this buffer */ 1767 _CORE_mutex_Flush(&bd_buf->transfer_sema, NULL, 1768 CORE_MUTEX_STATUS_SUCCESSFUL); 1769 } 1770 else 1771 { 1772 if (bd_buf->in_progress) 1773 { 1774 rtems_interrupt_disable(level); 1775 _CORE_mutex_Seize(&bd_buf->transfer_sema, 0, TRUE, 0, level); 1776 } 1777 } 1778 bd_buf->use_count--; 1779 1780 /* Another task have chance to use this buffer, or even 1781 * modify it. If buffer is not in use, insert it in appropriate chain 1782 * and release semaphore */ 1783 if (bd_buf->use_count == 0) 1784 { 1785 if (bd_buf->modified) 1786 { 1787 rtems_chain_append(&rtems_bdbuf_ctx.mod, &bd_buf->link); 1788 rc = rtems_semaphore_release(rtems_bdbuf_ctx.flush_sema); 1789 } 1790 else 1791 { 1792 rtems_chain_append(&bd_pool->lru, &bd_buf->link); 1793 rc = rtems_semaphore_release(bd_pool->bufget_sema); 1794 } 1795 } 2315 boolean update_timers = TRUE; 2316 2317 /* 2318 * If we write buffers to any disk perform a check again. We only 2319 * write a single device at a time and a pool may have more than 2320 * one devices buffers modified waiting to be written. 2321 */ 2322 boolean transfered_buffers; 2323 2324 do 2325 { 2326 rtems_bdpool_id pid; 2327 2328 transfered_buffers = FALSE; 2329 2330 /* 2331 * Loop over each pool extacting all the buffers we find for a specific 2332 * device. The device is the first one we find on a modified list of a 2333 * pool. Process the sync queue of buffers first. 2334 */ 2335 for (pid = 0; pid < context->npools; pid++) 2336 { 2337 if (rtems_bdbuf_swapout_pool_processing (pid, 2338 timer_delta, 2339 update_timers, 2340 write_req)) 2341 { 2342 transfered_buffers = TRUE; 1796 2343 } 1797 } 1798 } 1799 1800 /* rtems_bdbuf_find_pool -- 1801 * Find first appropriate buffer pool. This primitive returns the index 1802 * of first buffer pool which block size is greater than or equal to 1803 * specified size. 2344 } 2345 2346 /* 2347 * Only update the timers once. 2348 */ 2349 update_timers = FALSE; 2350 } 2351 while (transfered_buffers); 2352 2353 sc = rtems_event_receive (RTEMS_BDBUF_SWAPOUT_SYNC, 2354 RTEMS_EVENT_ALL | RTEMS_WAIT, 2355 period_in_ticks, 2356 &out); 2357 2358 if ((sc != RTEMS_SUCCESSFUL) && (sc != RTEMS_TIMEOUT)) 2359 rtems_fatal_error_occurred (BLKDEV_FATAL_BDBUF_SWAPOUT_RE); 2360 } 2361 2362 free (write_req); 2363 2364 rtems_task_delete (RTEMS_SELF); 2365 } 2366 2367 /** 2368 * Find first appropriate buffer pool. This primitive returns the index of 2369 * first buffer pool which block size is greater than or equal to specified 2370 * size. 1804 2371 * 1805 2372 * PARAMETERS: … … 1814 2381 */ 1815 2382 rtems_status_code 1816 rtems_bdbuf_find_pool(int block_size, rtems_bdpool_id *pool) 1817 { 1818 rtems_bdpool_id i; 1819 bdbuf_pool *p; 1820 int cursize = INT_MAX; 1821 rtems_bdpool_id curid = -1; 1822 rtems_boolean found = FALSE; 1823 int j; 1824 1825 for (j = block_size; (j != 0) && ((j & 1) == 0); j >>= 1); 1826 if (j != 1) 1827 return RTEMS_INVALID_SIZE; 1828 1829 for (i = 0, p = rtems_bdbuf_ctx.pool; i < rtems_bdbuf_ctx.npools; i++, p++) 1830 { 1831 if ((p->blksize >= block_size) && 1832 (p->blksize < cursize)) 1833 { 1834 curid = i; 1835 cursize = p->blksize; 1836 found = TRUE; 1837 } 1838 } 1839 1840 if (found) 1841 { 1842 if (pool != NULL) 1843 *pool = curid; 1844 return RTEMS_SUCCESSFUL; 1845 } 1846 else 1847 { 1848 return RTEMS_NOT_DEFINED; 1849 } 1850 } 1851 1852 /* rtems_bdbuf_get_pool_info -- 1853 * Obtain characteristics of buffer pool with specified number. 2383 rtems_bdbuf_find_pool (int block_size, rtems_bdpool_id *pool) 2384 { 2385 rtems_bdbuf_pool* p; 2386 rtems_bdpool_id i; 2387 rtems_bdpool_id curid = -1; 2388 rtems_boolean found = FALSE; 2389 int cursize = INT_MAX; 2390 int j; 2391 2392 for (j = block_size; (j != 0) && ((j & 1) == 0); j >>= 1); 2393 if (j != 1) 2394 return RTEMS_INVALID_SIZE; 2395 2396 for (i = 0; i < rtems_bdbuf_ctx.npools; i++) 2397 { 2398 p = rtems_bdbuf_get_pool (i); 2399 if ((p->blksize >= block_size) && 2400 (p->blksize < cursize)) 2401 { 2402 curid = i; 2403 cursize = p->blksize; 2404 found = TRUE; 2405 } 2406 } 2407 2408 if (found) 2409 { 2410 if (pool != NULL) 2411 *pool = curid; 2412 return RTEMS_SUCCESSFUL; 2413 } 2414 else 2415 { 2416 return RTEMS_NOT_DEFINED; 2417 } 2418 } 2419 2420 /** 2421 * Obtain characteristics of buffer pool with specified number. 1854 2422 * 1855 2423 * PARAMETERS: … … 1867 2435 */ 1868 2436 rtems_status_code 1869 rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int *block_size, 1870 int *blocks) 1871 { 1872 if (pool >= rtems_bdbuf_ctx.npools) 1873 return RTEMS_INVALID_NUMBER; 1874 1875 if (block_size != NULL) 1876 { 1877 *block_size = rtems_bdbuf_ctx.pool[pool].blksize; 1878 } 1879 1880 if (blocks != NULL) 1881 { 1882 *blocks = rtems_bdbuf_ctx.pool[pool].nblks; 1883 } 1884 1885 return RTEMS_SUCCESSFUL; 1886 } 2437 rtems_bdbuf_get_pool_info(rtems_bdpool_id pool, int* block_size, int* blocks) 2438 { 2439 if (pool >= rtems_bdbuf_ctx.npools) 2440 return RTEMS_INVALID_NUMBER; 2441 2442 if (block_size != NULL) 2443 { 2444 *block_size = rtems_bdbuf_ctx.pool[pool].blksize; 2445 } 2446 2447 if (blocks != NULL) 2448 { 2449 *blocks = rtems_bdbuf_ctx.pool[pool].nblks; 2450 } 2451 2452 return RTEMS_SUCCESSFUL; 2453 } -
cpukit/libblock/src/blkdev.c
r1b39f18 r3899a537 39 39 unsigned int blkofs; 40 40 dev_t dev; 41 disk_device *dd;42 43 dev = rtems_filesystem_make_dev_t(major, minor); 44 dd = rtems_disk_ lookup(dev);41 rtems_disk_device *dd; 42 43 dev = rtems_filesystem_make_dev_t(major, minor); 44 dd = rtems_disk_obtain(dev); 45 45 if (dd == NULL) 46 46 return RTEMS_INVALID_NUMBER; … … 58 58 while (count > 0) 59 59 { 60 bdbuf_buffer *diskbuf;60 rtems_bdbuf_buffer *diskbuf; 61 61 int copy; 62 62 rtems_status_code rc; … … 100 100 dev_t dev; 101 101 rtems_status_code rc; 102 disk_device *dd;103 104 dev = rtems_filesystem_make_dev_t(major, minor); 105 dd = rtems_disk_ lookup(dev);102 rtems_disk_device *dd; 103 104 dev = rtems_filesystem_make_dev_t(major, minor); 105 dd = rtems_disk_obtain(dev); 106 106 if (dd == NULL) 107 107 return RTEMS_INVALID_NUMBER; … … 119 119 while (count > 0) 120 120 { 121 bdbuf_buffer *diskbuf;121 rtems_bdbuf_buffer *diskbuf; 122 122 int copy; 123 123 … … 157 157 { 158 158 dev_t dev; 159 disk_device *dd;160 161 dev = rtems_filesystem_make_dev_t(major, minor); 162 dd = rtems_disk_ lookup(dev);159 rtems_disk_device *dd; 160 161 dev = rtems_filesystem_make_dev_t(major, minor); 162 dd = rtems_disk_obtain(dev); 163 163 if (dd == NULL) 164 164 return RTEMS_INVALID_NUMBER; … … 182 182 { 183 183 dev_t dev; 184 disk_device *dd;185 186 dev = rtems_filesystem_make_dev_t(major, minor); 187 dd = rtems_disk_ lookup(dev);184 rtems_disk_device *dd; 185 186 dev = rtems_filesystem_make_dev_t(major, minor); 187 dd = rtems_disk_obtain(dev); 188 188 if (dd == NULL) 189 189 return RTEMS_INVALID_NUMBER; … … 207 207 rtems_libio_ioctl_args_t *args = arg; 208 208 dev_t dev; 209 disk_device *dd;209 rtems_disk_device *dd; 210 210 int rc; 211 211 212 212 dev = rtems_filesystem_make_dev_t(major, minor); 213 dd = rtems_disk_ lookup(dev);213 dd = rtems_disk_obtain(dev); 214 214 if (dd == NULL) 215 215 return RTEMS_INVALID_NUMBER; … … 217 217 switch (args->command) 218 218 { 219 case BLKIO_GETBLKSIZE:219 case RTEMS_BLKIO_GETBLKSIZE: 220 220 args->ioctl_return = dd->block_size; 221 221 break; 222 222 223 case BLKIO_GETSIZE:223 case RTEMS_BLKIO_GETSIZE: 224 224 args->ioctl_return = dd->size; 225 225 break; 226 226 227 case BLKIO_SYNCDEV:227 case RTEMS_BLKIO_SYNCDEV: 228 228 rc = rtems_bdbuf_syncdev(dd->dev); 229 229 args->ioctl_return = (rc == RTEMS_SUCCESSFUL ? 0 : -1); 230 230 break; 231 231 232 case BLKIO_REQUEST:232 case RTEMS_BLKIO_REQUEST: 233 233 { 234 blkdev_request *req = args->buffer;234 rtems_blkdev_request *req = args->buffer; 235 235 req->start += dd->start; 236 236 args->ioctl_return = dd->ioctl(dd->phys_dev->dev, args->command, -
cpukit/libblock/src/diskdevs.c
r1b39f18 r3899a537 24 24 25 25 /* Table of disk devices having the same major number */ 26 structdisk_device_table {27 disk_device **minor; /* minor-indexed disk device table */26 typedef struct rtems_disk_device_table { 27 rtems_disk_device **minor; /* minor-indexed disk device table */ 28 28 int size; /* Number of entries in the table */ 29 } ;29 } rtems_disk_device_table; 30 30 31 31 /* Pointer to [major].minor[minor] indexed array of disk devices */ 32 static structdisk_device_table *disktab;32 static rtems_disk_device_table *disktab; 33 33 34 34 /* Number of allocated entries in disktab table */ … … 65 65 * available for its creation. 66 66 */ 67 static disk_device *67 static rtems_disk_device * 68 68 create_disk_entry(dev_t dev) 69 69 { 70 70 rtems_device_major_number major; 71 71 rtems_device_minor_number minor; 72 structdisk_device **d;72 rtems_disk_device **d; 73 73 74 74 rtems_filesystem_split_dev_t (dev, major, minor); … … 76 76 if (major >= disktab_size) 77 77 { 78 structdisk_device_table *p;78 rtems_disk_device_table *p; 79 79 int newsize; 80 80 int i; … … 82 82 if (major >= newsize) 83 83 newsize = major + 1; 84 p = realloc(disktab, sizeof( structdisk_device_table) * newsize);84 p = realloc(disktab, sizeof(rtems_disk_device_table) * newsize); 85 85 if (p == NULL) 86 86 return NULL; … … 98 98 { 99 99 int newsize; 100 disk_device **p;100 rtems_disk_device **p; 101 101 int i; 102 102 int s = disktab[major].size; … … 109 109 newsize = minor + 1; 110 110 111 p = realloc(disktab[major].minor, sizeof(disk_device *) * newsize); 111 p = realloc(disktab[major].minor, 112 sizeof(rtems_disk_device *) * newsize); 112 113 if (p == NULL) 113 114 return NULL; … … 122 123 if (*d == NULL) 123 124 { 124 *d = calloc(1, sizeof( disk_device));125 *d = calloc(1, sizeof(rtems_disk_device)); 125 126 } 126 127 return *d; … … 137 138 * device number, or NULL if disk device with such number not exists. 138 139 */ 139 static inlinedisk_device *140 static rtems_disk_device * 140 141 get_disk_entry(dev_t dev) 141 142 { 142 143 rtems_device_major_number major; 143 144 rtems_device_minor_number minor; 144 structdisk_device_table *dtab;145 rtems_disk_device_table *dtab; 145 146 146 147 rtems_filesystem_split_dev_t (dev, major, minor); … … 172 173 */ 173 174 static rtems_status_code 174 create_disk(dev_t dev, const char *name, disk_device **diskdev)175 { 176 disk_device *dd;175 create_disk(dev_t dev, const char *name, rtems_disk_device **diskdev) 176 { 177 rtems_disk_device *dd; 177 178 char *n; 178 179 … … 235 236 rtems_status_code 236 237 rtems_disk_create_phys(dev_t dev, int block_size, int disk_size, 237 block_device_ioctl handler,238 rtems_block_device_ioctl handler, 238 239 const char *name) 239 240 { 240 241 int bs_log2; 241 242 int i; 242 disk_device *dd;243 rtems_disk_device *dd; 243 244 rtems_status_code rc; 244 245 rtems_bdpool_id pool; … … 285 286 rc = rtems_io_register_name(name, major, minor); 286 287 288 if (handler (dd->phys_dev->dev, 289 RTEMS_BLKDEV_CAPABILITIES, 290 &dd->capabilities) < 0) 291 dd->capabilities = 0; 292 287 293 diskdevs_protected = FALSE; 288 294 rtems_semaphore_release(diskdevs_mutex); … … 318 324 rtems_disk_create_log(dev_t dev, dev_t phys, int start, int size, char *name) 319 325 { 320 disk_device *dd;321 disk_device *pdd;326 rtems_disk_device *dd; 327 rtems_disk_device *pdd; 322 328 rtems_status_code rc; 323 329 rtems_device_major_number major; … … 394 400 for (maj = 0; maj < disktab_size; maj++) 395 401 { 396 structdisk_device_table *dtab = disktab + maj;402 rtems_disk_device_table *dtab = disktab + maj; 397 403 if (dtab != NULL) 398 404 { 399 405 for (min = 0; min < dtab->size; min++) 400 406 { 401 disk_device *dd = dtab->minor[min];407 rtems_disk_device *dd = dtab->minor[min]; 402 408 if ((dd != NULL) && (dd->phys_dev->dev == dev)) 403 409 used += dd->uses; … … 416 422 for (maj = 0; maj < disktab_size; maj++) 417 423 { 418 structdisk_device_table *dtab = disktab +maj;424 rtems_disk_device_table *dtab = disktab +maj; 419 425 if (dtab != NULL) 420 426 { 421 427 for (min = 0; min < dtab->size; min++) 422 428 { 423 disk_device *dd = dtab->minor[min];429 rtems_disk_device *dd = dtab->minor[min]; 424 430 if ((dd != NULL) && (dd->phys_dev->dev == dev)) 425 431 { … … 438 444 } 439 445 440 /* rtems_disk_ lookup--446 /* rtems_disk_obtain -- 441 447 * Find block device descriptor by its device identifier. 442 448 * … … 448 454 * exists. 449 455 */ 450 disk_device *451 rtems_disk_ lookup(dev_t dev)456 rtems_disk_device * 457 rtems_disk_obtain(dev_t dev) 452 458 { 453 459 rtems_interrupt_level level; 454 disk_device *dd;460 rtems_disk_device *dd; 455 461 rtems_status_code rc; 456 462 … … 481 487 482 488 /* rtems_disk_release -- 483 * Release disk_device structure (decrement usage counter to 1).489 * Release rtems_disk_device structure (decrement usage counter to 1). 484 490 * 485 491 * PARAMETERS: … … 490 496 */ 491 497 rtems_status_code 492 rtems_disk_release( disk_device *dd)498 rtems_disk_release(rtems_disk_device *dd) 493 499 { 494 500 rtems_interrupt_level level; … … 511 517 * devices enumerated. 512 518 */ 513 disk_device *519 rtems_disk_device * 514 520 rtems_disk_next(dev_t dev) 515 521 { 516 522 rtems_device_major_number major; 517 523 rtems_device_minor_number minor; 518 structdisk_device_table *dtab;524 rtems_disk_device_table *dtab; 519 525 520 526 dev++; … … 563 569 564 570 disktab_size = DISKTAB_INITIAL_SIZE; 565 disktab = calloc(disktab_size, sizeof( structdisk_device_table));571 disktab = calloc(disktab_size, sizeof(rtems_disk_device_table)); 566 572 if (disktab == NULL) 567 573 return RTEMS_NO_MEMORY; … … 579 585 } 580 586 581 rc = rtems_bdbuf_init(rtems_bdbuf_configuration, 582 rtems_bdbuf_configuration_size); 587 rc = rtems_bdbuf_init(); 583 588 584 589 if (rc != RTEMS_SUCCESSFUL) … … 613 618 for (maj = 0; maj < disktab_size; maj++) 614 619 { 615 structdisk_device_table *dtab = disktab + maj;620 rtems_disk_device_table *dtab = disktab + maj; 616 621 if (dtab != NULL) 617 622 { 618 623 for (min = 0; min < dtab->size; min++) 619 624 { 620 disk_device *dd = dtab->minor[min];625 rtems_disk_device *dd = dtab->minor[min]; 621 626 unlink(dd->name); 622 627 free(dd->name); -
cpukit/libblock/src/flashdisk.c
r1b39f18 r3899a537 2058 2058 */ 2059 2059 static int 2060 rtems_fdisk_read (rtems_flashdisk* fd, blkdev_request* req) 2061 { 2062 blkdev_sg_buffer* sg = req->bufs; 2063 uint32_t block = req->start; 2064 uint32_t b; 2065 int ret = 0; 2066 2067 for (b = 0; b < req->bufnum; b++, block++, sg++) 2060 rtems_fdisk_read (rtems_flashdisk* fd, rtems_blkdev_request* req) 2061 { 2062 rtems_blkdev_sg_buffer* sg = req->bufs; 2063 uint32_t b; 2064 int ret = 0; 2065 2066 for (b = 0; b < req->bufnum; b++, sg++) 2068 2067 { 2069 2068 uint32_t length = sg->length; … … 2078 2077 } 2079 2078 2080 ret = rtems_fdisk_read_block (fd, block, sg->buffer);2079 ret = rtems_fdisk_read_block (fd, sg->block, sg->buffer); 2081 2080 2082 2081 if (ret) … … 2099 2098 */ 2100 2099 static int 2101 rtems_fdisk_write (rtems_flashdisk* fd, blkdev_request* req) 2102 { 2103 blkdev_sg_buffer* sg = req->bufs; 2104 uint32_t block = req->start; 2105 uint32_t b; 2106 int ret = 0; 2107 2108 for (b = 0; b < req->bufnum; b++, block++, sg++) 2100 rtems_fdisk_write (rtems_flashdisk* fd, rtems_blkdev_request* req) 2101 { 2102 rtems_blkdev_sg_buffer* sg = req->bufs; 2103 uint32_t b; 2104 int ret = 0; 2105 2106 for (b = 0; b < req->bufnum; b++, sg++) 2109 2107 { 2110 2108 if (sg->length != fd->block_size) … … 2114 2112 } 2115 2113 2116 ret = rtems_fdisk_write_block (fd, block, sg->buffer);2114 ret = rtems_fdisk_write_block (fd, sg->block, sg->buffer); 2117 2115 2118 2116 if (ret) … … 2357 2355 { 2358 2356 rtems_device_minor_number minor = rtems_filesystem_dev_minor_t (dev); 2359 blkdev_request*r = argp;2357 rtems_blkdev_request* r = argp; 2360 2358 rtems_status_code sc; 2361 2359 … … 2369 2367 switch (req) 2370 2368 { 2371 case BLKIO_REQUEST:2369 case RTEMS_BLKIO_REQUEST: 2372 2370 if ((minor >= rtems_flashdisk_count) || 2373 2371 (rtems_flashdisks[minor].device_count == 0)) … … 2379 2377 switch (r->req) 2380 2378 { 2381 case BLKDEV_REQ_READ:2379 case RTEMS_BLKDEV_REQ_READ: 2382 2380 errno = rtems_fdisk_read (&rtems_flashdisks[minor], r); 2383 2381 break; 2384 2382 2385 case BLKDEV_REQ_WRITE:2383 case RTEMS_BLKDEV_REQ_WRITE: 2386 2384 errno = rtems_fdisk_write (&rtems_flashdisks[minor], r); 2387 2385 break; -
cpukit/libblock/src/ide_part_table.c
r1b39f18 r3899a537 47 47 */ 48 48 static rtems_status_code 49 get_sector(dev_t dev, uint32_t sector_num, sector_data_t **sector)50 { 51 sector_data_t*s;52 bdbuf_buffer*buf;53 rtems_status_code rc;49 get_sector(dev_t dev, uint32_t sector_num, rtems_sector_data_t **sector) 50 { 51 rtems_sector_data_t *s; 52 rtems_bdbuf_buffer *buf; 53 rtems_status_code rc; 54 54 55 55 if (sector == NULL) … … 58 58 } 59 59 60 s = ( sector_data_t *) malloc(sizeof(sector_data_t) + RTEMS_IDE_SECTOR_SIZE);60 s = (rtems_sector_data_t *) malloc(sizeof(rtems_sector_data_t) + RTEMS_IDE_SECTOR_SIZE); 61 61 if (s == NULL) 62 62 { … … 93 93 */ 94 94 static rtems_boolean 95 msdos_signature_check ( sector_data_t *sector)95 msdos_signature_check (rtems_sector_data_t *sector) 96 96 { 97 97 uint8_t *p = sector->data + RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_OFFSET; … … 157 157 */ 158 158 static rtems_status_code 159 data_to_part_desc(uint8_t *data, part_desc_t **new_part_desc)160 { 161 part_desc_t *part_desc;162 uint32_t temp;159 data_to_part_desc(uint8_t *data, rtems_part_desc_t **new_part_desc) 160 { 161 rtems_part_desc_t *part_desc; 162 uint32_t temp; 163 163 164 164 if (new_part_desc == NULL) … … 169 169 *new_part_desc = NULL; 170 170 171 if ((part_desc = calloc(1, sizeof( part_desc_t))) == NULL)171 if ((part_desc = calloc(1, sizeof(rtems_part_desc_t))) == NULL) 172 172 { 173 173 return RTEMS_NO_MEMORY; … … 220 220 */ 221 221 static rtems_status_code 222 read_extended_partition(uint32_t start, part_desc_t *ext_part)223 { 224 int i;225 dev_t dev;226 sector_data_t*sector;227 uint32_t here;228 uint8_t *data;229 part_desc_t*new_part_desc;230 rtems_status_code rc;222 read_extended_partition(uint32_t start, rtems_part_desc_t *ext_part) 223 { 224 int i; 225 dev_t dev; 226 rtems_sector_data_t *sector; 227 uint32_t here; 228 uint8_t *data; 229 rtems_part_desc_t *new_part_desc; 230 rtems_status_code rc; 231 231 232 232 if ((ext_part == NULL) || (ext_part->disk_desc == NULL)) … … 287 287 else 288 288 { 289 disk_desc_t *disk_desc = new_part_desc->disk_desc;289 rtems_disk_desc_t *disk_desc = new_part_desc->disk_desc; 290 290 disk_desc->partitions[disk_desc->last_log_id] = new_part_desc; 291 291 new_part_desc->log_id = ++disk_desc->last_log_id; … … 315 315 */ 316 316 static rtems_status_code 317 read_mbr( disk_desc_t *disk_desc)318 { 319 int part_num;320 sector_data_t*sector;321 part_desc_t*part_desc;322 uint8_t *data;323 rtems_status_code rc;324 dev_t dev = disk_desc->dev;317 read_mbr(rtems_disk_desc_t *disk_desc) 318 { 319 int part_num; 320 rtems_sector_data_t *sector; 321 rtems_part_desc_t *part_desc; 322 uint8_t *data; 323 rtems_status_code rc; 324 dev_t dev = disk_desc->dev; 325 325 326 326 /* get MBR sector */ … … 399 399 */ 400 400 static void 401 partition_free( part_desc_t *part_desc)401 partition_free(rtems_part_desc_t *part_desc) 402 402 { 403 403 int part_num; … … 430 430 */ 431 431 void 432 rtems_ide_part_table_free( disk_desc_t *disk_desc)432 rtems_ide_part_table_free(rtems_disk_desc_t *disk_desc) 433 433 { 434 434 int part_num; … … 456 456 */ 457 457 rtems_status_code 458 rtems_ide_part_table_get(const char *dev_name, disk_desc_t *disk_desc)458 rtems_ide_part_table_get(const char *dev_name, rtems_disk_desc_t *disk_desc) 459 459 { 460 460 struct stat dev_stat; … … 495 495 int part_num; 496 496 dev_t dev; 497 disk_desc_t*disk_desc;497 rtems_disk_desc_t *disk_desc; 498 498 rtems_device_major_number major; 499 499 rtems_device_minor_number minor; 500 500 rtems_status_code rc; 501 part_desc_t*part_desc;501 rtems_part_desc_t *part_desc; 502 502 503 503 /* logical device name /dev/hdxyy */ 504 504 char name[RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX]; 505 505 506 disk_desc = ( disk_desc_t *) calloc(1, sizeof(disk_desc_t));506 disk_desc = (rtems_disk_desc_t *) calloc(1, sizeof(rtems_disk_desc_t)); 507 507 if (disk_desc == NULL) 508 508 { -
cpukit/libblock/src/nvdisk.c
r1b39f18 r3899a537 52 52 */ 53 53 #if !defined (RTEMS_NVDISK_TRACE) 54 #define RTEMS_NVDISK_TRACE 154 #define RTEMS_NVDISK_TRACE 0 55 55 #endif 56 56 … … 166 166 * Print a message to the nvdisk output and flush it. 167 167 * 168 * @param fd The flashdisk control structure.168 * @param nvd The nvdisk control structure. 169 169 * @param format The format string. See printf for details. 170 170 * @param ... The arguments for the format text. … … 190 190 * Print a info message to the nvdisk output and flush it. 191 191 * 192 * @param fd The flashdisk control structure.192 * @param nvd The nvdisk control structure. 193 193 * @param format The format string. See printf for details. 194 194 * @param ... The arguments for the format text. … … 214 214 * Print a warning to the nvdisk output and flush it. 215 215 * 216 * @param fd The flashdisk control structure.216 * @param nvd The nvdisk control structure. 217 217 * @param format The format string. See printf for details. 218 218 * @param ... The arguments for the format text. … … 257 257 258 258 /** 259 * Print an abort message, flush it then abort the program.260 *261 * @param format The format string. See printf for details.262 * @param ... The arguments for the format text.263 */264 static void265 rtems_nvdisk_abort (const char *format, ...)266 {267 va_list args;268 va_start (args, format);269 fprintf (stderr, "nvdisk:abort:");270 vfprintf (stderr, format, args);271 fprintf (stderr, "\n");272 fflush (stderr);273 exit (1);274 }275 276 /**277 259 * Get the descriptor for a device. 278 260 */ … … 325 307 } 326 308 309 #if NOT_USED 327 310 /** 328 311 * Verify the data with the data in a segment. … … 345 328 return ops->verify (device, dd->flags, dd->base, offset, buffer, size); 346 329 } 330 #endif 347 331 348 332 /** … … 372 356 page * nvd->block_size, 373 357 buffer, nvd->block_size); 374 }375 376 /**377 * Verify a page of data with the data in the device.378 */379 static int380 rtems_nvdisk_verify_page (const rtems_nvdisk* nvd,381 uint32_t device,382 uint32_t page,383 const void* buffer)384 {385 return rtems_nvdisk_device_verify (nvd, device,386 page * nvd->block_size,387 buffer, nvd->block_size);388 358 } 389 359 … … 533 503 if (crc == 0xffff) 534 504 { 505 #if RTEMS_NVDISK_TRACE 535 506 rtems_nvdisk_warning (nvd, "read-block: crc not set: %d", block); 507 #endif 536 508 memset (buffer, 0, nvd->block_size); 537 509 return 0; … … 606 578 */ 607 579 static int 608 rtems_nvdisk_read (rtems_nvdisk* nvd, blkdev_request* req) 609 { 610 blkdev_sg_buffer* sg = req->bufs; 611 uint32_t block = req->start; 612 uint32_t b; 613 int32_t remains; 614 int ret = 0; 580 rtems_nvdisk_read (rtems_nvdisk* nvd, rtems_blkdev_request* req) 581 { 582 rtems_blkdev_sg_buffer* sg = req->bufs; 583 uint32_t b; 584 int32_t remains; 585 int ret = 0; 615 586 616 587 #if RTEMS_NVDISK_TRACE … … 620 591 remains = req->count * nvd->block_size; 621 592 622 for (b = 0; b < req->bufnum; b++, block++,sg++)593 for (b = 0; b < req->bufnum; b++, sg++) 623 594 { 624 595 uint32_t length = sg->length; … … 659 630 */ 660 631 static int 661 rtems_nvdisk_write (rtems_nvdisk* nvd, blkdev_request* req) 662 { 663 blkdev_sg_buffer* sg = req->bufs; 664 uint32_t block = req->start; 665 uint32_t b; 666 int ret = 0; 632 rtems_nvdisk_write (rtems_nvdisk* nvd, rtems_blkdev_request* req) 633 { 634 rtems_blkdev_sg_buffer* sg = req->bufs; 635 uint32_t b; 636 int ret = 0; 667 637 668 638 #if RTEMS_NVDISK_TRACE … … 670 640 #endif 671 641 672 for (b = 0; b < req->bufnum; b++, block++,sg++)642 for (b = 0; b < req->bufnum; b++, sg++) 673 643 { 674 644 if (sg->length != nvd->block_size) … … 721 691 722 692 /** 723 * MV disk IOCTL handler.693 * NV disk IOCTL handler. 724 694 * 725 695 * @param dev Device number (major, minor number). … … 732 702 { 733 703 rtems_device_minor_number minor = rtems_filesystem_dev_minor_t (dev); 734 blkdev_request*r = argp;704 rtems_blkdev_request* r = argp; 735 705 rtems_status_code sc; 736 706 707 if (minor >= rtems_nvdisk_count) 708 { 709 errno = ENODEV; 710 return -1; 711 } 712 713 if (rtems_nvdisks[minor].device_count == 0) 714 { 715 errno = ENODEV; 716 return -1; 717 } 718 737 719 errno = 0; 738 720 … … 744 726 switch (req) 745 727 { 746 case BLKIO_REQUEST: 747 if ((minor >= rtems_nvdisk_count) || 748 (rtems_nvdisks[minor].device_count == 0)) 728 case RTEMS_BLKIO_REQUEST: 729 switch (r->req) 749 730 { 750 errno = ENODEV; 751 } 752 else 753 { 754 switch (r->req) 755 { 756 case BLKDEV_REQ_READ: 757 errno = rtems_nvdisk_read (&rtems_nvdisks[minor], r); 758 break; 759 760 case BLKDEV_REQ_WRITE: 761 errno = rtems_nvdisk_write (&rtems_nvdisks[minor], r); 762 break; 763 764 default: 765 errno = EBADRQC; 766 break; 767 } 731 case RTEMS_BLKDEV_REQ_READ: 732 errno = rtems_nvdisk_read (&rtems_nvdisks[minor], r); 733 break; 734 735 case RTEMS_BLKDEV_REQ_WRITE: 736 errno = rtems_nvdisk_write (&rtems_nvdisks[minor], r); 737 break; 738 739 default: 740 errno = EBADRQC; 741 break; 768 742 } 769 743 break; … … 772 746 errno = rtems_nvdisk_erase_disk (&rtems_nvdisks[minor]); 773 747 break; 774 748 775 749 case RTEMS_NVDISK_IOCTL_INFO_LEVEL: 776 750 rtems_nvdisks[minor].info_level = (uint32_t) argp; 777 751 break; 778 752 779 753 default: 780 754 errno = EBADRQC; -
cpukit/libblock/src/ramdisk.c
r1b39f18 r3899a537 22 22 #include "rtems/diskdevs.h" 23 23 #include "rtems/ramdisk.h" 24 25 /** 26 * Control tracing. It can be compiled out of the code for small 27 * footprint targets. Leave in by default. 28 */ 29 #if !defined (RTEMS_RAMDISK_TRACE) 30 #define RTEMS_RAMDISK_TRACE 0 31 #endif 24 32 25 33 #define RAMDISK_DEVICE_BASE_NAME "/dev/ramdisk" … … 33 41 rtems_boolean malloced; /* != 0, if memory allocated by malloc for this 34 42 RAM disk */ 43 #if RTEMS_RAMDISK_TRACE 44 int info_level; /* Trace level */ 45 #endif 35 46 }; 36 47 37 48 static struct ramdisk *ramdisk; 38 49 static int nramdisks; 50 51 #if RTEMS_RAMDISK_TRACE 52 /** 53 * Print a message to the ramdisk output and flush it. 54 * 55 * @param rd The ramdisk control structure. 56 * @param format The format string. See printf for details. 57 * @param ... The arguments for the format text. 58 * @return int The number of bytes written to the output. 59 */ 60 static int 61 rtems_ramdisk_printf (struct ramdisk *rd, const char *format, ...) 62 { 63 int ret = 0; 64 if (rd->info_level >= 1) 65 { 66 va_list args; 67 va_start (args, format); 68 fprintf (stdout, "ramdisk:"); 69 ret = vfprintf (stdout, format, args); 70 fprintf (stdout, "\n"); 71 fflush (stdout); 72 } 73 return ret; 74 } 75 #endif 39 76 40 77 /* ramdisk_read -- … … 50 87 */ 51 88 static int 52 ramdisk_read(struct ramdisk *rd, blkdev_request *req)89 ramdisk_read(struct ramdisk *rd, rtems_blkdev_request *req) 53 90 { 54 91 char *from; 55 92 uint32_t i; 56 blkdev_sg_buffer *sg;93 rtems_blkdev_sg_buffer *sg; 57 94 uint32_t remains; 58 95 59 from = (char *)rd->area + (req->start * rd->block_size); 96 #if RTEMS_RAMDISK_TRACE 97 rtems_ramdisk_printf (rd, "ramdisk read: start=%d, blocks=%d remains=%d", 98 req->bufs[0].block, req->bufnum, 99 rd->block_size * req->count); 100 #endif 101 60 102 remains = rd->block_size * req->count; 61 103 sg = req->bufs; … … 63 105 { 64 106 int count = sg->length; 107 from = ((char *)rd->area + (sg->block * rd->block_size)); 65 108 if (count > remains) 66 109 count = remains; … … 85 128 */ 86 129 static int 87 ramdisk_write(struct ramdisk *rd, blkdev_request *req)130 ramdisk_write(struct ramdisk *rd, rtems_blkdev_request *req) 88 131 { 89 132 char *to; 90 133 uint32_t i; 91 blkdev_sg_buffer *sg;134 rtems_blkdev_sg_buffer *sg; 92 135 uint32_t remains; 93 136 94 to = (char *)rd->area + (req->start * rd->block_size); 137 #if RTEMS_RAMDISK_TRACE 138 rtems_ramdisk_printf (rd, "ramdisk write: start=%d, blocks=%d remains=%d", 139 req->bufs[0].block, req->bufnum, 140 rd->block_size * req->count); 141 #endif 95 142 remains = rd->block_size * req->count; 96 143 sg = req->bufs; … … 98 145 { 99 146 int count = sg->length; 147 to = ((char *)rd->area + (sg->block * rd->block_size)); 100 148 if (count > remains) 101 149 count = remains; … … 124 172 switch (req) 125 173 { 126 case BLKIO_REQUEST:174 case RTEMS_BLKIO_REQUEST: 127 175 { 128 176 rtems_device_minor_number minor; 129 blkdev_request *r = argp;177 rtems_blkdev_request *r = argp; 130 178 struct ramdisk *rd; 131 179 … … 141 189 switch (r->req) 142 190 { 143 case BLKDEV_REQ_READ:191 case RTEMS_BLKDEV_REQ_READ: 144 192 return ramdisk_read(rd, r); 145 193 146 case BLKDEV_REQ_WRITE:194 case RTEMS_BLKDEV_REQ_WRITE: 147 195 return ramdisk_write(rd, r); 148 196 … … 189 237 r = ramdisk = calloc(rtems_ramdisk_configuration_size, 190 238 sizeof(struct ramdisk)); 191 239 #if RTEMS_RAMDISK_TRACE 240 r->info_level = 1; 241 #endif 192 242 for (i = 0; i < rtems_ramdisk_configuration_size; i++, c++, r++) 193 243 {
Note: See TracChangeset
for help on using the changeset viewer.