[PATCH 1/8] libblock: Add sparse disk

Gedare Bloom gedare at rtems.org
Thu Nov 29 16:55:16 UTC 2012


On Thu, Nov 29, 2012 at 9:32 AM, Ralf Kirchner <
ralf.kirchner at embedded-brains.de> wrote:

> ---
>  cpukit/Makefile.am                                |    1 +
>  cpukit/libblock/Makefile.am                       |    1 +
>  cpukit/libblock/include/rtems/sparse-disk.h       |  139 +++++++
>  cpukit/libblock/src/sparse-disk.c                 |  372 +++++++++++++++++
>  cpukit/preinstall.am                              |    4 +
>  testsuites/libtests/Makefile.am                   |    1 +
>  testsuites/libtests/configure.ac                  |    1 +
>  testsuites/libtests/sparsedisk01/Makefile.am      |   19 +
>  testsuites/libtests/sparsedisk01/init.c           |  439
> +++++++++++++++++++++
>  testsuites/libtests/sparsedisk01/sparsedisk01.doc |   11 +
>  10 Dateien geändert, 988 Zeilen hinzugefügt(+)
>  create mode 100644 cpukit/libblock/include/rtems/sparse-disk.h
>  create mode 100644 cpukit/libblock/src/sparse-disk.c
>  create mode 100644 testsuites/libtests/sparsedisk01/Makefile.am
>  create mode 100644 testsuites/libtests/sparsedisk01/init.c
>  create mode 100644 testsuites/libtests/sparsedisk01/sparsedisk01.doc
>  create mode 100644 testsuites/libtests/sparsedisk01/sparsedisk01.scn
>
> diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
> index b5569fa..5b11e7e 100644
> --- a/cpukit/Makefile.am
> +++ b/cpukit/Makefile.am
> @@ -124,6 +124,7 @@ include_rtems_HEADERS +=
> libblock/include/rtems/flashdisk.h
>  include_rtems_HEADERS += libblock/include/rtems/ramdisk.h
>  include_rtems_HEADERS += libblock/include/rtems/nvdisk.h
>  include_rtems_HEADERS += libblock/include/rtems/nvdisk-sram.h
> +include_rtems_HEADERS += libblock/include/rtems/sparse-disk.h
>  include_rtems_HEADERS += libblock/include/rtems/ide_part_table.h
>  include_rtems_HEADERS += libblock/include/rtems/bdpart.h
>  include_rtems_HEADERS += libblock/include/rtems/media.h
> diff --git a/cpukit/libblock/Makefile.am b/cpukit/libblock/Makefile.am
> index d07eb5e..0f720f2 100644
> --- a/cpukit/libblock/Makefile.am
> +++ b/cpukit/libblock/Makefile.am
> @@ -31,6 +31,7 @@ libblock_a_SOURCES = src/bdbuf.c \
>      src/media-server.c \
>      src/media-desc.c \
>      src/media-dev-ident.c \
> +    src/sparse-disk.c \
>      include/rtems/bdbuf.h include/rtems/blkdev.h \
>      include/rtems/diskdevs.h include/rtems/flashdisk.h \
>      include/rtems/ramdisk.h include/rtems/nvdisk.h
> include/rtems/nvdisk-sram.h \
> diff --git a/cpukit/libblock/include/rtems/sparse-disk.h
> b/cpukit/libblock/include/rtems/sparse-disk.h
> new file mode 100644
> index 0000000..54e3fe9
> --- /dev/null
> +++ b/cpukit/libblock/include/rtems/sparse-disk.h
> @@ -0,0 +1,139 @@
> +/**
> + * @file
> + *
> + * @ingroup rtems_sparse_disk
> + *
> + * @brief Sparse disk block device API.
> + */
> +
> +/*
> + * Copyright (c) 2012 embedded brains GmbH.  All rights reserved.
> + *
> + *  embedded brains GmbH
> + *  Obere Lagerstr. 30
> + *  82178 Puchheim
> + *  Germany
> + *  <rtems at embedded-brains.de>
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.com/license/LICENSE.
> + */
> +
> +#ifndef SPARSE_DISK_H
> +#define SPARSE_DISK_H
> +
> +#include <stddef.h>
> +#include <stdint.h>
> +#include <rtems.h>
> +#include <rtems/diskdevs.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif /* __cplusplus */
> +
> +
>
only leave one blank line anywhere. fix here, and in other places.


> +/**
> + * @defgroup rtems_sparse_disk Sparse Disk Device
> + *
> + * @ingroup rtems_blkdev
> + *
> + * @{
> + */
> +
> +
> +
> +typedef struct {
> +  rtems_blkdev_bnum  block;
> +  void              *data;
> +} rtems_sparse_disk_key;
> +
> +typedef struct rtems_sparse_disk *sparse_disk_ptr;
>
we don't normally obscure pointers behind typedefs. this should be
considered more carefully. I'm not even sure this type gets used
anywhere... I see the same name used as a variable, which is confusing.


