[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