aboutsummaryrefslogtreecommitdiff
path: root/ubi-utils
diff options
context:
space:
mode:
Diffstat (limited to 'ubi-utils')
-rw-r--r--ubi-utils/Makemodule.am9
-rw-r--r--ubi-utils/mtdinfo.c14
-rw-r--r--ubi-utils/ubiattach.c25
-rw-r--r--ubi-utils/ubinfo.c10
-rw-r--r--ubi-utils/ubiscan.c318
5 files changed, 359 insertions, 17 deletions
diff --git a/ubi-utils/Makemodule.am b/ubi-utils/Makemodule.am
index 7491a8a..66c0238 100644
--- a/ubi-utils/Makemodule.am
+++ b/ubi-utils/Makemodule.am
@@ -25,6 +25,9 @@ ubinize_LDADD = libubi.a libubigen.a libmtd.a libiniparser.a
ubiformat_SOURCES = ubi-utils/ubiformat.c include/mtd_swab.h
ubiformat_LDADD = libubi.a libubigen.a libmtd.a libscan.a
+ubiscan_SOURCES = ubi-utils/ubiscan.c include/mtd_swab.h
+ubiscan_LDADD = libubi.a libubigen.a libscan.a libmtd.a
+
ubirename_SOURCES = ubi-utils/ubirename.c
ubirename_LDADD = libmtd.a libubi.a
@@ -37,16 +40,14 @@ ubirsvol_LDADD = libmtd.a libubi.a
ubiblock_SOURCES = ubi-utils/ubiblock.c
ubiblock_LDADD = libmtd.a libubi.a
-if WITH_GETRANDOM
ubihealthd_SOURCES = ubi-utils/ubihealthd.c
ubihealthd_LDADD = libmtd.a libubi.a
-endif
sbin_PROGRAMS += \
ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \
- ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock
+ ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock ubiscan
-if WITH_GETRANDOM
+if WITH_UBIHEALTHD
sbin_PROGRAMS += ubihealthd
endif
diff --git a/ubi-utils/mtdinfo.c b/ubi-utils/mtdinfo.c
index 8bd0fc8..7dff0de 100644
--- a/ubi-utils/mtdinfo.c
+++ b/ubi-utils/mtdinfo.c
@@ -30,6 +30,7 @@
#include <string.h>
#include <unistd.h>
#include <mtd/mtd-user.h>
+#include <mtd/ubi-media.h>
#include <libubigen.h>
#include <libmtd.h>
@@ -54,7 +55,7 @@ static void display_help(void)
printf(
"%1$s version %2$s - a tool to print MTD information.\n"
"\n"
- "Usage: %1$s <MTD node file path> [--map | -M] [--ubi-info | -u]\n"
+ "Usage: %1$s <mtd device> [--map | -M] [--ubi-info | -u]\n"
" %1$s --all [--ubi-info | -u]\n"
" %1$s [--help | --version]\n"
"\n"
@@ -68,6 +69,8 @@ static void display_help(void)
"-h, --help print help message\n"
"-V, --version print program version\n"
"\n"
+ "<mtd device> MTD device node or 'mtd:<name>'\n"
+ "\n"
"Examples:\n"
" %1$s /dev/mtd0 print information MTD device /dev/mtd0\n"
" %1$s /dev/mtd0 -u print information MTD device /dev/mtd0\n"
@@ -124,10 +127,13 @@ static int parse_opt(int argc, char * const argv[])
}
}
- if (optind == argc - 1)
- args.node = argv[optind];
- else if (optind < argc)
+ if (optind == argc - 1) {
+ args.node = mtd_find_dev_node(argv[optind]);
+ if (!args.node)
+ return errmsg("Failed to find MTD device %s", argv[optind]);
+ } else if (optind < argc) {
return errmsg("more then one MTD device specified (use -h for help)");
+ }
if (args.all && args.node)
args.node = NULL;
diff --git a/ubi-utils/ubiattach.c b/ubi-utils/ubiattach.c
index 09f85af..e758dab 100644
--- a/ubi-utils/ubiattach.c
+++ b/ubi-utils/ubiattach.c
@@ -42,6 +42,8 @@ struct args {
const char *node;
const char *dev;
int max_beb_per1024;
+ bool disable_fm;
+ bool need_resv_pool;
};
static struct args args = {
@@ -51,6 +53,8 @@ static struct args args = {
.node = NULL,
.dev = NULL,
.max_beb_per1024 = 0,
+ .disable_fm = false,
+ .need_resv_pool = false,
};
static const char doc[] = PROGRAM_NAME " version " VERSION
@@ -67,6 +71,11 @@ static const char optionsstr[] =
"-b, --max-beb-per1024 maximum expected bad block number per 1024 eraseblock.\n"
" The default value is correct for most NAND devices.\n"
" Allowed range is 0-768, 0 means the default kernel value.\n"
+"-f, --disable-fastmap don't create new fastmap and do full scanning (existed\n"
+" fastmap will be destroyed) for the given ubi device.\n"
+"-r, --reserve-pool Slow down the frequency of updating fastmap by reserving\n"
+" pebs for filling pool/wl_pool, which can prolong flash\n"
+" service life.\n"
"-h, --help print help message\n"
"-V, --version print program version";
@@ -74,7 +83,7 @@ static const char usage[] =
"Usage: " PROGRAM_NAME " [<UBI control device node file name>]\n"
"\t[-m <MTD device number>] [-d <UBI device number>] [-p <path to device>]\n"
"\t[--mtdn=<MTD device number>] [--devn=<UBI device number>]\n"
-"\t[--dev-path=<path to device>]\n"
+"\t[--dev-path=<path to device>] [-f] [--disable-fastmap] [-r] [--reserve-pool]\n"
"\t[--max-beb-per1024=<maximum bad block number per 1024 blocks>]\n"
"UBI control device defaults to " DEFAULT_CTRL_DEV " if not supplied.\n"
"Example 1: " PROGRAM_NAME " -p /dev/mtd0 - attach /dev/mtd0 to UBI\n"
@@ -93,6 +102,8 @@ static const struct option long_options[] = {
{ .name = "mtdn", .has_arg = 1, .flag = NULL, .val = 'm' },
{ .name = "vid-hdr-offset", .has_arg = 1, .flag = NULL, .val = 'O' },
{ .name = "max-beb-per1024", .has_arg = 1, .flag = NULL, .val = 'b' },
+ { .name = "disable-fastmap", .has_arg = 0, .flag = NULL, .val = 'f' },
+ { .name = "reserve-pool", .has_arg = 0, .flag = NULL, .val = 'r' },
{ .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
{ .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
{ NULL, 0, NULL, 0},
@@ -103,7 +114,7 @@ static int parse_opt(int argc, char * const argv[])
while (1) {
int key, error = 0;
- key = getopt_long(argc, argv, "p:m:d:O:b:hV", long_options, NULL);
+ key = getopt_long(argc, argv, "p:m:d:O:b:frhV", long_options, NULL);
if (key == -1)
break;
@@ -143,6 +154,14 @@ static int parse_opt(int argc, char * const argv[])
break;
+ case 'f':
+ args.disable_fm = true;
+ break;
+
+ case 'r':
+ args.need_resv_pool = true;
+ break;
+
case 'h':
printf("%s\n\n", doc);
printf("%s\n\n", usage);
@@ -213,6 +232,8 @@ int main(int argc, char * const argv[])
req.vid_hdr_offset = args.vidoffs;
req.mtd_dev_node = args.dev;
req.max_beb_per1024 = args.max_beb_per1024;
+ req.disable_fm = args.disable_fm;
+ req.need_resv_pool = args.need_resv_pool;
err = ubi_attach(libubi, args.node, &req);
if (err < 0) {
diff --git a/ubi-utils/ubinfo.c b/ubi-utils/ubinfo.c
index 29530be..6c5b19e 100644
--- a/ubi-utils/ubinfo.c
+++ b/ubi-utils/ubinfo.c
@@ -417,12 +417,9 @@ int main(int argc, char * const argv[])
goto out_libubi;
}
- if (args.devn != -1 && args.vol_id != -1) {
- print_vol_info(libubi, args.devn, args.vol_id);
- goto out;
- }
-
- if (args.devn == -1 && args.vol_id == -1)
+ if (args.devn != -1 && args.vol_id != -1)
+ err = print_vol_info(libubi, args.devn, args.vol_id);
+ else if (args.devn == -1 && args.vol_id == -1)
err = print_general_info(libubi, args.all);
else if (args.devn != -1 && args.vol_id == -1)
err = print_dev_info(libubi, args.devn, args.all);
@@ -430,7 +427,6 @@ int main(int argc, char * const argv[])
if (err)
goto out_libubi;
-out:
libubi_close(libubi);
return 0;
diff --git a/ubi-utils/ubiscan.c b/ubi-utils/ubiscan.c
new file mode 100644
index 0000000..66af12a
--- /dev/null
+++ b/ubi-utils/ubiscan.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2021 Diego Ismirlian
+ *
+ * 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.
+ */
+
+/*
+ * An utility to scan MTD devices.
+ *
+ * Author: Diego Ismirlian dismirlian (at) google's mail
+ */
+
+#define PROGRAM_NAME "ubiscan"
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#include <mtd/ubi-media.h>
+#include <libubi.h>
+#include <libmtd.h>
+#include <libscan.h>
+#include "common.h"
+
+#define MAX_BINS 50
+
+/* The variables below are set by command line arguments */
+struct args {
+ int verbose;
+ const char *node;
+ int node_fd;
+ int bin_thresholds[MAX_BINS - 1];
+ int nbins;
+};
+
+static struct args args = {
+ .verbose = 0,
+ .nbins = 6,
+ .bin_thresholds = {
+ 10,
+ 100,
+ 1000,
+ 10000,
+ 100000,
+ },
+};
+
+static const char doc[] = PROGRAM_NAME " version " VERSION
+ " - a tool to scan MTD devices";
+
+static const char optionsstr[] =
+"-h, -?, --help print help message\n"
+"-H, --histrogram=<list> comma-separated list of bin thresholds\n"
+"-v, --verbose be verbose\n"
+"-V, --version print program version\n";
+
+static const char usage[] =
+"Usage: " PROGRAM_NAME " <MTD device node file name> "
+"\t\t\t[--help] [--version] [--verbose] [--histogram=<list>]";
+
+static const struct option long_options[] = {
+ { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' },
+ { .name = "histogram", .has_arg = 1, .flag = NULL, .val = 'H' },
+ { .name = "verbose", .has_arg = 0, .flag = NULL, .val = 'v' },
+ { .name = "version", .has_arg = 0, .flag = NULL, .val = 'V' },
+ { NULL, 0, NULL, 0},
+};
+
+static int parse_opt(int argc, char * const argv[])
+{
+ int last_bin = 0;
+ while (1) {
+ int key;
+
+ key = getopt_long(argc, argv, "h?VvH:", long_options, NULL);
+ if (key == -1)
+ break;
+
+ switch (key) {
+ case 'v':
+ args.verbose = 1;
+ break;
+ case 'H': {
+ args.nbins = 1;
+ char *token = strtok(optarg, ",");
+ while (token) {
+ if (args.nbins == MAX_BINS)
+ return errmsg("too many bins");
+ int th = atoi(token);
+ if (th <= last_bin)
+ return errmsg("bad bin threshold list");
+ args.bin_thresholds[args.nbins - 1] = th;
+ last_bin = th;
+ args.nbins++;
+ token = strtok(NULL, ",");
+ }
+ } break;
+ case 'V':
+ common_print_version();
+ exit(EXIT_SUCCESS);
+ case 'h':
+ printf("%s\n\n", doc);
+ printf("%s\n\n", usage);
+ printf("%s\n", optionsstr);
+ exit(EXIT_SUCCESS);
+ case '?':
+ printf("%s\n\n", doc);
+ printf("%s\n\n", usage);
+ printf("%s\n", optionsstr);
+ return -1;
+
+ case ':':
+ return errmsg("parameter is missing");
+
+ default:
+ fprintf(stderr, "Use -h for help\n");
+ return -1;
+ }
+ }
+
+ if (optind == argc)
+ return errmsg("MTD device name was not specified (use -h for help)");
+ else if (optind != argc - 1)
+ return errmsg("more then one MTD device specified (use -h for help)");
+
+ args.node = argv[optind];
+ return 0;
+}
+
+int main(int argc, char * const argv[])
+{
+ int err;
+ libmtd_t libmtd;
+ struct mtd_info mtd_info;
+ struct mtd_dev_info mtd;
+ struct ubi_scan_info *si;
+ int max, min;
+
+ struct {
+ int min;
+ int max;
+ int cnt;
+ uint64_t mean;
+ } bins[MAX_BINS];
+
+ err = parse_opt(argc, argv);
+ if (err)
+ return -1;
+
+ libmtd = libmtd_open();
+ if (!libmtd)
+ return errmsg("MTD subsystem is not present");
+
+ err = mtd_get_info(libmtd, &mtd_info);
+ if (err) {
+ sys_errmsg("cannot get MTD information");
+ goto out_close_mtd;
+ }
+
+ err = mtd_get_dev_info(libmtd, args.node, &mtd);
+ if (err) {
+ sys_errmsg("cannot get information about \"%s\"", args.node);
+ goto out_close_mtd;
+ }
+
+ args.node_fd = open(args.node, O_RDONLY);
+ if (args.node_fd == -1) {
+ sys_errmsg("cannot open \"%s\"", args.node);
+ goto out_close_mtd;
+ }
+
+ printf("Summary\n");
+ printf("=========================================================\n");
+ printf("mtd : %d\n", mtd.mtd_num);
+ printf("type : %s\n", mtd.type_str);
+ printf("size : ");
+ util_print_bytes(mtd.size, 1);
+ printf("\n");
+ printf("PEBs : %d\n", mtd.eb_cnt);
+ printf("min I/O: %d bytes\n", mtd.min_io_size);
+
+ printf("\n");
+ printf("PEB erase counters\n");
+ printf("=========================================================\n");
+ err = ubi_scan(&mtd, args.node_fd, &si, 0);
+ if (err) {
+ errmsg("failed to scan mtd%d (%s)", mtd.mtd_num, args.node);
+ goto out_close;
+ }
+
+ memset(bins, 0, sizeof(bins));
+
+ for (int j = 0; j < args.nbins; j++)
+ bins[j].min = INT_MAX;
+
+ min = INT_MAX;
+ max = 0;
+
+ for (int eb = 0; eb < mtd.eb_cnt; eb++) {
+ uint32_t ec = si->ec[eb];
+ switch (ec) {
+ case EB_EMPTY:
+ case EB_CORRUPTED:
+ case EB_ALIEN:
+ case EB_BAD:
+ case EC_MAX:
+ break;
+ default: {
+ int bin = 0;
+
+ if (ec > max)
+ max = ec;
+ if (ec < min)
+ min = ec;
+
+ for (int j = 0; j < args.nbins - 1 && ec >= args.bin_thresholds[j]; j++, bin++);
+
+ bins[bin].cnt++;
+ bins[bin].mean += ec;
+ if (ec < bins[bin].min)
+ bins[bin].min = ec;
+ if (ec > bins[bin].max)
+ bins[bin].max = ec;
+
+ } break;
+ }
+ }
+
+ printf("valid : %d\n", si->ok_cnt);
+ printf("empty : %d\n", si->empty_cnt);
+ printf("corrupted: %d\n", si->corrupted_cnt);
+ printf("alien : %d\n", si->alien_cnt);
+ printf("bad : %d\n", si->bad_cnt);
+
+ if (si->ok_cnt == 0)
+ min = 0;
+
+ printf("\n");
+ printf("Histogram\n");
+ printf("=========================================================\n");
+ printf("from to count min avg max\n");
+ printf("---------------------------------------------------------\n");
+ for (int j = 0; j < args.nbins; j++) {
+ if (bins[j].cnt)
+ bins[j].mean /= bins[j].cnt;
+ else
+ bins[j].min = 0;
+
+ int from = (j == 0) ? 0 : args.bin_thresholds[j - 1];
+ if (j == args.nbins - 1)
+ printf("%-8d .. inf: %8d %8d %8" PRIu64 " %8d\n",
+ from, bins[j].cnt, bins[j].min, bins[j].mean, bins[j].max);
+ else
+ printf("%-8d .. %8d: %8d %8d %8" PRIu64 " %8d\n",
+ from, args.bin_thresholds[j] - 1,
+ bins[j].cnt, bins[j].min, bins[j].mean, bins[j].max);
+ }
+ printf("---------------------------------------------------------\n");
+ printf("Total : %8d %8d %8llu %8d\n", si->ok_cnt, min, si->mean_ec, max);
+
+ if (args.verbose) {
+ printf("\n");
+ printf("Details\n");
+ printf("=========================================================\n");
+ for (int eb = 0; eb < mtd.eb_cnt; eb++) {
+ printf("PEB %8d: ", eb);
+ uint32_t ec = si->ec[eb];
+ switch (ec) {
+ case EB_EMPTY:
+ printf("EB_EMPTY\n");
+ break;
+ case EB_CORRUPTED:
+ printf("EB_CORRUPTED\n");
+ break;
+ case EB_ALIEN:
+ printf("EB_ALIEN\n");
+ break;
+ case EB_BAD:
+ printf("EB_BAD\n");
+ break;
+ case EC_MAX:
+ printf("EC_MAX\n");
+ break;
+ default:
+ printf("%u\n", ec);
+ break;
+ }
+ }
+ }
+
+ ubi_scan_free(si);
+ close(args.node_fd);
+ libmtd_close(libmtd);
+ return 0;
+
+out_close:
+ close(args.node_fd);
+out_close_mtd:
+ libmtd_close(libmtd);
+ return -1;
+}
+