> +
> +
> +typedef struct {
> +  rtems_id                       mutex;
> +  rtems_blkdev_bnum              blocks_allocated;
> +  size_t                         used_count;
> +  uint32_t                       block_size;
> +  void                          *delete_hdlr;
>
eliminate abbreviation.. don't know what hdlr means.


> +  uint8_t                        fill_pattern;
> +  rtems_sparse_disk_key         *key_table;
> +} rtems_sparse_disk;
> +
> +typedef void (*rtems_sparse_disk_delete_hdlr)(rtems_sparse_disk
> *sparse_disk);
> +
> +
> +
> +/**
> + * @brief Allocates a sparse disk.
> + *
> + * The block size will be @a block_size.
> + * The disk storage will be allocated. The number of actually
> + * allocated blocks will be @a blocks_allocated.
> + * The disk will get allocated to the address pointed to by
> + * @a sparse_disk
> + *
> + * @retval RTEMS_SUCCESSFUL Successful operation.
> + * @retval RTEMS_INVALID_NUMBER Block size or block count is not positive.
> + * @retval RTEMS_INVALID_ADDRESS Invalid sparse disk address.
> + * @retval RTEMS_NO_MEMORY Not enough memory.
> + */
> +rtems_status_code rtems_sparse_disk_create(
> +  uint32_t            block_size,
> +  rtems_blkdev_bnum   blocks_allocated,
> +  rtems_sparse_disk **sparse_disk
> +  );
> +
> +/**
> + * @brief Deallocates a sparse disk.
> + *
> + * A disk created with rtems_sparse_disk_create() and pointed to
> + * by @a sparse_disk will get deallocated
> + */
> +void rtems_sparse_disk_delete(
> +  rtems_sparse_disk *sparse_disk
> + );
> +
> +
> +
> +
>
delete extra blanks.


