From 1ba6959299cb386faf178317b21ffd61689246b5 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 20 Dec 2007 17:34:55 +0200 Subject: ubi-utils: move UBI tests to tests/ubi-tests/ Clean-up ubi-utils a little by moving tests to a proper place. Signed-off-by: Artem Bityutskiy --- tests/ubi-tests/Makefile | 41 +++ tests/ubi-tests/README.udev | 25 ++ tests/ubi-tests/common.c | 336 ++++++++++++++++++ tests/ubi-tests/common.h | 103 ++++++ tests/ubi-tests/integ.c | 783 ++++++++++++++++++++++++++++++++++++++++++ tests/ubi-tests/io_basic.c | 182 ++++++++++ tests/ubi-tests/io_paral.c | 251 ++++++++++++++ tests/ubi-tests/io_read.c | 398 +++++++++++++++++++++ tests/ubi-tests/io_update.c | 370 ++++++++++++++++++++ tests/ubi-tests/mkvol_bad.c | 304 ++++++++++++++++ tests/ubi-tests/mkvol_basic.c | 253 ++++++++++++++ tests/ubi-tests/mkvol_paral.c | 112 ++++++ tests/ubi-tests/rmvol.c | 308 +++++++++++++++++ tests/ubi-tests/rsvol.c | 310 +++++++++++++++++ tests/ubi-tests/runtests.sh | 39 +++ ubi-utils/tests/Makefile | 41 --- ubi-utils/tests/README.udev | 25 -- ubi-utils/tests/common.c | 336 ------------------ ubi-utils/tests/common.h | 103 ------ ubi-utils/tests/integ.c | 783 ------------------------------------------ ubi-utils/tests/io_basic.c | 182 ---------- ubi-utils/tests/io_paral.c | 251 -------------- ubi-utils/tests/io_read.c | 398 --------------------- ubi-utils/tests/io_update.c | 370 -------------------- ubi-utils/tests/mkvol_bad.c | 304 ---------------- ubi-utils/tests/mkvol_basic.c | 253 -------------- ubi-utils/tests/mkvol_paral.c | 112 ------ ubi-utils/tests/rmvol.c | 308 ----------------- ubi-utils/tests/rsvol.c | 310 ----------------- ubi-utils/tests/runtests.sh | 39 --- 30 files changed, 3815 insertions(+), 3815 deletions(-) create mode 100644 tests/ubi-tests/Makefile create mode 100644 tests/ubi-tests/README.udev create mode 100644 tests/ubi-tests/common.c create mode 100644 tests/ubi-tests/common.h create mode 100644 tests/ubi-tests/integ.c create mode 100644 tests/ubi-tests/io_basic.c create mode 100644 tests/ubi-tests/io_paral.c create mode 100644 tests/ubi-tests/io_read.c create mode 100644 tests/ubi-tests/io_update.c create mode 100644 tests/ubi-tests/mkvol_bad.c create mode 100644 tests/ubi-tests/mkvol_basic.c create mode 100644 tests/ubi-tests/mkvol_paral.c create mode 100644 tests/ubi-tests/rmvol.c create mode 100644 tests/ubi-tests/rsvol.c create mode 100755 tests/ubi-tests/runtests.sh delete mode 100644 ubi-utils/tests/Makefile delete mode 100644 ubi-utils/tests/README.udev delete mode 100644 ubi-utils/tests/common.c delete mode 100644 ubi-utils/tests/common.h delete mode 100644 ubi-utils/tests/integ.c delete mode 100644 ubi-utils/tests/io_basic.c delete mode 100644 ubi-utils/tests/io_paral.c delete mode 100644 ubi-utils/tests/io_read.c delete mode 100644 ubi-utils/tests/io_update.c delete mode 100644 ubi-utils/tests/mkvol_bad.c delete mode 100644 ubi-utils/tests/mkvol_basic.c delete mode 100644 ubi-utils/tests/mkvol_paral.c delete mode 100644 ubi-utils/tests/rmvol.c delete mode 100644 ubi-utils/tests/rsvol.c delete mode 100755 ubi-utils/tests/runtests.sh diff --git a/tests/ubi-tests/Makefile b/tests/ubi-tests/Makefile new file mode 100644 index 0000000..a2a49d0 --- /dev/null +++ b/tests/ubi-tests/Makefile @@ -0,0 +1,41 @@ +UBIUTILS=../../ubi-utils +INCLUDE1=$(UBIUTILS)/inc +INCLUDE2=../../include +LIB=. + +CC := $(CROSS)gcc + +ALL_FILES=libubi io_update rmvol integ +ALL_FILES+=io_paral io_read io_basic mkvol_basic mkvol_bad mkvol_paral rsvol + +CFLAGS += -Wall -I$(INCLUDE1) -I$(INCLUDE2) -L$(LIB) -ggdb + +all: $(ALL_FILES) + +libubi: $(UBIUTILS)/src/libubi.c $(UBIUTILS)/inc/libubi.h $(UBIUTILS)/src/libubi_int.h + $(CC) $(CFLAGS) -DUDEV_SETTLE_HACK -c $(UBIUTILS)/src/libubi.c -o libubi.o + ar cr libubi.a libubi.o + +io_paral: io_paral.c common.c + $(CC) $(CFLAGS) $^ -lubi -lpthread -o $@ +io_update: io_update.c common.c + $(CC) $(CFLAGS) $^ -lubi -o $@ +io_read: io_read.c common.c + $(CC) $(CFLAGS) $^ -lubi -o $@ +io_basic: io_basic.c common.c + $(CC) $(CFLAGS) $^ -lubi -o $@ +mkvol_basic: mkvol_basic.c common.c + $(CC) $(CFLAGS) $^ -lubi -o $@ +mkvol_bad: mkvol_bad.c common.c + $(CC) $(CFLAGS) $^ -lubi -o $@ +mkvol_paral: mkvol_paral.c common.c + $(CC) $(CFLAGS) $^ -lubi -lpthread -o $@ +rsvol: rsvol.c common.c + $(CC) $(CFLAGS) $^ -lubi -o $@ +rmvol: rmvol.c common.c + $(CC) $(CFLAGS) $^ -lubi -o $@ +integ: integ.c + $(CC) $(CFLAGS) $^ -lubi -o $@ + +clean: + rm -rf $(ALL_FILES) $(addsuffix .o, $(ALL_FILES)) diff --git a/tests/ubi-tests/README.udev b/tests/ubi-tests/README.udev new file mode 100644 index 0000000..06e71d3 --- /dev/null +++ b/tests/ubi-tests/README.udev @@ -0,0 +1,25 @@ +There is a problem with udev: when a volume is created, there is a delay +before corresponding /dev/ubiX_Y device node is created by udev, so some +tests fail because of this. The symptom is error messages like +"cannot open /dev/ubi0_0". + +One possible solution of this problem is to pre-create UBI device and volume +nodes. There is even a script which may be used for this in ubi-utils/scripts/. +But this is not enough because udev will still remove and re-create the nodes +and tests will still fail. So you need to stop removing device nodes using +the following udev rule: + + KERNEL=="ubi*_*", ACTION=="remove", OPTIONS+="ignore_device" + +In our Ubuntu distribution we put that to new file: +/etc/udev/rules.d/50-local.rules + +Another possibility is to call udevsettle utility in libubi after the volume +has been created See src/libubi.c - the call is compiled in only if +UDEV_SETTLE_HACK is defined. This is anyway an ugly hack, but works, although +makes the tests slower. Suggestions are welcome. + +So, if you have udevsettel unility in your system, you do not have to do +anyting, and the tests should work, because we compile libubi with +UDEV_SETTLE_HACK. Otherwise, you should remove -D UDEV_SETTLE_HACK +from the makefile and pre-create UBI device nodes. diff --git a/tests/ubi-tests/common.c b/tests/ubi-tests/common.c new file mode 100644 index 0000000..cb63e77 --- /dev/null +++ b/tests/ubi-tests/common.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem B. Bityutskiy + * + * The stuff which is common for many tests. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libubi.h" +#include "common.h" + +/** + * __initial_check - check that common prerequisites which are required to run + * tests. + * + * @test test name + * @argc count of command-line arguments + * @argv command-line arguments + * + * This function returns %0 if all is fine and test may be run and %-1 if not. + */ +int __initial_check(const char *test, int argc, char * const argv[]) +{ + libubi_t libubi; + struct ubi_dev_info dev_info; + + /* + * All tests require UBI character device name as the first parameter, + * check this. + */ + if (argc < 2) { + __err_msg(test, __FUNCTION__, __LINE__, + "UBI character device node is not specified"); + return -1; + } + + libubi = libubi_open(); + if (libubi == NULL) { + __failed(test, __FUNCTION__, __LINE__, "libubi_open"); + return -1; + } + + if (ubi_get_dev_info(libubi, argv[1], &dev_info)) { + __failed(test, __FUNCTION__, __LINE__, "ubi_get_dev_info"); + goto close; + } + + if (dev_info.avail_ebs < MIN_AVAIL_EBS) { + __err_msg(test, __FUNCTION__, __LINE__, + "insufficient available eraseblocks %d on UBI " + "device, required %d", + dev_info.avail_ebs, MIN_AVAIL_EBS); + goto close; + } + + if (dev_info.vol_count != 0) { + __err_msg(test, __FUNCTION__, __LINE__, + "device %s is not empty", argv[1]); + goto close; + } + + libubi_close(libubi); + return 0; + +close: + libubi_close(libubi); + return -1; +} + +/** + * __err_msg - print a message to stderr. + * + * @test test name + * @func function name + * @line line number + * @fmt format string + */ +void __err_msg(const char *test, const char *func, int line, + const char *fmt, ...) +{ + va_list args; + + fprintf(stderr, "[%s] %s():%d: ", test, func, line); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); +} + +/** + * __failed - print function fail message. + * + * @test test name + * @func calling function name + * @line line number + * @failed failed function name + */ +void __failed(const char *test, const char *func, int line, + const char *failed) +{ + fprintf(stderr, "[%s] %s():%d: function %s() failed with error %d (%s)\n", + test, func, line, failed, errno, strerror(errno)); +} + +/** + * __check_volume - check volume information. + * + * @libubi libubi descriptor + * @dev_info UBI device description + * @test test name + * @func function name + * @line line number + * @vol_id ID of existing volume to check + * @req volume creation request to compare with + * + * This function checks if a volume created using @req request has exactly the + * requested characteristics. Returns 0 in case of success and %-1 in case of + * error. + */ +int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info, + const char *test, const char *func, int line, int vol_id, + const struct ubi_mkvol_request *req) +{ + int ret; + struct ubi_vol_info vol_info; + int eb_size; + long long rsvd_bytes; + + ret = ubi_get_vol_info1(libubi, dev_info->dev_num, vol_id, &vol_info); + if (ret) { + __failed(test, func, line, "ubi_get_vol_info"); + return -1; + } + + if (req->alignment != vol_info.alignment) { + __err_msg(test, func, line, + "bad alignment: requested %d, got %d", + req->alignment, vol_info.alignment); + return -1; + } + if (req->vol_type != vol_info.type) { + __err_msg(test, func, line, "bad type: requested %d, got %d", + req->vol_type, vol_info.type); + return -1; + } + if (strlen(req->name) != strlen(&vol_info.name[0]) || + strcmp(req->name, &vol_info.name[0]) != 0) { + __err_msg(test, func, line, + "bad name: requested \"%s\", got \"%s\"", + req->name, &vol_info.name[0]); + return -1; + } + if (vol_info.corrupted) { + __err_msg(test, func, line, "corrupted new volume"); + return -1; + } + + eb_size = dev_info->eb_size - (dev_info->eb_size % req->alignment); + if (eb_size != vol_info.eb_size) { + __err_msg(test, func, line, + "bad usable LEB size %d, should be %d", + vol_info.eb_size, eb_size); + return -1; + } + + rsvd_bytes = req->bytes; + if (rsvd_bytes % eb_size) + rsvd_bytes += eb_size - (rsvd_bytes % eb_size); + + if (rsvd_bytes != vol_info.rsvd_bytes) { + __err_msg(test, func, line, + "bad reserved bytes %lld, should be %lld", + vol_info.rsvd_bytes, rsvd_bytes); + return -1; + } + + return 0; +} + +/** + * __check_vol_patt - check that volume contains certain data + * + * @libubi libubi descriptor + * @dev_info UBI device description + * @test test name + * @func function name + * @line line number + * @node volume character device node + * @byte data pattern to check + * + * This function returns %0 if the volume contains only @byte bytes, and %-1 if + * not. + */ +int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info, + const char *test, const char *func, int line, + const char *node, uint8_t byte) +{ + int ret, fd; + long long bytes = 0; + struct ubi_vol_info vol_info; + unsigned char buf[512]; + + fd = open(node, O_RDONLY); + if (fd == -1) { + __failed(test, func, line, "open"); + __err_msg(test, func, line, "cannot open \"%s\"\n", node); + return -1; + } + + ret = ubi_get_vol_info(libubi, node, &vol_info); + if (ret) { + __failed(test, func, line, "ubi_get_vol_info"); + goto close; + } + + while (bytes < vol_info.data_bytes) { + int i; + + memset(&buf[0], ~byte, 512); + ret = read(fd, &buf[0], 512); + if (ret == -1) { + __failed(test, func, line, "read"); + __err_msg(test, func, line, "bytes = %lld, ret = %d", + bytes, ret); + goto close; + } + + if (ret == 0 && bytes + ret < vol_info.data_bytes) { + __err_msg(test, func, line, + "EOF, but read only %lld bytes of %lld", + bytes + ret, vol_info.data_bytes); + goto close; + } + + for (i = 0; i < ret; i++) + if (buf[i] != byte) { + __err_msg(test, func, line, + "byte at %lld is not %#x but %#x", + bytes + i, byte, (int)buf[i]); + goto close; + } + + bytes += ret; + } + + close(fd); + return 0; + +close: + close(fd); + return -1; +} + +/** + * __update_vol_patt - update volume using a certain byte pattern + * + * @libubi libubi descriptor + * @dev_info UBI device description + * @test test name + * @func function name + * @line line number + * @node volume character device node + * @byte data pattern to check + * + * This function returns %0 in case of success, and %-1 if in case of failure. + */ +int __update_vol_patt(libubi_t libubi, const char *test, const char *func, + int line, const char *node, long long bytes, uint8_t byte) +{ + int ret, fd; + long long written = 0; + unsigned char buf[512]; + + fd = open(node, O_RDWR); + if (fd == -1) { + __failed(test, func, line, "open"); + __err_msg(test, func, line, "cannot open \"%s\"\n", node); + return -1; + } + + if (ubi_update_start(libubi, fd, bytes)) { + __failed(test, func, line, "ubi_update_start"); + __err_msg(test, func, line, "bytes = %lld", bytes); + goto close; + } + + memset(&buf[0], byte, 512); + + while (written != bytes) { + ret = write(fd, &buf[0], 512); + if (ret == -1) { + __failed(test, func, line, "write"); + __err_msg(test, func, line, "written = %lld, ret = %d", + written, ret); + goto close; + } + written += ret; + + if (written > bytes) { + __err_msg(test, func, line, "update length %lld bytes, " + "but %lld bytes are already written", + bytes, written); + goto close; + } + } + + close(fd); + return 0; + +close: + close(fd); + return -1; +} diff --git a/tests/ubi-tests/common.h b/tests/ubi-tests/common.h new file mode 100644 index 0000000..3e8ada8 --- /dev/null +++ b/tests/ubi-tests/common.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem B. Bityutskiy + * + * The stuff which is common for many tests. + */ + +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UBI_VOLUME_PATTERN "/dev/ubi%d_%d" +#define MIN_AVAIL_EBS 5 +#define PAGE_SIZE 4096 + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#define err_msg(fmt, ...) \ + __err_msg(TESTNAME, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) + +#define failed(name) \ + __failed(TESTNAME, __FUNCTION__, __LINE__, name) + +#define initial_check(argc, argv) \ + __initial_check(TESTNAME, argc, argv) + +#define check_volume(vol_id, req) \ + __check_volume(libubi, &dev_info, TESTNAME, __FUNCTION__, \ + __LINE__, vol_id, req) + +#define check_vol_patt(node, byte) \ + __check_vol_patt(libubi, &dev_info, TESTNAME, __FUNCTION__, __LINE__, \ + node, byte) + +#define update_vol_patt(node, bytes, byte) \ + __update_vol_patt(libubi, TESTNAME, __FUNCTION__, __LINE__, \ + node, bytes, byte) + +#define check_failed(ret, error, func, fmt, ...) ({ \ + int __ret; \ + \ + if (!ret) { \ + err_msg("%s() returned success but should have failed", func); \ + err_msg(fmt, ##__VA_ARGS__); \ + __ret = -1; \ + } \ + if (errno != (error)) { \ + err_msg("%s failed with error %d (%s), expected %d (%s)", \ + func, errno, strerror(errno), error, strerror(error)); \ + err_msg(fmt, ##__VA_ARGS__); \ + __ret = -1; \ + } \ + __ret = 0; \ +}) + +/* Alignments to test, @s is eraseblock size */ +#define ALIGNMENTS(s) \ + {3, 5, 27, 666, 512, 1024, 2048, (s)/2-3, (s)/2-2, (s)/2-1, (s)/2+1, \ + (s)/2+2, (s)/2+3, (s)/3-3, (s)/3-2, (s)/3-1, (s)/3+1, (s)/3+2, \ + (s)/3+3, (s)/4-3, (s)/4-2, (s)/4-1, (s)/4+1, (s)/4+2, (s)/4+3, \ + (s)/5-3, (s)/5-2, (s)/5-1, (s)/5+1, (s)/5+2, (s)/5+3, (s)-17, (s)-9, \ + (s)-8, (s)-6, (s)-4, (s)-1, (s)}; + +extern void __err_msg(const char *test, const char *func, int line, + const char *fmt, ...); +void __failed(const char *test, const char *func, int line, + const char *failed); +int __initial_check(const char *test, int argc, char * const argv[]); +int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info, + const char *test, const char *func, int line, int vol_id, + const struct ubi_mkvol_request *req); +int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info, + const char *test, const char *func, int line, + const char *node, uint8_t byte); +int __update_vol_patt(libubi_t libubi, const char *test, const char *func, + int line, const char *node, long long bytes, + uint8_t byte); + +#ifdef __cplusplus +} +#endif + +#endif /* !__COMMON_H__ */ diff --git a/tests/ubi-tests/integ.c b/tests/ubi-tests/integ.c new file mode 100644 index 0000000..4da7121 --- /dev/null +++ b/tests/ubi-tests/integ.c @@ -0,0 +1,783 @@ +#define _LARGEFILE64_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "libubi.h" + +struct erase_block_info; +struct volume_info; +struct ubi_device_info; + +struct write_info +{ + struct write_info *next; + struct erase_block_info *erase_block; + int offset_within_block; /* Offset within erase block */ + off64_t offset; /* Offset within volume */ + int size; + int random_seed; +}; + +struct erase_block_info +{ + struct volume_info *volume; + int block_number; + off64_t offset; /* Offset within volume */ + off64_t top_of_data; + int touched; /* Have we done anything at all with this erase block */ + int erased; /* This erased block is currently erased */ + struct write_info *writes; +}; + +struct volume_fd +{ + struct volume_fd *next; + struct volume_info *volume; + int fd; +}; + +struct volume_info +{ + struct volume_info *next; + struct ubi_device_info *ubi_device; + struct volume_fd *fds; + struct erase_block_info *erase_blocks; + const char *device_file_name; + struct ubi_vol_info info; +}; + +struct ubi_device_info +{ + struct volume_info *volumes; + const char *device_file_name; + struct ubi_dev_info info; +}; + +struct open_volume_fd +{ + struct open_volume_fd *next; + struct volume_fd *vol_fd; +}; + +#define MAX_UBI_DEVICES 64 + +static libubi_t libubi; + +static struct ubi_info info; +static struct ubi_device_info ubi_array[MAX_UBI_DEVICES]; + +static uint64_t total_written = 0; +static uint64_t total_space = 0; + +static struct open_volume_fd *open_volumes; +static size_t open_volume_count = 0; + +static const char *ubi_module_load_string; + +static unsigned char *write_buffer = NULL; +static unsigned char *read_buffer = NULL; + +static long long max_ebs_per_vol = 0; /* max number of ebs per vol (zero => no max) */ + +static unsigned long next_seed = 1; + +static unsigned get_next_seed() +{ + next_seed = next_seed * 1103515245 + 12345; + return ((unsigned) (next_seed / 65536) % 32768); +} + +static void error_exit(const char *msg) +{ + int eno = errno; + fprintf(stderr,"UBI Integrity Test Error: %s\n",msg); + if (eno) { + fprintf(stderr, "errno = %d\n", eno); + fprintf(stderr, "strerror = %s\n", strerror(eno)); + } + exit(1); +} + +static void *allocate(size_t n) +{ + void *p = malloc(n); + if (!p) + error_exit("Memory allocation failure"); + memset(p, 0, n); + return p; +} + +static unsigned get_random_number(unsigned n) +{ + uint64_t r, b; + + if (n < 1) + return 0; + r = rand(); + r *= n; + b = RAND_MAX; + b += 1; + r /= b; + return r; +} + +static struct volume_fd *open_volume(struct volume_info *vol) +{ + struct volume_fd *s; + struct open_volume_fd *ofd; + int fd; + + if (vol->fds) { + /* If already open dup it */ + fd = dup(vol->fds->fd); + if (fd == -1) + error_exit("Failed to dup volume device file des"); + } else { + fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE); + if (fd == -1) + error_exit("Failed to open volume device file"); + } + s = allocate(sizeof(*s)); + s->fd = fd; + s->volume = vol; + s->next = vol->fds; + vol->fds = s; + /* Add to open volumes list */ + ofd = allocate(sizeof(*ofd)); + ofd->vol_fd = s; + ofd->next = open_volumes; + open_volumes = ofd; + open_volume_count += 1; + return 0; +} + +static void close_volume(struct volume_fd *vol_fd) +{ + struct volume_fd *vfd, *vfd_last; + struct open_volume_fd *ofd, *ofd_last; + int fd = vol_fd->fd; + + /* Remove from open volumes list */ + ofd_last = NULL; + ofd = open_volumes; + while (ofd) { + if (ofd->vol_fd == vol_fd) { + if (ofd_last) + ofd_last->next = ofd->next; + else + open_volumes = ofd->next; + free(ofd); + open_volume_count -= 1; + break; + } + ofd_last = ofd; + ofd = ofd->next; + } + /* Remove from volume fd list */ + vfd_last = NULL; + vfd = vol_fd->volume->fds; + while (vfd) { + if (vfd == vol_fd) { + if (vfd_last) + vfd_last->next = vfd->next; + else + vol_fd->volume->fds = vfd->next; + free(vfd); + break; + } + vfd_last = vfd; + vfd = vfd->next; + } + /* Close volume device file */ + if (close(fd) == -1) + error_exit("Failed to close volume file descriptor"); +} + +static void set_random_data(unsigned seed, unsigned char *buf, int size) +{ + int i; + unsigned r; + + r = rand(); + srand(seed); + for (i = 0; i < size; ++i) + buf[i] = rand(); + srand(r); +} + +#if 0 +static void print_write_info(struct write_info *w) +{ + printf("Offset: %lld Size:%d Seed:%u\n", w->offset, w->size, w->random_seed); + fflush(stdout); +} +#endif + +static void check_erase_block(struct erase_block_info *erase_block, int fd) +{ + struct write_info *w; + off64_t gap_end; + int eb_size = erase_block->volume->info.eb_size; + ssize_t bytes_read; + + w = erase_block->writes; + gap_end = erase_block->offset + eb_size; + while (w) { + if (w->offset + w->size < gap_end) { + /* There is a gap. Check all 0xff */ + off64_t gap_start = w->offset + w->size; + size_t size = gap_end - gap_start; + if (lseek64(fd, gap_start, SEEK_SET) != gap_start) + error_exit("lseek64 failed"); + memset(read_buffer, 0 , size); + errno = 0; + bytes_read = read(fd, read_buffer, size); + if (bytes_read != size) + error_exit("read failed in gap"); + while (size) + if (read_buffer[--size] != 0xff) { + fprintf(stderr, "block no. = %d\n" , erase_block->block_number); + fprintf(stderr, "offset = %lld\n" , (long long) gap_start); + fprintf(stderr, "size = %ld\n" , (long) bytes_read); + error_exit("verify 0xff failed"); + } + } + if (lseek64(fd, w->offset, SEEK_SET) != w->offset) + error_exit("lseek64 failed"); + memset(read_buffer, 0 , w->size); + errno = 0; + bytes_read = read(fd, read_buffer, w->size); + if (bytes_read != w->size) { + fprintf(stderr, "offset = %lld\n" , (long long) w->offset); + fprintf(stderr, "size = %ld\n" , (long) w->size); + fprintf(stderr, "bytes_read = %ld\n" , (long) bytes_read); + error_exit("read failed"); + } + set_random_data(w->random_seed, write_buffer, w->size); + if (memcmp(read_buffer, write_buffer, w->size)) + error_exit("verify failed"); + gap_end = w->offset; + w = w->next; + } + if (gap_end > erase_block->offset) { + /* Check all 0xff */ + off64_t gap_start = erase_block->offset; + size_t size = gap_end - gap_start; + if (lseek64(fd, gap_start, SEEK_SET) != gap_start) + error_exit("lseek64 failed"); + memset(read_buffer, 0 , size); + errno = 0; + bytes_read = read(fd, read_buffer, size); + if (bytes_read != size) + error_exit("read failed in gap"); + while (size) + if (read_buffer[--size] != 0xff) { + fprintf(stderr, "block no. = %d\n" , erase_block->block_number); + fprintf(stderr, "offset = %lld\n" , (long long) gap_start); + fprintf(stderr, "size = %ld\n" , (long) bytes_read); + error_exit("verify 0xff failed!"); + } + } +} + +static int write_to_erase_block(struct erase_block_info *erase_block, int fd) +{ + int page_size = erase_block->volume->ubi_device->info.min_io_size; + int eb_size = erase_block->volume->info.eb_size; + int next_offset = 0; + int space, size; + off64_t offset; + unsigned seed; + struct write_info *w; + + if (erase_block->writes) + next_offset = erase_block->writes->offset_within_block + erase_block->writes->size; + space = eb_size - next_offset; + if (space <= 0) + return 0; /* No space */ + if (!get_random_number(10)) { + /* 1 time in 10 leave a gap */ + next_offset += get_random_number(space); + next_offset = (next_offset / page_size) * page_size; + space = eb_size - next_offset; + } + if (get_random_number(2)) + size = 1 * page_size; + else if (get_random_number(2)) + size = 2 * page_size; + else if (get_random_number(2)) + size = 3 * page_size; + else if (get_random_number(2)) + size = 4 * page_size; + else { + if (get_random_number(4)) + size = get_random_number(space); + else + size = space; + size = (size / page_size) * page_size; + } + if (size == 0 || size > space) + size = page_size; + if (next_offset + size > eb_size) + error_exit("internal error"); + offset = erase_block->offset + next_offset; + if (offset < erase_block->top_of_data) + error_exit("internal error!"); + if (lseek64(fd, offset, SEEK_SET) != offset) + error_exit("lseek64 failed"); + /* Do write */ + seed = get_next_seed(); + if (!seed) + seed = 1; + set_random_data(seed, write_buffer, size); + if (write(fd, write_buffer, size) != size) + error_exit("write failed"); + erase_block->top_of_data = offset + size; + /* Make write info and add to eb */ + w = allocate(sizeof(*w)); + w->offset_within_block = next_offset; + w->offset = offset; + w->size = size; + w->random_seed = seed; + w->next = erase_block->writes; + erase_block->writes = w; + erase_block->touched = 1; + erase_block->erased = 0; + total_written += size; + return 1; +} + +static void erase_erase_block(struct erase_block_info *erase_block, int fd) +{ + struct write_info *w; + uint32_t eb_no; + int res; + + eb_no = erase_block->block_number; + res = ioctl(fd, UBI_IOCEBER, &eb_no); + if (res) + error_exit("Failed to erase an erase block"); + /* Remove writes from this eb */ + while (erase_block->writes) { + w = erase_block->writes; + erase_block->writes = erase_block->writes->next; + free(w); + } + erase_block->erased = 1; + erase_block->touched = 1; + erase_block->top_of_data = erase_block->offset; +} + +static void operate_on_erase_block(struct erase_block_info *erase_block, int fd) +{ + /* + Possible operations: + read from it and verify + write to it + erase it + */ + int work_done = 1; + static int no_work_done_count = 0; + + if (!get_random_number(10) && no_work_done_count <= 5) { + check_erase_block(erase_block, fd); + work_done = 0; + } else if (get_random_number(100)) { + if (!write_to_erase_block(erase_block, fd)) { + /* The erase block was full */ + if (get_random_number(2) || no_work_done_count > 5) + erase_erase_block(erase_block, fd); + else + work_done = 0; + } + } else + erase_erase_block(erase_block, fd); + if (work_done) + no_work_done_count = 0; + else + no_work_done_count += 1; +} + +static void operate_on_open_volume(struct volume_fd *vol_fd) +{ + /* + Possible operations: + operate on an erase block + close volume + */ + if (get_random_number(100) == 0) + close_volume(vol_fd); + else { + /* Pick an erase block at random */ + int eb_no = get_random_number(vol_fd->volume->info.rsvd_ebs); + operate_on_erase_block(&vol_fd->volume->erase_blocks[eb_no], vol_fd->fd); + } +} + +static void operate_on_volume(struct volume_info *vol) +{ + /* + Possible operations: + open it + resize it (must close fd's first) <- TODO + delete it (must close fd's first) <- TODO + */ + open_volume(vol); +} + +static int ubi_major(const char *device_file_name) +{ + struct stat buf; + static int maj = 0; + + if (maj) + return maj; + if (stat(device_file_name, &buf) == -1) + error_exit("Failed to stat ubi device file"); + maj = major(buf.st_rdev); + return maj; +} + +static void operate_on_ubi_device(struct ubi_device_info *ubi_device) +{ + /* + TODO: + Possible operations: + create a new volume + operate on existing volume + */ + /* + Simplified operation (i.e. only have 1 volume): + If there are no volumes create 1 volumne + Then operate on the volume + */ + if (ubi_device->info.vol_count == 0) { + /* Create the one-and-only volume we will use */ + char dev_name[1024]; + int i, n, maj, fd; + struct volume_info *s; + struct ubi_mkvol_request req; + + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; /* TODO: What is this? */ + req.bytes = ubi_device->info.eb_size * max_ebs_per_vol; + if (req.bytes == 0 || req.bytes > ubi_device->info.avail_bytes) + req.bytes = ubi_device->info.avail_bytes; + req.vol_type = UBI_DYNAMIC_VOLUME; + req.name = "integ-test-vol"; + if (ubi_mkvol(libubi, ubi_device->device_file_name, &req)) + error_exit("ubi_mkvol failed"); + s = allocate(sizeof(*s)); + s->ubi_device = ubi_device; + if (ubi_get_vol_info1(libubi, ubi_device->info.dev_num, req.vol_id, &s->info)) + error_exit("ubi_get_vol_info failed"); + n = s->info.rsvd_ebs; + s->erase_blocks = allocate(sizeof(struct erase_block_info) * n); + for (i = 0; i < n; ++i) { + s->erase_blocks[i].volume = s; + s->erase_blocks[i].block_number = i; + s->erase_blocks[i].offset = i * (off64_t) s->info.eb_size; + s->erase_blocks[i].top_of_data = s->erase_blocks[i].offset; + } + /* FIXME: Correctly get device file name */ + sprintf(dev_name, "%s_%d", ubi_device->device_file_name, req.vol_id); + s->device_file_name = strdup(dev_name); + ubi_device->volumes = s; + ubi_device->info.vol_count += 1; + sleep(1); + fd = open(s->device_file_name, O_RDONLY); + if (fd == -1) { + /* FIXME: Correctly make node */ + maj = ubi_major(ubi_device->device_file_name); + sprintf(dev_name, "mknod %s c %d %d", s->device_file_name, maj, req.vol_id + 1); + system(dev_name); + } else if (close(fd) == -1) + error_exit("Failed to close volume device file"); + } + operate_on_volume(ubi_device->volumes); +} + +static void do_an_operation(void) +{ + int too_few = (open_volume_count < info.dev_count * 3); + int too_many = (open_volume_count > info.dev_count * 5); + + if (too_many || (!too_few && get_random_number(1000) > 0)) { + /* Operate on an open volume */ + size_t pos; + struct open_volume_fd *ofd; + pos = get_random_number(open_volume_count); + for (ofd = open_volumes; pos && ofd && ofd->next; --pos) + ofd = ofd->next; + operate_on_open_volume(ofd->vol_fd); + } else if (info.dev_count > 0) { + /* Operate on a ubi device */ + size_t ubi_pos = 0; + if (info.dev_count > 1) + ubi_pos = get_random_number(info.dev_count - 1); + operate_on_ubi_device(&ubi_array[ubi_pos]); + } else + error_exit("Internal error"); +} + +static void get_ubi_devices_info(void) +{ + int i, ubi_pos = 0; + char dev_name[1024]; + size_t buf_size = 1024 * 128; + + if (ubi_get_info(libubi, &info)) + error_exit("ubi_get_info failed"); + if (info.dev_count > MAX_UBI_DEVICES) + error_exit("Too many ubi devices"); + for (i = info.lowest_dev_num; i <= info.highest_dev_num; ++i) { + struct ubi_device_info *s; + s = &ubi_array[ubi_pos++]; + if (ubi_get_dev_info1(libubi, i, &s->info)) + error_exit("ubi_get_dev_info1 failed"); + if (s->info.vol_count) + error_exit("There are existing volumes"); + /* FIXME: Correctly get device file name */ + sprintf(dev_name, "/dev/ubi%d", i); + s->device_file_name = strdup(dev_name); + if (buf_size < s->info.eb_size) + buf_size = s->info.eb_size; + if (max_ebs_per_vol && s->info.eb_size * max_ebs_per_vol < s->info.avail_bytes) + total_space += s->info.eb_size * max_ebs_per_vol; + else + total_space += s->info.avail_bytes; + } + write_buffer = allocate(buf_size); + read_buffer = allocate(buf_size); +} + +static void load_ubi(void) +{ + system("rmmod ubi"); + if (system(ubi_module_load_string) != 0) + error_exit("Failed to load UBI module"); + sleep(1); +} + +static void do_some_operations(void) +{ + unsigned i = 0; + total_written = 0; + printf("Total space: %llu\n", (unsigned long long) total_space); + while (total_written < total_space * 3) { + do_an_operation(); + if (i++ % 10000 == 0) + printf("Total written: %llu\n", (unsigned long long) total_written); + } + printf("Total written: %llu\n", (unsigned long long) total_written); +} + +static void reload_ubi(void) +{ + /* Remove module */ + if (system("rmmod ubi") != 0) + error_exit("Failed to remove UBI module"); + /* Install module */ + if (system(ubi_module_load_string) != 0) + error_exit("Failed to load UBI module"); + sleep(1); +} + +static void check_volume(struct volume_info *vol) +{ + struct erase_block_info *eb = vol->erase_blocks; + int pos; + int fd; + + fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE); + if (fd == -1) + error_exit("Failed to open volume device file"); + for (pos = 0; pos < vol->info.rsvd_ebs; ++pos) + check_erase_block(eb++, fd); + if (close(fd) == -1) + error_exit("Failed to close volume device file"); +} + +static void check_ubi_device(struct ubi_device_info *ubi_device) +{ + struct volume_info *vol; + + vol = ubi_device->volumes; + while (vol) { + check_volume(vol); + vol = vol->next; + } +} + +static void check_ubi(void) +{ + int i; + + for (i = 0; i < info.dev_count; ++i) + check_ubi_device(&ubi_array[i]); +} + +static int is_all_digits(const char *s) +{ + const char *digits = "0123456789"; + if (!s || !*s) + return 0; + for (;*s;++s) + if (!strchr(digits,*s)) + return 0; + return 1; +} + +static int get_short_arg(int *pos,const char *name,long long *result,int argc,char *argv[]) +{ + const char *p = NULL; + int i = *pos; + size_t n = strlen(name); + + if (strlen(argv[i]) > n) + p = argv[i] + n; + else if (++i < argc) + p = argv[i]; + if (!is_all_digits(p)) + return 1; + *result = atoll(p); + *pos = i; + return 0; +} + +static int get_long_arg(int *pos,const char *name,long long *result,int argc,char *argv[]) +{ + const char *p = NULL; + int i = *pos; + size_t n = strlen(name); + + if (strlen(argv[i]) > n) + p = argv[i] + n; + else if (++i < argc) + p = argv[i]; + if (p && *p == '=') { + p += 1; + if (!*p && ++i < argc) + p = argv[i]; + } + if (!is_all_digits(p)) + return 1; + *result = atoll(p); + *pos = i; + return 0; +} + +static int remove_all_volumes(void) +{ + int i; + + for (i = 0; i < info.dev_count; ++i) { + struct ubi_device_info *ubi_device = &ubi_array[i]; + struct volume_info *vol; + vol = ubi_device->volumes; + while (vol) { + int res = ubi_rmvol(libubi, + ubi_device->device_file_name, + vol->info.vol_id); + if (res) + return res; + vol = vol->next; + } + } + return 0; +} + +int main(int argc,char *argv[]) +{ + int i; + long long r, repeat = 1; + int initial_seed = 1, args_ok = 1; + + printf("UBI Integrity Test\n"); + + /* Get arguments */ + ubi_module_load_string = 0; + for (i = 1; i < argc; ++i) { + if (strncmp(argv[i], "-h", 2) == 0) + args_ok = 0; + else if (strncmp(argv[i], "--help", 6) == 0) + args_ok = 0; + else if (strncmp(argv[i], "-n", 2) == 0) { + if (get_short_arg(&i, "-n", &repeat, argc, argv)) + args_ok = 0; + } else if (strncmp(argv[i], "--repeat", 8) == 0) { + if (get_long_arg(&i, "--repeat", &repeat, argc, argv)) + args_ok = 0; + } else if (strncmp(argv[i], "-m", 2) == 0) { + if (get_short_arg(&i,"-m", &max_ebs_per_vol, argc, argv)) + args_ok = 0; + } else if (strncmp(argv[i], "--maxebs", 8) == 0) { + if (get_long_arg(&i, "--maxebs", &max_ebs_per_vol, argc, argv)) + args_ok = 0; + } else if (!ubi_module_load_string) + ubi_module_load_string = argv[i]; + else + args_ok = 0; + } + if (!args_ok || !ubi_module_load_string) { + fprintf(stderr, "Usage is: ubi_integ [] \n"); + fprintf(stderr, " Options: \n"); + fprintf(stderr, " -h, --help Help\n"); + fprintf(stderr, " -n arg, --repeat=arg Repeat test arg times\n"); + fprintf(stderr, " -m arg, --maxebs=arg Max no. of erase blocks\n"); + return 1; + } + + initial_seed = getpid(); + printf("Initial seed = %u\n", (unsigned) initial_seed); + next_seed = initial_seed; + srand(initial_seed); + load_ubi(); + + libubi = libubi_open(); + if (!libubi) + error_exit("Failed to open libubi"); + + get_ubi_devices_info(); + + r = 0; + while (repeat == 0 || r++ < repeat) { + printf("Cycle %lld\n", r); + do_some_operations(); + + /* Close all volumes */ + while (open_volumes) + close_volume(open_volumes->vol_fd); + + check_ubi(); + + libubi_close(libubi); + + reload_ubi(); + + libubi = libubi_open(); + if (!libubi) + error_exit("Failed to open libubi"); + + check_ubi(); + } + + if (remove_all_volumes()) + error_exit("Failed to remove all volumes"); + + libubi_close(libubi); + + printf("UBI Integrity Test completed ok\n"); + return 0; +} diff --git a/tests/ubi-tests/io_basic.c b/tests/ubi-tests/io_basic.c new file mode 100644 index 0000000..2e8809a --- /dev/null +++ b/tests/ubi-tests/io_basic.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem B. Bityutskiy + * + * Test basic UBI volume I/O capabilities. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libubi.h" +#define TESTNAME "io_basic" +#include "common.h" + +static libubi_t libubi; +static struct ubi_dev_info dev_info; +const char *node; + +static int test_basic(int type); +static int test_aligned(int type); + +int main(int argc, char * const argv[]) +{ + if (initial_check(argc, argv)) + return 1; + + node = argv[1]; + + libubi = libubi_open(); + if (libubi == NULL) { + failed("libubi_open"); + return 1; + } + + if (ubi_get_dev_info(libubi, node, &dev_info)) { + failed("ubi_get_dev_info"); + goto close; + } + + if (test_basic(UBI_DYNAMIC_VOLUME)) + goto close; + if (test_basic(UBI_STATIC_VOLUME)) + goto close; + if (test_aligned(UBI_DYNAMIC_VOLUME)) + goto close; + if (test_aligned(UBI_STATIC_VOLUME)) + goto close; + + libubi_close(libubi); + return 0; + +close: + libubi_close(libubi); + return 1; +} + +/** + * test_basic - check basic volume read and update capabilities. + * + * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * + * Thus function returns %0 in case of success and %-1 in case of failure. + */ +static int test_basic(int type) +{ + struct ubi_mkvol_request req; + const char *name = TESTNAME ":test_basic()"; + char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; + + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = dev_info.avail_bytes; + req.vol_type = type; + req.name = name; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); + + /* Make sure newly created volume contains only 0xFF bytes */ + if (check_vol_patt(&vol_node[0], 0xFF)) + goto remove; + + /* Write 0xA5 bytes to the volume */ + if (update_vol_patt(&vol_node[0], dev_info.avail_bytes, 0xA5)) + goto remove; + if (check_vol_patt(&vol_node[0], 0xA5)) + goto remove; + + if (ubi_rmvol(libubi, node, req.vol_id)) { + failed("ubi_rmvol"); + return -1; + } + + return 0; + +remove: + ubi_rmvol(libubi, node, req.vol_id); + return -1; +} + +/** + * test_aligned - test volume alignment feature. + * + * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * + * Thus function returns %0 in case of success and %-1 in case of failure. + */ +static int test_aligned(int type) +{ + int i, ebsz; + struct ubi_mkvol_request req; + const char *name = TESTNAME ":test_aligned()"; + char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; + int alignments[] = ALIGNMENTS(dev_info.eb_size); + + req.vol_type = type; + req.name = name; + + for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { + req.vol_id = UBI_VOL_NUM_AUTO; + + req.alignment = alignments[i]; + req.alignment -= req.alignment % dev_info.min_io_size; + if (req.alignment == 0) + req.alignment = dev_info.min_io_size; + + ebsz = dev_info.eb_size - dev_info.eb_size % req.alignment; + req.bytes = MIN_AVAIL_EBS * ebsz; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); + + /* Make sure newly created volume contains only 0xFF bytes */ + if (check_vol_patt(&vol_node[0], 0xFF)) + goto remove; + + /* Write 0xA5 bytes to the volume */ + if (update_vol_patt(&vol_node[0], req.bytes, 0xA5)) + goto remove; + if (check_vol_patt(&vol_node[0], 0xA5)) + goto remove; + + if (ubi_rmvol(libubi, node, req.vol_id)) { + failed("ubi_rmvol"); + return -1; + } + } + + return 0; + +remove: + ubi_rmvol(libubi, node, req.vol_id); + return -1; +} diff --git a/tests/ubi-tests/io_paral.c b/tests/ubi-tests/io_paral.c new file mode 100644 index 0000000..488a0b0 --- /dev/null +++ b/tests/ubi-tests/io_paral.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem B. Bityutskiy + * + * This test does a lot of I/O to volumes in parallel. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libubi.h" +#define TESTNAME "io_paral" +#include "common.h" + +#define THREADS_NUM 3 +#define ITERATIONS 10 + +static libubi_t libubi; +static struct ubi_dev_info dev_info; +const char *node; +static int iterations = ITERATIONS; +int total_bytes; + +static void * the_thread(void *ptr); + +static long long memory_limit(void) +{ + long long result = 0; + FILE *f; + + f = fopen("/proc/meminfo", "r"); + if (!f) + return 0; + fscanf(f, "%*s %lld", &result); + fclose(f); + return result * 1024 / 4; +} + +int main(int argc, char * const argv[]) +{ + int i, ret; + pthread_t threads[THREADS_NUM]; + struct ubi_mkvol_request req; + long long mem_limit; + + if (initial_check(argc, argv)) + return 1; + + node = argv[1]; + + libubi = libubi_open(); + if (libubi == NULL) { + failed("libubi_open"); + return 1; + } + + if (ubi_get_dev_info(libubi, node, &dev_info)) { + failed("ubi_get_dev_info"); + goto close; + } + + req.alignment = 1; + mem_limit = memory_limit(); + if (mem_limit && mem_limit < dev_info.avail_bytes) + total_bytes = req.bytes = + (mem_limit / dev_info.eb_size / THREADS_NUM) + * dev_info.eb_size; + else + total_bytes = req.bytes = + ((dev_info.avail_ebs - 3) / THREADS_NUM) + * dev_info.eb_size; + for (i = 0; i < THREADS_NUM; i++) { + char name[100]; + + req.vol_id = i; + sprintf(&name[0], TESTNAME":%d", i); + req.name = &name[0]; + req.vol_type = (i & 1) ? UBI_STATIC_VOLUME : UBI_DYNAMIC_VOLUME; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + goto remove; + } + } + + /* Create one volume with static data to make WL work more */ + req.vol_id = THREADS_NUM; + req.name = TESTNAME ":static"; + req.vol_type = UBI_DYNAMIC_VOLUME; + req.bytes = 3*dev_info.eb_size; + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + goto remove; + } + + for (i = 0; i < THREADS_NUM; i++) { + ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i); + if (ret) { + failed("pthread_create"); + goto remove; + } + } + + for (i = 0; i < THREADS_NUM; i++) + pthread_join(threads[i], NULL); + + for (i = 0; i <= THREADS_NUM; i++) { + if (ubi_rmvol(libubi, node, i)) { + failed("ubi_rmvol"); + goto remove; + } + } + + libubi_close(libubi); + return 0; + +remove: + for (i = 0; i <= THREADS_NUM; i++) + ubi_rmvol(libubi, node, i); + +close: + libubi_close(libubi); + return 1; +} + +/** + * the_thread - the testing thread. + * + * @ptr thread number + */ +static void * the_thread(void *ptr) +{ + int fd, iter = iterations, vol_id = (int)ptr; + unsigned char *wbuf, *rbuf; + char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; + + wbuf = malloc(total_bytes); + rbuf = malloc(total_bytes); + if (!wbuf || !rbuf) { + failed("malloc"); + goto free; + } + + sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, vol_id); + + while (iter--) { + int i, ret, written = 0, rd = 0; + int bytes = (random() % (total_bytes - 1)) + 1; + + fd = open(vol_node, O_RDWR); + if (fd == -1) { + failed("open"); + err_msg("cannot open \"%s\"\n", node); + goto free; + } + + for (i = 0; i < bytes; i++) + wbuf[i] = random() % 255; + memset(rbuf, '\0', bytes); + + do { + ret = ubi_update_start(libubi, fd, bytes); + if (ret && errno != EBUSY) { + failed("ubi_update_start"); + err_msg("vol_id %d", vol_id); + goto close; + } + } while (ret); + + while (written < bytes) { + int to_write = random() % (bytes - written); + + if (to_write == 0) + to_write = 1; + + ret = write(fd, wbuf, to_write); + if (ret != to_write) { + failed("write"); + err_msg("failed to write %d bytes at offset %d " + "of volume %d", to_write, written, + vol_id); + err_msg("update: %d bytes", bytes); + goto close; + } + + written += to_write; + } + + close(fd); + + fd = open(vol_node, O_RDONLY); + if (fd == -1) { + failed("open"); + err_msg("cannot open \"%s\"\n", node); + goto free; + } + + /* read data back and check */ + while (rd < bytes) { + int to_read = random() % (bytes - rd); + + if (to_read == 0) + to_read = 1; + + ret = read(fd, rbuf, to_read); + if (ret != to_read) { + failed("read"); + err_msg("failed to read %d bytes at offset %d " + "of volume %d", to_read, rd, vol_id); + goto close; + } + + rd += to_read; + } + + close(fd); + + } + + free(wbuf); + free(rbuf); + return NULL; + +close: + close(fd); +free: + free(wbuf); + free(rbuf); + return NULL; +} diff --git a/tests/ubi-tests/io_read.c b/tests/ubi-tests/io_read.c new file mode 100644 index 0000000..c5d1da7 --- /dev/null +++ b/tests/ubi-tests/io_read.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem B. Bityutskiy + * + * Test UBI volume read. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libubi.h" +#define TESTNAME "io_basic" +#include "common.h" + +static libubi_t libubi; +static struct ubi_dev_info dev_info; +const char *node; + +static int test_static(void); +static int test_read(int type); + +int main(int argc, char * const argv[]) +{ + if (initial_check(argc, argv)) + return 1; + + node = argv[1]; + + libubi = libubi_open(); + if (libubi == NULL) { + failed("libubi_open"); + return 1; + } + + if (ubi_get_dev_info(libubi, node, &dev_info)) { + failed("ubi_get_dev_info"); + goto close; + } + + if (test_static()) + goto close; + if (test_read(UBI_DYNAMIC_VOLUME)) + goto close; + if (test_read(UBI_STATIC_VOLUME)) + goto close; + + libubi_close(libubi); + return 0; + +close: + libubi_close(libubi); + return 1; +} + +/** + * test_static - test static volume-specific features. + * + * Thus function returns %0 in case of success and %-1 in case of failure. + */ +static int test_static(void) +{ + struct ubi_mkvol_request req; + const char *name = TESTNAME ":io_basic()"; + char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; + struct ubi_vol_info vol_info; + int fd, ret; + char buf[20]; + + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = dev_info.avail_bytes; + req.vol_type = UBI_STATIC_VOLUME; + req.name = name; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); + + fd = open(vol_node, O_RDWR); + if (fd == -1) { + failed("open"); + err_msg("cannot open \"%s\"\n", node); + goto remove; + } + + if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { + failed("ubi_get_vol_info"); + goto close; + } + + /* Make sure new static volume contains no data */ + if (vol_info.data_bytes != 0) { + err_msg("data_bytes = %lld, not zero", vol_info.data_bytes); + goto close; + } + + /* Ensure read returns EOF */ + ret = read(fd, &buf[0], 1); + if (ret < 0) { + failed("read"); + goto close; + } + if (ret != 0) { + err_msg("read data from free static volume"); + goto close; + } + + if (ubi_update_start(libubi, fd, 10)) { + failed("ubi_update_start"); + goto close; + } + + ret = write(fd, &buf[0], 10); + if (ret < 0) { + failed("write"); + goto close; + } + if (ret != 10) { + err_msg("written %d bytes", ret); + goto close; + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + failed("seek"); + goto close; + } + ret = read(fd, &buf[0], 20); + if (ret < 0) { + failed("read"); + goto close; + } + if (ret != 10) { + err_msg("read %d bytes", ret); + goto close; + } + + close(fd); + if (ubi_rmvol(libubi, node, req.vol_id)) { + failed("ubi_rmvol"); + return -1; + } + + return 0; + +close: + close(fd); +remove: + ubi_rmvol(libubi, node, req.vol_id); + return -1; +} + +static int test_read1(struct ubi_vol_info *vol_info); + +/** + * test_read - test UBI volume reading from different offsets. + * + * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * + * Thus function returns %0 in case of success and %-1 in case of failure. + */ +static int test_read(int type) +{ + const char *name = TESTNAME ":test_read()"; + int alignments[] = ALIGNMENTS(dev_info.eb_size); + char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; + struct ubi_mkvol_request req; + int i; + + for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { + int eb_size; + struct ubi_vol_info vol_info; + + req.vol_id = UBI_VOL_NUM_AUTO; + req.vol_type = type; + req.name = name; + + req.alignment = alignments[i]; + req.alignment -= req.alignment % dev_info.min_io_size; + if (req.alignment == 0) + req.alignment = dev_info.min_io_size; + + eb_size = dev_info.eb_size - dev_info.eb_size % req.alignment; + req.bytes = MIN_AVAIL_EBS * eb_size; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, + req.vol_id); + + if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { + failed("ubi_get_vol_info"); + goto remove; + } + + if (test_read1(&vol_info)) { + err_msg("alignment = %d", req.alignment); + goto remove; + } + + if (ubi_rmvol(libubi, node, req.vol_id)) { + failed("ubi_rmvol"); + return -1; + } + } + + return 0; + +remove: + ubi_rmvol(libubi, node, req.vol_id); + return -1; +} + +static int test_read2(const struct ubi_vol_info *vol_info, int len); + +static int fd; + +/* Data lengthes to test, @io - minimal I/O unit size, @s - eraseblock size */ +#define LENGTHES(io, s) \ + {1, (io), (io)+1, 2*(io), 3*(io)-1, 3*(io), \ + PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io), \ + (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s), \ + 2*(s)+(io), 3*(s), 3*(s)+(io)}; + +/* + * A helper function for test_read(). + */ +static int test_read1(struct ubi_vol_info *vol_info) +{ + int i, written = 0; + char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; + int lengthes[] = LENGTHES(dev_info.min_io_size, vol_info->eb_size); + + sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, + vol_info->vol_id); + + fd = open(vol_node, O_RDWR); + if (fd == -1) { + failed("open"); + err_msg("cannot open \"%s\"\n", node); + return -1; + } + + /* Write some pattern to the volume */ + if (ubi_update_start(libubi, fd, vol_info->rsvd_bytes)) { + failed("ubi_update_start"); + err_msg("bytes = %lld", vol_info->rsvd_bytes); + goto close; + } + + while (written < vol_info->rsvd_bytes) { + int i, ret; + unsigned char buf[512]; + + for (i = 0; i < 512; i++) + buf[i] = (unsigned char)(written + i); + + ret = write(fd, &buf[0], 512); + if (ret == -1) { + failed("write"); + err_msg("written = %d, ret = %d", written, ret); + goto close; + } + written += ret; + } + + close(fd); + + if (ubi_get_vol_info(libubi, vol_node, vol_info)) { + failed("ubi_get_vol_info"); + return -1; + } + + fd = open(vol_node, O_RDONLY); + if (fd == -1) { + failed("open"); + err_msg("cannot open \"%s\"\n", node); + return -1; + } + + for (i = 0; i < sizeof(lengthes)/sizeof(int); i++) { + if (test_read2(vol_info, lengthes[i])) { + err_msg("length = %d", lengthes[i]); + goto close; + } + } + + close(fd); + return 0; + +close: + close(fd); + return -1; +} + +static int test_read3(const struct ubi_vol_info *vol_info, int len, off_t off); + +/* + * Offsets to test, @io - minimal I/O unit size, @s - eraseblock size, @sz - + * volume size. + */ +#define OFFSETS(io, s, sz) \ + {0, (io)-1, (io), (io)+1, 2*(io)-1, 2*(io), 3*(io)-1, 3*(io), \ + PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io), \ + (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s), \ + 2*(s)+(io), 3*(s), (sz)-(s)-1, (sz)-(io)-1, (sz)-PAGE_SIZE-1}; + +/* + * A helper function for test_read1(). + */ +static int test_read2(const struct ubi_vol_info *vol_info, int len) +{ + int i; + off_t offsets[] = OFFSETS(dev_info.min_io_size, vol_info->eb_size, + vol_info->data_bytes); + + for (i = 0; i < sizeof(offsets)/sizeof(off_t); i++) { + if (test_read3(vol_info, len, offsets[i])) { + err_msg("offset = %d", offsets[i]); + return -1; + } + } + + return 0; +} + +/* + * A helper function for test_read2(). + */ +static int test_read3(const struct ubi_vol_info *vol_info, int len, off_t off) +{ + int i, len1; + unsigned char ck_buf[len], buf[len]; + off_t new_off; + + if (off + len > vol_info->data_bytes) + len1 = vol_info->data_bytes - off; + else + len1 = len; + + if (lseek(fd, off, SEEK_SET) != off) { + failed("seek"); + err_msg("len = %d", len); + return -1; + } + if (read(fd, &buf[0], len) != len1) { + failed("read"); + err_msg("len = %d", len); + return -1; + } + + new_off = lseek(fd, 0, SEEK_CUR); + if (new_off != off + len1) { + if (new_off == -1) + failed("lseek"); + else + err_msg("read %d bytes from %lld, but resulting " + "offset is %lld", len1, (long long) off, (long long) new_off); + return -1; + } + + for (i = 0; i < len1; i++) + ck_buf[i] = (unsigned char)(off + i); + + if (memcmp(&buf[0], &ck_buf[0], len1)) { + err_msg("incorrect data read from offset %lld", + (long long)off); + err_msg("len = %d", len); + return -1; + } + + return 0; +} diff --git a/tests/ubi-tests/io_update.c b/tests/ubi-tests/io_update.c new file mode 100644 index 0000000..2e3422a --- /dev/null +++ b/tests/ubi-tests/io_update.c @@ -0,0 +1,370 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem B. Bityutskiy + * + * Test UBI volume update. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libubi.h" +#define TESTNAME "io_update" +#include "common.h" + +static libubi_t libubi; +static struct ubi_dev_info dev_info; +const char *node; + +static int test_update(int type); +static int test_update_ff(void); + +int main(int argc, char * const argv[]) +{ + if (initial_check(argc, argv)) + return 1; + + node = argv[1]; + + libubi = libubi_open(); + if (libubi == NULL) { + failed("libubi_open"); + return 1; + } + + if (ubi_get_dev_info(libubi, node, &dev_info)) { + failed("ubi_get_dev_info"); + goto close; + } + + if (test_update(UBI_DYNAMIC_VOLUME)) + goto close; + if (test_update(UBI_STATIC_VOLUME)) + goto close; + if (test_update_ff()) + goto close; + + libubi_close(libubi); + return 0; + +close: + libubi_close(libubi); + return 1; +} + +static int test_update1(struct ubi_vol_info *vol_info); + +/** + * test_update - check volume update capabilities. + * + * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * + * This function returns %0 in case of success and %-1 in case of failure. + */ +static int test_update(int type) +{ + struct ubi_mkvol_request req; + const char *name = TESTNAME ":io_update()"; + int alignments[] = ALIGNMENTS(dev_info.eb_size); + struct ubi_vol_info vol_info; + char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; + int i; + + for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { + int eb_size; + + req.vol_id = UBI_VOL_NUM_AUTO; + req.vol_type = type; + req.name = name; + + req.alignment = alignments[i]; + req.alignment -= req.alignment % dev_info.min_io_size; + if (req.alignment == 0) + req.alignment = dev_info.min_io_size; + + eb_size = dev_info.eb_size - dev_info.eb_size % req.alignment; + req.bytes = MIN_AVAIL_EBS * eb_size; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, + req.vol_id); + if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { + failed("ubi_get_vol_info"); + goto remove; + } + + if (test_update1(&vol_info)) { + err_msg("alignment = %d", req.alignment); + goto remove; + } + + if (ubi_rmvol(libubi, node, req.vol_id)) { + failed("ubi_rmvol"); + return -1; + } + } + + return 0; + +remove: + ubi_rmvol(libubi, node, req.vol_id); + return -1; +} + +#define SEQUENCES(io, s) { \ + {3*(s)-(io)-1, 1}, \ + {512}, \ + {666}, \ + {2048}, \ + {(io), (io), PAGE_SIZE}, \ + {(io)+1, (io)+1, PAGE_SIZE}, \ + {PAGE_SIZE}, \ + {PAGE_SIZE-1}, \ + {PAGE_SIZE+(io)}, \ + {(s)}, \ + {(s)-1}, \ + {(s)+1}, \ + {(io), (s)+1}, \ + {(s)+(io), PAGE_SIZE}, \ + {2*(s), PAGE_SIZE}, \ + {PAGE_SIZE, 2*(s), 1}, \ + {PAGE_SIZE, 2*(s)}, \ + {2*(s)-1, 2*(s)-1}, \ + {3*(s), PAGE_SIZE + 1}, \ + {1, PAGE_SIZE}, \ + {(io), (s)} \ +} +#define SEQ_SZ 21 + +/* + * test_update1 - helper function for test_update(). + */ +static int test_update1(struct ubi_vol_info *vol_info) +{ + int sequences[SEQ_SZ][3] = SEQUENCES(dev_info.min_io_size, + vol_info->eb_size); + char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; + unsigned char buf[vol_info->rsvd_bytes]; + int fd, i, j; + + sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, + vol_info->vol_id); + + for (i = 0; i < vol_info->rsvd_bytes; i++) + buf[i] = (unsigned char)i; + + fd = open(vol_node, O_RDWR); + if (fd == -1) { + failed("open"); + err_msg("cannot open \"%s\"\n", node); + return -1; + } + + for (i = 0; i < SEQ_SZ; i++) { + int ret, stop = 0, len; + off_t off = 0; + unsigned char buf1[vol_info->rsvd_bytes]; + + if (ubi_update_start(libubi, fd, vol_info->rsvd_bytes)) { + failed("ubi_update_start"); + goto close; + } + + for (j = 0; off < vol_info->rsvd_bytes; j++) { + if (!stop) { + if (sequences[i][j] != 0) + len = sequences[i][j]; + else + stop = 1; + } + + ret = write(fd, &buf[off], len); + if (ret < 0) { + failed("write"); + err_msg("failed to write %d bytes at offset " + "%lld", len, (long long) off); + goto close; + } + if (off + len > vol_info->rsvd_bytes) + len = vol_info->rsvd_bytes - off; + if (ret != len) { + err_msg("failed to write %d bytes at offset " + "%lld, wrote %d", len, (long long) off, ret); + goto close; + } + off += len; + } + + /* Check data */ + if ((ret = lseek(fd, SEEK_SET, 0)) != 0) { + if (ret < 0) + failed("lseek"); + err_msg("cannot seek to 0"); + goto close; + } + memset(&buf1[0], 0x01, vol_info->rsvd_bytes); + ret = read(fd, &buf1[0], vol_info->rsvd_bytes + 1); + if (ret < 0) { + failed("read"); + err_msg("failed to read %d bytes", + vol_info->rsvd_bytes + 1); + goto close; + } + if (ret != vol_info->rsvd_bytes) { + err_msg("failed to read %d bytes, read %d", + vol_info->rsvd_bytes, ret); + goto close; + } + if (memcmp(&buf[0], &buf1[0], vol_info->rsvd_bytes)) { + err_msg("data corruption"); + goto close; + } + } + + close(fd); + return 0; + +close: + close(fd); + return -1; +} + +/** + * test_update_ff - check volume with 0xFF data + * + * This function returns %0 in case of success and %-1 in case of failure. + */ +static int test_update_ff(void) +{ + struct ubi_mkvol_request req; + const char *name = TESTNAME ":io_update()"; + struct ubi_vol_info vol_info; + char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; + int i, fd, ret, types[2]; + int upd_len = MIN_AVAIL_EBS * dev_info.eb_size; + char buf[upd_len], buf1[upd_len]; + + for(i = 0; i < MIN_AVAIL_EBS; i++) { + if (i % 1) + memset(&buf[0], 0xAB, upd_len); + else + memset(&buf[0], 0xFF, upd_len); + } + + types[0] = UBI_DYNAMIC_VOLUME; + types[1] = UBI_STATIC_VOLUME; + + for (i = 0; i < 2; i++) { + req.vol_id = UBI_VOL_NUM_AUTO; + req.vol_type = types[i]; + req.name = name; + + req.alignment = 1; + req.bytes = upd_len; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, + req.vol_id); + if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { + failed("ubi_get_vol_info"); + goto remove; + } + + fd = open(vol_node, O_RDWR); + if (fd == -1) { + failed("open"); + err_msg("cannot open \"%s\"\n", node); + goto remove; + } + + if (ubi_update_start(libubi, fd, upd_len)) { + failed("ubi_update_start"); + goto close; + } + + + ret = write(fd, &buf[0], upd_len); + if (ret < 0 || ret != upd_len) { + failed("write"); + err_msg("failed to write %d bytes", upd_len); + goto close; + } + + /* Check data */ + if ((ret = lseek(fd, SEEK_SET, 0)) != 0) { + if (ret < 0) + failed("lseek"); + err_msg("cannot seek to 0"); + goto close; + } + + close(fd); + + fd = open(vol_node, O_RDWR); + if (fd == -1) { + failed("open"); + err_msg("cannot open \"%s\"\n", node); + goto remove; + } + + memset(&buf1[0], 0x00, upd_len); + ret = read(fd, &buf1[0], upd_len); + if (ret < 0) { + failed("read"); + err_msg("failed to read %d bytes", upd_len); + goto close; + } + if (ret != upd_len) { + err_msg("failed to read %d bytes, read %d", + upd_len, ret); + goto close; + } + if (memcmp(&buf[0], &buf1[0], upd_len)) { + err_msg("data corruption"); + goto close; + } + + close(fd); + + if (ubi_rmvol(libubi, node, req.vol_id)) { + failed("ubi_rmvol"); + return -1; + } + } + + return 0; + +close: + close(fd); +remove: + ubi_rmvol(libubi, node, req.vol_id); + return -1; +} diff --git a/tests/ubi-tests/mkvol_bad.c b/tests/ubi-tests/mkvol_bad.c new file mode 100644 index 0000000..023b06b --- /dev/null +++ b/tests/ubi-tests/mkvol_bad.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem B. Bityutskiy + * + * Test UBI volume creation and deletion ioctl()s with bad input and in case of + * incorrect usage. + */ + +#include +#include +#include +#include "libubi.h" +#define TESTNAME "mkvol_bad" +#include "common.h" + +static libubi_t libubi; +static struct ubi_dev_info dev_info; +const char *node; + +static int test_mkvol(void); +static int test_rmvol(void); + +int main(int argc, char * const argv[]) +{ + if (initial_check(argc, argv)) + return 1; + + node = argv[1]; + + libubi = libubi_open(); + if (libubi == NULL) { + failed("libubi_open"); + return 1; + } + + if (ubi_get_dev_info(libubi, node, &dev_info)) { + failed("ubi_get_dev_info"); + goto close; + } + + if (test_mkvol()) + goto close; + + if (test_rmvol()) + goto close; + + libubi_close(libubi); + return 0; + +close: + libubi_close(libubi); + return 1; +} + +/** + * test_mkvol - test that UBI mkvol ioctl rejects bad input parameters. + * + * This function returns %0 if the test passed and %-1 if not. + */ +static int test_mkvol(void) +{ + int ret, i; + struct ubi_mkvol_request req; + const char *name = TESTNAME ":test_mkvol()"; + + req.alignment = 1; + req.bytes = dev_info.avail_bytes; + req.vol_type = UBI_DYNAMIC_VOLUME; + req.name = name; + + /* Bad volume ID */ + req.vol_id = -2; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id)) + return -1; + + req.vol_id = dev_info.max_vol_count; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id)) + return -1; + + /* Bad alignment */ + req.vol_id = 0; + req.alignment = 0; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", + req.alignment)) + return -1; + + req.alignment = -1; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", + req.alignment)) + return -1; + + req.alignment = dev_info.eb_size + 1; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", + req.alignment)) + return -1; + + if (dev_info.min_io_size > 1) { + req.alignment = dev_info.min_io_size + 1; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", + req.alignment)) + return -1; + } + + /* Bad bytes */ + req.alignment = 1; + req.bytes = -1; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes)) + return -1; + + req.bytes = 0; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes)) + return -1; + + req.bytes = dev_info.avail_bytes + 1; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes)) + return -1; + + req.alignment = dev_info.eb_size - dev_info.min_io_size; + req.bytes = (dev_info.eb_size - dev_info.eb_size % req.alignment) * + dev_info.avail_ebs + 1; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes)) + return -1; + + /* Bad vol_type */ + req.alignment = 1; + req.bytes = dev_info.eb_size; + req.vol_type = UBI_DYNAMIC_VOLUME + UBI_STATIC_VOLUME; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_type = %d", + req.vol_type)) + return -1; + + req.vol_type = UBI_DYNAMIC_VOLUME; + + /* Too long name */ + { + char name[UBI_VOL_NAME_MAX + 5]; + + memset(&name[0], 'x', UBI_VOL_NAME_MAX + 1); + name[UBI_VOL_NAME_MAX + 1] = '\0'; + + req.name = &name[0]; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EINVAL, "ubi_mkvol", "name_len = %d", + UBI_VOL_NAME_MAX + 1)) + return -1; + } + + /* Try to create 2 volumes with the same ID and name */ + req.name = name; + req.vol_id = 0; + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EEXIST, "ubi_mkvol", + "volume with ID 0 created twice")) + return -1; + + req.vol_id = 1; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EEXIST, "ubi_mkvol", + "volume with name \"%s\" created twice", name)) + return -1; + + if (ubi_rmvol(libubi, node, 0)) { + failed("ubi_rmvol"); + return -1; + } + + /* Try to use too much space */ + req.vol_id = 0; + req.bytes = dev_info.avail_bytes; + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + req.bytes = 1; + req.vol_id = 1; + ret = ubi_mkvol(libubi, node, &req); + if (check_failed(ret, EEXIST, "ubi_mkvol", + "created volume of maximum size %lld, but still " + "can create more volumes", dev_info.avail_bytes)) + return -1; + + if (ubi_rmvol(libubi, node, 0)) { + failed("ubi_rmvol"); + return -1; + } + + /* Try to create too many volumes */ + for (i = 0; i < dev_info.max_vol_count; i++) { + char nm[strlen(name) + 50]; + + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = 1; + req.vol_type = UBI_STATIC_VOLUME; + + sprintf(&nm[0], "%s:%d", name, i); + req.name = &nm[0]; + + if (ubi_mkvol(libubi, node, &req)) { + /* + * Note, because of gluebi we may be unable to create + * dev_info.max_vol_count devices (MTD restrictions). + */ + if (errno == ENFILE) + break; + failed("ubi_mkvol"); + err_msg("vol_id %d", i); + goto remove; + } + } + + for (i = 0; i < dev_info.max_vol_count + 1; i++) + ubi_rmvol(libubi, node, i); + + return 0; + +remove: + for (i = 0; i < dev_info.max_vol_count + 1; i++) + ubi_rmvol(libubi, node, i); + return -1; +} + +/** + * test_rmvol - test that UBI rmvol ioctl rejects bad input parameters. + * + * This function returns %0 if the test passed and %-1 if not. + */ +static int test_rmvol(void) +{ + int ret; + struct ubi_mkvol_request req; + const char *name = TESTNAME ":test_rmvol()"; + + /* Bad vol_id */ + ret = ubi_rmvol(libubi, node, -1); + if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = -1")) + return -1; + + ret = ubi_rmvol(libubi, node, dev_info.max_vol_count); + if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = %d", + dev_info.max_vol_count)) + return -1; + + /* Try to remove non-existing volume */ + ret = ubi_rmvol(libubi, node, 0); + if (check_failed(ret, ENODEV, "ubi_rmvol", + "removed non-existing volume 0")) + return -1; + + /* Try to remove volume twice */ + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = dev_info.avail_bytes; + req.vol_type = UBI_DYNAMIC_VOLUME; + req.name = name; + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + if (ubi_rmvol(libubi, node, req.vol_id)) { + failed("ubi_rmvol"); + return -1; + } + + ret = ubi_rmvol(libubi, node, req.vol_id); + if (check_failed(ret, ENODEV, "ubi_rmvol", "volume %d removed twice", + req.vol_id)) + return -1; + + return 0; +} diff --git a/tests/ubi-tests/mkvol_basic.c b/tests/ubi-tests/mkvol_basic.c new file mode 100644 index 0000000..e2120e9 --- /dev/null +++ b/tests/ubi-tests/mkvol_basic.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem B. Bityutskiy + * + * Test test checks basic volume creation and deletion capabilities. + */ + +#include +#include +#include +#include "libubi.h" +#define TESTNAME "mkvol_basic" +#include "common.h" + +static libubi_t libubi; +static struct ubi_dev_info dev_info; +const char *node; + +static int mkvol_basic(void); +static int mkvol_alignment(void); +static int mkvol_multiple(void); + +int main(int argc, char * const argv[]) +{ + if (initial_check(argc, argv)) + return 1; + + node = argv[1]; + + libubi = libubi_open(); + if (libubi == NULL) { + failed("libubi_open"); + return 1; + } + + if (ubi_get_dev_info(libubi, node, &dev_info)) { + failed("ubi_get_dev_info"); + goto close; + } + + if (mkvol_basic()) + goto close; + + if (mkvol_alignment()) + goto close; + + if (mkvol_multiple()) + goto close; + + libubi_close(libubi); + return 0; + +close: + libubi_close(libubi); + return 1; +} + +/** + * mkvol_alignment - create volumes with different alignments. + * + * Thus function returns %0 in case of success and %-1 in case of failure. + */ +static int mkvol_alignment(void) +{ + struct ubi_mkvol_request req; + int i, vol_id, ebsz; + const char *name = TESTNAME ":mkvol_alignment()"; + int alignments[] = ALIGNMENTS(dev_info.eb_size); + + for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { + req.vol_id = UBI_VOL_NUM_AUTO; + + /* Alignment should actually be multiple of min. I/O size */ + req.alignment = alignments[i]; + req.alignment -= req.alignment % dev_info.min_io_size; + if (req.alignment == 0) + req.alignment = dev_info.min_io_size; + + /* Bear in mind alignment reduces EB size */ + ebsz = dev_info.eb_size - dev_info.eb_size % req.alignment; + req.bytes = dev_info.avail_ebs * ebsz; + + req.vol_type = UBI_DYNAMIC_VOLUME; + req.name = name; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + err_msg("alignment %d", req.alignment); + return -1; + } + + vol_id = req.vol_id; + if (check_volume(vol_id, &req)) + goto remove; + + if (ubi_rmvol(libubi, node, vol_id)) { + failed("ubi_rmvol"); + return -1; + } + } + + return 0; + +remove: + ubi_rmvol(libubi, node, vol_id); + return -1; +} + +/** + * mkvol_basic - simple test that checks basic volume creation capability. + * + * Thus function returns %0 in case of success and %-1 in case of failure. + */ +static int mkvol_basic(void) +{ + struct ubi_mkvol_request req; + struct ubi_vol_info vol_info; + int vol_id, ret; + const char *name = TESTNAME ":mkvol_basic()"; + + /* Create dynamic volume of maximum size */ + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = dev_info.avail_bytes; + req.vol_type = UBI_DYNAMIC_VOLUME; + req.name = name; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + vol_id = req.vol_id; + if (check_volume(vol_id, &req)) + goto remove; + + if (ubi_rmvol(libubi, node, vol_id)) { + failed("ubi_rmvol"); + return -1; + } + + /* Create static volume of maximum size */ + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = dev_info.avail_bytes; + req.vol_type = UBI_STATIC_VOLUME; + req.name = name; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + vol_id = req.vol_id; + if (check_volume(vol_id, &req)) + goto remove; + + if (ubi_rmvol(libubi, node, vol_id)) { + failed("ubi_rmvol"); + return -1; + } + + /* Make sure volume does not exist */ + ret = ubi_get_vol_info1(libubi, dev_info.dev_num, vol_id, &vol_info); + if (ret == 0) { + err_msg("removed volume %d exists", vol_id); + goto remove; + } + + return 0; + +remove: + ubi_rmvol(libubi, node, vol_id); + return -1; +} + +/** + * mkvol_multiple - test multiple volumes creation + * + * Thus function returns %0 if the test passed and %-1 if not. + */ +static int mkvol_multiple(void) +{ + struct ubi_mkvol_request req; + int i, ret, max = dev_info.max_vol_count; + const char *name = TESTNAME ":mkvol_multiple()"; + + /* Create maximum number of volumes */ + for (i = 0; i < max; i++) { + char nm[strlen(name) + 50]; + + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = 1; + req.vol_type = UBI_STATIC_VOLUME; + + sprintf(&nm[0], "%s:%d", name, i); + req.name = &nm[0]; + + if (ubi_mkvol(libubi, node, &req)) { + if (errno == ENFILE) { + max = i; + break; + } + failed("ubi_mkvol"); + err_msg("vol_id %d", i); + goto remove; + } + + if (check_volume(req.vol_id, &req)) { + err_msg("vol_id %d", i); + goto remove; + } + } + + for (i = 0; i < max; i++) { + struct ubi_vol_info vol_info; + + if (ubi_rmvol(libubi, node, i)) { + failed("ubi_rmvol"); + return -1; + } + + /* Make sure volume does not exist */ + ret = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info); + if (ret == 0) { + err_msg("removed volume %d exists", i); + goto remove; + } + } + + return 0; + +remove: + for (i = 0; i < dev_info.max_vol_count + 1; i++) + ubi_rmvol(libubi, node, i); + return -1; +} diff --git a/tests/ubi-tests/mkvol_paral.c b/tests/ubi-tests/mkvol_paral.c new file mode 100644 index 0000000..faf085c --- /dev/null +++ b/tests/ubi-tests/mkvol_paral.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem B. Bityutskiy + * + * This test creates and deletes volumes in parallel. + */ + +#include +#include +#include +#include +#include "libubi.h" +#define TESTNAME "mkvol_paral" +#include "common.h" + +#define THREADS_NUM 4 +#define ITERATIONS 500 + +static libubi_t libubi; +static struct ubi_dev_info dev_info; +const char *node; +static int iterations = ITERATIONS; + +static void * the_thread(void *ptr); + +int main(int argc, char * const argv[]) +{ + int i, ret; + pthread_t threads[THREADS_NUM]; + + if (initial_check(argc, argv)) + return 1; + + node = argv[1]; + + libubi = libubi_open(); + if (libubi == NULL) { + failed("libubi_open"); + return 1; + } + + if (ubi_get_dev_info(libubi, node, &dev_info)) { + failed("ubi_get_dev_info"); + goto close; + } + + for (i = 0; i < THREADS_NUM; i++) { + ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i); + if (ret) { + failed("pthread_create"); + goto close; + } + } + + for (i = 0; i < THREADS_NUM; i++) + pthread_join(threads[i], NULL); + + libubi_close(libubi); + return 0; + +close: + libubi_close(libubi); + return 1; +} + +/** + * the_thread - the testing thread. + * + * @ptr thread number + */ +static void * the_thread(void *ptr) +{ + int n = (int)ptr, iter = iterations; + struct ubi_mkvol_request req; + const char *name = TESTNAME ":the_thread()"; + char nm[strlen(name) + 50]; + + req.alignment = 1; + req.bytes = dev_info.avail_bytes/ITERATIONS; + req.vol_type = UBI_DYNAMIC_VOLUME; + sprintf(&nm[0], "%s:%d", name, n); + req.name = &nm[0]; + + while (iter--) { + req.vol_id = UBI_VOL_NUM_AUTO; + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return NULL; + } + if (ubi_rmvol(libubi, node, req.vol_id)) { + failed("ubi_rmvol"); + return NULL; + } + } + + return NULL; +} diff --git a/tests/ubi-tests/rmvol.c b/tests/ubi-tests/rmvol.c new file mode 100644 index 0000000..fb9b344 --- /dev/null +++ b/tests/ubi-tests/rmvol.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) Nokia Corporation, 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem B. Bityutskiy + * + * Test volume reference counting - create a volume, open a sysfs file + * belonging to the volume, delete the volume but do not close the file, make + * sure the file cannot be read, make sure the volume cannot be open, close the + * file, make sure the volume disappeard, make sure its sysfs subtree + * disappeared. + */ + +#include +#include +#include +#include +#include +#include "libubi.h" +#define TESTNAME "rmvol" +#include "common.h" + +#define SYSFS_FILE "/sys/class/ubi/ubi%d_%d/usable_eb_size" + +int main(int argc, char * const argv[]) +{ + int ret, fd; + char fname[sizeof(SYSFS_FILE) + 20]; + const char *node; + libubi_t libubi; + struct ubi_dev_info dev_info; + struct ubi_mkvol_request req; + char tmp[100]; + + if (initial_check(argc, argv)) + return 1; + + node = argv[1]; + + libubi = libubi_open(); + if (libubi == NULL) { + failed("libubi_open"); + return 1; + } + + if (ubi_get_dev_info(libubi, node, &dev_info)) { + failed("ubi_get_dev_info"); + goto out_libubi; + } + + /* Create a small dynamic volume */ + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = dev_info.min_io_size; + req.bytes = dev_info.eb_size; + req.vol_type = UBI_DYNAMIC_VOLUME; + req.name = "rmvol"; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + perror("ubi_mkvol"); + goto out_libubi; + } + + /* Open volume-related sysfs file */ + sprintf(fname, SYSFS_FILE, dev_info.dev_num, req.vol_id); + fd = open(fname, O_RDONLY); + if (fd == -1) { + failed("open"); + perror("open"); + goto out_rmvol; + } + + /* Remove the volume, but do not close the file */ + if (ubi_rmvol(libubi, node, req.vol_id)) { + failed("ubi_rmvol"); + perror("ubi_rmvol"); + goto out_close; + } + + /* Try to read from the file, this should fail */ + ret = read(fd, tmp, 100); + if (ret != -1) { + failed("read"); + err_msg("read returned %d, expected -1", ret); + goto out_close; + } + + /* Close the file and try to open it again, should fail */ + close(fd); + fd = open(fname, O_RDONLY); + if (fd != -1) { + failed("open"); + err_msg("opened %s again, open returned %d, expected -1", + fname, fd); + goto out_libubi; + } + + libubi_close(libubi); + return 0; + +out_rmvol: + ubi_rmvol(libubi, node, req.vol_id); +out_libubi: + libubi_close(libubi); + return 1; + +out_close: + close(fd); + libubi_close(libubi); + return 1; +} + +#if 0 +/** + * mkvol_alignment - create volumes with different alignments. + * + * Thus function returns %0 in case of success and %-1 in case of failure. + */ +static int mkvol_alignment(void) +{ + struct ubi_mkvol_request req; + int i, vol_id, ebsz; + const char *name = TESTNAME ":mkvol_alignment()"; + int alignments[] = ALIGNMENTS(dev_info.eb_size); + + for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { + req.vol_id = UBI_VOL_NUM_AUTO; + + /* Alignment should actually be multiple of min. I/O size */ + req.alignment = alignments[i]; + req.alignment -= req.alignment % dev_info.min_io_size; + if (req.alignment == 0) + req.alignment = dev_info.min_io_size; + + /* Bear in mind alignment reduces EB size */ + ebsz = dev_info.eb_size - dev_info.eb_size % req.alignment; + req.bytes = dev_info.avail_ebs * ebsz; + + req.vol_type = UBI_DYNAMIC_VOLUME; + req.name = name; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + err_msg("alignment %d", req.alignment); + return -1; + } + + vol_id = req.vol_id; + if (check_volume(vol_id, &req)) + goto remove; + + if (ubi_rmvol(libubi, node, vol_id)) { + failed("ubi_rmvol"); + return -1; + } + } + + return 0; + +remove: + ubi_rmvol(libubi, node, vol_id); + return -1; +} + +/** + * mkvol_basic - simple test that checks basic volume creation capability. + * + * Thus function returns %0 in case of success and %-1 in case of failure. + */ +static int mkvol_basic(void) +{ + struct ubi_mkvol_request req; + struct ubi_vol_info vol_info; + int vol_id, ret; + const char *name = TESTNAME ":mkvol_basic()"; + + /* Create dynamic volume of maximum size */ + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = dev_info.avail_bytes; + req.vol_type = UBI_DYNAMIC_VOLUME; + req.name = name; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + vol_id = req.vol_id; + if (check_volume(vol_id, &req)) + goto remove; + + if (ubi_rmvol(libubi, node, vol_id)) { + failed("ubi_rmvol"); + return -1; + } + + /* Create static volume of maximum size */ + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = dev_info.avail_bytes; + req.vol_type = UBI_STATIC_VOLUME; + req.name = name; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + vol_id = req.vol_id; + if (check_volume(vol_id, &req)) + goto remove; + + if (ubi_rmvol(libubi, node, vol_id)) { + failed("ubi_rmvol"); + return -1; + } + + /* Make sure volume does not exist */ + ret = ubi_get_vol_info1(libubi, dev_info.dev_num, vol_id, &vol_info); + if (ret == 0) { + err_msg("removed volume %d exists", vol_id); + goto remove; + } + + return 0; + +remove: + ubi_rmvol(libubi, node, vol_id); + return -1; +} + +/** + * mkvol_multiple - test multiple volumes creation + * + * Thus function returns %0 if the test passed and %-1 if not. + */ +static int mkvol_multiple(void) +{ + struct ubi_mkvol_request req; + int i, ret, max = dev_info.max_vol_count; + const char *name = TESTNAME ":mkvol_multiple()"; + + /* Create maximum number of volumes */ + for (i = 0; i < max; i++) { + char nm[strlen(name) + 50]; + + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = 1; + req.vol_type = UBI_STATIC_VOLUME; + + sprintf(&nm[0], "%s:%d", name, i); + req.name = &nm[0]; + + if (ubi_mkvol(libubi, node, &req)) { + if (errno == ENFILE) { + max = i; + break; + } + failed("ubi_mkvol"); + err_msg("vol_id %d", i); + goto remove; + } + + if (check_volume(req.vol_id, &req)) { + err_msg("vol_id %d", i); + goto remove; + } + } + + for (i = 0; i < max; i++) { + struct ubi_vol_info vol_info; + + if (ubi_rmvol(libubi, node, i)) { + failed("ubi_rmvol"); + return -1; + } + + /* Make sure volume does not exist */ + ret = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info); + if (ret == 0) { + err_msg("removed volume %d exists", i); + goto remove; + } + } + + return 0; + +remove: + for (i = 0; i < dev_info.max_vol_count + 1; i++) + ubi_rmvol(libubi, node, i); + return -1; +} +#endif diff --git a/tests/ubi-tests/rsvol.c b/tests/ubi-tests/rsvol.c new file mode 100644 index 0000000..7a9e5ea --- /dev/null +++ b/tests/ubi-tests/rsvol.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Artem B. Bityutskiy + * + * Tes UBI volume re-size. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "libubi.h" +#define TESTNAME "rsvol" +#include "common.h" + +static libubi_t libubi; +static struct ubi_dev_info dev_info; +const char *node; + +static int test_basic(int type); +static int test_rsvol(int type); + +int main(int argc, char * const argv[]) +{ + if (initial_check(argc, argv)) + return 1; + + node = argv[1]; + + libubi = libubi_open(); + if (libubi == NULL) { + failed("libubi_open"); + return 1; + } + + if (ubi_get_dev_info(libubi, node, &dev_info)) { + failed("ubi_get_dev_info"); + goto close; + } + + if (test_basic(UBI_DYNAMIC_VOLUME)) + goto close; + if (test_basic(UBI_STATIC_VOLUME)) + goto close; + if (test_rsvol(UBI_DYNAMIC_VOLUME)) + goto close; + if (test_rsvol(UBI_STATIC_VOLUME)) + goto close; + + libubi_close(libubi); + return 0; + +close: + libubi_close(libubi); + return 1; +} + +/** + * test_basic - check volume re-size capability. + * + * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * + * Thus function returns %0 in case of success and %-1 in case of failure. + */ +static int test_basic(int type) +{ + struct ubi_mkvol_request req; + const char *name = TESTNAME ":test_basic()"; + + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + req.bytes = MIN_AVAIL_EBS * dev_info.eb_size; + req.vol_type = type; + req.name = name; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + req.bytes = dev_info.eb_size; + if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { + failed("ubi_rsvol"); + goto remove; + } + + if (check_volume(req.vol_id, &req)) + goto remove; + + req.bytes = (MIN_AVAIL_EBS + 1) * dev_info.eb_size; + if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { + failed("ubi_rsvol"); + goto remove; + } + + if (check_volume(req.vol_id, &req)) + goto remove; + + req.bytes -= 1; + if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { + failed("ubi_rsvol"); + goto remove; + } + + if (check_volume(req.vol_id, &req)) + goto remove; + + if (ubi_rmvol(libubi, node, req.vol_id)) { + failed("ubi_rmvol"); + return -1; + } + + return 0; + +remove: + ubi_rmvol(libubi, node, req.vol_id); + return -1; +} + +static int test_rsvol1(struct ubi_vol_info *vol_info); + +/** + * test_rsvol - test UBI volume re-size. + * + * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * + * Thus function returns %0 in case of success and %-1 in case of failure. + */ +static int test_rsvol(int type) +{ + const char *name = TESTNAME "test_rsvol:()"; + int alignments[] = ALIGNMENTS(dev_info.eb_size); + char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; + struct ubi_mkvol_request req; + int i; + + for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { + int eb_size; + struct ubi_vol_info vol_info; + + req.vol_id = UBI_VOL_NUM_AUTO; + req.vol_type = type; + req.name = name; + + req.alignment = alignments[i]; + req.alignment -= req.alignment % dev_info.min_io_size; + if (req.alignment == 0) + req.alignment = dev_info.min_io_size; + + eb_size = dev_info.eb_size - dev_info.eb_size % req.alignment; + req.bytes = MIN_AVAIL_EBS * eb_size; + + if (ubi_mkvol(libubi, node, &req)) { + failed("ubi_mkvol"); + return -1; + } + + sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, + req.vol_id); + + if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { + failed("ubi_get_vol_info"); + goto remove; + } + + if (test_rsvol1(&vol_info)) { + err_msg("alignment = %d", req.alignment); + goto remove; + } + + if (ubi_rmvol(libubi, node, req.vol_id)) { + failed("ubi_rmvol"); + return -1; + } + } + + return 0; + +remove: + ubi_rmvol(libubi, node, req.vol_id); + return -1; +} + +/* + * Helper function for test_rsvol(). + */ +static int test_rsvol1(struct ubi_vol_info *vol_info) +{ + long long bytes; + struct ubi_vol_info vol_info1; + char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; + unsigned char buf[vol_info->rsvd_bytes]; + int fd, i, ret; + + /* Make the volume smaller and check basic volume I/O */ + bytes = vol_info->rsvd_bytes - vol_info->eb_size; + if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes - 1)) { + failed("ubi_rsvol"); + return -1; + } + + if (ubi_get_vol_info1(libubi, vol_info->dev_num, vol_info->vol_id, + &vol_info1)) { + failed("ubi_get_vol_info"); + return -1; + } + + if (vol_info1.rsvd_bytes != bytes) { + err_msg("rsvd_bytes %lld, must be %lld", + vol_info1.rsvd_bytes, bytes); + return -1; + } + + if (vol_info1.rsvd_ebs != vol_info->rsvd_ebs - 1) { + err_msg("rsvd_ebs %d, must be %d", + vol_info1.rsvd_ebs, vol_info->rsvd_ebs - 1); + return -1; + } + + /* Write data to the volume */ + sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, + vol_info->vol_id); + + fd = open(vol_node, O_RDWR); + if (fd == -1) { + failed("open"); + err_msg("cannot open \"%s\"\n", vol_node); + return -1; + } + + bytes = vol_info->rsvd_bytes - vol_info->eb_size - 1; + if (ubi_update_start(libubi, fd, bytes)) { + failed("ubi_update_start"); + goto close; + } + + for (i = 0; i < bytes; i++) + buf[i] = (unsigned char)i; + + ret = write(fd, &buf[0], bytes); + if (ret != bytes) { + failed("write"); + goto close; + } + + close(fd); + + if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes)) { + failed("ubi_rsvol"); + return -1; + } + + if (ubi_rsvol(libubi, node, vol_info->vol_id, + vol_info->eb_size * dev_info.avail_ebs)) { + failed("ubi_rsvol"); + return -1; + } + + fd = open(vol_node, O_RDWR); + if (fd == -1) { + failed("open"); + err_msg("cannot open \"%s\"\n", vol_node); + return -1; + } + + /* Read data back */ + if (lseek(fd, 0, SEEK_SET) != 0) { + failed("seek"); + goto close; + } + memset(&buf[0], 0, bytes); + ret = read(fd, &buf[0], bytes); + if (ret != bytes) { + failed("read"); + goto close; + } + + for (i = 0; i < bytes; i++) { + if (buf[i] != (unsigned char)i) { + err_msg("bad data"); + goto close; + } + } + + close(fd); + return 0; + +close: + close(fd); + return -1; +} diff --git a/tests/ubi-tests/runtests.sh b/tests/ubi-tests/runtests.sh new file mode 100755 index 0000000..7072e03 --- /dev/null +++ b/tests/ubi-tests/runtests.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +ubidev="$1" +tests="mkvol_basic mkvol_bad mkvol_paral rsvol io_basic io_read io_update +io_paral rmvol" + +if test -z "$ubidev"; +then + echo "Usage:" + echo "$0 " + exit 1 +fi + +ubiname=`echo $ubidev | cut -d/ -f3` + +major=`cat /sys/class/ubi/$ubiname/dev | cut -d: -f1` + +for minor in `seq 0 4`; do + if test ! -e ${ubidev}_${minor} ; + then + mknod ${ubidev}_${minor} c $major $(($minor + 1)) + fi +done + +if ! test -c "$ubidev"; +then + echo "Error: $ubidev is not character device" + exit 1 +fi + +for t in `echo $tests`; +do + echo "Running $t $ubidev" + "./$t" "$ubidev" || exit 1 +done + +echo SUCCESS + +exit 0 diff --git a/ubi-utils/tests/Makefile b/ubi-utils/tests/Makefile deleted file mode 100644 index ca0069d..0000000 --- a/ubi-utils/tests/Makefile +++ /dev/null @@ -1,41 +0,0 @@ - -INCLUDE1=../inc -INCLUDE2=../../include -LIB=. - -CC := $(CROSS)gcc - -ALL_FILES=libubi io_update rmvol integ -ALL_FILES+=io_paral io_read io_basic mkvol_basic mkvol_bad mkvol_paral rsvol - -CFLAGS += -Wall -I$(INCLUDE1) -I$(INCLUDE2) -L$(LIB) -ggdb - -all: $(ALL_FILES) - -libubi: ../src/libubi.c ../inc/libubi.h ../src/libubi_int.h - $(CC) $(CFLAGS) -DUDEV_SETTLE_HACK -c ../src/libubi.c -o libubi.o - ar cr libubi.a libubi.o - -io_paral: io_paral.c common.c - $(CC) $(CFLAGS) $^ -lubi -lpthread -o $@ -io_update: io_update.c common.c - $(CC) $(CFLAGS) $^ -lubi -o $@ -io_read: io_read.c common.c - $(CC) $(CFLAGS) $^ -lubi -o $@ -io_basic: io_basic.c common.c - $(CC) $(CFLAGS) $^ -lubi -o $@ -mkvol_basic: mkvol_basic.c common.c - $(CC) $(CFLAGS) $^ -lubi -o $@ -mkvol_bad: mkvol_bad.c common.c - $(CC) $(CFLAGS) $^ -lubi -o $@ -mkvol_paral: mkvol_paral.c common.c - $(CC) $(CFLAGS) $^ -lubi -lpthread -o $@ -rsvol: rsvol.c common.c - $(CC) $(CFLAGS) $^ -lubi -o $@ -rmvol: rmvol.c common.c - $(CC) $(CFLAGS) $^ -lubi -o $@ -integ: integ.c - $(CC) $(CFLAGS) $^ -lubi -o $@ - -clean: - rm -rf $(ALL_FILES) $(addsuffix .o, $(ALL_FILES)) diff --git a/ubi-utils/tests/README.udev b/ubi-utils/tests/README.udev deleted file mode 100644 index 06e71d3..0000000 --- a/ubi-utils/tests/README.udev +++ /dev/null @@ -1,25 +0,0 @@ -There is a problem with udev: when a volume is created, there is a delay -before corresponding /dev/ubiX_Y device node is created by udev, so some -tests fail because of this. The symptom is error messages like -"cannot open /dev/ubi0_0". - -One possible solution of this problem is to pre-create UBI device and volume -nodes. There is even a script which may be used for this in ubi-utils/scripts/. -But this is not enough because udev will still remove and re-create the nodes -and tests will still fail. So you need to stop removing device nodes using -the following udev rule: - - KERNEL=="ubi*_*", ACTION=="remove", OPTIONS+="ignore_device" - -In our Ubuntu distribution we put that to new file: -/etc/udev/rules.d/50-local.rules - -Another possibility is to call udevsettle utility in libubi after the volume -has been created See src/libubi.c - the call is compiled in only if -UDEV_SETTLE_HACK is defined. This is anyway an ugly hack, but works, although -makes the tests slower. Suggestions are welcome. - -So, if you have udevsettel unility in your system, you do not have to do -anyting, and the tests should work, because we compile libubi with -UDEV_SETTLE_HACK. Otherwise, you should remove -D UDEV_SETTLE_HACK -from the makefile and pre-create UBI device nodes. diff --git a/ubi-utils/tests/common.c b/ubi-utils/tests/common.c deleted file mode 100644 index cb63e77..0000000 --- a/ubi-utils/tests/common.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Artem B. Bityutskiy - * - * The stuff which is common for many tests. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "libubi.h" -#include "common.h" - -/** - * __initial_check - check that common prerequisites which are required to run - * tests. - * - * @test test name - * @argc count of command-line arguments - * @argv command-line arguments - * - * This function returns %0 if all is fine and test may be run and %-1 if not. - */ -int __initial_check(const char *test, int argc, char * const argv[]) -{ - libubi_t libubi; - struct ubi_dev_info dev_info; - - /* - * All tests require UBI character device name as the first parameter, - * check this. - */ - if (argc < 2) { - __err_msg(test, __FUNCTION__, __LINE__, - "UBI character device node is not specified"); - return -1; - } - - libubi = libubi_open(); - if (libubi == NULL) { - __failed(test, __FUNCTION__, __LINE__, "libubi_open"); - return -1; - } - - if (ubi_get_dev_info(libubi, argv[1], &dev_info)) { - __failed(test, __FUNCTION__, __LINE__, "ubi_get_dev_info"); - goto close; - } - - if (dev_info.avail_ebs < MIN_AVAIL_EBS) { - __err_msg(test, __FUNCTION__, __LINE__, - "insufficient available eraseblocks %d on UBI " - "device, required %d", - dev_info.avail_ebs, MIN_AVAIL_EBS); - goto close; - } - - if (dev_info.vol_count != 0) { - __err_msg(test, __FUNCTION__, __LINE__, - "device %s is not empty", argv[1]); - goto close; - } - - libubi_close(libubi); - return 0; - -close: - libubi_close(libubi); - return -1; -} - -/** - * __err_msg - print a message to stderr. - * - * @test test name - * @func function name - * @line line number - * @fmt format string - */ -void __err_msg(const char *test, const char *func, int line, - const char *fmt, ...) -{ - va_list args; - - fprintf(stderr, "[%s] %s():%d: ", test, func, line); - va_start(args, fmt); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - va_end(args); -} - -/** - * __failed - print function fail message. - * - * @test test name - * @func calling function name - * @line line number - * @failed failed function name - */ -void __failed(const char *test, const char *func, int line, - const char *failed) -{ - fprintf(stderr, "[%s] %s():%d: function %s() failed with error %d (%s)\n", - test, func, line, failed, errno, strerror(errno)); -} - -/** - * __check_volume - check volume information. - * - * @libubi libubi descriptor - * @dev_info UBI device description - * @test test name - * @func function name - * @line line number - * @vol_id ID of existing volume to check - * @req volume creation request to compare with - * - * This function checks if a volume created using @req request has exactly the - * requested characteristics. Returns 0 in case of success and %-1 in case of - * error. - */ -int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info, - const char *test, const char *func, int line, int vol_id, - const struct ubi_mkvol_request *req) -{ - int ret; - struct ubi_vol_info vol_info; - int eb_size; - long long rsvd_bytes; - - ret = ubi_get_vol_info1(libubi, dev_info->dev_num, vol_id, &vol_info); - if (ret) { - __failed(test, func, line, "ubi_get_vol_info"); - return -1; - } - - if (req->alignment != vol_info.alignment) { - __err_msg(test, func, line, - "bad alignment: requested %d, got %d", - req->alignment, vol_info.alignment); - return -1; - } - if (req->vol_type != vol_info.type) { - __err_msg(test, func, line, "bad type: requested %d, got %d", - req->vol_type, vol_info.type); - return -1; - } - if (strlen(req->name) != strlen(&vol_info.name[0]) || - strcmp(req->name, &vol_info.name[0]) != 0) { - __err_msg(test, func, line, - "bad name: requested \"%s\", got \"%s\"", - req->name, &vol_info.name[0]); - return -1; - } - if (vol_info.corrupted) { - __err_msg(test, func, line, "corrupted new volume"); - return -1; - } - - eb_size = dev_info->eb_size - (dev_info->eb_size % req->alignment); - if (eb_size != vol_info.eb_size) { - __err_msg(test, func, line, - "bad usable LEB size %d, should be %d", - vol_info.eb_size, eb_size); - return -1; - } - - rsvd_bytes = req->bytes; - if (rsvd_bytes % eb_size) - rsvd_bytes += eb_size - (rsvd_bytes % eb_size); - - if (rsvd_bytes != vol_info.rsvd_bytes) { - __err_msg(test, func, line, - "bad reserved bytes %lld, should be %lld", - vol_info.rsvd_bytes, rsvd_bytes); - return -1; - } - - return 0; -} - -/** - * __check_vol_patt - check that volume contains certain data - * - * @libubi libubi descriptor - * @dev_info UBI device description - * @test test name - * @func function name - * @line line number - * @node volume character device node - * @byte data pattern to check - * - * This function returns %0 if the volume contains only @byte bytes, and %-1 if - * not. - */ -int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info, - const char *test, const char *func, int line, - const char *node, uint8_t byte) -{ - int ret, fd; - long long bytes = 0; - struct ubi_vol_info vol_info; - unsigned char buf[512]; - - fd = open(node, O_RDONLY); - if (fd == -1) { - __failed(test, func, line, "open"); - __err_msg(test, func, line, "cannot open \"%s\"\n", node); - return -1; - } - - ret = ubi_get_vol_info(libubi, node, &vol_info); - if (ret) { - __failed(test, func, line, "ubi_get_vol_info"); - goto close; - } - - while (bytes < vol_info.data_bytes) { - int i; - - memset(&buf[0], ~byte, 512); - ret = read(fd, &buf[0], 512); - if (ret == -1) { - __failed(test, func, line, "read"); - __err_msg(test, func, line, "bytes = %lld, ret = %d", - bytes, ret); - goto close; - } - - if (ret == 0 && bytes + ret < vol_info.data_bytes) { - __err_msg(test, func, line, - "EOF, but read only %lld bytes of %lld", - bytes + ret, vol_info.data_bytes); - goto close; - } - - for (i = 0; i < ret; i++) - if (buf[i] != byte) { - __err_msg(test, func, line, - "byte at %lld is not %#x but %#x", - bytes + i, byte, (int)buf[i]); - goto close; - } - - bytes += ret; - } - - close(fd); - return 0; - -close: - close(fd); - return -1; -} - -/** - * __update_vol_patt - update volume using a certain byte pattern - * - * @libubi libubi descriptor - * @dev_info UBI device description - * @test test name - * @func function name - * @line line number - * @node volume character device node - * @byte data pattern to check - * - * This function returns %0 in case of success, and %-1 if in case of failure. - */ -int __update_vol_patt(libubi_t libubi, const char *test, const char *func, - int line, const char *node, long long bytes, uint8_t byte) -{ - int ret, fd; - long long written = 0; - unsigned char buf[512]; - - fd = open(node, O_RDWR); - if (fd == -1) { - __failed(test, func, line, "open"); - __err_msg(test, func, line, "cannot open \"%s\"\n", node); - return -1; - } - - if (ubi_update_start(libubi, fd, bytes)) { - __failed(test, func, line, "ubi_update_start"); - __err_msg(test, func, line, "bytes = %lld", bytes); - goto close; - } - - memset(&buf[0], byte, 512); - - while (written != bytes) { - ret = write(fd, &buf[0], 512); - if (ret == -1) { - __failed(test, func, line, "write"); - __err_msg(test, func, line, "written = %lld, ret = %d", - written, ret); - goto close; - } - written += ret; - - if (written > bytes) { - __err_msg(test, func, line, "update length %lld bytes, " - "but %lld bytes are already written", - bytes, written); - goto close; - } - } - - close(fd); - return 0; - -close: - close(fd); - return -1; -} diff --git a/ubi-utils/tests/common.h b/ubi-utils/tests/common.h deleted file mode 100644 index 3e8ada8..0000000 --- a/ubi-utils/tests/common.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Artem B. Bityutskiy - * - * The stuff which is common for many tests. - */ - -#ifndef __COMMON_H__ -#define __COMMON_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define UBI_VOLUME_PATTERN "/dev/ubi%d_%d" -#define MIN_AVAIL_EBS 5 -#define PAGE_SIZE 4096 - -#define min(a, b) ((a) < (b) ? (a) : (b)) - -#define err_msg(fmt, ...) \ - __err_msg(TESTNAME, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__) - -#define failed(name) \ - __failed(TESTNAME, __FUNCTION__, __LINE__, name) - -#define initial_check(argc, argv) \ - __initial_check(TESTNAME, argc, argv) - -#define check_volume(vol_id, req) \ - __check_volume(libubi, &dev_info, TESTNAME, __FUNCTION__, \ - __LINE__, vol_id, req) - -#define check_vol_patt(node, byte) \ - __check_vol_patt(libubi, &dev_info, TESTNAME, __FUNCTION__, __LINE__, \ - node, byte) - -#define update_vol_patt(node, bytes, byte) \ - __update_vol_patt(libubi, TESTNAME, __FUNCTION__, __LINE__, \ - node, bytes, byte) - -#define check_failed(ret, error, func, fmt, ...) ({ \ - int __ret; \ - \ - if (!ret) { \ - err_msg("%s() returned success but should have failed", func); \ - err_msg(fmt, ##__VA_ARGS__); \ - __ret = -1; \ - } \ - if (errno != (error)) { \ - err_msg("%s failed with error %d (%s), expected %d (%s)", \ - func, errno, strerror(errno), error, strerror(error)); \ - err_msg(fmt, ##__VA_ARGS__); \ - __ret = -1; \ - } \ - __ret = 0; \ -}) - -/* Alignments to test, @s is eraseblock size */ -#define ALIGNMENTS(s) \ - {3, 5, 27, 666, 512, 1024, 2048, (s)/2-3, (s)/2-2, (s)/2-1, (s)/2+1, \ - (s)/2+2, (s)/2+3, (s)/3-3, (s)/3-2, (s)/3-1, (s)/3+1, (s)/3+2, \ - (s)/3+3, (s)/4-3, (s)/4-2, (s)/4-1, (s)/4+1, (s)/4+2, (s)/4+3, \ - (s)/5-3, (s)/5-2, (s)/5-1, (s)/5+1, (s)/5+2, (s)/5+3, (s)-17, (s)-9, \ - (s)-8, (s)-6, (s)-4, (s)-1, (s)}; - -extern void __err_msg(const char *test, const char *func, int line, - const char *fmt, ...); -void __failed(const char *test, const char *func, int line, - const char *failed); -int __initial_check(const char *test, int argc, char * const argv[]); -int __check_volume(libubi_t libubi, struct ubi_dev_info *dev_info, - const char *test, const char *func, int line, int vol_id, - const struct ubi_mkvol_request *req); -int __check_vol_patt(libubi_t libubi, struct ubi_dev_info *dev_info, - const char *test, const char *func, int line, - const char *node, uint8_t byte); -int __update_vol_patt(libubi_t libubi, const char *test, const char *func, - int line, const char *node, long long bytes, - uint8_t byte); - -#ifdef __cplusplus -} -#endif - -#endif /* !__COMMON_H__ */ diff --git a/ubi-utils/tests/integ.c b/ubi-utils/tests/integ.c deleted file mode 100644 index 4da7121..0000000 --- a/ubi-utils/tests/integ.c +++ /dev/null @@ -1,783 +0,0 @@ -#define _LARGEFILE64_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "libubi.h" - -struct erase_block_info; -struct volume_info; -struct ubi_device_info; - -struct write_info -{ - struct write_info *next; - struct erase_block_info *erase_block; - int offset_within_block; /* Offset within erase block */ - off64_t offset; /* Offset within volume */ - int size; - int random_seed; -}; - -struct erase_block_info -{ - struct volume_info *volume; - int block_number; - off64_t offset; /* Offset within volume */ - off64_t top_of_data; - int touched; /* Have we done anything at all with this erase block */ - int erased; /* This erased block is currently erased */ - struct write_info *writes; -}; - -struct volume_fd -{ - struct volume_fd *next; - struct volume_info *volume; - int fd; -}; - -struct volume_info -{ - struct volume_info *next; - struct ubi_device_info *ubi_device; - struct volume_fd *fds; - struct erase_block_info *erase_blocks; - const char *device_file_name; - struct ubi_vol_info info; -}; - -struct ubi_device_info -{ - struct volume_info *volumes; - const char *device_file_name; - struct ubi_dev_info info; -}; - -struct open_volume_fd -{ - struct open_volume_fd *next; - struct volume_fd *vol_fd; -}; - -#define MAX_UBI_DEVICES 64 - -static libubi_t libubi; - -static struct ubi_info info; -static struct ubi_device_info ubi_array[MAX_UBI_DEVICES]; - -static uint64_t total_written = 0; -static uint64_t total_space = 0; - -static struct open_volume_fd *open_volumes; -static size_t open_volume_count = 0; - -static const char *ubi_module_load_string; - -static unsigned char *write_buffer = NULL; -static unsigned char *read_buffer = NULL; - -static long long max_ebs_per_vol = 0; /* max number of ebs per vol (zero => no max) */ - -static unsigned long next_seed = 1; - -static unsigned get_next_seed() -{ - next_seed = next_seed * 1103515245 + 12345; - return ((unsigned) (next_seed / 65536) % 32768); -} - -static void error_exit(const char *msg) -{ - int eno = errno; - fprintf(stderr,"UBI Integrity Test Error: %s\n",msg); - if (eno) { - fprintf(stderr, "errno = %d\n", eno); - fprintf(stderr, "strerror = %s\n", strerror(eno)); - } - exit(1); -} - -static void *allocate(size_t n) -{ - void *p = malloc(n); - if (!p) - error_exit("Memory allocation failure"); - memset(p, 0, n); - return p; -} - -static unsigned get_random_number(unsigned n) -{ - uint64_t r, b; - - if (n < 1) - return 0; - r = rand(); - r *= n; - b = RAND_MAX; - b += 1; - r /= b; - return r; -} - -static struct volume_fd *open_volume(struct volume_info *vol) -{ - struct volume_fd *s; - struct open_volume_fd *ofd; - int fd; - - if (vol->fds) { - /* If already open dup it */ - fd = dup(vol->fds->fd); - if (fd == -1) - error_exit("Failed to dup volume device file des"); - } else { - fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE); - if (fd == -1) - error_exit("Failed to open volume device file"); - } - s = allocate(sizeof(*s)); - s->fd = fd; - s->volume = vol; - s->next = vol->fds; - vol->fds = s; - /* Add to open volumes list */ - ofd = allocate(sizeof(*ofd)); - ofd->vol_fd = s; - ofd->next = open_volumes; - open_volumes = ofd; - open_volume_count += 1; - return 0; -} - -static void close_volume(struct volume_fd *vol_fd) -{ - struct volume_fd *vfd, *vfd_last; - struct open_volume_fd *ofd, *ofd_last; - int fd = vol_fd->fd; - - /* Remove from open volumes list */ - ofd_last = NULL; - ofd = open_volumes; - while (ofd) { - if (ofd->vol_fd == vol_fd) { - if (ofd_last) - ofd_last->next = ofd->next; - else - open_volumes = ofd->next; - free(ofd); - open_volume_count -= 1; - break; - } - ofd_last = ofd; - ofd = ofd->next; - } - /* Remove from volume fd list */ - vfd_last = NULL; - vfd = vol_fd->volume->fds; - while (vfd) { - if (vfd == vol_fd) { - if (vfd_last) - vfd_last->next = vfd->next; - else - vol_fd->volume->fds = vfd->next; - free(vfd); - break; - } - vfd_last = vfd; - vfd = vfd->next; - } - /* Close volume device file */ - if (close(fd) == -1) - error_exit("Failed to close volume file descriptor"); -} - -static void set_random_data(unsigned seed, unsigned char *buf, int size) -{ - int i; - unsigned r; - - r = rand(); - srand(seed); - for (i = 0; i < size; ++i) - buf[i] = rand(); - srand(r); -} - -#if 0 -static void print_write_info(struct write_info *w) -{ - printf("Offset: %lld Size:%d Seed:%u\n", w->offset, w->size, w->random_seed); - fflush(stdout); -} -#endif - -static void check_erase_block(struct erase_block_info *erase_block, int fd) -{ - struct write_info *w; - off64_t gap_end; - int eb_size = erase_block->volume->info.eb_size; - ssize_t bytes_read; - - w = erase_block->writes; - gap_end = erase_block->offset + eb_size; - while (w) { - if (w->offset + w->size < gap_end) { - /* There is a gap. Check all 0xff */ - off64_t gap_start = w->offset + w->size; - size_t size = gap_end - gap_start; - if (lseek64(fd, gap_start, SEEK_SET) != gap_start) - error_exit("lseek64 failed"); - memset(read_buffer, 0 , size); - errno = 0; - bytes_read = read(fd, read_buffer, size); - if (bytes_read != size) - error_exit("read failed in gap"); - while (size) - if (read_buffer[--size] != 0xff) { - fprintf(stderr, "block no. = %d\n" , erase_block->block_number); - fprintf(stderr, "offset = %lld\n" , (long long) gap_start); - fprintf(stderr, "size = %ld\n" , (long) bytes_read); - error_exit("verify 0xff failed"); - } - } - if (lseek64(fd, w->offset, SEEK_SET) != w->offset) - error_exit("lseek64 failed"); - memset(read_buffer, 0 , w->size); - errno = 0; - bytes_read = read(fd, read_buffer, w->size); - if (bytes_read != w->size) { - fprintf(stderr, "offset = %lld\n" , (long long) w->offset); - fprintf(stderr, "size = %ld\n" , (long) w->size); - fprintf(stderr, "bytes_read = %ld\n" , (long) bytes_read); - error_exit("read failed"); - } - set_random_data(w->random_seed, write_buffer, w->size); - if (memcmp(read_buffer, write_buffer, w->size)) - error_exit("verify failed"); - gap_end = w->offset; - w = w->next; - } - if (gap_end > erase_block->offset) { - /* Check all 0xff */ - off64_t gap_start = erase_block->offset; - size_t size = gap_end - gap_start; - if (lseek64(fd, gap_start, SEEK_SET) != gap_start) - error_exit("lseek64 failed"); - memset(read_buffer, 0 , size); - errno = 0; - bytes_read = read(fd, read_buffer, size); - if (bytes_read != size) - error_exit("read failed in gap"); - while (size) - if (read_buffer[--size] != 0xff) { - fprintf(stderr, "block no. = %d\n" , erase_block->block_number); - fprintf(stderr, "offset = %lld\n" , (long long) gap_start); - fprintf(stderr, "size = %ld\n" , (long) bytes_read); - error_exit("verify 0xff failed!"); - } - } -} - -static int write_to_erase_block(struct erase_block_info *erase_block, int fd) -{ - int page_size = erase_block->volume->ubi_device->info.min_io_size; - int eb_size = erase_block->volume->info.eb_size; - int next_offset = 0; - int space, size; - off64_t offset; - unsigned seed; - struct write_info *w; - - if (erase_block->writes) - next_offset = erase_block->writes->offset_within_block + erase_block->writes->size; - space = eb_size - next_offset; - if (space <= 0) - return 0; /* No space */ - if (!get_random_number(10)) { - /* 1 time in 10 leave a gap */ - next_offset += get_random_number(space); - next_offset = (next_offset / page_size) * page_size; - space = eb_size - next_offset; - } - if (get_random_number(2)) - size = 1 * page_size; - else if (get_random_number(2)) - size = 2 * page_size; - else if (get_random_number(2)) - size = 3 * page_size; - else if (get_random_number(2)) - size = 4 * page_size; - else { - if (get_random_number(4)) - size = get_random_number(space); - else - size = space; - size = (size / page_size) * page_size; - } - if (size == 0 || size > space) - size = page_size; - if (next_offset + size > eb_size) - error_exit("internal error"); - offset = erase_block->offset + next_offset; - if (offset < erase_block->top_of_data) - error_exit("internal error!"); - if (lseek64(fd, offset, SEEK_SET) != offset) - error_exit("lseek64 failed"); - /* Do write */ - seed = get_next_seed(); - if (!seed) - seed = 1; - set_random_data(seed, write_buffer, size); - if (write(fd, write_buffer, size) != size) - error_exit("write failed"); - erase_block->top_of_data = offset + size; - /* Make write info and add to eb */ - w = allocate(sizeof(*w)); - w->offset_within_block = next_offset; - w->offset = offset; - w->size = size; - w->random_seed = seed; - w->next = erase_block->writes; - erase_block->writes = w; - erase_block->touched = 1; - erase_block->erased = 0; - total_written += size; - return 1; -} - -static void erase_erase_block(struct erase_block_info *erase_block, int fd) -{ - struct write_info *w; - uint32_t eb_no; - int res; - - eb_no = erase_block->block_number; - res = ioctl(fd, UBI_IOCEBER, &eb_no); - if (res) - error_exit("Failed to erase an erase block"); - /* Remove writes from this eb */ - while (erase_block->writes) { - w = erase_block->writes; - erase_block->writes = erase_block->writes->next; - free(w); - } - erase_block->erased = 1; - erase_block->touched = 1; - erase_block->top_of_data = erase_block->offset; -} - -static void operate_on_erase_block(struct erase_block_info *erase_block, int fd) -{ - /* - Possible operations: - read from it and verify - write to it - erase it - */ - int work_done = 1; - static int no_work_done_count = 0; - - if (!get_random_number(10) && no_work_done_count <= 5) { - check_erase_block(erase_block, fd); - work_done = 0; - } else if (get_random_number(100)) { - if (!write_to_erase_block(erase_block, fd)) { - /* The erase block was full */ - if (get_random_number(2) || no_work_done_count > 5) - erase_erase_block(erase_block, fd); - else - work_done = 0; - } - } else - erase_erase_block(erase_block, fd); - if (work_done) - no_work_done_count = 0; - else - no_work_done_count += 1; -} - -static void operate_on_open_volume(struct volume_fd *vol_fd) -{ - /* - Possible operations: - operate on an erase block - close volume - */ - if (get_random_number(100) == 0) - close_volume(vol_fd); - else { - /* Pick an erase block at random */ - int eb_no = get_random_number(vol_fd->volume->info.rsvd_ebs); - operate_on_erase_block(&vol_fd->volume->erase_blocks[eb_no], vol_fd->fd); - } -} - -static void operate_on_volume(struct volume_info *vol) -{ - /* - Possible operations: - open it - resize it (must close fd's first) <- TODO - delete it (must close fd's first) <- TODO - */ - open_volume(vol); -} - -static int ubi_major(const char *device_file_name) -{ - struct stat buf; - static int maj = 0; - - if (maj) - return maj; - if (stat(device_file_name, &buf) == -1) - error_exit("Failed to stat ubi device file"); - maj = major(buf.st_rdev); - return maj; -} - -static void operate_on_ubi_device(struct ubi_device_info *ubi_device) -{ - /* - TODO: - Possible operations: - create a new volume - operate on existing volume - */ - /* - Simplified operation (i.e. only have 1 volume): - If there are no volumes create 1 volumne - Then operate on the volume - */ - if (ubi_device->info.vol_count == 0) { - /* Create the one-and-only volume we will use */ - char dev_name[1024]; - int i, n, maj, fd; - struct volume_info *s; - struct ubi_mkvol_request req; - - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; /* TODO: What is this? */ - req.bytes = ubi_device->info.eb_size * max_ebs_per_vol; - if (req.bytes == 0 || req.bytes > ubi_device->info.avail_bytes) - req.bytes = ubi_device->info.avail_bytes; - req.vol_type = UBI_DYNAMIC_VOLUME; - req.name = "integ-test-vol"; - if (ubi_mkvol(libubi, ubi_device->device_file_name, &req)) - error_exit("ubi_mkvol failed"); - s = allocate(sizeof(*s)); - s->ubi_device = ubi_device; - if (ubi_get_vol_info1(libubi, ubi_device->info.dev_num, req.vol_id, &s->info)) - error_exit("ubi_get_vol_info failed"); - n = s->info.rsvd_ebs; - s->erase_blocks = allocate(sizeof(struct erase_block_info) * n); - for (i = 0; i < n; ++i) { - s->erase_blocks[i].volume = s; - s->erase_blocks[i].block_number = i; - s->erase_blocks[i].offset = i * (off64_t) s->info.eb_size; - s->erase_blocks[i].top_of_data = s->erase_blocks[i].offset; - } - /* FIXME: Correctly get device file name */ - sprintf(dev_name, "%s_%d", ubi_device->device_file_name, req.vol_id); - s->device_file_name = strdup(dev_name); - ubi_device->volumes = s; - ubi_device->info.vol_count += 1; - sleep(1); - fd = open(s->device_file_name, O_RDONLY); - if (fd == -1) { - /* FIXME: Correctly make node */ - maj = ubi_major(ubi_device->device_file_name); - sprintf(dev_name, "mknod %s c %d %d", s->device_file_name, maj, req.vol_id + 1); - system(dev_name); - } else if (close(fd) == -1) - error_exit("Failed to close volume device file"); - } - operate_on_volume(ubi_device->volumes); -} - -static void do_an_operation(void) -{ - int too_few = (open_volume_count < info.dev_count * 3); - int too_many = (open_volume_count > info.dev_count * 5); - - if (too_many || (!too_few && get_random_number(1000) > 0)) { - /* Operate on an open volume */ - size_t pos; - struct open_volume_fd *ofd; - pos = get_random_number(open_volume_count); - for (ofd = open_volumes; pos && ofd && ofd->next; --pos) - ofd = ofd->next; - operate_on_open_volume(ofd->vol_fd); - } else if (info.dev_count > 0) { - /* Operate on a ubi device */ - size_t ubi_pos = 0; - if (info.dev_count > 1) - ubi_pos = get_random_number(info.dev_count - 1); - operate_on_ubi_device(&ubi_array[ubi_pos]); - } else - error_exit("Internal error"); -} - -static void get_ubi_devices_info(void) -{ - int i, ubi_pos = 0; - char dev_name[1024]; - size_t buf_size = 1024 * 128; - - if (ubi_get_info(libubi, &info)) - error_exit("ubi_get_info failed"); - if (info.dev_count > MAX_UBI_DEVICES) - error_exit("Too many ubi devices"); - for (i = info.lowest_dev_num; i <= info.highest_dev_num; ++i) { - struct ubi_device_info *s; - s = &ubi_array[ubi_pos++]; - if (ubi_get_dev_info1(libubi, i, &s->info)) - error_exit("ubi_get_dev_info1 failed"); - if (s->info.vol_count) - error_exit("There are existing volumes"); - /* FIXME: Correctly get device file name */ - sprintf(dev_name, "/dev/ubi%d", i); - s->device_file_name = strdup(dev_name); - if (buf_size < s->info.eb_size) - buf_size = s->info.eb_size; - if (max_ebs_per_vol && s->info.eb_size * max_ebs_per_vol < s->info.avail_bytes) - total_space += s->info.eb_size * max_ebs_per_vol; - else - total_space += s->info.avail_bytes; - } - write_buffer = allocate(buf_size); - read_buffer = allocate(buf_size); -} - -static void load_ubi(void) -{ - system("rmmod ubi"); - if (system(ubi_module_load_string) != 0) - error_exit("Failed to load UBI module"); - sleep(1); -} - -static void do_some_operations(void) -{ - unsigned i = 0; - total_written = 0; - printf("Total space: %llu\n", (unsigned long long) total_space); - while (total_written < total_space * 3) { - do_an_operation(); - if (i++ % 10000 == 0) - printf("Total written: %llu\n", (unsigned long long) total_written); - } - printf("Total written: %llu\n", (unsigned long long) total_written); -} - -static void reload_ubi(void) -{ - /* Remove module */ - if (system("rmmod ubi") != 0) - error_exit("Failed to remove UBI module"); - /* Install module */ - if (system(ubi_module_load_string) != 0) - error_exit("Failed to load UBI module"); - sleep(1); -} - -static void check_volume(struct volume_info *vol) -{ - struct erase_block_info *eb = vol->erase_blocks; - int pos; - int fd; - - fd = open(vol->device_file_name, O_RDWR | O_LARGEFILE); - if (fd == -1) - error_exit("Failed to open volume device file"); - for (pos = 0; pos < vol->info.rsvd_ebs; ++pos) - check_erase_block(eb++, fd); - if (close(fd) == -1) - error_exit("Failed to close volume device file"); -} - -static void check_ubi_device(struct ubi_device_info *ubi_device) -{ - struct volume_info *vol; - - vol = ubi_device->volumes; - while (vol) { - check_volume(vol); - vol = vol->next; - } -} - -static void check_ubi(void) -{ - int i; - - for (i = 0; i < info.dev_count; ++i) - check_ubi_device(&ubi_array[i]); -} - -static int is_all_digits(const char *s) -{ - const char *digits = "0123456789"; - if (!s || !*s) - return 0; - for (;*s;++s) - if (!strchr(digits,*s)) - return 0; - return 1; -} - -static int get_short_arg(int *pos,const char *name,long long *result,int argc,char *argv[]) -{ - const char *p = NULL; - int i = *pos; - size_t n = strlen(name); - - if (strlen(argv[i]) > n) - p = argv[i] + n; - else if (++i < argc) - p = argv[i]; - if (!is_all_digits(p)) - return 1; - *result = atoll(p); - *pos = i; - return 0; -} - -static int get_long_arg(int *pos,const char *name,long long *result,int argc,char *argv[]) -{ - const char *p = NULL; - int i = *pos; - size_t n = strlen(name); - - if (strlen(argv[i]) > n) - p = argv[i] + n; - else if (++i < argc) - p = argv[i]; - if (p && *p == '=') { - p += 1; - if (!*p && ++i < argc) - p = argv[i]; - } - if (!is_all_digits(p)) - return 1; - *result = atoll(p); - *pos = i; - return 0; -} - -static int remove_all_volumes(void) -{ - int i; - - for (i = 0; i < info.dev_count; ++i) { - struct ubi_device_info *ubi_device = &ubi_array[i]; - struct volume_info *vol; - vol = ubi_device->volumes; - while (vol) { - int res = ubi_rmvol(libubi, - ubi_device->device_file_name, - vol->info.vol_id); - if (res) - return res; - vol = vol->next; - } - } - return 0; -} - -int main(int argc,char *argv[]) -{ - int i; - long long r, repeat = 1; - int initial_seed = 1, args_ok = 1; - - printf("UBI Integrity Test\n"); - - /* Get arguments */ - ubi_module_load_string = 0; - for (i = 1; i < argc; ++i) { - if (strncmp(argv[i], "-h", 2) == 0) - args_ok = 0; - else if (strncmp(argv[i], "--help", 6) == 0) - args_ok = 0; - else if (strncmp(argv[i], "-n", 2) == 0) { - if (get_short_arg(&i, "-n", &repeat, argc, argv)) - args_ok = 0; - } else if (strncmp(argv[i], "--repeat", 8) == 0) { - if (get_long_arg(&i, "--repeat", &repeat, argc, argv)) - args_ok = 0; - } else if (strncmp(argv[i], "-m", 2) == 0) { - if (get_short_arg(&i,"-m", &max_ebs_per_vol, argc, argv)) - args_ok = 0; - } else if (strncmp(argv[i], "--maxebs", 8) == 0) { - if (get_long_arg(&i, "--maxebs", &max_ebs_per_vol, argc, argv)) - args_ok = 0; - } else if (!ubi_module_load_string) - ubi_module_load_string = argv[i]; - else - args_ok = 0; - } - if (!args_ok || !ubi_module_load_string) { - fprintf(stderr, "Usage is: ubi_integ [] \n"); - fprintf(stderr, " Options: \n"); - fprintf(stderr, " -h, --help Help\n"); - fprintf(stderr, " -n arg, --repeat=arg Repeat test arg times\n"); - fprintf(stderr, " -m arg, --maxebs=arg Max no. of erase blocks\n"); - return 1; - } - - initial_seed = getpid(); - printf("Initial seed = %u\n", (unsigned) initial_seed); - next_seed = initial_seed; - srand(initial_seed); - load_ubi(); - - libubi = libubi_open(); - if (!libubi) - error_exit("Failed to open libubi"); - - get_ubi_devices_info(); - - r = 0; - while (repeat == 0 || r++ < repeat) { - printf("Cycle %lld\n", r); - do_some_operations(); - - /* Close all volumes */ - while (open_volumes) - close_volume(open_volumes->vol_fd); - - check_ubi(); - - libubi_close(libubi); - - reload_ubi(); - - libubi = libubi_open(); - if (!libubi) - error_exit("Failed to open libubi"); - - check_ubi(); - } - - if (remove_all_volumes()) - error_exit("Failed to remove all volumes"); - - libubi_close(libubi); - - printf("UBI Integrity Test completed ok\n"); - return 0; -} diff --git a/ubi-utils/tests/io_basic.c b/ubi-utils/tests/io_basic.c deleted file mode 100644 index 2e8809a..0000000 --- a/ubi-utils/tests/io_basic.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Artem B. Bityutskiy - * - * Test basic UBI volume I/O capabilities. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "libubi.h" -#define TESTNAME "io_basic" -#include "common.h" - -static libubi_t libubi; -static struct ubi_dev_info dev_info; -const char *node; - -static int test_basic(int type); -static int test_aligned(int type); - -int main(int argc, char * const argv[]) -{ - if (initial_check(argc, argv)) - return 1; - - node = argv[1]; - - libubi = libubi_open(); - if (libubi == NULL) { - failed("libubi_open"); - return 1; - } - - if (ubi_get_dev_info(libubi, node, &dev_info)) { - failed("ubi_get_dev_info"); - goto close; - } - - if (test_basic(UBI_DYNAMIC_VOLUME)) - goto close; - if (test_basic(UBI_STATIC_VOLUME)) - goto close; - if (test_aligned(UBI_DYNAMIC_VOLUME)) - goto close; - if (test_aligned(UBI_STATIC_VOLUME)) - goto close; - - libubi_close(libubi); - return 0; - -close: - libubi_close(libubi); - return 1; -} - -/** - * test_basic - check basic volume read and update capabilities. - * - * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) - * - * Thus function returns %0 in case of success and %-1 in case of failure. - */ -static int test_basic(int type) -{ - struct ubi_mkvol_request req; - const char *name = TESTNAME ":test_basic()"; - char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; - - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; - req.bytes = dev_info.avail_bytes; - req.vol_type = type; - req.name = name; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); - - /* Make sure newly created volume contains only 0xFF bytes */ - if (check_vol_patt(&vol_node[0], 0xFF)) - goto remove; - - /* Write 0xA5 bytes to the volume */ - if (update_vol_patt(&vol_node[0], dev_info.avail_bytes, 0xA5)) - goto remove; - if (check_vol_patt(&vol_node[0], 0xA5)) - goto remove; - - if (ubi_rmvol(libubi, node, req.vol_id)) { - failed("ubi_rmvol"); - return -1; - } - - return 0; - -remove: - ubi_rmvol(libubi, node, req.vol_id); - return -1; -} - -/** - * test_aligned - test volume alignment feature. - * - * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) - * - * Thus function returns %0 in case of success and %-1 in case of failure. - */ -static int test_aligned(int type) -{ - int i, ebsz; - struct ubi_mkvol_request req; - const char *name = TESTNAME ":test_aligned()"; - char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; - int alignments[] = ALIGNMENTS(dev_info.eb_size); - - req.vol_type = type; - req.name = name; - - for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { - req.vol_id = UBI_VOL_NUM_AUTO; - - req.alignment = alignments[i]; - req.alignment -= req.alignment % dev_info.min_io_size; - if (req.alignment == 0) - req.alignment = dev_info.min_io_size; - - ebsz = dev_info.eb_size - dev_info.eb_size % req.alignment; - req.bytes = MIN_AVAIL_EBS * ebsz; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); - - /* Make sure newly created volume contains only 0xFF bytes */ - if (check_vol_patt(&vol_node[0], 0xFF)) - goto remove; - - /* Write 0xA5 bytes to the volume */ - if (update_vol_patt(&vol_node[0], req.bytes, 0xA5)) - goto remove; - if (check_vol_patt(&vol_node[0], 0xA5)) - goto remove; - - if (ubi_rmvol(libubi, node, req.vol_id)) { - failed("ubi_rmvol"); - return -1; - } - } - - return 0; - -remove: - ubi_rmvol(libubi, node, req.vol_id); - return -1; -} diff --git a/ubi-utils/tests/io_paral.c b/ubi-utils/tests/io_paral.c deleted file mode 100644 index 488a0b0..0000000 --- a/ubi-utils/tests/io_paral.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Artem B. Bityutskiy - * - * This test does a lot of I/O to volumes in parallel. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "libubi.h" -#define TESTNAME "io_paral" -#include "common.h" - -#define THREADS_NUM 3 -#define ITERATIONS 10 - -static libubi_t libubi; -static struct ubi_dev_info dev_info; -const char *node; -static int iterations = ITERATIONS; -int total_bytes; - -static void * the_thread(void *ptr); - -static long long memory_limit(void) -{ - long long result = 0; - FILE *f; - - f = fopen("/proc/meminfo", "r"); - if (!f) - return 0; - fscanf(f, "%*s %lld", &result); - fclose(f); - return result * 1024 / 4; -} - -int main(int argc, char * const argv[]) -{ - int i, ret; - pthread_t threads[THREADS_NUM]; - struct ubi_mkvol_request req; - long long mem_limit; - - if (initial_check(argc, argv)) - return 1; - - node = argv[1]; - - libubi = libubi_open(); - if (libubi == NULL) { - failed("libubi_open"); - return 1; - } - - if (ubi_get_dev_info(libubi, node, &dev_info)) { - failed("ubi_get_dev_info"); - goto close; - } - - req.alignment = 1; - mem_limit = memory_limit(); - if (mem_limit && mem_limit < dev_info.avail_bytes) - total_bytes = req.bytes = - (mem_limit / dev_info.eb_size / THREADS_NUM) - * dev_info.eb_size; - else - total_bytes = req.bytes = - ((dev_info.avail_ebs - 3) / THREADS_NUM) - * dev_info.eb_size; - for (i = 0; i < THREADS_NUM; i++) { - char name[100]; - - req.vol_id = i; - sprintf(&name[0], TESTNAME":%d", i); - req.name = &name[0]; - req.vol_type = (i & 1) ? UBI_STATIC_VOLUME : UBI_DYNAMIC_VOLUME; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - goto remove; - } - } - - /* Create one volume with static data to make WL work more */ - req.vol_id = THREADS_NUM; - req.name = TESTNAME ":static"; - req.vol_type = UBI_DYNAMIC_VOLUME; - req.bytes = 3*dev_info.eb_size; - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - goto remove; - } - - for (i = 0; i < THREADS_NUM; i++) { - ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i); - if (ret) { - failed("pthread_create"); - goto remove; - } - } - - for (i = 0; i < THREADS_NUM; i++) - pthread_join(threads[i], NULL); - - for (i = 0; i <= THREADS_NUM; i++) { - if (ubi_rmvol(libubi, node, i)) { - failed("ubi_rmvol"); - goto remove; - } - } - - libubi_close(libubi); - return 0; - -remove: - for (i = 0; i <= THREADS_NUM; i++) - ubi_rmvol(libubi, node, i); - -close: - libubi_close(libubi); - return 1; -} - -/** - * the_thread - the testing thread. - * - * @ptr thread number - */ -static void * the_thread(void *ptr) -{ - int fd, iter = iterations, vol_id = (int)ptr; - unsigned char *wbuf, *rbuf; - char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; - - wbuf = malloc(total_bytes); - rbuf = malloc(total_bytes); - if (!wbuf || !rbuf) { - failed("malloc"); - goto free; - } - - sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, vol_id); - - while (iter--) { - int i, ret, written = 0, rd = 0; - int bytes = (random() % (total_bytes - 1)) + 1; - - fd = open(vol_node, O_RDWR); - if (fd == -1) { - failed("open"); - err_msg("cannot open \"%s\"\n", node); - goto free; - } - - for (i = 0; i < bytes; i++) - wbuf[i] = random() % 255; - memset(rbuf, '\0', bytes); - - do { - ret = ubi_update_start(libubi, fd, bytes); - if (ret && errno != EBUSY) { - failed("ubi_update_start"); - err_msg("vol_id %d", vol_id); - goto close; - } - } while (ret); - - while (written < bytes) { - int to_write = random() % (bytes - written); - - if (to_write == 0) - to_write = 1; - - ret = write(fd, wbuf, to_write); - if (ret != to_write) { - failed("write"); - err_msg("failed to write %d bytes at offset %d " - "of volume %d", to_write, written, - vol_id); - err_msg("update: %d bytes", bytes); - goto close; - } - - written += to_write; - } - - close(fd); - - fd = open(vol_node, O_RDONLY); - if (fd == -1) { - failed("open"); - err_msg("cannot open \"%s\"\n", node); - goto free; - } - - /* read data back and check */ - while (rd < bytes) { - int to_read = random() % (bytes - rd); - - if (to_read == 0) - to_read = 1; - - ret = read(fd, rbuf, to_read); - if (ret != to_read) { - failed("read"); - err_msg("failed to read %d bytes at offset %d " - "of volume %d", to_read, rd, vol_id); - goto close; - } - - rd += to_read; - } - - close(fd); - - } - - free(wbuf); - free(rbuf); - return NULL; - -close: - close(fd); -free: - free(wbuf); - free(rbuf); - return NULL; -} diff --git a/ubi-utils/tests/io_read.c b/ubi-utils/tests/io_read.c deleted file mode 100644 index c5d1da7..0000000 --- a/ubi-utils/tests/io_read.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Artem B. Bityutskiy - * - * Test UBI volume read. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "libubi.h" -#define TESTNAME "io_basic" -#include "common.h" - -static libubi_t libubi; -static struct ubi_dev_info dev_info; -const char *node; - -static int test_static(void); -static int test_read(int type); - -int main(int argc, char * const argv[]) -{ - if (initial_check(argc, argv)) - return 1; - - node = argv[1]; - - libubi = libubi_open(); - if (libubi == NULL) { - failed("libubi_open"); - return 1; - } - - if (ubi_get_dev_info(libubi, node, &dev_info)) { - failed("ubi_get_dev_info"); - goto close; - } - - if (test_static()) - goto close; - if (test_read(UBI_DYNAMIC_VOLUME)) - goto close; - if (test_read(UBI_STATIC_VOLUME)) - goto close; - - libubi_close(libubi); - return 0; - -close: - libubi_close(libubi); - return 1; -} - -/** - * test_static - test static volume-specific features. - * - * Thus function returns %0 in case of success and %-1 in case of failure. - */ -static int test_static(void) -{ - struct ubi_mkvol_request req; - const char *name = TESTNAME ":io_basic()"; - char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; - struct ubi_vol_info vol_info; - int fd, ret; - char buf[20]; - - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; - req.bytes = dev_info.avail_bytes; - req.vol_type = UBI_STATIC_VOLUME; - req.name = name; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, req.vol_id); - - fd = open(vol_node, O_RDWR); - if (fd == -1) { - failed("open"); - err_msg("cannot open \"%s\"\n", node); - goto remove; - } - - if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { - failed("ubi_get_vol_info"); - goto close; - } - - /* Make sure new static volume contains no data */ - if (vol_info.data_bytes != 0) { - err_msg("data_bytes = %lld, not zero", vol_info.data_bytes); - goto close; - } - - /* Ensure read returns EOF */ - ret = read(fd, &buf[0], 1); - if (ret < 0) { - failed("read"); - goto close; - } - if (ret != 0) { - err_msg("read data from free static volume"); - goto close; - } - - if (ubi_update_start(libubi, fd, 10)) { - failed("ubi_update_start"); - goto close; - } - - ret = write(fd, &buf[0], 10); - if (ret < 0) { - failed("write"); - goto close; - } - if (ret != 10) { - err_msg("written %d bytes", ret); - goto close; - } - - if (lseek(fd, 0, SEEK_SET) != 0) { - failed("seek"); - goto close; - } - ret = read(fd, &buf[0], 20); - if (ret < 0) { - failed("read"); - goto close; - } - if (ret != 10) { - err_msg("read %d bytes", ret); - goto close; - } - - close(fd); - if (ubi_rmvol(libubi, node, req.vol_id)) { - failed("ubi_rmvol"); - return -1; - } - - return 0; - -close: - close(fd); -remove: - ubi_rmvol(libubi, node, req.vol_id); - return -1; -} - -static int test_read1(struct ubi_vol_info *vol_info); - -/** - * test_read - test UBI volume reading from different offsets. - * - * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) - * - * Thus function returns %0 in case of success and %-1 in case of failure. - */ -static int test_read(int type) -{ - const char *name = TESTNAME ":test_read()"; - int alignments[] = ALIGNMENTS(dev_info.eb_size); - char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; - struct ubi_mkvol_request req; - int i; - - for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { - int eb_size; - struct ubi_vol_info vol_info; - - req.vol_id = UBI_VOL_NUM_AUTO; - req.vol_type = type; - req.name = name; - - req.alignment = alignments[i]; - req.alignment -= req.alignment % dev_info.min_io_size; - if (req.alignment == 0) - req.alignment = dev_info.min_io_size; - - eb_size = dev_info.eb_size - dev_info.eb_size % req.alignment; - req.bytes = MIN_AVAIL_EBS * eb_size; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, - req.vol_id); - - if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { - failed("ubi_get_vol_info"); - goto remove; - } - - if (test_read1(&vol_info)) { - err_msg("alignment = %d", req.alignment); - goto remove; - } - - if (ubi_rmvol(libubi, node, req.vol_id)) { - failed("ubi_rmvol"); - return -1; - } - } - - return 0; - -remove: - ubi_rmvol(libubi, node, req.vol_id); - return -1; -} - -static int test_read2(const struct ubi_vol_info *vol_info, int len); - -static int fd; - -/* Data lengthes to test, @io - minimal I/O unit size, @s - eraseblock size */ -#define LENGTHES(io, s) \ - {1, (io), (io)+1, 2*(io), 3*(io)-1, 3*(io), \ - PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io), \ - (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s), \ - 2*(s)+(io), 3*(s), 3*(s)+(io)}; - -/* - * A helper function for test_read(). - */ -static int test_read1(struct ubi_vol_info *vol_info) -{ - int i, written = 0; - char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; - int lengthes[] = LENGTHES(dev_info.min_io_size, vol_info->eb_size); - - sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, - vol_info->vol_id); - - fd = open(vol_node, O_RDWR); - if (fd == -1) { - failed("open"); - err_msg("cannot open \"%s\"\n", node); - return -1; - } - - /* Write some pattern to the volume */ - if (ubi_update_start(libubi, fd, vol_info->rsvd_bytes)) { - failed("ubi_update_start"); - err_msg("bytes = %lld", vol_info->rsvd_bytes); - goto close; - } - - while (written < vol_info->rsvd_bytes) { - int i, ret; - unsigned char buf[512]; - - for (i = 0; i < 512; i++) - buf[i] = (unsigned char)(written + i); - - ret = write(fd, &buf[0], 512); - if (ret == -1) { - failed("write"); - err_msg("written = %d, ret = %d", written, ret); - goto close; - } - written += ret; - } - - close(fd); - - if (ubi_get_vol_info(libubi, vol_node, vol_info)) { - failed("ubi_get_vol_info"); - return -1; - } - - fd = open(vol_node, O_RDONLY); - if (fd == -1) { - failed("open"); - err_msg("cannot open \"%s\"\n", node); - return -1; - } - - for (i = 0; i < sizeof(lengthes)/sizeof(int); i++) { - if (test_read2(vol_info, lengthes[i])) { - err_msg("length = %d", lengthes[i]); - goto close; - } - } - - close(fd); - return 0; - -close: - close(fd); - return -1; -} - -static int test_read3(const struct ubi_vol_info *vol_info, int len, off_t off); - -/* - * Offsets to test, @io - minimal I/O unit size, @s - eraseblock size, @sz - - * volume size. - */ -#define OFFSETS(io, s, sz) \ - {0, (io)-1, (io), (io)+1, 2*(io)-1, 2*(io), 3*(io)-1, 3*(io), \ - PAGE_SIZE-1, PAGE_SIZE-(io), 2*PAGE_SIZE, 2*PAGE_SIZE-(io), \ - (s)/2-1, (s)/2, (s)/2+1, (s)-1, (s), (s)+1, 2*(s)-(io), 2*(s), \ - 2*(s)+(io), 3*(s), (sz)-(s)-1, (sz)-(io)-1, (sz)-PAGE_SIZE-1}; - -/* - * A helper function for test_read1(). - */ -static int test_read2(const struct ubi_vol_info *vol_info, int len) -{ - int i; - off_t offsets[] = OFFSETS(dev_info.min_io_size, vol_info->eb_size, - vol_info->data_bytes); - - for (i = 0; i < sizeof(offsets)/sizeof(off_t); i++) { - if (test_read3(vol_info, len, offsets[i])) { - err_msg("offset = %d", offsets[i]); - return -1; - } - } - - return 0; -} - -/* - * A helper function for test_read2(). - */ -static int test_read3(const struct ubi_vol_info *vol_info, int len, off_t off) -{ - int i, len1; - unsigned char ck_buf[len], buf[len]; - off_t new_off; - - if (off + len > vol_info->data_bytes) - len1 = vol_info->data_bytes - off; - else - len1 = len; - - if (lseek(fd, off, SEEK_SET) != off) { - failed("seek"); - err_msg("len = %d", len); - return -1; - } - if (read(fd, &buf[0], len) != len1) { - failed("read"); - err_msg("len = %d", len); - return -1; - } - - new_off = lseek(fd, 0, SEEK_CUR); - if (new_off != off + len1) { - if (new_off == -1) - failed("lseek"); - else - err_msg("read %d bytes from %lld, but resulting " - "offset is %lld", len1, (long long) off, (long long) new_off); - return -1; - } - - for (i = 0; i < len1; i++) - ck_buf[i] = (unsigned char)(off + i); - - if (memcmp(&buf[0], &ck_buf[0], len1)) { - err_msg("incorrect data read from offset %lld", - (long long)off); - err_msg("len = %d", len); - return -1; - } - - return 0; -} diff --git a/ubi-utils/tests/io_update.c b/ubi-utils/tests/io_update.c deleted file mode 100644 index 2e3422a..0000000 --- a/ubi-utils/tests/io_update.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Artem B. Bityutskiy - * - * Test UBI volume update. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "libubi.h" -#define TESTNAME "io_update" -#include "common.h" - -static libubi_t libubi; -static struct ubi_dev_info dev_info; -const char *node; - -static int test_update(int type); -static int test_update_ff(void); - -int main(int argc, char * const argv[]) -{ - if (initial_check(argc, argv)) - return 1; - - node = argv[1]; - - libubi = libubi_open(); - if (libubi == NULL) { - failed("libubi_open"); - return 1; - } - - if (ubi_get_dev_info(libubi, node, &dev_info)) { - failed("ubi_get_dev_info"); - goto close; - } - - if (test_update(UBI_DYNAMIC_VOLUME)) - goto close; - if (test_update(UBI_STATIC_VOLUME)) - goto close; - if (test_update_ff()) - goto close; - - libubi_close(libubi); - return 0; - -close: - libubi_close(libubi); - return 1; -} - -static int test_update1(struct ubi_vol_info *vol_info); - -/** - * test_update - check volume update capabilities. - * - * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) - * - * This function returns %0 in case of success and %-1 in case of failure. - */ -static int test_update(int type) -{ - struct ubi_mkvol_request req; - const char *name = TESTNAME ":io_update()"; - int alignments[] = ALIGNMENTS(dev_info.eb_size); - struct ubi_vol_info vol_info; - char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; - int i; - - for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { - int eb_size; - - req.vol_id = UBI_VOL_NUM_AUTO; - req.vol_type = type; - req.name = name; - - req.alignment = alignments[i]; - req.alignment -= req.alignment % dev_info.min_io_size; - if (req.alignment == 0) - req.alignment = dev_info.min_io_size; - - eb_size = dev_info.eb_size - dev_info.eb_size % req.alignment; - req.bytes = MIN_AVAIL_EBS * eb_size; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, - req.vol_id); - if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { - failed("ubi_get_vol_info"); - goto remove; - } - - if (test_update1(&vol_info)) { - err_msg("alignment = %d", req.alignment); - goto remove; - } - - if (ubi_rmvol(libubi, node, req.vol_id)) { - failed("ubi_rmvol"); - return -1; - } - } - - return 0; - -remove: - ubi_rmvol(libubi, node, req.vol_id); - return -1; -} - -#define SEQUENCES(io, s) { \ - {3*(s)-(io)-1, 1}, \ - {512}, \ - {666}, \ - {2048}, \ - {(io), (io), PAGE_SIZE}, \ - {(io)+1, (io)+1, PAGE_SIZE}, \ - {PAGE_SIZE}, \ - {PAGE_SIZE-1}, \ - {PAGE_SIZE+(io)}, \ - {(s)}, \ - {(s)-1}, \ - {(s)+1}, \ - {(io), (s)+1}, \ - {(s)+(io), PAGE_SIZE}, \ - {2*(s), PAGE_SIZE}, \ - {PAGE_SIZE, 2*(s), 1}, \ - {PAGE_SIZE, 2*(s)}, \ - {2*(s)-1, 2*(s)-1}, \ - {3*(s), PAGE_SIZE + 1}, \ - {1, PAGE_SIZE}, \ - {(io), (s)} \ -} -#define SEQ_SZ 21 - -/* - * test_update1 - helper function for test_update(). - */ -static int test_update1(struct ubi_vol_info *vol_info) -{ - int sequences[SEQ_SZ][3] = SEQUENCES(dev_info.min_io_size, - vol_info->eb_size); - char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; - unsigned char buf[vol_info->rsvd_bytes]; - int fd, i, j; - - sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, - vol_info->vol_id); - - for (i = 0; i < vol_info->rsvd_bytes; i++) - buf[i] = (unsigned char)i; - - fd = open(vol_node, O_RDWR); - if (fd == -1) { - failed("open"); - err_msg("cannot open \"%s\"\n", node); - return -1; - } - - for (i = 0; i < SEQ_SZ; i++) { - int ret, stop = 0, len; - off_t off = 0; - unsigned char buf1[vol_info->rsvd_bytes]; - - if (ubi_update_start(libubi, fd, vol_info->rsvd_bytes)) { - failed("ubi_update_start"); - goto close; - } - - for (j = 0; off < vol_info->rsvd_bytes; j++) { - if (!stop) { - if (sequences[i][j] != 0) - len = sequences[i][j]; - else - stop = 1; - } - - ret = write(fd, &buf[off], len); - if (ret < 0) { - failed("write"); - err_msg("failed to write %d bytes at offset " - "%lld", len, (long long) off); - goto close; - } - if (off + len > vol_info->rsvd_bytes) - len = vol_info->rsvd_bytes - off; - if (ret != len) { - err_msg("failed to write %d bytes at offset " - "%lld, wrote %d", len, (long long) off, ret); - goto close; - } - off += len; - } - - /* Check data */ - if ((ret = lseek(fd, SEEK_SET, 0)) != 0) { - if (ret < 0) - failed("lseek"); - err_msg("cannot seek to 0"); - goto close; - } - memset(&buf1[0], 0x01, vol_info->rsvd_bytes); - ret = read(fd, &buf1[0], vol_info->rsvd_bytes + 1); - if (ret < 0) { - failed("read"); - err_msg("failed to read %d bytes", - vol_info->rsvd_bytes + 1); - goto close; - } - if (ret != vol_info->rsvd_bytes) { - err_msg("failed to read %d bytes, read %d", - vol_info->rsvd_bytes, ret); - goto close; - } - if (memcmp(&buf[0], &buf1[0], vol_info->rsvd_bytes)) { - err_msg("data corruption"); - goto close; - } - } - - close(fd); - return 0; - -close: - close(fd); - return -1; -} - -/** - * test_update_ff - check volume with 0xFF data - * - * This function returns %0 in case of success and %-1 in case of failure. - */ -static int test_update_ff(void) -{ - struct ubi_mkvol_request req; - const char *name = TESTNAME ":io_update()"; - struct ubi_vol_info vol_info; - char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; - int i, fd, ret, types[2]; - int upd_len = MIN_AVAIL_EBS * dev_info.eb_size; - char buf[upd_len], buf1[upd_len]; - - for(i = 0; i < MIN_AVAIL_EBS; i++) { - if (i % 1) - memset(&buf[0], 0xAB, upd_len); - else - memset(&buf[0], 0xFF, upd_len); - } - - types[0] = UBI_DYNAMIC_VOLUME; - types[1] = UBI_STATIC_VOLUME; - - for (i = 0; i < 2; i++) { - req.vol_id = UBI_VOL_NUM_AUTO; - req.vol_type = types[i]; - req.name = name; - - req.alignment = 1; - req.bytes = upd_len; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, - req.vol_id); - if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { - failed("ubi_get_vol_info"); - goto remove; - } - - fd = open(vol_node, O_RDWR); - if (fd == -1) { - failed("open"); - err_msg("cannot open \"%s\"\n", node); - goto remove; - } - - if (ubi_update_start(libubi, fd, upd_len)) { - failed("ubi_update_start"); - goto close; - } - - - ret = write(fd, &buf[0], upd_len); - if (ret < 0 || ret != upd_len) { - failed("write"); - err_msg("failed to write %d bytes", upd_len); - goto close; - } - - /* Check data */ - if ((ret = lseek(fd, SEEK_SET, 0)) != 0) { - if (ret < 0) - failed("lseek"); - err_msg("cannot seek to 0"); - goto close; - } - - close(fd); - - fd = open(vol_node, O_RDWR); - if (fd == -1) { - failed("open"); - err_msg("cannot open \"%s\"\n", node); - goto remove; - } - - memset(&buf1[0], 0x00, upd_len); - ret = read(fd, &buf1[0], upd_len); - if (ret < 0) { - failed("read"); - err_msg("failed to read %d bytes", upd_len); - goto close; - } - if (ret != upd_len) { - err_msg("failed to read %d bytes, read %d", - upd_len, ret); - goto close; - } - if (memcmp(&buf[0], &buf1[0], upd_len)) { - err_msg("data corruption"); - goto close; - } - - close(fd); - - if (ubi_rmvol(libubi, node, req.vol_id)) { - failed("ubi_rmvol"); - return -1; - } - } - - return 0; - -close: - close(fd); -remove: - ubi_rmvol(libubi, node, req.vol_id); - return -1; -} diff --git a/ubi-utils/tests/mkvol_bad.c b/ubi-utils/tests/mkvol_bad.c deleted file mode 100644 index 023b06b..0000000 --- a/ubi-utils/tests/mkvol_bad.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Artem B. Bityutskiy - * - * Test UBI volume creation and deletion ioctl()s with bad input and in case of - * incorrect usage. - */ - -#include -#include -#include -#include "libubi.h" -#define TESTNAME "mkvol_bad" -#include "common.h" - -static libubi_t libubi; -static struct ubi_dev_info dev_info; -const char *node; - -static int test_mkvol(void); -static int test_rmvol(void); - -int main(int argc, char * const argv[]) -{ - if (initial_check(argc, argv)) - return 1; - - node = argv[1]; - - libubi = libubi_open(); - if (libubi == NULL) { - failed("libubi_open"); - return 1; - } - - if (ubi_get_dev_info(libubi, node, &dev_info)) { - failed("ubi_get_dev_info"); - goto close; - } - - if (test_mkvol()) - goto close; - - if (test_rmvol()) - goto close; - - libubi_close(libubi); - return 0; - -close: - libubi_close(libubi); - return 1; -} - -/** - * test_mkvol - test that UBI mkvol ioctl rejects bad input parameters. - * - * This function returns %0 if the test passed and %-1 if not. - */ -static int test_mkvol(void) -{ - int ret, i; - struct ubi_mkvol_request req; - const char *name = TESTNAME ":test_mkvol()"; - - req.alignment = 1; - req.bytes = dev_info.avail_bytes; - req.vol_type = UBI_DYNAMIC_VOLUME; - req.name = name; - - /* Bad volume ID */ - req.vol_id = -2; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id)) - return -1; - - req.vol_id = dev_info.max_vol_count; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_id = %d", req.vol_id)) - return -1; - - /* Bad alignment */ - req.vol_id = 0; - req.alignment = 0; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", - req.alignment)) - return -1; - - req.alignment = -1; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", - req.alignment)) - return -1; - - req.alignment = dev_info.eb_size + 1; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", - req.alignment)) - return -1; - - if (dev_info.min_io_size > 1) { - req.alignment = dev_info.min_io_size + 1; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EINVAL, "ubi_mkvol", "alignment = %d", - req.alignment)) - return -1; - } - - /* Bad bytes */ - req.alignment = 1; - req.bytes = -1; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes)) - return -1; - - req.bytes = 0; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EINVAL, "ubi_mkvol", "bytes = %lld", req.bytes)) - return -1; - - req.bytes = dev_info.avail_bytes + 1; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes)) - return -1; - - req.alignment = dev_info.eb_size - dev_info.min_io_size; - req.bytes = (dev_info.eb_size - dev_info.eb_size % req.alignment) * - dev_info.avail_ebs + 1; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, ENOSPC, "ubi_mkvol", "bytes = %lld", req.bytes)) - return -1; - - /* Bad vol_type */ - req.alignment = 1; - req.bytes = dev_info.eb_size; - req.vol_type = UBI_DYNAMIC_VOLUME + UBI_STATIC_VOLUME; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EINVAL, "ubi_mkvol", "vol_type = %d", - req.vol_type)) - return -1; - - req.vol_type = UBI_DYNAMIC_VOLUME; - - /* Too long name */ - { - char name[UBI_VOL_NAME_MAX + 5]; - - memset(&name[0], 'x', UBI_VOL_NAME_MAX + 1); - name[UBI_VOL_NAME_MAX + 1] = '\0'; - - req.name = &name[0]; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EINVAL, "ubi_mkvol", "name_len = %d", - UBI_VOL_NAME_MAX + 1)) - return -1; - } - - /* Try to create 2 volumes with the same ID and name */ - req.name = name; - req.vol_id = 0; - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EEXIST, "ubi_mkvol", - "volume with ID 0 created twice")) - return -1; - - req.vol_id = 1; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EEXIST, "ubi_mkvol", - "volume with name \"%s\" created twice", name)) - return -1; - - if (ubi_rmvol(libubi, node, 0)) { - failed("ubi_rmvol"); - return -1; - } - - /* Try to use too much space */ - req.vol_id = 0; - req.bytes = dev_info.avail_bytes; - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - req.bytes = 1; - req.vol_id = 1; - ret = ubi_mkvol(libubi, node, &req); - if (check_failed(ret, EEXIST, "ubi_mkvol", - "created volume of maximum size %lld, but still " - "can create more volumes", dev_info.avail_bytes)) - return -1; - - if (ubi_rmvol(libubi, node, 0)) { - failed("ubi_rmvol"); - return -1; - } - - /* Try to create too many volumes */ - for (i = 0; i < dev_info.max_vol_count; i++) { - char nm[strlen(name) + 50]; - - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; - req.bytes = 1; - req.vol_type = UBI_STATIC_VOLUME; - - sprintf(&nm[0], "%s:%d", name, i); - req.name = &nm[0]; - - if (ubi_mkvol(libubi, node, &req)) { - /* - * Note, because of gluebi we may be unable to create - * dev_info.max_vol_count devices (MTD restrictions). - */ - if (errno == ENFILE) - break; - failed("ubi_mkvol"); - err_msg("vol_id %d", i); - goto remove; - } - } - - for (i = 0; i < dev_info.max_vol_count + 1; i++) - ubi_rmvol(libubi, node, i); - - return 0; - -remove: - for (i = 0; i < dev_info.max_vol_count + 1; i++) - ubi_rmvol(libubi, node, i); - return -1; -} - -/** - * test_rmvol - test that UBI rmvol ioctl rejects bad input parameters. - * - * This function returns %0 if the test passed and %-1 if not. - */ -static int test_rmvol(void) -{ - int ret; - struct ubi_mkvol_request req; - const char *name = TESTNAME ":test_rmvol()"; - - /* Bad vol_id */ - ret = ubi_rmvol(libubi, node, -1); - if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = -1")) - return -1; - - ret = ubi_rmvol(libubi, node, dev_info.max_vol_count); - if (check_failed(ret, EINVAL, "ubi_rmvol", "vol_id = %d", - dev_info.max_vol_count)) - return -1; - - /* Try to remove non-existing volume */ - ret = ubi_rmvol(libubi, node, 0); - if (check_failed(ret, ENODEV, "ubi_rmvol", - "removed non-existing volume 0")) - return -1; - - /* Try to remove volume twice */ - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; - req.bytes = dev_info.avail_bytes; - req.vol_type = UBI_DYNAMIC_VOLUME; - req.name = name; - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - if (ubi_rmvol(libubi, node, req.vol_id)) { - failed("ubi_rmvol"); - return -1; - } - - ret = ubi_rmvol(libubi, node, req.vol_id); - if (check_failed(ret, ENODEV, "ubi_rmvol", "volume %d removed twice", - req.vol_id)) - return -1; - - return 0; -} diff --git a/ubi-utils/tests/mkvol_basic.c b/ubi-utils/tests/mkvol_basic.c deleted file mode 100644 index e2120e9..0000000 --- a/ubi-utils/tests/mkvol_basic.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Artem B. Bityutskiy - * - * Test test checks basic volume creation and deletion capabilities. - */ - -#include -#include -#include -#include "libubi.h" -#define TESTNAME "mkvol_basic" -#include "common.h" - -static libubi_t libubi; -static struct ubi_dev_info dev_info; -const char *node; - -static int mkvol_basic(void); -static int mkvol_alignment(void); -static int mkvol_multiple(void); - -int main(int argc, char * const argv[]) -{ - if (initial_check(argc, argv)) - return 1; - - node = argv[1]; - - libubi = libubi_open(); - if (libubi == NULL) { - failed("libubi_open"); - return 1; - } - - if (ubi_get_dev_info(libubi, node, &dev_info)) { - failed("ubi_get_dev_info"); - goto close; - } - - if (mkvol_basic()) - goto close; - - if (mkvol_alignment()) - goto close; - - if (mkvol_multiple()) - goto close; - - libubi_close(libubi); - return 0; - -close: - libubi_close(libubi); - return 1; -} - -/** - * mkvol_alignment - create volumes with different alignments. - * - * Thus function returns %0 in case of success and %-1 in case of failure. - */ -static int mkvol_alignment(void) -{ - struct ubi_mkvol_request req; - int i, vol_id, ebsz; - const char *name = TESTNAME ":mkvol_alignment()"; - int alignments[] = ALIGNMENTS(dev_info.eb_size); - - for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { - req.vol_id = UBI_VOL_NUM_AUTO; - - /* Alignment should actually be multiple of min. I/O size */ - req.alignment = alignments[i]; - req.alignment -= req.alignment % dev_info.min_io_size; - if (req.alignment == 0) - req.alignment = dev_info.min_io_size; - - /* Bear in mind alignment reduces EB size */ - ebsz = dev_info.eb_size - dev_info.eb_size % req.alignment; - req.bytes = dev_info.avail_ebs * ebsz; - - req.vol_type = UBI_DYNAMIC_VOLUME; - req.name = name; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - err_msg("alignment %d", req.alignment); - return -1; - } - - vol_id = req.vol_id; - if (check_volume(vol_id, &req)) - goto remove; - - if (ubi_rmvol(libubi, node, vol_id)) { - failed("ubi_rmvol"); - return -1; - } - } - - return 0; - -remove: - ubi_rmvol(libubi, node, vol_id); - return -1; -} - -/** - * mkvol_basic - simple test that checks basic volume creation capability. - * - * Thus function returns %0 in case of success and %-1 in case of failure. - */ -static int mkvol_basic(void) -{ - struct ubi_mkvol_request req; - struct ubi_vol_info vol_info; - int vol_id, ret; - const char *name = TESTNAME ":mkvol_basic()"; - - /* Create dynamic volume of maximum size */ - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; - req.bytes = dev_info.avail_bytes; - req.vol_type = UBI_DYNAMIC_VOLUME; - req.name = name; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - vol_id = req.vol_id; - if (check_volume(vol_id, &req)) - goto remove; - - if (ubi_rmvol(libubi, node, vol_id)) { - failed("ubi_rmvol"); - return -1; - } - - /* Create static volume of maximum size */ - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; - req.bytes = dev_info.avail_bytes; - req.vol_type = UBI_STATIC_VOLUME; - req.name = name; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - vol_id = req.vol_id; - if (check_volume(vol_id, &req)) - goto remove; - - if (ubi_rmvol(libubi, node, vol_id)) { - failed("ubi_rmvol"); - return -1; - } - - /* Make sure volume does not exist */ - ret = ubi_get_vol_info1(libubi, dev_info.dev_num, vol_id, &vol_info); - if (ret == 0) { - err_msg("removed volume %d exists", vol_id); - goto remove; - } - - return 0; - -remove: - ubi_rmvol(libubi, node, vol_id); - return -1; -} - -/** - * mkvol_multiple - test multiple volumes creation - * - * Thus function returns %0 if the test passed and %-1 if not. - */ -static int mkvol_multiple(void) -{ - struct ubi_mkvol_request req; - int i, ret, max = dev_info.max_vol_count; - const char *name = TESTNAME ":mkvol_multiple()"; - - /* Create maximum number of volumes */ - for (i = 0; i < max; i++) { - char nm[strlen(name) + 50]; - - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; - req.bytes = 1; - req.vol_type = UBI_STATIC_VOLUME; - - sprintf(&nm[0], "%s:%d", name, i); - req.name = &nm[0]; - - if (ubi_mkvol(libubi, node, &req)) { - if (errno == ENFILE) { - max = i; - break; - } - failed("ubi_mkvol"); - err_msg("vol_id %d", i); - goto remove; - } - - if (check_volume(req.vol_id, &req)) { - err_msg("vol_id %d", i); - goto remove; - } - } - - for (i = 0; i < max; i++) { - struct ubi_vol_info vol_info; - - if (ubi_rmvol(libubi, node, i)) { - failed("ubi_rmvol"); - return -1; - } - - /* Make sure volume does not exist */ - ret = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info); - if (ret == 0) { - err_msg("removed volume %d exists", i); - goto remove; - } - } - - return 0; - -remove: - for (i = 0; i < dev_info.max_vol_count + 1; i++) - ubi_rmvol(libubi, node, i); - return -1; -} diff --git a/ubi-utils/tests/mkvol_paral.c b/ubi-utils/tests/mkvol_paral.c deleted file mode 100644 index faf085c..0000000 --- a/ubi-utils/tests/mkvol_paral.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Artem B. Bityutskiy - * - * This test creates and deletes volumes in parallel. - */ - -#include -#include -#include -#include -#include "libubi.h" -#define TESTNAME "mkvol_paral" -#include "common.h" - -#define THREADS_NUM 4 -#define ITERATIONS 500 - -static libubi_t libubi; -static struct ubi_dev_info dev_info; -const char *node; -static int iterations = ITERATIONS; - -static void * the_thread(void *ptr); - -int main(int argc, char * const argv[]) -{ - int i, ret; - pthread_t threads[THREADS_NUM]; - - if (initial_check(argc, argv)) - return 1; - - node = argv[1]; - - libubi = libubi_open(); - if (libubi == NULL) { - failed("libubi_open"); - return 1; - } - - if (ubi_get_dev_info(libubi, node, &dev_info)) { - failed("ubi_get_dev_info"); - goto close; - } - - for (i = 0; i < THREADS_NUM; i++) { - ret = pthread_create(&threads[i], NULL, &the_thread, (void*)i); - if (ret) { - failed("pthread_create"); - goto close; - } - } - - for (i = 0; i < THREADS_NUM; i++) - pthread_join(threads[i], NULL); - - libubi_close(libubi); - return 0; - -close: - libubi_close(libubi); - return 1; -} - -/** - * the_thread - the testing thread. - * - * @ptr thread number - */ -static void * the_thread(void *ptr) -{ - int n = (int)ptr, iter = iterations; - struct ubi_mkvol_request req; - const char *name = TESTNAME ":the_thread()"; - char nm[strlen(name) + 50]; - - req.alignment = 1; - req.bytes = dev_info.avail_bytes/ITERATIONS; - req.vol_type = UBI_DYNAMIC_VOLUME; - sprintf(&nm[0], "%s:%d", name, n); - req.name = &nm[0]; - - while (iter--) { - req.vol_id = UBI_VOL_NUM_AUTO; - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return NULL; - } - if (ubi_rmvol(libubi, node, req.vol_id)) { - failed("ubi_rmvol"); - return NULL; - } - } - - return NULL; -} diff --git a/ubi-utils/tests/rmvol.c b/ubi-utils/tests/rmvol.c deleted file mode 100644 index fb9b344..0000000 --- a/ubi-utils/tests/rmvol.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Copyright (c) Nokia Corporation, 2007 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Artem B. Bityutskiy - * - * Test volume reference counting - create a volume, open a sysfs file - * belonging to the volume, delete the volume but do not close the file, make - * sure the file cannot be read, make sure the volume cannot be open, close the - * file, make sure the volume disappeard, make sure its sysfs subtree - * disappeared. - */ - -#include -#include -#include -#include -#include -#include "libubi.h" -#define TESTNAME "rmvol" -#include "common.h" - -#define SYSFS_FILE "/sys/class/ubi/ubi%d_%d/usable_eb_size" - -int main(int argc, char * const argv[]) -{ - int ret, fd; - char fname[sizeof(SYSFS_FILE) + 20]; - const char *node; - libubi_t libubi; - struct ubi_dev_info dev_info; - struct ubi_mkvol_request req; - char tmp[100]; - - if (initial_check(argc, argv)) - return 1; - - node = argv[1]; - - libubi = libubi_open(); - if (libubi == NULL) { - failed("libubi_open"); - return 1; - } - - if (ubi_get_dev_info(libubi, node, &dev_info)) { - failed("ubi_get_dev_info"); - goto out_libubi; - } - - /* Create a small dynamic volume */ - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = dev_info.min_io_size; - req.bytes = dev_info.eb_size; - req.vol_type = UBI_DYNAMIC_VOLUME; - req.name = "rmvol"; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - perror("ubi_mkvol"); - goto out_libubi; - } - - /* Open volume-related sysfs file */ - sprintf(fname, SYSFS_FILE, dev_info.dev_num, req.vol_id); - fd = open(fname, O_RDONLY); - if (fd == -1) { - failed("open"); - perror("open"); - goto out_rmvol; - } - - /* Remove the volume, but do not close the file */ - if (ubi_rmvol(libubi, node, req.vol_id)) { - failed("ubi_rmvol"); - perror("ubi_rmvol"); - goto out_close; - } - - /* Try to read from the file, this should fail */ - ret = read(fd, tmp, 100); - if (ret != -1) { - failed("read"); - err_msg("read returned %d, expected -1", ret); - goto out_close; - } - - /* Close the file and try to open it again, should fail */ - close(fd); - fd = open(fname, O_RDONLY); - if (fd != -1) { - failed("open"); - err_msg("opened %s again, open returned %d, expected -1", - fname, fd); - goto out_libubi; - } - - libubi_close(libubi); - return 0; - -out_rmvol: - ubi_rmvol(libubi, node, req.vol_id); -out_libubi: - libubi_close(libubi); - return 1; - -out_close: - close(fd); - libubi_close(libubi); - return 1; -} - -#if 0 -/** - * mkvol_alignment - create volumes with different alignments. - * - * Thus function returns %0 in case of success and %-1 in case of failure. - */ -static int mkvol_alignment(void) -{ - struct ubi_mkvol_request req; - int i, vol_id, ebsz; - const char *name = TESTNAME ":mkvol_alignment()"; - int alignments[] = ALIGNMENTS(dev_info.eb_size); - - for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { - req.vol_id = UBI_VOL_NUM_AUTO; - - /* Alignment should actually be multiple of min. I/O size */ - req.alignment = alignments[i]; - req.alignment -= req.alignment % dev_info.min_io_size; - if (req.alignment == 0) - req.alignment = dev_info.min_io_size; - - /* Bear in mind alignment reduces EB size */ - ebsz = dev_info.eb_size - dev_info.eb_size % req.alignment; - req.bytes = dev_info.avail_ebs * ebsz; - - req.vol_type = UBI_DYNAMIC_VOLUME; - req.name = name; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - err_msg("alignment %d", req.alignment); - return -1; - } - - vol_id = req.vol_id; - if (check_volume(vol_id, &req)) - goto remove; - - if (ubi_rmvol(libubi, node, vol_id)) { - failed("ubi_rmvol"); - return -1; - } - } - - return 0; - -remove: - ubi_rmvol(libubi, node, vol_id); - return -1; -} - -/** - * mkvol_basic - simple test that checks basic volume creation capability. - * - * Thus function returns %0 in case of success and %-1 in case of failure. - */ -static int mkvol_basic(void) -{ - struct ubi_mkvol_request req; - struct ubi_vol_info vol_info; - int vol_id, ret; - const char *name = TESTNAME ":mkvol_basic()"; - - /* Create dynamic volume of maximum size */ - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; - req.bytes = dev_info.avail_bytes; - req.vol_type = UBI_DYNAMIC_VOLUME; - req.name = name; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - vol_id = req.vol_id; - if (check_volume(vol_id, &req)) - goto remove; - - if (ubi_rmvol(libubi, node, vol_id)) { - failed("ubi_rmvol"); - return -1; - } - - /* Create static volume of maximum size */ - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; - req.bytes = dev_info.avail_bytes; - req.vol_type = UBI_STATIC_VOLUME; - req.name = name; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - vol_id = req.vol_id; - if (check_volume(vol_id, &req)) - goto remove; - - if (ubi_rmvol(libubi, node, vol_id)) { - failed("ubi_rmvol"); - return -1; - } - - /* Make sure volume does not exist */ - ret = ubi_get_vol_info1(libubi, dev_info.dev_num, vol_id, &vol_info); - if (ret == 0) { - err_msg("removed volume %d exists", vol_id); - goto remove; - } - - return 0; - -remove: - ubi_rmvol(libubi, node, vol_id); - return -1; -} - -/** - * mkvol_multiple - test multiple volumes creation - * - * Thus function returns %0 if the test passed and %-1 if not. - */ -static int mkvol_multiple(void) -{ - struct ubi_mkvol_request req; - int i, ret, max = dev_info.max_vol_count; - const char *name = TESTNAME ":mkvol_multiple()"; - - /* Create maximum number of volumes */ - for (i = 0; i < max; i++) { - char nm[strlen(name) + 50]; - - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; - req.bytes = 1; - req.vol_type = UBI_STATIC_VOLUME; - - sprintf(&nm[0], "%s:%d", name, i); - req.name = &nm[0]; - - if (ubi_mkvol(libubi, node, &req)) { - if (errno == ENFILE) { - max = i; - break; - } - failed("ubi_mkvol"); - err_msg("vol_id %d", i); - goto remove; - } - - if (check_volume(req.vol_id, &req)) { - err_msg("vol_id %d", i); - goto remove; - } - } - - for (i = 0; i < max; i++) { - struct ubi_vol_info vol_info; - - if (ubi_rmvol(libubi, node, i)) { - failed("ubi_rmvol"); - return -1; - } - - /* Make sure volume does not exist */ - ret = ubi_get_vol_info1(libubi, dev_info.dev_num, i, &vol_info); - if (ret == 0) { - err_msg("removed volume %d exists", i); - goto remove; - } - } - - return 0; - -remove: - for (i = 0; i < dev_info.max_vol_count + 1; i++) - ubi_rmvol(libubi, node, i); - return -1; -} -#endif diff --git a/ubi-utils/tests/rsvol.c b/ubi-utils/tests/rsvol.c deleted file mode 100644 index 7a9e5ea..0000000 --- a/ubi-utils/tests/rsvol.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Author: Artem B. Bityutskiy - * - * Tes UBI volume re-size. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "libubi.h" -#define TESTNAME "rsvol" -#include "common.h" - -static libubi_t libubi; -static struct ubi_dev_info dev_info; -const char *node; - -static int test_basic(int type); -static int test_rsvol(int type); - -int main(int argc, char * const argv[]) -{ - if (initial_check(argc, argv)) - return 1; - - node = argv[1]; - - libubi = libubi_open(); - if (libubi == NULL) { - failed("libubi_open"); - return 1; - } - - if (ubi_get_dev_info(libubi, node, &dev_info)) { - failed("ubi_get_dev_info"); - goto close; - } - - if (test_basic(UBI_DYNAMIC_VOLUME)) - goto close; - if (test_basic(UBI_STATIC_VOLUME)) - goto close; - if (test_rsvol(UBI_DYNAMIC_VOLUME)) - goto close; - if (test_rsvol(UBI_STATIC_VOLUME)) - goto close; - - libubi_close(libubi); - return 0; - -close: - libubi_close(libubi); - return 1; -} - -/** - * test_basic - check volume re-size capability. - * - * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) - * - * Thus function returns %0 in case of success and %-1 in case of failure. - */ -static int test_basic(int type) -{ - struct ubi_mkvol_request req; - const char *name = TESTNAME ":test_basic()"; - - req.vol_id = UBI_VOL_NUM_AUTO; - req.alignment = 1; - req.bytes = MIN_AVAIL_EBS * dev_info.eb_size; - req.vol_type = type; - req.name = name; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - req.bytes = dev_info.eb_size; - if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { - failed("ubi_rsvol"); - goto remove; - } - - if (check_volume(req.vol_id, &req)) - goto remove; - - req.bytes = (MIN_AVAIL_EBS + 1) * dev_info.eb_size; - if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { - failed("ubi_rsvol"); - goto remove; - } - - if (check_volume(req.vol_id, &req)) - goto remove; - - req.bytes -= 1; - if (ubi_rsvol(libubi, node, req.vol_id, req.bytes)) { - failed("ubi_rsvol"); - goto remove; - } - - if (check_volume(req.vol_id, &req)) - goto remove; - - if (ubi_rmvol(libubi, node, req.vol_id)) { - failed("ubi_rmvol"); - return -1; - } - - return 0; - -remove: - ubi_rmvol(libubi, node, req.vol_id); - return -1; -} - -static int test_rsvol1(struct ubi_vol_info *vol_info); - -/** - * test_rsvol - test UBI volume re-size. - * - * @type volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) - * - * Thus function returns %0 in case of success and %-1 in case of failure. - */ -static int test_rsvol(int type) -{ - const char *name = TESTNAME "test_rsvol:()"; - int alignments[] = ALIGNMENTS(dev_info.eb_size); - char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; - struct ubi_mkvol_request req; - int i; - - for (i = 0; i < sizeof(alignments)/sizeof(int); i++) { - int eb_size; - struct ubi_vol_info vol_info; - - req.vol_id = UBI_VOL_NUM_AUTO; - req.vol_type = type; - req.name = name; - - req.alignment = alignments[i]; - req.alignment -= req.alignment % dev_info.min_io_size; - if (req.alignment == 0) - req.alignment = dev_info.min_io_size; - - eb_size = dev_info.eb_size - dev_info.eb_size % req.alignment; - req.bytes = MIN_AVAIL_EBS * eb_size; - - if (ubi_mkvol(libubi, node, &req)) { - failed("ubi_mkvol"); - return -1; - } - - sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, - req.vol_id); - - if (ubi_get_vol_info(libubi, vol_node, &vol_info)) { - failed("ubi_get_vol_info"); - goto remove; - } - - if (test_rsvol1(&vol_info)) { - err_msg("alignment = %d", req.alignment); - goto remove; - } - - if (ubi_rmvol(libubi, node, req.vol_id)) { - failed("ubi_rmvol"); - return -1; - } - } - - return 0; - -remove: - ubi_rmvol(libubi, node, req.vol_id); - return -1; -} - -/* - * Helper function for test_rsvol(). - */ -static int test_rsvol1(struct ubi_vol_info *vol_info) -{ - long long bytes; - struct ubi_vol_info vol_info1; - char vol_node[strlen(UBI_VOLUME_PATTERN) + 100]; - unsigned char buf[vol_info->rsvd_bytes]; - int fd, i, ret; - - /* Make the volume smaller and check basic volume I/O */ - bytes = vol_info->rsvd_bytes - vol_info->eb_size; - if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes - 1)) { - failed("ubi_rsvol"); - return -1; - } - - if (ubi_get_vol_info1(libubi, vol_info->dev_num, vol_info->vol_id, - &vol_info1)) { - failed("ubi_get_vol_info"); - return -1; - } - - if (vol_info1.rsvd_bytes != bytes) { - err_msg("rsvd_bytes %lld, must be %lld", - vol_info1.rsvd_bytes, bytes); - return -1; - } - - if (vol_info1.rsvd_ebs != vol_info->rsvd_ebs - 1) { - err_msg("rsvd_ebs %d, must be %d", - vol_info1.rsvd_ebs, vol_info->rsvd_ebs - 1); - return -1; - } - - /* Write data to the volume */ - sprintf(&vol_node[0], UBI_VOLUME_PATTERN, dev_info.dev_num, - vol_info->vol_id); - - fd = open(vol_node, O_RDWR); - if (fd == -1) { - failed("open"); - err_msg("cannot open \"%s\"\n", vol_node); - return -1; - } - - bytes = vol_info->rsvd_bytes - vol_info->eb_size - 1; - if (ubi_update_start(libubi, fd, bytes)) { - failed("ubi_update_start"); - goto close; - } - - for (i = 0; i < bytes; i++) - buf[i] = (unsigned char)i; - - ret = write(fd, &buf[0], bytes); - if (ret != bytes) { - failed("write"); - goto close; - } - - close(fd); - - if (ubi_rsvol(libubi, node, vol_info->vol_id, bytes)) { - failed("ubi_rsvol"); - return -1; - } - - if (ubi_rsvol(libubi, node, vol_info->vol_id, - vol_info->eb_size * dev_info.avail_ebs)) { - failed("ubi_rsvol"); - return -1; - } - - fd = open(vol_node, O_RDWR); - if (fd == -1) { - failed("open"); - err_msg("cannot open \"%s\"\n", vol_node); - return -1; - } - - /* Read data back */ - if (lseek(fd, 0, SEEK_SET) != 0) { - failed("seek"); - goto close; - } - memset(&buf[0], 0, bytes); - ret = read(fd, &buf[0], bytes); - if (ret != bytes) { - failed("read"); - goto close; - } - - for (i = 0; i < bytes; i++) { - if (buf[i] != (unsigned char)i) { - err_msg("bad data"); - goto close; - } - } - - close(fd); - return 0; - -close: - close(fd); - return -1; -} diff --git a/ubi-utils/tests/runtests.sh b/ubi-utils/tests/runtests.sh deleted file mode 100755 index 7072e03..0000000 --- a/ubi-utils/tests/runtests.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh - -ubidev="$1" -tests="mkvol_basic mkvol_bad mkvol_paral rsvol io_basic io_read io_update -io_paral rmvol" - -if test -z "$ubidev"; -then - echo "Usage:" - echo "$0 " - exit 1 -fi - -ubiname=`echo $ubidev | cut -d/ -f3` - -major=`cat /sys/class/ubi/$ubiname/dev | cut -d: -f1` - -for minor in `seq 0 4`; do - if test ! -e ${ubidev}_${minor} ; - then - mknod ${ubidev}_${minor} c $major $(($minor + 1)) - fi -done - -if ! test -c "$ubidev"; -then - echo "Error: $ubidev is not character device" - exit 1 -fi - -for t in `echo $tests`; -do - echo "Running $t $ubidev" - "./$t" "$ubidev" || exit 1 -done - -echo SUCCESS - -exit 0 -- cgit v1.2.3