Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:14

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup libblock
0007  *
0008  * @brief Block Device IMFS
0009  */
0010 
0011 /*
0012  * Copyright (C) 2012, 2018 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039 
0040 #include <sys/stat.h>
0041 #include <stdlib.h>
0042 #include <unistd.h>
0043 #include <fcntl.h>
0044 #include <string.h>
0045 
0046 #include <rtems/blkdev.h>
0047 #include <rtems/bdbuf.h>
0048 #include <rtems/imfs.h>
0049 
0050 typedef struct {
0051   rtems_disk_device dd;
0052   int fd;
0053 } rtems_blkdev_imfs_context;
0054 
0055 static ssize_t rtems_blkdev_imfs_read(
0056   rtems_libio_t *iop,
0057   void *buffer,
0058   size_t count
0059 )
0060 {
0061   int rv;
0062   rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
0063   rtems_disk_device *dd = &ctx->dd;
0064   ssize_t remaining = (ssize_t) count;
0065   off_t offset = iop->offset;
0066   ssize_t block_size = (ssize_t) rtems_disk_get_block_size(dd);
0067   rtems_blkdev_bnum block = (rtems_blkdev_bnum) (offset / block_size);
0068   ssize_t block_offset = (ssize_t) (offset % block_size);
0069   char *dst = buffer;
0070 
0071   while (remaining > 0) {
0072     rtems_bdbuf_buffer *bd;
0073     rtems_status_code sc = rtems_bdbuf_read(dd, block, &bd);
0074 
0075     if (sc == RTEMS_SUCCESSFUL) {
0076       ssize_t copy = block_size - block_offset;
0077 
0078       if (copy > remaining) {
0079         copy = remaining;
0080       }
0081 
0082       memcpy(dst, (char *) bd->buffer + block_offset, (size_t) copy);
0083 
0084       sc = rtems_bdbuf_release(bd);
0085       if (sc == RTEMS_SUCCESSFUL) {
0086         block_offset = 0;
0087         remaining -= copy;
0088         dst += copy;
0089         ++block;
0090       } else {
0091         remaining = -1;
0092       }
0093     } else {
0094       remaining = -1;
0095     }
0096   }
0097 
0098   if (remaining >= 0) {
0099     iop->offset += count;
0100     rv = (ssize_t) count;
0101   } else {
0102     errno = EIO;
0103     rv = -1;
0104   }
0105 
0106   return rv;
0107 }
0108 
0109 static ssize_t rtems_blkdev_imfs_write(
0110   rtems_libio_t *iop,
0111   const void *buffer,
0112   size_t count
0113 )
0114 {
0115   int rv;
0116   rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
0117   rtems_disk_device *dd = &ctx->dd;
0118   ssize_t remaining = (ssize_t) count;
0119   off_t offset = iop->offset;
0120   ssize_t block_size = (ssize_t) rtems_disk_get_block_size(dd);
0121   rtems_blkdev_bnum block = (rtems_blkdev_bnum) (offset / block_size);
0122   ssize_t block_offset = (ssize_t) (offset % block_size);
0123   const char *src = buffer;
0124 
0125   while (remaining > 0) {
0126     rtems_status_code sc;
0127     rtems_bdbuf_buffer *bd;
0128 
0129     if (block_offset == 0 && remaining >= block_size) {
0130        sc = rtems_bdbuf_get(dd, block, &bd);
0131     } else {
0132        sc = rtems_bdbuf_read(dd, block, &bd);
0133     }
0134 
0135     if (sc == RTEMS_SUCCESSFUL) {
0136       ssize_t copy = block_size - block_offset;
0137 
0138       if (copy > remaining) {
0139         copy = remaining;
0140       }
0141 
0142       memcpy((char *) bd->buffer + block_offset, src, (size_t) copy);
0143 
0144       sc = rtems_bdbuf_release_modified(bd);
0145       if (sc == RTEMS_SUCCESSFUL) {
0146         block_offset = 0;
0147         remaining -= copy;
0148         src += copy;
0149         ++block;
0150       } else {
0151         remaining = -1;
0152       }
0153     } else {
0154       remaining = -1;
0155     }
0156   }
0157 
0158   if (remaining >= 0) {
0159     iop->offset += count;
0160     rv = (ssize_t) count;
0161   } else {
0162     errno = EIO;
0163     rv = -1;
0164   }
0165 
0166   return rv;
0167 }
0168 
0169 static int rtems_blkdev_imfs_ioctl(
0170   rtems_libio_t *iop,
0171   ioctl_command_t request,
0172   void *buffer
0173 )
0174 {
0175   int rv = 0;
0176 
0177   if (request != RTEMS_BLKIO_REQUEST) {
0178     rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
0179     rtems_disk_device *dd = &ctx->dd;
0180 
0181     rv = (*dd->ioctl)(dd, request, buffer);
0182   } else {
0183     /*
0184      * It is not allowed to directly access the driver circumventing the cache.
0185      */
0186     errno = EINVAL;
0187     rv = -1;
0188   }
0189 
0190   return rv;
0191 }
0192 
0193 static int rtems_blkdev_imfs_fstat(
0194   const rtems_filesystem_location_info_t *loc,
0195   struct stat *buf
0196 )
0197 {
0198   rtems_blkdev_imfs_context *ctx;
0199   rtems_disk_device *dd;
0200   IMFS_jnode_t *node;
0201 
0202   ctx = IMFS_generic_get_context_by_location(loc);
0203   dd = &ctx->dd;
0204 
0205   buf->st_blksize = rtems_disk_get_block_size(dd);
0206   buf->st_blocks = rtems_disk_get_block_count(dd);
0207 
0208   node = loc->node_access;
0209   buf->st_rdev = IMFS_generic_get_device_identifier_by_node(node);
0210 
0211   return IMFS_stat(loc, buf);
0212 }
0213 
0214 static int rtems_blkdev_imfs_fsync_or_fdatasync(
0215   rtems_libio_t *iop
0216 )
0217 {
0218   int rv = 0;
0219   rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_iop(iop);
0220   rtems_disk_device *dd = &ctx->dd;
0221   rtems_status_code sc = rtems_bdbuf_syncdev(dd);
0222 
0223   if (sc != RTEMS_SUCCESSFUL) {
0224     errno = EIO;
0225     rv = -1;
0226   }
0227 
0228   return rv;
0229 }
0230 
0231 static const rtems_filesystem_file_handlers_r rtems_blkdev_imfs_node = {
0232   .open_h = rtems_filesystem_default_open,
0233   .close_h = rtems_filesystem_default_close,
0234   .read_h = rtems_blkdev_imfs_read,
0235   .write_h = rtems_blkdev_imfs_write,
0236   .ioctl_h = rtems_blkdev_imfs_ioctl,
0237   .lseek_h = rtems_filesystem_default_lseek_file,
0238   .fstat_h = rtems_blkdev_imfs_fstat,
0239   .ftruncate_h = rtems_filesystem_default_ftruncate,
0240   .fsync_h = rtems_blkdev_imfs_fsync_or_fdatasync,
0241   .fdatasync_h = rtems_blkdev_imfs_fsync_or_fdatasync,
0242   .fcntl_h = rtems_filesystem_default_fcntl,
0243   .kqfilter_h = rtems_filesystem_default_kqfilter,
0244   .mmap_h = rtems_filesystem_default_mmap,
0245   .poll_h = rtems_filesystem_default_poll,
0246   .readv_h = rtems_filesystem_default_readv,
0247   .writev_h = rtems_filesystem_default_writev
0248 };
0249 
0250 static IMFS_jnode_t *rtems_blkdev_imfs_initialize(
0251   IMFS_jnode_t *node,
0252   void *arg
0253 )
0254 {
0255   rtems_blkdev_imfs_context *ctx;
0256   rtems_disk_device *dd;
0257 
0258   node = IMFS_node_initialize_generic(node, arg);
0259 
0260   ctx = IMFS_generic_get_context_by_node(node);
0261   dd = &ctx->dd;
0262   dd->dev = IMFS_generic_get_device_identifier_by_node(node);
0263 
0264   return node;
0265 }
0266 
0267 static void rtems_blkdev_imfs_destroy(IMFS_jnode_t *node)
0268 {
0269   rtems_blkdev_imfs_context *ctx = IMFS_generic_get_context_by_node(node);
0270   rtems_disk_device *dd = &ctx->dd;
0271 
0272   (void) rtems_bdbuf_syncdev(dd);
0273   rtems_bdbuf_purge_dev(dd);
0274 
0275   if (ctx->fd >= 0) {
0276     close(ctx->fd);
0277   } else {
0278     (*dd->ioctl)(dd, RTEMS_BLKIO_DELETED, NULL);
0279   }
0280 
0281   free(ctx);
0282 
0283   IMFS_node_destroy_default(node);
0284 }
0285 
0286 static const IMFS_node_control rtems_blkdev_imfs_control =
0287   IMFS_GENERIC_INITIALIZER(
0288     &rtems_blkdev_imfs_node,
0289     rtems_blkdev_imfs_initialize,
0290     rtems_blkdev_imfs_destroy
0291   );
0292 
0293 rtems_status_code rtems_blkdev_create(
0294   const char *device,
0295   uint32_t media_block_size,
0296   rtems_blkdev_bnum media_block_count,
0297   rtems_block_device_ioctl handler,
0298   void *driver_data
0299 )
0300 {
0301   rtems_status_code sc;
0302   rtems_blkdev_imfs_context *ctx;
0303 
0304   sc = rtems_bdbuf_init();
0305   if (sc != RTEMS_SUCCESSFUL) {
0306     return RTEMS_INCORRECT_STATE;
0307   }
0308 
0309   ctx = malloc(sizeof(*ctx));
0310   if (ctx != NULL) {
0311     sc = rtems_disk_init_phys(
0312       &ctx->dd,
0313       media_block_size,
0314       media_block_count,
0315       handler,
0316       driver_data
0317     );
0318 
0319     ctx->fd = -1;
0320 
0321     if (sc == RTEMS_SUCCESSFUL) {
0322       int rv = IMFS_make_generic_node(
0323         device,
0324         S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO,
0325         &rtems_blkdev_imfs_control,
0326         ctx
0327       );
0328 
0329       if (rv != 0) {
0330         free(ctx);
0331         sc = RTEMS_UNSATISFIED;
0332       }
0333     } else {
0334       free(ctx);
0335     }
0336   } else {
0337     sc = RTEMS_NO_MEMORY;
0338   }
0339 
0340   return sc;
0341 }
0342 
0343 rtems_status_code rtems_blkdev_create_partition(
0344   const char *partition,
0345   const char *parent_block_device,
0346   rtems_blkdev_bnum media_block_begin,
0347   rtems_blkdev_bnum media_block_count
0348 )
0349 {
0350   rtems_status_code sc = RTEMS_SUCCESSFUL;
0351   int fd = open(parent_block_device, O_RDWR);
0352 
0353   if (fd >= 0) {
0354     int rv;
0355     struct stat st;
0356 
0357     rv = fstat(fd, &st);
0358     if (rv == 0 && S_ISBLK(st.st_mode)) {
0359       rtems_disk_device *phys_dd;
0360 
0361       rv = rtems_disk_fd_get_disk_device(fd, &phys_dd);
0362       if (rv == 0) {
0363         rtems_blkdev_imfs_context *ctx = malloc(sizeof(*ctx));
0364 
0365         if (ctx != NULL) {
0366           sc = rtems_disk_init_log(
0367             &ctx->dd,
0368             phys_dd,
0369             media_block_begin,
0370             media_block_count
0371           );
0372 
0373           if (sc == RTEMS_SUCCESSFUL) {
0374             ctx->fd = fd;
0375 
0376             rv = IMFS_make_generic_node(
0377               partition,
0378               S_IFBLK | S_IRWXU | S_IRWXG | S_IRWXO,
0379               &rtems_blkdev_imfs_control,
0380               ctx
0381             );
0382 
0383             if (rv != 0) {
0384               free(ctx);
0385               sc = RTEMS_UNSATISFIED;
0386             }
0387           } else {
0388             free(ctx);
0389           }
0390         } else {
0391           sc = RTEMS_NO_MEMORY;
0392         }
0393       } else {
0394         sc = RTEMS_NOT_IMPLEMENTED;
0395       }
0396     } else {
0397       sc = RTEMS_INVALID_NODE;
0398     }
0399 
0400     if (sc != RTEMS_SUCCESSFUL) {
0401       close(fd);
0402     }
0403   } else {
0404     sc = RTEMS_INVALID_ID;
0405   }
0406 
0407   return sc;
0408 }