diff options
Diffstat (limited to 'ubi-utils')
-rw-r--r-- | ubi-utils/Makemodule.am | 9 | ||||
-rw-r--r-- | ubi-utils/mtdinfo.c | 14 | ||||
-rw-r--r-- | ubi-utils/ubiattach.c | 25 | ||||
-rw-r--r-- | ubi-utils/ubinfo.c | 10 | ||||
-rw-r--r-- | ubi-utils/ubiscan.c | 318 |
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; +} + |