> +/**
> + * @brief Initializes and registers a sparse disk.
> + *
> + * Registers a device node with disk name path @a device_file_name.
> + * Initialization and registration will be done with the structure
> + * pointed to by @a sparse_disk.
> + * The block size will be @a block_size. The block count will be
> + * @a block_count. The number of actually allocated blocks will
> + * be @a blocks_allocated.
> + * The data in the allocated blocks will get initialized with @a
> fill_pattern.
> + * @a sparse_disk_delete is a pointer to a method to be called
> + * for deleting the sparse disk. If the sparse disk was allocated
> + * with method rtems_sparse_disk_create() you can pass
> rtems_sparse_disk_delete().
> + * Alternatively you can pass your own delete method.
> + *
> + * @retval RTEMS_SUCCESSFUL Successful operation.
> + * @retval RTEMS_INVALID_NUMBER Block size or block count is not positive.
> + * @retval RTEMS_INVALID_ADDRESS Invalid sparse disk address.
> + * @retval RTEMS_TOO_MANY Can not create semaphore
> + * @retval RTEMS_UNSATISFIED Cannot create generic device node.
> + */
> +rtems_status_code rtems_sparse_disk_register(
> +  const char                    *device_file_name,
> +  rtems_sparse_disk             *sparse_disk,
> +  uint32_t                       block_size,
> +  rtems_blkdev_bnum              block_count,
> +  rtems_blkdev_bnum              blocks_allocated,
> +  rtems_sparse_disk_delete_hdlr  sparse_disk_delete,
> +  uint8_t                        fill_pattern
> +);
> +
> +
> +/** @} */
> +
> +#ifdef __cplusplus
> +}
> +#endif /* __cplusplus */
> +
> +#endif /* SPARSE_DISK_H */
> diff --git a/cpukit/libblock/src/sparse-disk.c
> b/cpukit/libblock/src/sparse-disk.c
> new file mode 100644
> index 0000000..f6038e9
> --- /dev/null
> +++ b/cpukit/libblock/src/sparse-disk.c
> @@ -0,0 +1,372 @@
> +/**
> + * @file
> + *
> + * @ingroup rtems_sparse_disk
> + *
> + * @brief Sparse disk block device implementation.
> + */
> +
> +/*
> + * Copyright (c) 2012 embedded brains GmbH.  All rights reserved.
> + *
> + *  embedded brains GmbH
> + *  Obere Lagerstr. 30
> + *  82178 Puchheim
> + *  Germany
> + *  <rtems at embedded-brains.de>
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.com/license/LICENSE.
> + */
> +
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <string.h>
> +
> +#include <rtems.h>
> +#include <rtems/blkdev.h>
> +#include <rtems/fatal.h>
> +
> +#include "rtems/sparse-disk.h"
> +
> +
> +/*
> + * Allocate RAM for sparse disk
> + */
> +static rtems_sparse_disk*
> + sparse_disk_allocate(
> +  const uint32_t block_size,
> +  const rtems_blkdev_bnum blocks_allocated
> +)
> +{
> +  size_t const key_table_size = blocks_allocated *
> sizeof(rtems_sparse_disk_key);
> +  size_t const data_size = blocks_allocated * block_size;
> +  size_t const alloc_size = sizeof(rtems_sparse_disk) + key_table_size +
> data_size;
> +
> +  uint8_t* data = malloc(alloc_size);
> +  rtems_sparse_disk *const sd = (rtems_sparse_disk *) data;
>
why not just allocate directly into sd? i don't see a reason for the extra
variable 'data' here.

> +
> +  if (data == NULL) {
> +    return NULL;
> +  }
> +
> +  return sd;
> +}
> +
> +/*
> + * Initialize sparse disk data
> + */
> +static rtems_status_code
> + sparse_disk_initialize (rtems_sparse_disk* sd,
> +                         const uint32_t block_size,
> +                         const rtems_blkdev_bnum blocks_allocated,
> +                         const rtems_sparse_disk_delete_hdlr
> sparse_disk_delete,
> +                         const uint8_t fill_pattern)
> +{
> +  rtems_status_code sc;
> +  size_t i;
>
why size_t?


> +
> +  if (NULL == sd)
> +    return RTEMS_INVALID_ADDRESS;
> +
> +  uint8_t *data = (uint8_t *) sd;
>
again why the extra variable?

> +  size_t const key_table_size = blocks_allocated *
> sizeof(rtems_sparse_disk_key);
> +  size_t const data_size = blocks_allocated * block_size;
> +
> +  memset(data, 0, sizeof(rtems_sparse_disk) + key_table_size);
> +
> +  sd->fill_pattern = fill_pattern;
> +  memset((uint8_t*)(data + sizeof(rtems_sparse_disk) + key_table_size),
> sd->fill_pattern, data_size);
> +
> +
> +  sd->delete_hdlr = sparse_disk_delete;
> +
> +  sc = rtems_semaphore_create(
> +    rtems_build_name('S', 'P', 'A', 'R'),
> +    1,
> +    RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY,
> +    0,
> +    &sd->mutex
> +  );
>
This semaphore should be accounted in application configuration
requirements, either explicitly by applications that use the
rtems_sparse_disk, or with some macro that detects it..


> +  if (sc != RTEMS_SUCCESSFUL) {
> +    return sc;
> +  }
> +
> +  data += sizeof(rtems_sparse_disk);
> +
> +  sd->blocks_allocated = blocks_allocated;
> +  sd->key_table = (rtems_sparse_disk_key *) data;
> +
> +  data += key_table_size;
> +
> +  for (i = 0; i < blocks_allocated; ++i, data += block_size) {
> +    sd->key_table [i].data = data;
> +  }
> +  sd->block_size = block_size;
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +
> +
> +/*
> + * Block comparison
> + */
> +static int
> + sparse_disk_compare(const void *aa, const void *bb)
> +{
> +  const rtems_sparse_disk_key *a = aa;
> +  const rtems_sparse_disk_key *b = bb;
> +
> +  if (a->block < b->block) {
> +    return -1;
> +  } else if (a->block == b->block) {
> +    return 0;
> +  } else {
> +    return 1;
> +  }
> +}
> +
> +static rtems_sparse_disk_key *
> + sparse_disk_get_new_block(
> +  rtems_sparse_disk *sparse_disk,
> +  const rtems_blkdev_bnum block
> +)
> +{
> +  rtems_sparse_disk_key *key;
> +
> +  if (sparse_disk->used_count < sparse_disk->blocks_allocated) {
> +    key = &sparse_disk->key_table [sparse_disk->used_count];
> +    key->block = block;
> +    ++sparse_disk->used_count;
> +    qsort(sparse_disk->key_table, sparse_disk->used_count,
> sizeof(rtems_sparse_disk_key), sparse_disk_compare);
>
is quicksort every time OK here? is a sorted array the best structure to
use, or should a tree be used? Just wondering out loud.

+  } else
> +    return NULL;
> +
> +  return key;
> +}
> +
> +static int
> + sparse_disk_read_block(
> +  const rtems_sparse_disk *sparse_disk,
> +  const rtems_blkdev_bnum block,
> +  uint8_t *buffer,
> +  const size_t buffer_size
> +)
> +{
> +  rtems_sparse_disk_key *key;
> +  rtems_sparse_disk_key block_key = {
> +    .block = block,
> +    .data = NULL
> +  };
> +  size_t bytes_to_copy = sparse_disk->block_size;
> +
> +  if (buffer_size < bytes_to_copy)
> +    bytes_to_copy = buffer_size;
> +
> +  key = bsearch(
> +    &block_key,
> +    sparse_disk->key_table,
> +    sparse_disk->used_count,
> +    sizeof(rtems_sparse_disk_key),
> +    sparse_disk_compare
> +  );
> +
> +  if (NULL != key)
> +    memcpy (buffer, key->data, bytes_to_copy);
> +  else
> +    memset (buffer, sparse_disk->fill_pattern, buffer_size);
>
+  return bytes_to_copy;
> +}
> +
> +static int
> + sparse_disk_write_block(
> +  rtems_sparse_disk *sparse_disk,
> +  const rtems_blkdev_bnum block,
> +  const uint8_t *buffer,
> +  const size_t buffer_size
> +)
> +{
> +  unsigned int i;
> +  bool block_needs_writing = false;
> +  rtems_sparse_disk_key *key;
> +  rtems_sparse_disk_key block_key = {
> +    .block = block,
> +    .data = NULL
> +  };
> +  size_t bytes_to_copy = sparse_disk->block_size;
> +
> +  if (buffer_size < bytes_to_copy)
> +    bytes_to_copy = buffer_size;
> +
> +  /* we only need to write the block if it is different from the fill
> pattern.
> +   * If the read method does not find a block it will deliver the fill
> pattern anyway.
> +   */
> +
> +  key = bsearch(
> +    &block_key,
> +    sparse_disk->key_table,
> +    sparse_disk->used_count,
> +    sizeof(rtems_sparse_disk_key),
> +    sparse_disk_compare
> +  );
> +
> +  if (NULL == key) {
> +    for (i = 0; (! block_needs_writing) && (i < bytes_to_copy); ++i) {
> +      if (buffer[i] != sparse_disk->fill_pattern)
> +        block_needs_writing = true;
> +    }
> +    if (block_needs_writing) {
> +      key = sparse_disk_get_new_block (sparse_disk, block);
> +    }
> +  }
> +  if (NULL != key)
> +    memcpy (key->data, buffer, bytes_to_copy);
> +  else if (block_needs_writing)
> +    return -1;
> +
> +  return bytes_to_copy;
> +}
> +
> +/*
> + * Read/write handling
> + */
> +static int
> + sparse_disk_read_write(
> +  rtems_sparse_disk *sparse_disk,
> +  rtems_blkdev_request *req,
> +  const bool read)
> +{
> +  int rv = 0;
> +  uint32_t req_buffer;
> +  rtems_blkdev_sg_buffer *scatter_gather;
> +  rtems_blkdev_bnum block;
> +  uint8_t *buff;
> +  size_t buff_size;
> +  unsigned int bytes_handled;
> +
> +  rtems_semaphore_obtain(sparse_disk->mutex, RTEMS_WAIT,
> RTEMS_NO_TIMEOUT);
> +
> +  for (req_buffer = 0; (0 <= rv) && (req_buffer < req->bufnum);
> ++req_buffer) {
> +    scatter_gather = &req->bufs [req_buffer];
> +
> +    bytes_handled = 0;
> +    buff = (uint8_t*)scatter_gather->buffer;
> +    block = scatter_gather->block;
> +    buff_size = scatter_gather->length;
> +
> +    while ((0 <= rv) && (0 < buff_size))
> +    {
> +      if (read)
> +        rv = sparse_disk_read_block (sparse_disk, block,
> &buff[bytes_handled], buff_size);
> +      else
> +        rv = sparse_disk_write_block (sparse_disk, block,
> &buff[bytes_handled], buff_size);
> +      ++block;
> +      bytes_handled += rv;
> +      buff_size -= rv;
> +    }
> +  }
> +
> +  rtems_semaphore_release(sparse_disk->mutex);
> +
> +  if (0 > rv)
> +    rtems_blkdev_request_done (req, RTEMS_IO_ERROR);
> +  else
> +    rtems_blkdev_request_done (req, RTEMS_SUCCESSFUL);
> +
> +  return 0;
> +}
> +
> +/*
> + * ioctl handler to be passed to the block device handler
> + */
> +static int
> + sparse_disk_ioctl(rtems_disk_device *dd, uint32_t req, void *argp)
> +{
> +  rtems_status_code sc;
> +  rtems_sparse_disk *sd = rtems_disk_get_driver_data(dd);
> +
> +  if (RTEMS_BLKIO_REQUEST == req) {
> +    rtems_blkdev_request *r = argp;
> +
> +    switch (r->req) {
> +      case RTEMS_BLKDEV_REQ_READ:
> +      case RTEMS_BLKDEV_REQ_WRITE:
> +        return sparse_disk_read_write(sd, r, r->req ==
> RTEMS_BLKDEV_REQ_READ);
> +      default:
> +        break;
> +    }
> +  } else if (RTEMS_BLKIO_DELETED == req) {
> +    sc = rtems_semaphore_delete(sd->mutex);
> +    if (RTEMS_SUCCESSFUL != sc)
> +      rtems_fatal_error_occurred(0xdeadbeef);
> +    sd->mutex = RTEMS_ID_NONE;
> +    if (NULL != sd->delete_hdlr)
> +      ((rtems_sparse_disk_delete_hdlr)sd->delete_hdlr)(sd);
> +    return 0;
> +  }else {
> +    return rtems_blkdev_ioctl(dd, req, argp);
> +  }
> +
> +  errno = EINVAL;
> +  return -1;
> +}
> +
> +/*
> + * De-allocate the sparse disk
> + */
> +void
> + rtems_sparse_disk_delete(rtems_sparse_disk *sd)
> +{
> +  if (NULL != sd)
> +    free(sd);
> +}
> +
> +rtems_status_code rtems_sparse_disk_create(
> +  const uint32_t block_size,
> +  const rtems_blkdev_bnum blocks_allocated,
> +  rtems_sparse_disk **sparse_disk
> +)
> +{
> +  *sparse_disk = sparse_disk_allocate(
> +    block_size,
> +    blocks_allocated
> +  );
> +  if (NULL == *sparse_disk)
> +    return RTEMS_NO_MEMORY;
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_sparse_disk_register(
> +  const char *device_file_name,
> +  rtems_sparse_disk *sparse_disk,
> +  const uint32_t block_size,
> +  const rtems_blkdev_bnum block_count,
> +  const rtems_blkdev_bnum blocks_allocated,
> +  const rtems_sparse_disk_delete_hdlr sparse_disk_delete,
> +  const uint8_t fill_pattern
> +)
> +{
> +  rtems_status_code sc;
> +
> +    sc = sparse_disk_initialize(
> +    sparse_disk,
> +    block_size,
> +    blocks_allocated,
> +    sparse_disk_delete,
> +    fill_pattern
> +  );
> +  if (RTEMS_SUCCESSFUL != sc) {
> +    return sc;
> +  }
> +
> +  sc = rtems_blkdev_create(
> +    device_file_name,
> +    block_size,
> +    block_count,
> +    sparse_disk_ioctl,
> +    sparse_disk
> +  );
> +  return sc;
> +}
> diff --git a/cpukit/preinstall.am b/cpukit/preinstall.am
> index f6d24bb..26b90ec 100644
> --- a/cpukit/preinstall.am
> +++ b/cpukit/preinstall.am
> @@ -272,6 +272,10 @@ $(PROJECT_INCLUDE)/rtems/nvdisk-sram.h:
> libblock/include/rtems/nvdisk-sram.h $(P
>         $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/nvdisk-sram.h
>  PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/nvdisk-sram.h
>
> +$(PROJECT_INCLUDE)/rtems/sparse-disk.h:
> libblock/include/rtems/sparse-disk.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
> +       $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/sparse-disk.h
> +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/sparse-disk.h
> +
>  $(PROJECT_INCLUDE)/rtems/ide_part_table.h:
> libblock/include/rtems/ide_part_table.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
>         $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/ide_part_table.h
>  PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/ide_part_table.h
> diff --git a/testsuites/libtests/Makefile.am
> b/testsuites/libtests/Makefile.am
> index afd8605..1197742 100644
> --- a/testsuites/libtests/Makefile.am
> +++ b/testsuites/libtests/Makefile.am
> @@ -1,6 +1,7 @@
>  ACLOCAL_AMFLAGS = -I ../aclocal
>
>  SUBDIRS = POSIX
> +SUBDIRS += sparsedisk01
>  SUBDIRS += block16
>  SUBDIRS += block15
>  SUBDIRS += block14
> diff --git a/testsuites/libtests/configure.ac b/testsuites/libtests/
> configure.ac
> index 83e22ed..b8be927 100644
> --- a/testsuites/libtests/configure.ac
> +++ b/testsuites/libtests/configure.ac
> @@ -43,6 +43,7 @@ AM_CONDITIONAL(HAS_POSIX,test
> x"${rtems_cv_RTEMS_POSIX_API}" = x"yes")
>
>  # Explicitly list all Makefiles here
>  AC_CONFIG_FILES([Makefile
> +sparsedisk01/Makefile
>  block16/Makefile
>  mghttpd01/Makefile
>  block15/Makefile
> diff --git a/testsuites/libtests/sparsedisk01/Makefile.am
> b/testsuites/libtests/sparsedisk01/Makefile.am
> new file mode 100644
> index 0000000..3a836c8
> --- /dev/null
> +++ b/testsuites/libtests/sparsedisk01/Makefile.am
> @@ -0,0 +1,19 @@
> +rtems_tests_PROGRAMS = sparsedisk01
> +sparsedisk01_SOURCES = init.c
> +
> +dist_rtems_tests_DATA = sparsedisk01.scn sparsedisk01.doc
> +
> +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
> +include $(top_srcdir)/../automake/compile.am
> +include $(top_srcdir)/../automake/leaf.am
> +
> +AM_CPPFLAGS += -I$(top_srcdir)/../support/include
> +
> +LINK_OBJS = $(sparsedisk01_OBJECTS)
> +LINK_LIBS = $(sparsedisk01_LDLIBS)
> +
> +sparsedisk01$(EXEEXT): $(sparsedisk01_OBJECTS)
> $(sparsedisk01_DEPENDENCIES)
> +       @rm -f sparsedisk01$(EXEEXT)
> +       $(make-exe)
> +
> +include $(top_srcdir)/../automake/local.am
> diff --git a/testsuites/libtests/sparsedisk01/init.c
> b/testsuites/libtests/sparsedisk01/init.c
> new file mode 100644
> index 0000000..a76738f
> --- /dev/null
> +++ b/testsuites/libtests/sparsedisk01/init.c
> @@ -0,0 +1,439 @@
> +/*
> + * Copyright (c) 2012 embedded brains GmbH.  All rights reserved.
> + *
> + *  embedded brains GmbH
> + *  Obere Lagerstr. 30
> + *  82178 Puchheim
> + *  Germany
> + *  <rtems at embedded-brains.de>
> + *
> + * The license and distribution terms for this file may be
> + * found in the file LICENSE in this distribution or at
> + * http://www.rtems.com/license/LICENSE.
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +  #include "config.h"
> +#endif
> +
> +#include <fcntl.h>
> +#include <rtems/blkdev.h>
> +#include "rtems/sparse-disk.h"
> +
> +#include "tmacros.h"
> +
> +/* Number of bytes for test pattern within a sparse disk container */
> +#define STATIC_PATTERN_SIZE           4096
> +/* Block size used for the sparse disk in a sparse disk container */
> +#define STATIC_BLOCK_SIZE             4096
> +/* Number of block allocated for the sparse disk in a sparse disk
> container */
> +#define STATIC_ALLOCATED_BLOCK_COUNT     1
> +/* Blocks simulated by the sparse disk in a disk container */
> +#define STATIC_SIMULATED_BLOCK_COUNT  4096
> +
> +/*
> + * Container which cotains a sparse disk + memory for key table and data
> as would get
> + * allocated by rtems_sparse_disk_create() + memory for a memory test
> pattern
> + * By using this container white box testing of a sparse disk becomes
> possible
> + */
> +typedef struct {
> +  rtems_sparse_disk       sparse_disk;
> +  rtems_sparse_disk_key   keytable[STATIC_ALLOCATED_BLOCK_COUNT];
> +  uint8_t                 data[STATIC_BLOCK_SIZE *
> STATIC_ALLOCATED_BLOCK_COUNT];
> +  uint8_t                 pattern[STATIC_PATTERN_SIZE];
> +} sparse_disk_container;
> +
> +/*
> + * Black box test the disk parameters of a sparse disk
> + */
> +static void
> + test_disk_params(
> +   const int file_descriptor,
> +   const uint32_t block_size,
> +   const uint32_t media_block_size,
> +   const rtems_blkdev_bnum block_number
> +)
> +{
> +  int rv;
> +  uint32_t value = 0;
> +  rtems_disk_device *fd_dd = NULL;
> +  rtems_blkdev_bnum block_count = 0;
> +
> +  rv = rtems_disk_fd_get_media_block_size(file_descriptor, &value);
> +  rtems_test_assert(0 == rv);
> +  rtems_test_assert(media_block_size == value);
> +
> +  value = 0;
> +  rv = rtems_disk_fd_get_block_size(file_descriptor, &value);
> +  rtems_test_assert(0 == rv);
> +  rtems_test_assert(block_size == value);
> +
> +  block_count = 0;
> +  rv = rtems_disk_fd_get_block_count(file_descriptor, &block_count);
> +  rtems_test_assert(0 == rv);
> +  rtems_test_assert(block_number == block_count);
> +
> +  rv = rtems_disk_fd_get_disk_device(file_descriptor, &fd_dd);
> +  rtems_test_assert(0 == rv);
> +  rtems_test_assert(NULL != fd_dd);
> +}
> +
> +/*
> + * Verify that writing to a sparse disk delivers expected results
> + */
> +static void
> + test_writing(
> +  const int file_descriptor,
> +  const uint32_t block_size,
> +  const rtems_blkdev_bnum blocks_allocated
> +)
> +{
> +  int rv;
> +  rtems_blkdev_bnum block_count = 0;
> +  unsigned int byte_count;
> +  off_t file_pos;
> +  uint8_t buff[block_size];
> +
> +  // Write a pattern to all allocated blocks
> +  for (block_count = 0; block_count < blocks_allocated; block_count++) {
> +    file_pos = (off_t)block_count * block_size;
> +    rv = lseek(file_descriptor, file_pos, SEEK_SET);
> +    rtems_test_assert(file_pos == rv);
> +
> +    rv = read(file_descriptor, buff, block_size);
> +    rtems_test_assert(block_size == rv);
> +
> +    for (byte_count = 0; byte_count < (block_size / sizeof(byte_count));
> byte_count++) {
> +      memcpy (buff + (byte_count * sizeof(byte_count)), &byte_count,
> sizeof(byte_count));
> +    }
> +
> +    rv = lseek(file_descriptor, file_pos, SEEK_SET);
> +    rtems_test_assert(file_pos == rv);
> +
> +    rv = write(file_descriptor, buff, block_size);
> +    rtems_test_assert(block_size == rv);
> +  }
> +}
> +
> +/*
> + * Verify that black box reading for a sparse disk delivers expected
> results
> + */
> +static void
> + test_reading(
> +  const int file_descriptor,
> +  const uint32_t block_size,
> +  const rtems_blkdev_bnum blocks_allocated,
> +  const uint8_t fill_pattern
> +)
> +{
> +  int rv;
> +  rtems_blkdev_bnum block_count = 0;
> +  unsigned int byte_count;
> +  off_t file_pos;
> +  uint8_t buff[block_size];
> +  uint32_t value = 0;
> +
> +  rv = fsync(file_descriptor);
> +  rtems_test_assert(0 == rv);
> +
> +
> +  // Read back the patterns
> +  for (block_count = 0; block_count < blocks_allocated; block_count++) {
> +    file_pos = (off_t)block_count * block_size;
> +    value = lseek (file_descriptor, file_pos,  SEEK_SET);
> +    rtems_test_assert(file_pos == value);
> +
> +    rv = read (file_descriptor, &buff, block_size);
> +    rtems_test_assert(block_size <= rv);
> +
> +    for (byte_count = 0; byte_count < (block_size / sizeof(byte_count));
> byte_count++) {
> +      rv = memcmp(buff + (byte_count * sizeof(byte_count)), &byte_count,
> sizeof(byte_count));
> +      rtems_test_assert(0 == rv);
> +    }
> +  }
> +  // Try to read from unallocated block
> +  file_pos = (off_t)block_count * block_size;
> +  rv = lseek(file_descriptor, file_pos, SEEK_SET);
> +  rtems_test_assert(file_pos == rv);
> +
> +  rv = read(file_descriptor, buff, block_size);
> +  rtems_test_assert(block_size == rv);
> +
> +  for (byte_count = 0; byte_count < block_size; ++byte_count)
> +    rtems_test_assert(fill_pattern == buff[byte_count]);
> +}
> +
> +/*
> + * Do black box io testing on a sparse disk
> + */
> +static void
> + test_device_io (const char *device_name,
> +                 const uint32_t block_size,
> +                 const uint32_t media_block_size,
> +                 const rtems_blkdev_bnum block_number,
> +                 const rtems_blkdev_bnum blocks_allocated,
> +                 const uint8_t fill_pattern)
> +{
> +  int rv;
> +  int file_descriptor;
> +
> +  file_descriptor = open (device_name, O_RDWR);
> +  rtems_test_assert(0 <= file_descriptor);
> +
> +  test_disk_params (
> +    file_descriptor,
> +    block_size,
> +    media_block_size,
> +    block_number
> +  );
> +
> +
> +  test_writing (
> +    file_descriptor,
> +    block_size,
> +    blocks_allocated
> +  );
> +
> +  test_reading(
> +    file_descriptor,
> +    block_size,
> +    blocks_allocated,
> +    fill_pattern
> +  );
> +
> +  rv = close (file_descriptor);
> +  rtems_test_assert(0 == rv);
> +}
> +
> +/*
> + * In white box testing verify the key table of the sparse disk is correct
> + */
> +static void
> + test_static_key_table(
> +  const sparse_disk_container *disk_container,
> +  const  rtems_blkdev_bnum blocks_allocated,
> +  const uint32_t block_size
> +)
> +{
> +  unsigned int i;
> +
> +  for (i = 0; i < blocks_allocated; ++i)
> +  {
> +    rtems_test_assert(i == disk_container->keytable[i].block);
> +    rtems_test_assert(&disk_container->data[i * block_size] ==
> disk_container->keytable[i].data);
> +  }
> +
> +}
> +
> +/*
> + * Verify the test pattern used in white box testing is as expected
> + */
> +static void
> + test_static_pattern(
> +  const unsigned int pattern_size,
> +  const uint8_t *pattern
> +)
> +{
> +  unsigned int i;
> +
> +  for (i = 0; i < pattern_size; ++i)
> +    rtems_test_assert(((uint8_t)(pattern_size -1 - i)) == pattern[i]);
> +}
> +
> +/*
> + * Read write testing with a statically allocated disk. Thus white box
> testing can be done
> + */
> +static void
> + test_with_whitebox(const char *device_name)
> +{
> +  rtems_status_code sc;
> +  int rv;
> +  unsigned int i;
> +  sparse_disk_container disk_container;
> +  int file_descriptor;
> +  rtems_blkdev_bnum block_count = 0;
> +  unsigned int byte_count;
> +  uint8_t fill_pattern = 0;
> +
> +  memset (&disk_container.data, 0, sizeof(disk_container.data));
> +  memset (&disk_container.keytable, 0, sizeof(disk_container.keytable));
> +  for (i = 0; i < STATIC_PATTERN_SIZE; ++i)
> +    disk_container.pattern[i] = (uint8_t)(STATIC_PATTERN_SIZE -1 - i);
> +
> +  sc = rtems_sparse_disk_register(
> +    "/dev/sda1",
> +    &disk_container.sparse_disk,
> +    STATIC_BLOCK_SIZE,
> +    STATIC_SIMULATED_BLOCK_COUNT,
> +    STATIC_ALLOCATED_BLOCK_COUNT,
> +    NULL,
> +    fill_pattern
> +  );
> +  rtems_test_assert(RTEMS_SUCCESSFUL == sc);
> +
> +  test_static_key_table(
> +    &disk_container,
> +    STATIC_ALLOCATED_BLOCK_COUNT,
> +    STATIC_BLOCK_SIZE
> +   );
> +
> +  for (i = 0; i < (STATIC_BLOCK_SIZE * STATIC_ALLOCATED_BLOCK_COUNT); ++i)
> +    rtems_test_assert(0 == disk_container.data[i]);
> +
> +  test_static_pattern(
> +    STATIC_PATTERN_SIZE,
> +    &disk_container.pattern[0]
> +  );
> +
> +  file_descriptor = open (device_name, O_RDWR);
> +  rtems_test_assert(0 <= file_descriptor);
> +
> +  test_disk_params (
> +    file_descriptor,
> +    STATIC_BLOCK_SIZE,
> +    STATIC_BLOCK_SIZE,
> +    STATIC_SIMULATED_BLOCK_COUNT
> +  );
> +
> +  test_writing (
> +    file_descriptor,
> +    STATIC_BLOCK_SIZE,
> +    STATIC_ALLOCATED_BLOCK_COUNT
> +  );
> +
> +  test_reading(
> +    file_descriptor,
> +    STATIC_BLOCK_SIZE,
> +    STATIC_ALLOCATED_BLOCK_COUNT,
> +    fill_pattern
> +  );
> +
> +  rv = close (file_descriptor);
> +  rtems_test_assert(0 == rv);
> +
> +  test_static_key_table(
> +    &disk_container,
> +    STATIC_ALLOCATED_BLOCK_COUNT,
> +    STATIC_BLOCK_SIZE
> +   );
> +
> +  for (block_count = 0; block_count < STATIC_ALLOCATED_BLOCK_COUNT;
> block_count++) {
> +    for (byte_count = 0; byte_count < (STATIC_BLOCK_SIZE /
> sizeof(byte_count)); byte_count++) {
> +      rv = memcmp(&disk_container.data[byte_count * sizeof(byte_count)],
> &byte_count, sizeof(byte_count));
> +      rtems_test_assert(0 == rv);
> +    }
> +  }
> +
> +  test_static_pattern(
> +    STATIC_PATTERN_SIZE,
> +    &disk_container.pattern[0]
> +  );
> +
> +}
> +
> +
> +/*
> + * The test sequence
> + */
> +static
> + void test(void)
> +{
> +  rtems_status_code sc;
> +  int rv;
> +  char device_name[] = "/dev/sda1";
> +  uint32_t block_size;
> +  rtems_blkdev_bnum block_number;
> +  rtems_blkdev_bnum blocks_allocated;
> +  rtems_sparse_disk *sparse_disk_ptr = NULL;
> +  int file_descriptor;
> +  uint8_t fill_pattern = 0;
> +
> +  sc = rtems_disk_io_initialize();
> +  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
> +
> +  block_size = 512;
> +  block_number = 4 * 2 * 1024;
> +  blocks_allocated = 8;
> +  sc = rtems_sparse_disk_create(
> +    block_size,
> +    blocks_allocated,
> +    &sparse_disk_ptr
> +  );
> +  rtems_test_assert(RTEMS_SUCCESSFUL == sc);
> +  sc = rtems_sparse_disk_register(
> +    "/dev/sda1",
> +    sparse_disk_ptr,
> +    block_size,
> +    block_number,
> +    blocks_allocated,
> +    rtems_sparse_disk_delete,
> +    fill_pattern
> +  );
> +  rtems_test_assert(RTEMS_SUCCESSFUL == sc);
> +
> +  // Test reading and writing with sector size 512 and 8 such sectors
> allocated. Block size will default to 512
> +  test_device_io (
> +    device_name,
> +    block_size,
> +    block_size,
> +    block_number,
> +    blocks_allocated,
> +    fill_pattern
> +  );
> +
> +  file_descriptor = open (device_name, O_RDWR);
> +  rtems_test_assert(0 <= file_descriptor);
> +
> +  rv = rtems_disk_fd_set_block_size(file_descriptor, blocks_allocated *
> block_size);
> +  rtems_test_assert(0 == rv);
> +
> +  rv = close (file_descriptor);
> +  rtems_test_assert(0 == rv);
> +
> +  // Block size was increased to 4k. Thus all to allocated disk space
> corresponds to one block. Repeat the read write tests
> +  test_device_io (
> +    device_name,
> +    block_size * blocks_allocated,
> +    block_size,
> +    block_number,
> +    1,
> +    fill_pattern
> +  );
> +
> +  rv = unlink (device_name);
> +  rtems_test_assert(0 == rv);
> +
> +  // Do testing with a statically allocated disk. This permits white box
> testing
> +  test_with_whitebox(device_name);
> +
> +}
> +
> +static void Init(rtems_task_argument arg)
> +{
> +  (void) arg;
> +  puts("\n\n*** TEST sparsedisk01 ***");
> +
> +  test();
> +
> +  puts("*** END OF TEST sparsedisk01 ***");
> +
> +  rtems_test_exit(0);
> +}
> +
> +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
> +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
> +#define CONFIGURE_APPLICATION_NEEDS_LIBBLOCK
> +
> +#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
> +#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 4
> +
> +#define CONFIGURE_UNLIMITED_OBJECTS
> +#define CONFIGURE_UNIFIED_WORK_AREAS
> +
> +#define CONFIGURE_INIT_TASK_STACK_SIZE (16 * 1024)
> +
> +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
> +
> +#define CONFIGURE_INIT
> +
> +#include <rtems/confdefs.h>
> diff --git a/testsuites/libtests/sparsedisk01/sparsedisk01.doc
> b/testsuites/libtests/sparsedisk01/sparsedisk01.doc
> new file mode 100644
> index 0000000..e73746a
> --- /dev/null
> +++ b/testsuites/libtests/sparsedisk01/sparsedisk01.doc
> @@ -0,0 +1,11 @@
> +This file describes the directives and concepts tested by this test set.
> +
> +test set name: sparsedisk01
> +
> +directives:
> +
> +  TBD
> +
> +concepts:
> +
> +  TBD
> diff --git a/testsuites/libtests/sparsedisk01/sparsedisk01.scn
> b/testsuites/libtests/sparsedisk01/sparsedisk01.scn
> new file mode 100644
> index 0000000..e69de29
> --
> 1.7.10.4
>
> _______________________________________________
> rtems-devel mailing list
> rtems-devel at rtems.org
> http://www.rtems.org/mailman/listinfo/rtems-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/devel/attachments/20121129/1201484b/attachment-0001.html>


More information about the devel mailing list