File indexing completed on 2025-05-11 08:24:15
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <stdlib.h>
0037 #include <errno.h>
0038 #include <string.h>
0039
0040 #include <rtems.h>
0041 #include <rtems/blkdev.h>
0042 #include <rtems/fatal.h>
0043
0044 #include "rtems/sparse-disk.h"
0045
0046
0047
0048
0049 static rtems_sparse_disk *sparse_disk_allocate(
0050 const uint32_t media_block_size,
0051 const rtems_blkdev_bnum blocks_with_buffer )
0052 {
0053 size_t const key_table_size = blocks_with_buffer
0054 * sizeof( rtems_sparse_disk_key );
0055 size_t const data_size = blocks_with_buffer * media_block_size;
0056 size_t const alloc_size = sizeof( rtems_sparse_disk )
0057 + key_table_size + data_size;
0058
0059 rtems_sparse_disk *const sd = (rtems_sparse_disk *) malloc(
0060 alloc_size );
0061
0062 return sd;
0063 }
0064
0065
0066
0067
0068 static rtems_status_code sparse_disk_initialize( rtems_sparse_disk *sd,
0069 const uint32_t media_block_size,
0070 const rtems_blkdev_bnum blocks_with_buffer,
0071 const rtems_sparse_disk_delete_handler sparse_disk_delete,
0072 const uint8_t fill_pattern )
0073 {
0074 rtems_blkdev_bnum i;
0075
0076 if ( NULL == sd )
0077 return RTEMS_INVALID_ADDRESS;
0078
0079 uint8_t *data = (uint8_t *) sd;
0080 size_t const key_table_size = blocks_with_buffer
0081 * sizeof( rtems_sparse_disk_key );
0082 size_t const data_size = blocks_with_buffer * media_block_size;
0083
0084 memset( data, 0, sizeof( rtems_sparse_disk ) + key_table_size );
0085
0086 sd->fill_pattern = fill_pattern;
0087 memset( (uint8_t *) ( data + sizeof( rtems_sparse_disk ) + key_table_size ),
0088 sd->fill_pattern,
0089 data_size );
0090
0091 sd->delete_handler = sparse_disk_delete;
0092
0093 rtems_mutex_init( &sd->mutex, "Sparse Disk" );
0094
0095 data += sizeof( rtems_sparse_disk );
0096
0097 sd->blocks_with_buffer = blocks_with_buffer;
0098 sd->key_table = (rtems_sparse_disk_key *) data;
0099
0100 data += key_table_size;
0101
0102 for ( i = 0; i < blocks_with_buffer; ++i, data += media_block_size ) {
0103 sd->key_table[i].data = data;
0104 }
0105
0106 sd->media_block_size = media_block_size;
0107 return RTEMS_SUCCESSFUL;
0108 }
0109
0110
0111
0112
0113 static int sparse_disk_compare( const void *aa, const void *bb )
0114 {
0115 const rtems_sparse_disk_key *a = aa;
0116 const rtems_sparse_disk_key *b = bb;
0117
0118 if ( a->block < b->block ) {
0119 return -1;
0120 } else if ( a->block == b->block ) {
0121 return 0;
0122 } else {
0123 return 1;
0124 }
0125 }
0126
0127 static rtems_sparse_disk_key *sparse_disk_find_block(
0128 const rtems_sparse_disk *sparse_disk,
0129 rtems_blkdev_bnum block
0130 )
0131 {
0132 rtems_sparse_disk_key key = { .block = block };
0133
0134 return bsearch(
0135 &key,
0136 sparse_disk->key_table,
0137 sparse_disk->used_count,
0138 sizeof( rtems_sparse_disk_key ),
0139 sparse_disk_compare
0140 );
0141 }
0142
0143 static rtems_sparse_disk_key *sparse_disk_get_new_block(
0144 rtems_sparse_disk *sparse_disk,
0145 const rtems_blkdev_bnum block
0146 )
0147 {
0148 rtems_sparse_disk_key *key;
0149
0150 if ( sparse_disk->used_count >= sparse_disk->blocks_with_buffer ) {
0151 return NULL;
0152 }
0153
0154 key = &sparse_disk->key_table[ sparse_disk->used_count ];
0155 key->block = block;
0156 ++sparse_disk->used_count;
0157 qsort(
0158 sparse_disk->key_table,
0159 sparse_disk->used_count,
0160 sizeof( rtems_sparse_disk_key ),
0161 sparse_disk_compare
0162 );
0163 return sparse_disk_find_block( sparse_disk, block );
0164 }
0165
0166 static int sparse_disk_read_block(
0167 const rtems_sparse_disk *sparse_disk,
0168 const rtems_blkdev_bnum block,
0169 uint8_t *buffer,
0170 const size_t buffer_size )
0171 {
0172 size_t bytes_to_copy = sparse_disk->media_block_size;
0173 rtems_sparse_disk_key *key;
0174
0175 if ( buffer_size < bytes_to_copy )
0176 bytes_to_copy = buffer_size;
0177
0178 key = sparse_disk_find_block( sparse_disk, block );
0179
0180 if ( NULL != key )
0181 memcpy( buffer, key->data, bytes_to_copy );
0182 else
0183 memset( buffer, sparse_disk->fill_pattern, buffer_size );
0184
0185 return bytes_to_copy;
0186 }
0187
0188 static int sparse_disk_write_block(
0189 rtems_sparse_disk *sparse_disk,
0190 const rtems_blkdev_bnum block,
0191 const uint8_t *buffer,
0192 const size_t buffer_size )
0193 {
0194 size_t bytes_to_copy = sparse_disk->media_block_size;
0195 bool block_needs_writing = false;
0196 rtems_sparse_disk_key *key;
0197 size_t i;
0198
0199 if ( buffer_size < bytes_to_copy )
0200 bytes_to_copy = buffer_size;
0201
0202
0203
0204
0205
0206 key = sparse_disk_find_block( sparse_disk, block );
0207
0208 if ( NULL == key ) {
0209 for ( i = 0; ( !block_needs_writing ) && ( i < bytes_to_copy ); ++i ) {
0210 if ( buffer[i] != sparse_disk->fill_pattern )
0211 block_needs_writing = true;
0212 }
0213
0214 if ( block_needs_writing ) {
0215 key = sparse_disk_get_new_block( sparse_disk, block );
0216 }
0217 }
0218
0219 if ( NULL != key )
0220 memcpy( key->data, buffer, bytes_to_copy );
0221 else if ( block_needs_writing )
0222 return -1;
0223
0224 return bytes_to_copy;
0225 }
0226
0227
0228
0229
0230 static int sparse_disk_read_write(
0231 rtems_sparse_disk *sparse_disk,
0232 rtems_blkdev_request *req,
0233 const bool read )
0234 {
0235 int rv = 0;
0236 uint32_t req_buffer;
0237 rtems_blkdev_sg_buffer *scatter_gather;
0238 rtems_blkdev_bnum block;
0239 uint8_t *buff;
0240 size_t buff_size;
0241 unsigned int bytes_handled;
0242
0243 rtems_mutex_lock( &sparse_disk->mutex );
0244
0245 for ( req_buffer = 0;
0246 ( 0 <= rv ) && ( req_buffer < req->bufnum );
0247 ++req_buffer ) {
0248 scatter_gather = &req->bufs[req_buffer];
0249
0250 bytes_handled = 0;
0251 buff = (uint8_t *) scatter_gather->buffer;
0252 block = scatter_gather->block;
0253 buff_size = scatter_gather->length;
0254
0255 while ( ( 0 <= rv ) && ( 0 < buff_size ) ) {
0256 if ( read )
0257 rv = sparse_disk_read_block( sparse_disk,
0258 block,
0259 &buff[bytes_handled],
0260 buff_size );
0261 else
0262 rv = sparse_disk_write_block( sparse_disk,
0263 block,
0264 &buff[bytes_handled],
0265 buff_size );
0266
0267 ++block;
0268 bytes_handled += rv;
0269 buff_size -= rv;
0270 }
0271 }
0272
0273 rtems_mutex_unlock( &sparse_disk->mutex );
0274
0275 if ( 0 > rv )
0276 rtems_blkdev_request_done( req, RTEMS_IO_ERROR );
0277 else
0278 rtems_blkdev_request_done( req, RTEMS_SUCCESSFUL );
0279
0280 return 0;
0281 }
0282
0283
0284
0285
0286 static int sparse_disk_ioctl( rtems_disk_device *dd, uint32_t req, void *argp )
0287 {
0288 rtems_sparse_disk *sd = rtems_disk_get_driver_data( dd );
0289
0290 if ( RTEMS_BLKIO_REQUEST == req ) {
0291 rtems_blkdev_request *r = argp;
0292
0293 switch ( r->req ) {
0294 case RTEMS_BLKDEV_REQ_READ:
0295 case RTEMS_BLKDEV_REQ_WRITE:
0296 return sparse_disk_read_write( sd, r, r->req == RTEMS_BLKDEV_REQ_READ );
0297 default:
0298 break;
0299 }
0300 } else if ( RTEMS_BLKIO_DELETED == req ) {
0301 rtems_mutex_destroy( &sd->mutex );
0302
0303 if ( NULL != sd->delete_handler )
0304 ( *sd->delete_handler )( sd );
0305
0306 return 0;
0307 } else {
0308 return rtems_blkdev_ioctl( dd, req, argp );
0309 }
0310
0311 errno = EINVAL;
0312 return -1;
0313 }
0314
0315 void rtems_sparse_disk_free( rtems_sparse_disk *sd )
0316 {
0317 free( sd );
0318 }
0319
0320 rtems_status_code rtems_sparse_disk_create_and_register(
0321 const char *device_file_name,
0322 uint32_t media_block_size,
0323 rtems_blkdev_bnum blocks_with_buffer,
0324 rtems_blkdev_bnum media_block_count,
0325 uint8_t fill_pattern )
0326 {
0327 rtems_status_code sc = RTEMS_SUCCESSFUL;
0328 rtems_sparse_disk *sparse_disk = sparse_disk_allocate(
0329 media_block_size,
0330 blocks_with_buffer
0331 );
0332
0333 if ( sparse_disk != NULL ) {
0334 sc = rtems_sparse_disk_register(
0335 device_file_name,
0336 sparse_disk,
0337 media_block_size,
0338 blocks_with_buffer,
0339 media_block_count,
0340 fill_pattern,
0341 rtems_sparse_disk_free
0342 );
0343 } else {
0344 sc = RTEMS_NO_MEMORY;
0345 }
0346
0347 return sc;
0348 }
0349
0350 rtems_status_code rtems_sparse_disk_register(
0351 const char *device_file_name,
0352 rtems_sparse_disk *sparse_disk,
0353 uint32_t media_block_size,
0354 rtems_blkdev_bnum blocks_with_buffer,
0355 rtems_blkdev_bnum media_block_count,
0356 uint8_t fill_pattern,
0357 rtems_sparse_disk_delete_handler sparse_disk_delete )
0358 {
0359 rtems_status_code sc;
0360
0361 if ( blocks_with_buffer <= media_block_count ) {
0362 sc = sparse_disk_initialize(
0363 sparse_disk,
0364 media_block_size,
0365 blocks_with_buffer,
0366 sparse_disk_delete,
0367 fill_pattern
0368 );
0369
0370 if ( RTEMS_SUCCESSFUL == sc ) {
0371 sc = rtems_blkdev_create(
0372 device_file_name,
0373 media_block_size,
0374 media_block_count,
0375 sparse_disk_ioctl,
0376 sparse_disk
0377 );
0378 }
0379 } else {
0380 sc = RTEMS_INVALID_NUMBER;
0381 }
0382
0383 return sc;
0384 }