From patchwork Fri Mar 14 14:13:01 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ezequiel Garcia X-Patchwork-Id: 330328 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from casper.infradead.org (casper.infradead.org [IPv6:2001:770:15f::2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 08DAA2C00C3 for ; Sat, 15 Mar 2014 01:14:19 +1100 (EST) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1WOSsA-0000YX-DH; Fri, 14 Mar 2014 14:14:06 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WOSs8-0004IO-Q4; Fri, 14 Mar 2014 14:14:04 +0000 Received: from top.free-electrons.com ([176.31.233.9] helo=mail.free-electrons.com) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1WOSs5-0004HD-6i for linux-mtd@lists.infradead.org; Fri, 14 Mar 2014 14:14:02 +0000 Received: by mail.free-electrons.com (Postfix, from userid 106) id D37B07C8; Fri, 14 Mar 2014 15:13:24 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on mail.free-electrons.com X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=ALL_TRUSTED,SHORTCIRCUIT shortcircuit=ham autolearn=disabled version=3.3.2 Received: from localhost.localdomain (unknown [190.2.108.71]) by mail.free-electrons.com (Postfix) with ESMTPSA id 45DFD61B; Fri, 14 Mar 2014 15:13:23 +0100 (CET) From: Ezequiel Garcia To: Artem Bityutskiy , Subject: [PATCH] ubi-utils: Add ubiblock tool Date: Fri, 14 Mar 2014 11:13:01 -0300 Message-Id: <1394806381-25458-1-git-send-email-ezequiel.garcia@free-electrons.com> X-Mailer: git-send-email 1.9.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140314_101401_480951_74A0C776 X-CRM114-Status: GOOD ( 28.31 ) X-Spam-Score: -1.2 (-) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-1.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay domain 0.7 SPF_SOFTFAIL SPF: sender does not match SPF record (softfail) -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Ezequiel Garcia X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org With the addition of block device access to UBI volumes, we now add a simple userspace tool to access the new ioctls. Usage of this tool is as simple as it gets: $ ubiblock --attach /dev/ubi0_0 will create a new block device /dev/ubiblock0_0, and $ ubiblock --detach /dev/ubi0_0 will remove the device. Signed-off-by: Ezequiel Garcia --- Changes from previous attempts: * Rename the tool to ubiblock, as per Artem's suggestion. * Update new ioctls name and parameter. * Take advantage of ENOTTY and ENOSYS to report a proper error message; ENOTTY will be typically be obtained on old kernels where the UBI block ioctl's haven't been introduced. ENOSYS, on the other side, will happen when UBI is supported but not enabled in the running kernel (iow, not present). Makefile | 2 +- include/mtd/ubi-user.h | 22 ++++++ ubi-utils/.gitignore | 1 + ubi-utils/include/libubi.h | 16 ++++ ubi-utils/libubi.c | 10 +++ ubi-utils/ubiblock.c | 181 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 ubi-utils/ubiblock.c diff --git a/Makefile b/Makefile index 4ff8a49..d316a3d 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ MTD_BINS = \ sumtool jffs2reader UBI_BINS = \ ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \ - ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol + ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock BINS = $(MTD_BINS) BINS += mkfs.ubifs/mkfs.ubifs diff --git a/include/mtd/ubi-user.h b/include/mtd/ubi-user.h index 1c06d88..2b50dad 100644 --- a/include/mtd/ubi-user.h +++ b/include/mtd/ubi-user.h @@ -132,6 +132,16 @@ * used. A pointer to a &struct ubi_set_vol_prop_req object is expected to be * passed. The object describes which property should be set, and to which value * it should be set. + * + * Block devices on UBI volumes + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * To create a R/O block device on top of an UBI volume the %UBI_IOCVOLCRBLK + * should be used. A pointer to a &struct ubi_blkcreate_req object is expected + * to be passed, which is not used and reserved for future usage. + * + * Conversely, to remove a block device the %UBI_IOCVOLRMBLK should be used, + * which takes no arguments. */ /* @@ -186,6 +196,10 @@ /* Set an UBI volume property */ #define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \ struct ubi_set_vol_prop_req) +/* Create a R/O block device on top of an UBI volume */ +#define UBI_IOCVOLCRBLK _IOW(UBI_VOL_IOC_MAGIC, 7, struct ubi_blkcreate_req) +/* Remove the R/O block device */ +#define UBI_IOCVOLRMBLK _IO(UBI_VOL_IOC_MAGIC, 8) /* Maximum MTD device name length supported by UBI */ #define MAX_UBI_MTD_NAME_LEN 127 @@ -415,4 +429,12 @@ struct ubi_set_vol_prop_req { uint64_t value; } __attribute__((packed)); +/** + * struct ubi_blkcreate_req - a data structure used in block creation requests. + * @padding: reserved for future, not used, has to be zeroed + */ +struct ubi_blkcreate_req { + int8_t padding[128]; +} __attribute__((packed)); + #endif /* __UBI_USER_H__ */ diff --git a/ubi-utils/.gitignore b/ubi-utils/.gitignore index c035c97..19653a8 100644 --- a/ubi-utils/.gitignore +++ b/ubi-utils/.gitignore @@ -9,4 +9,5 @@ /ubirmvol /ubiupdatevol /ubirsvol +/ubiblock /mtdinfo diff --git a/ubi-utils/include/libubi.h b/ubi-utils/include/libubi.h index 47f40e2..4d6a7ee 100644 --- a/ubi-utils/include/libubi.h +++ b/ubi-utils/include/libubi.h @@ -400,6 +400,22 @@ int ubi_get_vol_info1_nm(libubi_t desc, int dev_num, const char *name, struct ubi_vol_info *info); /** + * ubi_vol_block_create - create a block device on top of an UBI volume. + * @fd: volume character device file descriptor + * + * Returns %0 in case of success and %-1 in case of failure. + */ +int ubi_vol_block_create(int fd); + +/** + * ubi_vol_block_remove - remove a block device from an UBI volume. + * @fd: volume character device file descriptor + * + * Returns %0 in case of success and %-1 in case of failure. + */ +int ubi_vol_block_remove(int fd); + +/** * ubi_update_start - start UBI volume update. * @desc: UBI library descriptor * @fd: volume character device file descriptor diff --git a/ubi-utils/libubi.c b/ubi-utils/libubi.c index a7463e8..598191e 100644 --- a/ubi-utils/libubi.c +++ b/ubi-utils/libubi.c @@ -1109,6 +1109,16 @@ int ubi_rsvol(libubi_t desc, const char *node, int vol_id, long long bytes) return ret; } +int ubi_vol_block_create(int fd) +{ + return ioctl(fd, UBI_IOCVOLCRBLK); +} + +int ubi_vol_block_remove(int fd) +{ + return ioctl(fd, UBI_IOCVOLRMBLK); +} + int ubi_update_start(libubi_t desc, int fd, long long bytes) { desc = desc; diff --git a/ubi-utils/ubiblock.c b/ubi-utils/ubiblock.c new file mode 100644 index 0000000..bdbd931 --- /dev/null +++ b/ubi-utils/ubiblock.c @@ -0,0 +1,181 @@ +/* + * ubiblock: + * An utility to attach block devices to UBI volumes. + * + * Copyright (c) Ezequiel Garcia, 2014 + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Usage + * ----- + * Since the ioctls have no arguments, usage of this tool is as simple + * as it gets: + * + * $ ubiblock --create /dev/ubi0_0 + * + * will make a new device /dev/ubiblock0_0 available, and + * + * $ ubiblock --remove /dev/ubi0_0 + * + * will remove the device. + */ + +#define PROGRAM_NAME "ubiblock" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "common.h" + +struct args { + const char *node; + int create; +}; + +static struct args args; + +static const char doc[] = PROGRAM_NAME " version " VERSION + " - a tool to create/remove block device interface from UBI volumes."; + +static const char optionsstr[] = +"-c, --create create block on top of a volume\n" +"-r, --remove remove block from volume\n" +"-h, --help print help message\n" +"-V, --version print program version"; + +static const char usage[] = +"Usage: " PROGRAM_NAME " [-c,-r] \n" +"Example: " PROGRAM_NAME " --create /dev/ubi0_0"; + +static const struct option long_options[] = { + { .name = "create", .has_arg = 1, .flag = NULL, .val = 'c' }, + { .name = "remove", .has_arg = 1, .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} +}; + +static int parse_opt(int argc, char * const argv[]) +{ + while (1) { + int key; + + key = getopt_long(argc, argv, "c:r:h?V", long_options, NULL); + if (key == -1) + break; + + switch (key) { + case 'c': + args.create = 1; + case 'r': + args.node = optarg; + break; + case 'h': + case '?': + printf("%s\n\n", doc); + printf("%s\n\n", usage); + printf("%s\n", optionsstr); + exit(EXIT_SUCCESS); + + case 'V': + common_print_version(); + exit(EXIT_SUCCESS); + + default: + fprintf(stderr, "Use -h for help\n"); + return -1; + } + } + + if (!args.node) + return errmsg("invalid arguments (use -h for help)"); + + return 0; +} + +int main(int argc, char * const argv[]) +{ + int err, fd; + libubi_t libubi; + + err = parse_opt(argc, argv); + if (err) + return -1; + + libubi = libubi_open(); + if (!libubi) { + if (errno == 0) + errmsg("UBI is not present in the system"); + return sys_errmsg("cannot open libubi"); + } + + err = ubi_probe_node(libubi, args.node); + if (err == 1) { + errmsg("\"%s\" is an UBI device node, not an UBI volume node", + args.node); + goto out_libubi; + } else if (err < 0) { + if (errno == ENODEV) + errmsg("\"%s\" is not an UBI volume node", args.node); + else + sys_errmsg("error while probing \"%s\"", args.node); + goto out_libubi; + } + + fd = open(args.node, O_RDWR); + if (fd == -1) { + sys_errmsg("cannot open UBI volume \"%s\"", args.node); + goto out_libubi; + } + + if (args.create) { + err = ubi_vol_block_create(fd); + if (err) { + if (errno == ENOSYS) + errmsg("UBI block is not present in the system"); + if (errno == ENOTTY) + errmsg("UBI block not supported (check your kernel version)"); + sys_errmsg("cannot create block device"); + goto out_close; + } + } else { + err = ubi_vol_block_remove(fd); + if (err) { + if (errno == ENOSYS) + errmsg("UBI block is not present in the system"); + if (errno == ENOTTY) + errmsg("UBI block not supported (check your kernel version)"); + sys_errmsg("cannot remove block device"); + goto out_close; + } + } + + close(fd); + libubi_close(libubi); + return 0; + +out_close: + close(fd); +out_libubi: + libubi_close(libubi); + return -1; +}