[f6c7bcfe] | 1 | /** |
---|
| 2 | * @file |
---|
| 3 | * |
---|
| 4 | * @brief Block Device IMFS |
---|
| 5 | * @ingroup libblock |
---|
| 6 | */ |
---|
| 7 | |
---|
[01211720] | 8 | /* |
---|
[30c3898] | 9 | * Copyright (c) 2012, 2018 embedded brains GmbH. All rights reserved. |
---|
[01211720] | 10 | * |
---|
| 11 | * embedded brains GmbH |
---|
[30c3898] | 12 | * Dornierstr. 4 |
---|
[01211720] | 13 | * 82178 Puchheim |
---|
| 14 | * Germany |
---|
| 15 | * <rtems@embedded-brains.de> |
---|
| 16 | * |
---|
| 17 | * The license and distribution terms for this file may be |
---|
| 18 | * found in the file LICENSE in this distribution or at |
---|
[c499856] | 19 | * http://www.rtems.org/license/LICENSE. |
---|
[01211720] | 20 | */ |
---|
| 21 | |
---|
| 22 | #if HAVE_CONFIG_H |
---|
| 23 | #include "config.h" |
---|
| 24 | #endif |
---|
| 25 | |
---|
| 26 | #include <sys/stat.h> |
---|
| 27 | #include <stdlib.h> |
---|
| 28 | #include <unistd.h> |
---|
| 29 | #include <fcntl.h> |
---|
| 30 | #include <string.h> |
---|
| 31 | |
---|
| 32 | #include <rtems/blkdev.h> |
---|
| 33 | #include <rtems/bdbuf.h> |
---|
| 34 | #include <rtems/imfs.h> |
---|
| 35 | |
---|
| 36 | typedef struct { |
---|
| 37 | rtems_disk_device dd; |
---|
| 38 | int fd; |
---|
| 39 | } rtems_blkdev_imfs_context; |
---|
| 40 | |
---|
| 41 | static ssize_t rtems_blkdev_imfs_read( |
---|
| 42 | rtems_libio_t *iop, |
---|
| 43 | void *buffer, |
---|
| 44 | size_t count |
---|
| 45 | ) |
---|
| 46 | { |
---|
| 47 | int rv; |
---|
[40284de] | 48 | rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop); |
---|
| 49 | rtems_disk_device *dd = &ctx->dd; |
---|
[01211720] | 50 | ssize_t remaining = (ssize_t) count; |
---|
| 51 | off_t offset = iop->offset; |
---|
| 52 | ssize_t block_size = (ssize_t) rtems_disk_get_block_size(dd); |
---|
| 53 | rtems_blkdev_bnum block = (rtems_blkdev_bnum) (offset / block_size); |
---|
| 54 | ssize_t block_offset = (ssize_t) (offset % block_size); |
---|
| 55 | char *dst = buffer; |
---|
| 56 | |
---|
| 57 | while (remaining > 0) { |
---|
| 58 | rtems_bdbuf_buffer *bd; |
---|
| 59 | rtems_status_code sc = rtems_bdbuf_read(dd, block, &bd); |
---|
| 60 | |
---|
| 61 | if (sc == RTEMS_SUCCESSFUL) { |
---|
| 62 | ssize_t copy = block_size - block_offset; |
---|
| 63 | |
---|
| 64 | if (copy > remaining) { |
---|
| 65 | copy = remaining; |
---|
| 66 | } |
---|
| 67 | |
---|
| 68 | memcpy(dst, (char *) bd->buffer + block_offset, (size_t) copy); |
---|
| 69 | |
---|
| 70 | sc = rtems_bdbuf_release(bd); |
---|
| 71 | if (sc == RTEMS_SUCCESSFUL) { |
---|
| 72 | block_offset = 0; |
---|
| 73 | remaining -= copy; |
---|
| 74 | dst += copy; |
---|
| 75 | ++block; |
---|
| 76 | } else { |
---|
| 77 | remaining = -1; |
---|
| 78 | } |
---|
| 79 | } else { |
---|
| 80 | remaining = -1; |
---|
| 81 | } |
---|
| 82 | } |
---|
| 83 | |
---|
| 84 | if (remaining >= 0) { |
---|
[53da07e] | 85 | iop->offset += count; |
---|
[01211720] | 86 | rv = (ssize_t) count; |
---|
| 87 | } else { |
---|
| 88 | errno = EIO; |
---|
| 89 | rv = -1; |
---|
| 90 | } |
---|
| 91 | |
---|
| 92 | return rv; |
---|
| 93 | } |
---|
| 94 | |
---|
| 95 | static ssize_t rtems_blkdev_imfs_write( |
---|
| 96 | rtems_libio_t *iop, |
---|
| 97 | const void *buffer, |
---|
| 98 | size_t count |
---|
| 99 | ) |
---|
| 100 | { |
---|
| 101 | int rv; |
---|
[40284de] | 102 | rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop); |
---|
| 103 | rtems_disk_device *dd = &ctx->dd; |
---|
[01211720] | 104 | ssize_t remaining = (ssize_t) count; |
---|
| 105 | off_t offset = iop->offset; |
---|
| 106 | ssize_t block_size = (ssize_t) rtems_disk_get_block_size(dd); |
---|
| 107 | rtems_blkdev_bnum block = (rtems_blkdev_bnum) (offset / block_size); |
---|
| 108 | ssize_t block_offset = (ssize_t) (offset % block_size); |
---|
| 109 | const char *src = buffer; |
---|
| 110 | |
---|
| 111 | while (remaining > 0) { |
---|
| 112 | rtems_status_code sc; |
---|
| 113 | rtems_bdbuf_buffer *bd; |
---|
| 114 | |
---|
| 115 | if (block_offset == 0 && remaining >= block_size) { |
---|
| 116 | sc = rtems_bdbuf_get(dd, block, &bd); |
---|
| 117 | } else { |
---|
| 118 | sc = rtems_bdbuf_read(dd, block, &bd); |
---|
| 119 | } |
---|
| 120 | |
---|
| 121 | if (sc == RTEMS_SUCCESSFUL) { |
---|
| 122 | ssize_t copy = block_size - block_offset; |
---|
| 123 | |
---|
| 124 | if (copy > remaining) { |
---|
| 125 | copy = remaining; |
---|
| 126 | } |
---|
| 127 | |
---|
| 128 | memcpy((char *) bd->buffer + block_offset, src, (size_t) copy); |
---|
| 129 | |
---|
| 130 | sc = rtems_bdbuf_release_modified(bd); |
---|
| 131 | if (sc == RTEMS_SUCCESSFUL) { |
---|
| 132 | block_offset = 0; |
---|
| 133 | remaining -= copy; |
---|
| 134 | src += copy; |
---|
| 135 | ++block; |
---|
| 136 | } else { |
---|
| 137 | remaining = -1; |
---|
| 138 | } |
---|
| 139 | } else { |
---|
| 140 | remaining = -1; |
---|
| 141 | } |
---|
| 142 | } |
---|
| 143 | |
---|
| 144 | if (remaining >= 0) { |
---|
[53da07e] | 145 | iop->offset += count; |
---|
[01211720] | 146 | rv = (ssize_t) count; |
---|
| 147 | } else { |
---|
| 148 | errno = EIO; |
---|
| 149 | rv = -1; |
---|
| 150 | } |
---|
| 151 | |
---|
| 152 | return rv; |
---|
| 153 | } |
---|
| 154 | |
---|
| 155 | static int rtems_blkdev_imfs_ioctl( |
---|
| 156 | rtems_libio_t *iop, |
---|
[9d1522ed] | 157 | ioctl_command_t request, |
---|
[01211720] | 158 | void *buffer |
---|
| 159 | ) |
---|
| 160 | { |
---|
| 161 | int rv = 0; |
---|
| 162 | |
---|
| 163 | if (request != RTEMS_BLKIO_REQUEST) { |
---|
| 164 | rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop); |
---|
| 165 | rtems_disk_device *dd = &ctx->dd; |
---|
| 166 | |
---|
| 167 | rv = (*dd->ioctl)(dd, request, buffer); |
---|
| 168 | } else { |
---|
| 169 | /* |
---|
| 170 | * It is not allowed to directly access the driver circumventing the cache. |
---|
| 171 | */ |
---|
| 172 | errno = EINVAL; |
---|
| 173 | rv = -1; |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | return rv; |
---|
| 177 | } |
---|
| 178 | |
---|
| 179 | static int rtems_blkdev_imfs_fstat( |
---|
| 180 | const rtems_filesystem_location_info_t *loc, |
---|
| 181 | struct stat *buf |
---|
| 182 | ) |
---|
| 183 | { |
---|
[0b038bd4] | 184 | rtems_blkdev_imfs_context *ctx; |
---|
| 185 | rtems_disk_device *dd; |
---|
| 186 | IMFS_jnode_t *node; |
---|
| 187 | |
---|
| 188 | ctx = IMFS_generic_get_context_by_location(loc); |
---|
| 189 | dd = &ctx->dd; |
---|
[01211720] | 190 | |
---|
| 191 | buf->st_blksize = rtems_disk_get_block_size(dd); |
---|
| 192 | buf->st_blocks = rtems_disk_get_block_count(dd); |
---|
| 193 | |
---|
[0b038bd4] | 194 | node = loc->node_access; |
---|
| 195 | buf->st_rdev = IMFS_generic_get_device_identifier_by_node(node); |
---|
| 196 | |
---|
[01211720] | 197 | return IMFS_stat(loc, buf); |
---|
| 198 | } |
---|
| 199 | |
---|
| 200 | static int rtems_blkdev_imfs_fsync_or_fdatasync( |
---|
| 201 | rtems_libio_t *iop |
---|
| 202 | ) |
---|
| 203 | { |
---|
| 204 | int rv = 0; |
---|
[40284de] | 205 | rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop); |
---|
| 206 | rtems_disk_device *dd = &ctx->dd; |
---|
[01211720] | 207 | rtems_status_code sc = rtems_bdbuf_syncdev(dd); |
---|
| 208 | |
---|
| 209 | if (sc != RTEMS_SUCCESSFUL) { |
---|
| 210 | errno = EIO; |
---|
| 211 | rv = -1; |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | return rv; |
---|
| 215 | } |
---|
| 216 | |
---|
| 217 | static const rtems_filesystem_file_handlers_r rtems_blkdev_imfs_node = { |
---|
| 218 | .open_h = rtems_filesystem_default_open, |
---|
| 219 | .close_h = rtems_filesystem_default_close, |
---|
| 220 | .read_h = rtems_blkdev_imfs_read, |
---|
| 221 | .write_h = rtems_blkdev_imfs_write, |
---|
| 222 | .ioctl_h = rtems_blkdev_imfs_ioctl, |
---|
[30d4124] | 223 | .lseek_h = rtems_filesystem_default_lseek_file, |
---|
[01211720] | 224 | .fstat_h = rtems_blkdev_imfs_fstat, |
---|
| 225 | .ftruncate_h = rtems_filesystem_default_ftruncate, |
---|
| 226 | .fsync_h = rtems_blkdev_imfs_fsync_or_fdatasync, |
---|
| 227 | .fdatasync_h = rtems_blkdev_imfs_fsync_or_fdatasync, |
---|
[2f68778] | 228 | .fcntl_h = rtems_filesystem_default_fcntl, |
---|
[56bea43] | 229 | .kqfilter_h = rtems_filesystem_default_kqfilter, |
---|
[c6bb1c33] | 230 | .mmap_h = rtems_filesystem_default_mmap, |
---|
[56bea43] | 231 | .poll_h = rtems_filesystem_default_poll, |
---|
[2f68778] | 232 | .readv_h = rtems_filesystem_default_readv, |
---|
| 233 | .writev_h = rtems_filesystem_default_writev |
---|
[01211720] | 234 | }; |
---|
| 235 | |
---|
| 236 | static IMFS_jnode_t *rtems_blkdev_imfs_initialize( |
---|
| 237 | IMFS_jnode_t *node, |
---|
[cf36b70] | 238 | void *arg |
---|
[01211720] | 239 | ) |
---|
| 240 | { |
---|
| 241 | rtems_blkdev_imfs_context *ctx; |
---|
| 242 | rtems_disk_device *dd; |
---|
| 243 | |
---|
[cf36b70] | 244 | node = IMFS_node_initialize_generic(node, arg); |
---|
[01211720] | 245 | |
---|
| 246 | ctx = IMFS_generic_get_context_by_node(node); |
---|
| 247 | dd = &ctx->dd; |
---|
| 248 | dd->dev = IMFS_generic_get_device_identifier_by_node(node); |
---|
| 249 | |
---|
| 250 | return node; |
---|
| 251 | } |
---|
| 252 | |
---|
[cf36b70] | 253 | static void rtems_blkdev_imfs_destroy(IMFS_jnode_t *node) |
---|
[01211720] | 254 | { |
---|
| 255 | rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_node(node); |
---|
| 256 | rtems_disk_device *dd = &ctx->dd; |
---|
| 257 | |
---|
| 258 | rtems_bdbuf_syncdev(dd); |
---|
| 259 | rtems_bdbuf_purge_dev(dd); |
---|
| 260 | |
---|
| 261 | if (ctx->fd >= 0) { |
---|
| 262 | close(ctx->fd); |
---|
| 263 | } else { |
---|
| 264 | (*dd->ioctl)(dd, RTEMS_BLKIO_DELETED, NULL); |
---|
| 265 | } |
---|
| 266 | |
---|
| 267 | free(ctx); |
---|
| 268 | |
---|
[cf36b70] | 269 | IMFS_node_destroy_default(node); |
---|
[01211720] | 270 | } |
---|
| 271 | |
---|
[cf36b70] | 272 | static const IMFS_node_control rtems_blkdev_imfs_control = |
---|
| 273 | IMFS_GENERIC_INITIALIZER( |
---|
| 274 | &rtems_blkdev_imfs_node, |
---|
| 275 | rtems_blkdev_imfs_initialize, |
---|
| 276 | rtems_blkdev_imfs_destroy |
---|
| 277 | ); |
---|
[01211720] | 278 | |
---|
| 279 | rtems_status_code rtems_blkdev_create( |
---|
| 280 | const char *device, |
---|
[eb93595] | 281 | uint32_t media_block_size, |
---|
| 282 | rtems_blkdev_bnum media_block_count, |
---|
[01211720] | 283 | rtems_block_device_ioctl handler, |
---|
| 284 | void *driver_data |
---|
| 285 | ) |
---|
| 286 | { |
---|
[30c3898] | 287 | rtems_status_code sc; |
---|
| 288 | rtems_blkdev_imfs_context *ctx; |
---|
| 289 | |
---|
| 290 | sc = rtems_bdbuf_init(); |
---|
| 291 | if (sc != RTEMS_SUCCESSFUL) { |
---|
| 292 | return RTEMS_INCORRECT_STATE; |
---|
| 293 | } |
---|
[01211720] | 294 | |
---|
[30c3898] | 295 | ctx = malloc(sizeof(*ctx)); |
---|
[73c09b3b] | 296 | if (ctx != NULL) { |
---|
| 297 | sc = rtems_disk_init_phys( |
---|
| 298 | &ctx->dd, |
---|
[eb93595] | 299 | media_block_size, |
---|
| 300 | media_block_count, |
---|
[73c09b3b] | 301 | handler, |
---|
| 302 | driver_data |
---|
| 303 | ); |
---|
[01211720] | 304 | |
---|
[73c09b3b] | 305 | ctx->fd = -1; |
---|
[01211720] | 306 | |
---|
[73c09b3b] | 307 | if (sc == RTEMS_SUCCESSFUL) { |
---|
| 308 | int rv = IMFS_make_generic_node( |
---|
| 309 | device, |
---|
| 310 | S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO, |
---|
| 311 | &rtems_blkdev_imfs_control, |
---|
| 312 | ctx |
---|
| 313 | ); |
---|
| 314 | |
---|
| 315 | if (rv != 0) { |
---|
[01211720] | 316 | free(ctx); |
---|
[73c09b3b] | 317 | sc = RTEMS_UNSATISFIED; |
---|
[01211720] | 318 | } |
---|
| 319 | } else { |
---|
[73c09b3b] | 320 | free(ctx); |
---|
[01211720] | 321 | } |
---|
| 322 | } else { |
---|
[73c09b3b] | 323 | sc = RTEMS_NO_MEMORY; |
---|
[01211720] | 324 | } |
---|
| 325 | |
---|
| 326 | return sc; |
---|
| 327 | } |
---|
| 328 | |
---|
| 329 | rtems_status_code rtems_blkdev_create_partition( |
---|
| 330 | const char *partition, |
---|
[eb93595] | 331 | const char *parent_block_device, |
---|
| 332 | rtems_blkdev_bnum media_block_begin, |
---|
| 333 | rtems_blkdev_bnum media_block_count |
---|
[01211720] | 334 | ) |
---|
| 335 | { |
---|
| 336 | rtems_status_code sc = RTEMS_SUCCESSFUL; |
---|
[eb93595] | 337 | int fd = open(parent_block_device, O_RDWR); |
---|
[01211720] | 338 | |
---|
| 339 | if (fd >= 0) { |
---|
| 340 | int rv; |
---|
| 341 | struct stat st; |
---|
| 342 | |
---|
| 343 | rv = fstat(fd, &st); |
---|
| 344 | if (rv == 0 && S_ISBLK(st.st_mode)) { |
---|
[73c09b3b] | 345 | rtems_disk_device *phys_dd; |
---|
[01211720] | 346 | |
---|
[73c09b3b] | 347 | rv = rtems_disk_fd_get_disk_device(fd, &phys_dd); |
---|
[01211720] | 348 | if (rv == 0) { |
---|
[73c09b3b] | 349 | rtems_blkdev_imfs_context *ctx = malloc(sizeof(*ctx)); |
---|
[01211720] | 350 | |
---|
[73c09b3b] | 351 | if (ctx != NULL) { |
---|
| 352 | sc = rtems_disk_init_log( |
---|
| 353 | &ctx->dd, |
---|
| 354 | phys_dd, |
---|
[eb93595] | 355 | media_block_begin, |
---|
| 356 | media_block_count |
---|
[73c09b3b] | 357 | ); |
---|
[01211720] | 358 | |
---|
[73c09b3b] | 359 | if (sc == RTEMS_SUCCESSFUL) { |
---|
[01211720] | 360 | ctx->fd = fd; |
---|
| 361 | |
---|
| 362 | rv = IMFS_make_generic_node( |
---|
| 363 | partition, |
---|
| 364 | S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO, |
---|
| 365 | &rtems_blkdev_imfs_control, |
---|
| 366 | ctx |
---|
| 367 | ); |
---|
| 368 | |
---|
| 369 | if (rv != 0) { |
---|
| 370 | free(ctx); |
---|
| 371 | sc = RTEMS_UNSATISFIED; |
---|
| 372 | } |
---|
| 373 | } else { |
---|
[73c09b3b] | 374 | free(ctx); |
---|
[01211720] | 375 | } |
---|
| 376 | } else { |
---|
[73c09b3b] | 377 | sc = RTEMS_NO_MEMORY; |
---|
[01211720] | 378 | } |
---|
| 379 | } else { |
---|
| 380 | sc = RTEMS_NOT_IMPLEMENTED; |
---|
| 381 | } |
---|
| 382 | } else { |
---|
| 383 | sc = RTEMS_INVALID_NODE; |
---|
| 384 | } |
---|
| 385 | |
---|
| 386 | if (sc != RTEMS_SUCCESSFUL) { |
---|
| 387 | close(fd); |
---|
| 388 | } |
---|
| 389 | } else { |
---|
| 390 | sc = RTEMS_INVALID_ID; |
---|
| 391 | } |
---|
| 392 | |
---|
| 393 | return sc; |
---|
| 394 | } |
---|