From 85dccb92982450cacc0d7dd393f16778388582a6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 22 Sep 2016 09:37:14 +0200 Subject: mtd: ubi: Add API calls to create/remove volumes Currently we use a ioctl API to create/remove ubi volumes. This means we always have to carry all function code for ubi volume manipulation when the ioctl is compiled in. This adds a function API to create/remove volumes so that the linker can throw the unused code away later. Signed-off-by: Sascha Hauer --- drivers/mtd/ubi/barebox.c | 23 +++++++++++++++++++++++ include/linux/mtd/ubi.h | 3 +++ 2 files changed, 26 insertions(+) diff --git a/drivers/mtd/ubi/barebox.c b/drivers/mtd/ubi/barebox.c index fc60aaeec5..13c2a47afc 100644 --- a/drivers/mtd/ubi/barebox.c +++ b/drivers/mtd/ubi/barebox.c @@ -257,6 +257,29 @@ void ubi_volume_cdev_remove(struct ubi_volume *vol) kfree(priv); } +int ubi_api_create_volume(int ubi_num, struct ubi_mkvol_req *req) +{ + struct ubi_device *ubi; + int ret; + + ubi = ubi_get_device(ubi_num); + if (!ubi) + return -ENODEV; + + if (!req->bytes) + req->bytes = (__s64)ubi->avail_pebs * ubi->leb_size; + ret = ubi_create_volume(ubi, req); + + ubi_put_device(ubi); + + return ret; +} + +int ubi_api_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) +{ + return ubi_remove_volume(desc, no_vtbl); +} + static int ubi_cdev_ioctl(struct cdev *cdev, int cmd, void *buf) { struct ubi_volume_desc *desc; diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h index 0614681d73..c72f95b327 100644 --- a/include/linux/mtd/ubi.h +++ b/include/linux/mtd/ubi.h @@ -218,6 +218,9 @@ int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum); int ubi_sync(int ubi_num); int ubi_flush(int ubi_num, int vol_id, int lnum); +int ubi_api_create_volume(int ubi_num, struct ubi_mkvol_req *req); +int ubi_api_remove_volume(struct ubi_volume_desc *desc, int no_vtbl); + /* * This function is the same as the 'ubi_leb_read()' function, but it does not * provide the checking capability. -- cgit v1.2.3 From 0f5b72a110b1267e7b101a60b7df7f2ff2985cf6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 22 Sep 2016 09:38:17 +0200 Subject: mtd: ubi: introduce barebox specific ioctl to get ubi_num Code wishing to manipulate ubi devices from outside the ubi layer needs the ubi_num as reference. Add an ioctl to get the ubi_num from a filedescriptor. Signed-off-by: Sascha Hauer --- drivers/mtd/ubi/barebox.c | 3 +++ include/mtd/ubi-user.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/mtd/ubi/barebox.c b/drivers/mtd/ubi/barebox.c index 13c2a47afc..cb9223ebab 100644 --- a/drivers/mtd/ubi/barebox.c +++ b/drivers/mtd/ubi/barebox.c @@ -299,6 +299,9 @@ static int ubi_cdev_ioctl(struct cdev *cdev, int cmd, void *buf) if (!req->bytes) req->bytes = (__s64)ubi->avail_pebs * ubi->leb_size; return ubi_create_volume(ubi, req); + case UBI_IOCGETUBINUM: + *(u32 *)buf = ubi->ubi_num; + break; }; return 0; diff --git a/include/mtd/ubi-user.h b/include/mtd/ubi-user.h index 8c02f96e4c..9425533d19 100644 --- a/include/mtd/ubi-user.h +++ b/include/mtd/ubi-user.h @@ -161,6 +161,8 @@ /* Re-name volumes */ #define UBI_IOCRNVOL _IOW(UBI_IOC_MAGIC, 3, struct ubi_rnvol_req) +#define UBI_IOCGETUBINUM _IOR(UBI_IOC_MAGIC, 32, __u32) + /* ioctl commands of the UBI control character device */ #define UBI_CTRL_IOC_MAGIC 'o' -- cgit v1.2.3 From 520226a0149b59de3fa1cb5013bf458ee66d16c8 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 22 Sep 2016 09:39:08 +0200 Subject: mtd: ubi: commands: use function API to access ubi volumes We have a function API to manipulate ubi volumes, use it. Signed-off-by: Sascha Hauer --- commands/ubi.c | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/commands/ubi.c b/commands/ubi.c index 26b521f374..2c8fe6ff5a 100644 --- a/commands/ubi.c +++ b/commands/ubi.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -104,6 +105,7 @@ static int do_ubimkvol(int argc, char *argv[]) struct ubi_mkvol_req req; int fd, ret; uint64_t size; + uint32_t ubinum; req.vol_type = UBI_DYNAMIC_VOLUME; @@ -140,9 +142,14 @@ static int do_ubimkvol(int argc, char *argv[]) return 1; } - ret = ioctl(fd, UBI_IOCMKVOL, &req); - if (ret) - printf("failed to create: %s\n", strerror(-ret)); + ret = ioctl(fd, UBI_IOCGETUBINUM, &ubinum); + if (ret) { + printf("failed to get ubinum: %s\n", strerror(-ret)); + goto err; + } + + ret = ubi_api_create_volume(ubinum, &req); +err: close(fd); return ret ? 1 : 0; @@ -272,24 +279,38 @@ BAREBOX_CMD_END static int do_ubirmvol(int argc, char *argv[]) { - struct ubi_mkvol_req req; + struct ubi_volume_desc *desc; + uint32_t ubinum; int fd, ret; if (argc != 3) return COMMAND_ERROR_USAGE; - strncpy(req.name, argv[2], UBI_VOL_NAME_MAX); - req.name[UBI_VOL_NAME_MAX] = 0; - fd = open(argv[1], O_WRONLY); if (fd < 0) { perror("open"); return 1; } - ret = ioctl(fd, UBI_IOCRMVOL, &req); + ret = ioctl(fd, UBI_IOCGETUBINUM, &ubinum); + if (ret) { + printf("failed to get ubinum: %s\n", strerror(-ret)); + goto err; + } + + desc = ubi_open_volume_nm(ubinum, argv[2], UBI_EXCLUSIVE); + if (IS_ERR(desc)) { + ret = PTR_ERR(desc); + printf("failed to open volume %s: %s\n", argv[2], strerror(-ret)); + goto err; + } + + ret = ubi_api_remove_volume(desc, 0); if (ret) - printf("failed to delete: %s\n", strerror(-ret)); + printf("failed to remove volume %s: %s\n", argv[2], strerror(-ret)); + + ubi_close_volume(desc); +err: close(fd); return ret ? 1 : 0; -- cgit v1.2.3 From 29c844b965ec3d28f0791c6f0ba64882e2ea0ffe Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 22 Sep 2016 09:39:25 +0200 Subject: mtd: ubi: remove now unused ioctls The only ioctl needed is the one to get the ubi_num from a file descriptor. The remaining ioctls are now implemented as regular function calls. Signed-off-by: Sascha Hauer --- drivers/mtd/ubi/barebox.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/mtd/ubi/barebox.c b/drivers/mtd/ubi/barebox.c index cb9223ebab..23c4bfd841 100644 --- a/drivers/mtd/ubi/barebox.c +++ b/drivers/mtd/ubi/barebox.c @@ -282,23 +282,14 @@ int ubi_api_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) static int ubi_cdev_ioctl(struct cdev *cdev, int cmd, void *buf) { - struct ubi_volume_desc *desc; struct ubi_device *ubi = cdev->priv; - struct ubi_mkvol_req *req = buf; switch (cmd) { - case UBI_IOCRMVOL: - desc = ubi_open_volume_nm(ubi->ubi_num, req->name, - UBI_EXCLUSIVE); - if (IS_ERR(desc)) - return PTR_ERR(desc); - ubi_remove_volume(desc, 0); - ubi_close_volume(desc); - break; - case UBI_IOCMKVOL: - if (!req->bytes) - req->bytes = (__s64)ubi->avail_pebs * ubi->leb_size; - return ubi_create_volume(ubi, req); + /* + * Only supported ioctl is a barebox specific one to get the ubi_num + * from the file descriptor. The rest is implemented as function calls + * directly. + */ case UBI_IOCGETUBINUM: *(u32 *)buf = ubi->ubi_num; break; -- cgit v1.2.3 From fc428987c867e5731334fe5b01686e7b3deaeefd Mon Sep 17 00:00:00 2001 From: Giorgio Dal Molin Date: Mon, 26 Sep 2016 12:52:32 +0200 Subject: mtd: ubi: add API call to rename volumes. Signed-off-by: Giorgio Dal Molin Signed-off-by: Sascha Hauer --- drivers/mtd/ubi/barebox.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/mtd/ubi/vmt.c | 3 + include/linux/mtd/ubi.h | 1 + 3 files changed, 160 insertions(+) diff --git a/drivers/mtd/ubi/barebox.c b/drivers/mtd/ubi/barebox.c index 23c4bfd841..329cf4564a 100644 --- a/drivers/mtd/ubi/barebox.c +++ b/drivers/mtd/ubi/barebox.c @@ -280,6 +280,162 @@ int ubi_api_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) return ubi_remove_volume(desc, no_vtbl); } +int ubi_api_rename_volumes(int ubi_num, struct ubi_rnvol_req *req) +{ + int i, n, err; + struct list_head rename_list; + struct ubi_rename_entry *re, *re1; + struct ubi_device *ubi; + + if (req->count < 0 || req->count > UBI_MAX_RNVOL) + return -EINVAL; + + if (req->count == 0) + return 0; + + ubi = ubi_get_device(ubi_num); + if (!ubi) + return -ENODEV; + + /* Validate volume IDs and names in the request */ + for (i = 0; i < req->count; i++) { + if (req->ents[i].vol_id < 0 || + req->ents[i].vol_id >= ubi->vtbl_slots) + return -EINVAL; + if (req->ents[i].name_len < 0) + return -EINVAL; + if (req->ents[i].name_len > UBI_VOL_NAME_MAX) + return -ENAMETOOLONG; + req->ents[i].name[req->ents[i].name_len] = '\0'; + n = strlen(req->ents[i].name); + if (n != req->ents[i].name_len) + return -EINVAL; + } + + /* Make sure volume IDs and names are unique */ + for (i = 0; i < req->count - 1; i++) { + for (n = i + 1; n < req->count; n++) { + if (req->ents[i].vol_id == req->ents[n].vol_id) { + ubi_err(ubi, "duplicated volume id %d", + req->ents[i].vol_id); + return -EINVAL; + } + if (!strcmp(req->ents[i].name, req->ents[n].name)) { + ubi_err(ubi, "duplicated volume name \"%s\"", + req->ents[i].name); + return -EINVAL; + } + } + } + + /* Create the re-name list */ + INIT_LIST_HEAD(&rename_list); + for (i = 0; i < req->count; i++) { + int vol_id = req->ents[i].vol_id; + int name_len = req->ents[i].name_len; + const char *name = req->ents[i].name; + + re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL); + if (!re) { + err = -ENOMEM; + goto out_free; + } + + re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_READONLY); + if (IS_ERR(re->desc)) { + err = PTR_ERR(re->desc); + ubi_err(ubi, "cannot open volume %d, error %d", + vol_id, err); + kfree(re); + goto out_free; + } + + /* Skip this re-naming if the name does not really change */ + if (re->desc->vol->name_len == name_len && + !memcmp(re->desc->vol->name, name, name_len)) { + ubi_close_volume(re->desc); + kfree(re); + continue; + } + + re->new_name_len = name_len; + memcpy(re->new_name, name, name_len); + list_add_tail(&re->list, &rename_list); + dbg_gen("will rename volume %d from \"%s\" to \"%s\"", + vol_id, re->desc->vol->name, name); + } + + if (list_empty(&rename_list)) + return 0; + + /* Find out the volumes which have to be removed */ + list_for_each_entry(re, &rename_list, list) { + struct ubi_volume_desc *desc; + int no_remove_needed = 0; + + /* + * Volume @re->vol_id is going to be re-named to + * @re->new_name, while its current name is @name. If a volume + * with name @re->new_name currently exists, it has to be + * removed, unless it is also re-named in the request (@req). + */ + list_for_each_entry(re1, &rename_list, list) { + if (re->new_name_len == re1->desc->vol->name_len && + !memcmp(re->new_name, re1->desc->vol->name, + re1->desc->vol->name_len)) { + no_remove_needed = 1; + break; + } + } + + if (no_remove_needed) + continue; + + /* + * It seems we need to remove volume with name @re->new_name, + * if it exists. + */ + desc = ubi_open_volume_nm(ubi->ubi_num, re->new_name, + UBI_EXCLUSIVE); + if (IS_ERR(desc)) { + err = PTR_ERR(desc); + if (err == -ENODEV) + /* Re-naming into a non-existing volume name */ + continue; + + /* The volume exists but busy, or an error occurred */ + ubi_err(ubi, "cannot open volume \"%s\", error %d", + re->new_name, err); + goto out_free; + } + + re1 = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL); + if (!re1) { + err = -ENOMEM; + ubi_close_volume(desc); + goto out_free; + } + + re1->remove = 1; + re1->desc = desc; + list_add(&re1->list, &rename_list); + dbg_gen("will remove volume %d, name \"%s\"", + re1->desc->vol->vol_id, re1->desc->vol->name); + } + + mutex_lock(&ubi->device_mutex); + err = ubi_rename_volumes(ubi, &rename_list); + mutex_unlock(&ubi->device_mutex); + +out_free: + list_for_each_entry_safe(re, re1, &rename_list, list) { + ubi_close_volume(re->desc); + list_del(&re->list); + kfree(re); + } + return err; +} + static int ubi_cdev_ioctl(struct cdev *cdev, int cmd, void *buf) { struct ubi_device *ubi = cdev->priv; diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 41b814cf90..ed043646b8 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -411,6 +411,9 @@ int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list) vol->name_len = re->new_name_len; memcpy(vol->name, re->new_name, re->new_name_len + 1); + free(vol->cdev.name); + vol->cdev.name = basprintf("%s.%s", ubi->cdev.name, vol->name); + vol->cdev.size = vol->used_bytes; ubi_volume_notify(ubi, vol, UBI_VOLUME_RENAMED); } } diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h index c72f95b327..c215ff20f7 100644 --- a/include/linux/mtd/ubi.h +++ b/include/linux/mtd/ubi.h @@ -220,6 +220,7 @@ int ubi_flush(int ubi_num, int vol_id, int lnum); int ubi_api_create_volume(int ubi_num, struct ubi_mkvol_req *req); int ubi_api_remove_volume(struct ubi_volume_desc *desc, int no_vtbl); +int ubi_api_rename_volumes(int ubi_num, struct ubi_rnvol_req *req); /* * This function is the same as the 'ubi_leb_read()' function, but it does not -- cgit v1.2.3 From fed9b1ba3f6240541e6cfbcda9c5f8189095c2ac Mon Sep 17 00:00:00 2001 From: Giorgio Dal Molin Date: Mon, 26 Sep 2016 12:52:33 +0200 Subject: mtd: ubi: commands: added the new command 'ubirename'. Signed-off-by: Giorgio Dal Molin Signed-off-by: Sascha Hauer --- commands/ubi.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/commands/ubi.c b/commands/ubi.c index 2c8fe6ff5a..4c445d2216 100644 --- a/commands/ubi.c +++ b/commands/ubi.c @@ -327,3 +327,80 @@ BAREBOX_CMD_START(ubirmvol) BAREBOX_CMD_GROUP(CMD_GRP_PART) BAREBOX_CMD_HELP(cmd_ubirmvol_help) BAREBOX_CMD_END + +static int get_vol_id(u32 ubi_num, const char *name) +{ + struct ubi_volume_desc *desc; + struct ubi_volume_info vi; + + desc = ubi_open_volume_nm(ubi_num, name, UBI_READONLY); + if(IS_ERR(desc)) + return PTR_ERR(desc); + + ubi_get_volume_info(desc, &vi); + ubi_close_volume(desc); + + return vi.vol_id; +}; + +static int do_ubirename(int argc, char *argv[]) +{ + struct ubi_rnvol_req req; + u32 ubi_num; + int i, j, fd, ret; + + if ((argc < 4) || (argc % 2)) + return COMMAND_ERROR_USAGE; + + req.count = (argc / 2) - 1; + if (req.count > UBI_MAX_RNVOL) { + printf("too many volume renames. (max: %u)\n", UBI_MAX_RNVOL); + return COMMAND_ERROR_USAGE; + } + + fd = open(argv[1], O_WRONLY); + if (fd < 0) { + perror("unable to open the UBI device"); + return 1; + } + + ret = ioctl(fd, UBI_IOCGETUBINUM, &ubi_num); + + close(fd); + + if (ret) { + printf("failed to get ubi num for %s: %s\n", argv[1], strerror(-ret)); + return 1; + } + + for (i = 2, j = 0; i < argc; ++j, i += 2) { + req.ents[j].vol_id = get_vol_id(ubi_num, argv[i]); + + if (req.ents[j].vol_id < 0) { + printf("Volume '%s' does not exist on %s\n", argv[i], argv[1]); + ret = -EINVAL; + goto err; + } + + strncpy(req.ents[j].name, argv[i + 1], UBI_MAX_VOLUME_NAME); + req.ents[j].name_len = strlen(req.ents[j].name); + } + + ret = ubi_api_rename_volumes(ubi_num, &req); + if (ret) + printf("failed to rename: %s", strerror(-ret)); +err: + return ret ? 1 : 0; +}; + +BAREBOX_CMD_HELP_START(ubirename) +BAREBOX_CMD_HELP_TEXT("Rename UBI volume(s) from UBIDEV") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(ubirename) + .cmd = do_ubirename, + BAREBOX_CMD_DESC("rename UBI volume(s)") + BAREBOX_CMD_OPTS("UBIDEV OLD_NAME NEW_NAME [OLD_NAME NEW_NAME ...]") + BAREBOX_CMD_GROUP(CMD_GRP_PART) + BAREBOX_CMD_HELP(cmd_ubirename_help) +BAREBOX_CMD_END -- cgit v1.2.3