On fre, sep 05, 2025 at 18:50, Ahmad Fatoum <[email protected]> wrote:
> On 8/28/25 5:05 PM, Tobias Waldekranz wrote:
>> Verify that the 'linear' target works as expected.
>> 
>> Do this by (1) creating a dm device with a couple of linear mappings
>> to two underlying ramdisks, and then (2) verify that data is returned
>> in the expected order when reading it through the dm device.
>
> Thanks for writing a test! :)
>
>> Signed-off-by: Tobias Waldekranz <[email protected]>
>> ---
>>  test/self/Kconfig  |   7 ++
>>  test/self/Makefile |   1 +
>>  test/self/dm.c     | 159 +++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 167 insertions(+)
>
> Please add to common/boards/configs/enable_self_test.config, so CI also
> tests this.

Ah right, tests are more useful if you execute them :)

I have told SELFTEST_ENABLE_ALL to select SELFTEST_DM and all checks
pass (https://github.com/wkz/barebox/actions/runs/17545487677), but I'm
not exactly sure which job is running the selftests, and how I can see
whether the dm tests are included.

>>  create mode 100644 test/self/dm.c
>> 
>> diff --git a/test/self/Kconfig b/test/self/Kconfig
>> index 4c43dfe394..a6dfd5f9ae 100644
>> --- a/test/self/Kconfig
>> +++ b/test/self/Kconfig
>> @@ -125,4 +125,11 @@ config SELFTEST_TLV
>>      select BASE64
>>      select BOARD_LXA
>>  
>> +config SELFTEST_DM
>> +    bool "Device mapper selftest"
>> +    depends on DM_BLK
>> +    select RAMDISK_BLK
>> +    help
>> +      Tests the available device mapper targets
>> +
>>  endif
>> diff --git a/test/self/Makefile b/test/self/Makefile
>> index 9aa8aab78b..3d74bf9e98 100644
>> --- a/test/self/Makefile
>> +++ b/test/self/Makefile
>> @@ -20,6 +20,7 @@ obj-$(CONFIG_SELFTEST_REGULATOR) += regulator.o 
>> test_regulator.dtbo.o
>>  obj-$(CONFIG_SELFTEST_TEST_COMMAND) += test_command.o
>>  obj-$(CONFIG_SELFTEST_IDR) += idr.o
>>  obj-$(CONFIG_SELFTEST_TLV) += tlv.o tlv.dtb.o
>> +obj-$(CONFIG_SELFTEST_DM) += dm.o
>>  
>>  ifdef REGENERATE_KEYTOC
>>  
>> diff --git a/test/self/dm.c b/test/self/dm.c
>> new file mode 100644
>> index 0000000000..e2add03a48
>> --- /dev/null
>> +++ b/test/self/dm.c
>> @@ -0,0 +1,159 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +
>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>> +
>> +#include <common.h>
>> +#include <fcntl.h>
>> +#include <fs.h>
>> +#include <disks.h>
>> +#include <dirent.h>
>> +#include <libfile.h>
>> +#include <sys/stat.h>
>> +#include <unistd.h>
>> +#include <bselftest.h>
>> +#include <linux/sizes.h>
>> +#include <ramdisk.h>
>> +#include <dm.h>
>> +#include <driver.h>
>> +#include <block.h>
>> +
>> +BSELFTEST_GLOBALS();
>> +
>> +struct rdctx {
>> +    char mem[16][SECTOR_SIZE];
>> +    struct ramdisk *rd;
>> +    const char *name;
>> +};
>> +
>> +static struct rdctx rdctx[2];
>> +
>> +static int rd_create(void)
>> +{
>> +    struct block_device *blk;
>> +    struct rdctx *ctx;
>> +    char base;
>> +    int i, s;
>> +
>> +
>> +    for (i = 0, ctx = rdctx; i < 2; i++, ctx++) {
>> +            /* In case tests are run multiple times */
>> +            memset(ctx->mem, '\0', sizeof(ctx->mem));
>> +
>> +            /* Add an identifying mark ('a'-'p' and 'A'-'P') at
>> +             * the start and end of every sector in both disks, so
>> +             * that we have something to compare against when we
>> +             * read them back through the DM device.
>> +             */
>> +            base = i ? 'A' : 'a';
>> +            for (s = 0; s < 16; s++) {
>> +                    ctx->mem[s][0] = base + s;
>> +                    ctx->mem[s][SECTOR_SIZE - 1] = base + s;
>> +            }
>> +
>> +            ctx->rd = ramdisk_init(SECTOR_SIZE);
>> +            if (!ctx->rd) {
>> +                    failed_tests++;
>> +                    pr_err("Could not create ramdisk\n");
>> +                    return 1;
>> +            }
>> +
>> +            ramdisk_setup_rw(ctx->rd, ctx->mem, sizeof(ctx->mem));
>> +            blk = ramdisk_get_block_device(ctx->rd);
>> +            ctx->name = cdev_name(&blk->cdev);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static void rd_destroy(void)
>> +{
>> +    ramdisk_free(rdctx[0].rd);
>> +    ramdisk_free(rdctx[1].rd);
>> +}
>> +
>> +static void verify_read(const char *pattern, const char *buf)
>> +{
>> +    off_t first, last;
>> +    int s, len;
>> +
>> +    for (s = 0, len = strlen(pattern); s < len; s++) {
>> +            first = s << SECTOR_SHIFT;
>> +            last = first + SECTOR_SIZE - 1;
>> +
>> +            if (buf[first] != pattern[s]) {
>> +                    failed_tests++;
>> +                    pr_err("Expected '%c' at beginning of sector %d, read 
>> '%c'\n",
>> +                           pattern[s], s, buf[first]);
>> +                    return;
>> +            }
>> +
>> +            if (buf[last] != pattern[s]) {
>> +                    failed_tests++;
>> +                    pr_err("Expected '%c' at end of sector %d, read '%c'\n",
>> +                           pattern[s], s, buf[last]);
>> +                    return;
>> +            }
>> +    }
>> +}
>> +
>> +static void test_dm_linear(void)
>> +{
>> +    static const char pattern[] = "DEFaghijklmnopNOP";
>> +    const size_t dmsize = (sizeof(pattern) - 1) * SECTOR_SIZE;
>> +    struct dm_device *dm;
>> +    struct cdev *cdev;
>> +    char *buf, *table;
>> +
>> +    total_tests++;
>> +
>> +    if (!IS_ENABLED(CONFIG_DM_BLK_LINEAR)) {
>> +            pr_info("skipping dm-linear test: disabled in config\n");
>> +            skipped_tests++;
>> +            return;
>> +    }
>> +
>> +    if (rd_create())
>> +            return;
>> +
>> +    table = xasprintf(" 0  3 linear /dev/%s  3\n" /* "DEF" */
>> +                      " 3  1 linear /dev/%s  0\n" /* "a"   */
>> +                      " 4 10 linear /dev/%s  6\n" /* "ghijklmnop" */
>> +                      "14  3 linear /dev/%s 13\n" /* "NOP" */,
>> +                      rdctx[1].name,
>> +                      rdctx[0].name,
>> +                      rdctx[0].name,
>> +                      rdctx[1].name);
>> +
>> +    dm = dm_create("dmtest", table);
>> +    free(table);
>> +
>> +    if (IS_ERR_OR_NULL(dm)) {
>> +            failed_tests++;
>> +            pr_err("Could not create dm device\n");
>> +            goto out_destroy;
>> +    }
>> +
>> +    cdev = cdev_by_name("dmtest");
>> +    if (!cdev) {
>> +            failed_tests++;
>> +            pr_err("Could not find dm device\n");
>> +            goto out_destroy;
>> +    }
>> +
>> +    buf = xmalloc(dmsize);
>> +
>> +    if (cdev_read(cdev, buf, dmsize, 0, 0) < dmsize) {
>> +            failed_tests++;
>> +            pr_err("Could not read dm device\n");
>> +            goto out_free_buf;
>> +    }
>> +
>> +    verify_read(pattern, buf);
>> +
>> +out_free_buf:
>> +    free(buf);
>> +out_destroy:
>> +    dm_destroy(dm);
>> +    rd_destroy();
>> +}
>> +bselftest(core, test_dm_linear);
>
> -- 
> Pengutronix e.K.                  |                             |
> Steuerwalder Str. 21              | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany         | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |

Reply via email to