diff options
| -rw-r--r-- | drivers/mtd/ubi/build.c | 1 | ||||
| -rw-r--r-- | drivers/mtd/ubi/cdev.c | 188 | ||||
| -rw-r--r-- | drivers/mtd/ubi/ubi.h | 33 | ||||
| -rw-r--r-- | drivers/mtd/ubi/vmt.c | 57 | ||||
| -rw-r--r-- | drivers/mtd/ubi/vtbl.c | 51 | ||||
| -rw-r--r-- | include/mtd/ubi-user.h | 60 |
6 files changed, 375 insertions, 15 deletions
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 7210e1da1fcb..4418a2369b56 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c | |||
| @@ -806,6 +806,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) | |||
| 806 | 806 | ||
| 807 | mutex_init(&ubi->buf_mutex); | 807 | mutex_init(&ubi->buf_mutex); |
| 808 | mutex_init(&ubi->ckvol_mutex); | 808 | mutex_init(&ubi->ckvol_mutex); |
| 809 | mutex_init(&ubi->mult_mutex); | ||
| 809 | mutex_init(&ubi->volumes_mutex); | 810 | mutex_init(&ubi->volumes_mutex); |
| 810 | spin_lock_init(&ubi->volumes_lock); | 811 | spin_lock_init(&ubi->volumes_lock); |
| 811 | 812 | ||
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 7c19918cc914..bc8199c6a9f5 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c | |||
| @@ -605,6 +605,166 @@ static int verify_rsvol_req(const struct ubi_device *ubi, | |||
| 605 | return 0; | 605 | return 0; |
| 606 | } | 606 | } |
| 607 | 607 | ||
| 608 | /** | ||
| 609 | * rename_volumes - rename UBI volumes. | ||
| 610 | * @ubi: UBI device description object | ||
| 611 | * @req: volumes re-name request | ||
| 612 | * | ||
| 613 | * This is a helper function for the volume re-name IOCTL which validates the | ||
| 614 | * the request, opens the volume and calls corresponding volumes management | ||
| 615 | * function. Returns zero in case of success and a negative error code in case | ||
| 616 | * of failure. | ||
| 617 | */ | ||
| 618 | static int rename_volumes(struct ubi_device *ubi, | ||
| 619 | struct ubi_rnvol_req *req) | ||
| 620 | { | ||
| 621 | int i, n, err; | ||
| 622 | struct list_head rename_list; | ||
| 623 | struct ubi_rename_entry *re, *re1; | ||
| 624 | |||
| 625 | if (req->count < 0 || req->count > UBI_MAX_RNVOL) | ||
| 626 | return -EINVAL; | ||
| 627 | |||
| 628 | if (req->count == 0) | ||
| 629 | return 0; | ||
| 630 | |||
| 631 | /* Validate volume IDs and names in the request */ | ||
| 632 | for (i = 0; i < req->count; i++) { | ||
| 633 | if (req->ents[i].vol_id < 0 || | ||
| 634 | req->ents[i].vol_id >= ubi->vtbl_slots) | ||
| 635 | return -EINVAL; | ||
| 636 | if (req->ents[i].name_len < 0) | ||
| 637 | return -EINVAL; | ||
| 638 | if (req->ents[i].name_len > UBI_VOL_NAME_MAX) | ||
| 639 | return -ENAMETOOLONG; | ||
| 640 | req->ents[i].name[req->ents[i].name_len] = '\0'; | ||
| 641 | n = strlen(req->ents[i].name); | ||
| 642 | if (n != req->ents[i].name_len) | ||
| 643 | err = -EINVAL; | ||
| 644 | } | ||
| 645 | |||
| 646 | /* Make sure volume IDs and names are unique */ | ||
| 647 | for (i = 0; i < req->count - 1; i++) { | ||
| 648 | for (n = i + 1; n < req->count; n++) { | ||
| 649 | if (req->ents[i].vol_id == req->ents[n].vol_id) { | ||
| 650 | dbg_err("duplicated volume id %d", | ||
| 651 | req->ents[i].vol_id); | ||
| 652 | return -EINVAL; | ||
| 653 | } | ||
| 654 | if (!strcmp(req->ents[i].name, req->ents[n].name)) { | ||
| 655 | dbg_err("duplicated volume name \"%s\"", | ||
| 656 | req->ents[i].name); | ||
| 657 | return -EINVAL; | ||
| 658 | } | ||
| 659 | } | ||
| 660 | } | ||
| 661 | |||
| 662 | /* Create the re-name list */ | ||
| 663 | INIT_LIST_HEAD(&rename_list); | ||
| 664 | for (i = 0; i < req->count; i++) { | ||
| 665 | int vol_id = req->ents[i].vol_id; | ||
| 666 | int name_len = req->ents[i].name_len; | ||
| 667 | const char *name = req->ents[i].name; | ||
| 668 | |||
| 669 | re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL); | ||
| 670 | if (!re) { | ||
| 671 | err = -ENOMEM; | ||
| 672 | goto out_free; | ||
| 673 | } | ||
| 674 | |||
| 675 | re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE); | ||
| 676 | if (IS_ERR(re->desc)) { | ||
| 677 | err = PTR_ERR(re->desc); | ||
| 678 | dbg_err("cannot open volume %d, error %d", vol_id, err); | ||
| 679 | kfree(re); | ||
| 680 | goto out_free; | ||
| 681 | } | ||
| 682 | |||
| 683 | /* Skip this re-naming if the name does not really change */ | ||
| 684 | if (re->desc->vol->name_len == name_len && | ||
| 685 | !memcmp(re->desc->vol->name, name, name_len)) { | ||
| 686 | ubi_close_volume(re->desc); | ||
| 687 | kfree(re); | ||
| 688 | continue; | ||
| 689 | } | ||
| 690 | |||
| 691 | re->new_name_len = name_len; | ||
| 692 | memcpy(re->new_name, name, name_len); | ||
| 693 | list_add_tail(&re->list, &rename_list); | ||
| 694 | dbg_msg("will rename volume %d from \"%s\" to \"%s\"", | ||
| 695 | vol_id, re->desc->vol->name, name); | ||
| 696 | } | ||
| 697 | |||
| 698 | if (list_empty(&rename_list)) | ||
| 699 | return 0; | ||
| 700 | |||
| 701 | /* Find out the volumes which have to be removed */ | ||
| 702 | list_for_each_entry(re, &rename_list, list) { | ||
| 703 | struct ubi_volume_desc *desc; | ||
| 704 | int no_remove_needed = 0; | ||
| 705 | |||
| 706 | /* | ||
| 707 | * Volume @re->vol_id is going to be re-named to | ||
| 708 | * @re->new_name, while its current name is @name. If a volume | ||
| 709 | * with name @re->new_name currently exists, it has to be | ||
| 710 | * removed, unless it is also re-named in the request (@req). | ||
| 711 | */ | ||
| 712 | list_for_each_entry(re1, &rename_list, list) { | ||
| 713 | if (re->new_name_len == re1->desc->vol->name_len && | ||
| 714 | !memcmp(re->new_name, re1->desc->vol->name, | ||
| 715 | re1->desc->vol->name_len)) { | ||
| 716 | no_remove_needed = 1; | ||
| 717 | break; | ||
| 718 | } | ||
| 719 | } | ||
| 720 | |||
| 721 | if (no_remove_needed) | ||
| 722 | continue; | ||
| 723 | |||
| 724 | /* | ||
| 725 | * It seems we need to remove volume with name @re->new_name, | ||
| 726 | * if it exists. | ||
| 727 | */ | ||
| 728 | desc = ubi_open_volume_nm(ubi->ubi_num, re->new_name, UBI_EXCLUSIVE); | ||
| 729 | if (IS_ERR(desc)) { | ||
| 730 | err = PTR_ERR(desc); | ||
| 731 | if (err == -ENODEV) | ||
| 732 | /* Re-naming into a non-existing volume name */ | ||
| 733 | continue; | ||
| 734 | |||
| 735 | /* The volume exists but busy, or an error occurred */ | ||
| 736 | dbg_err("cannot open volume \"%s\", error %d", | ||
| 737 | re->new_name, err); | ||
| 738 | goto out_free; | ||
| 739 | } | ||
| 740 | |||
| 741 | re = kzalloc(sizeof(struct ubi_rename_entry), GFP_KERNEL); | ||
| 742 | if (!re) { | ||
| 743 | err = -ENOMEM; | ||
| 744 | ubi_close_volume(desc); | ||
| 745 | goto out_free; | ||
| 746 | } | ||
| 747 | |||
| 748 | re->remove = 1; | ||
| 749 | re->desc = desc; | ||
| 750 | list_add(&re->list, &rename_list); | ||
| 751 | dbg_msg("will remove volume %d, name \"%s\"", | ||
| 752 | re->desc->vol->vol_id, re->desc->vol->name); | ||
| 753 | } | ||
| 754 | |||
| 755 | mutex_lock(&ubi->volumes_mutex); | ||
| 756 | err = ubi_rename_volumes(ubi, &rename_list); | ||
| 757 | mutex_unlock(&ubi->volumes_mutex); | ||
| 758 | |||
| 759 | out_free: | ||
| 760 | list_for_each_entry_safe(re, re1, &rename_list, list) { | ||
| 761 | ubi_close_volume(re->desc); | ||
| 762 | list_del(&re->list); | ||
| 763 | kfree(re); | ||
| 764 | } | ||
| 765 | return err; | ||
| 766 | } | ||
| 767 | |||
| 608 | static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | 768 | static int ubi_cdev_ioctl(struct inode *inode, struct file *file, |
| 609 | unsigned int cmd, unsigned long arg) | 769 | unsigned int cmd, unsigned long arg) |
| 610 | { | 770 | { |
| @@ -670,7 +830,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 670 | } | 830 | } |
| 671 | 831 | ||
| 672 | mutex_lock(&ubi->volumes_mutex); | 832 | mutex_lock(&ubi->volumes_mutex); |
| 673 | err = ubi_remove_volume(desc); | 833 | err = ubi_remove_volume(desc, 0); |
| 674 | mutex_unlock(&ubi->volumes_mutex); | 834 | mutex_unlock(&ubi->volumes_mutex); |
| 675 | 835 | ||
| 676 | /* | 836 | /* |
| @@ -717,6 +877,32 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file, | |||
| 717 | break; | 877 | break; |
| 718 | } | 878 | } |
| 719 | 879 | ||
| 880 | /* Re-name volumes command */ | ||
| 881 | case UBI_IOCRNVOL: | ||
| 882 | { | ||
| 883 | struct ubi_rnvol_req *req; | ||
| 884 | |||
| 885 | dbg_msg("re-name volumes"); | ||
| 886 | req = kmalloc(sizeof(struct ubi_rnvol_req), GFP_KERNEL); | ||
| 887 | if (!req) { | ||
| 888 | err = -ENOMEM; | ||
| 889 | break; | ||
| 890 | }; | ||
| 891 | |||
| 892 | err = copy_from_user(req, argp, sizeof(struct ubi_rnvol_req)); | ||
| 893 | if (err) { | ||
| 894 | err = -EFAULT; | ||
| 895 | kfree(req); | ||
| 896 | break; | ||
| 897 | } | ||
| 898 | |||
| 899 | mutex_lock(&ubi->mult_mutex); | ||
| 900 | err = rename_volumes(ubi, req); | ||
| 901 | mutex_unlock(&ubi->mult_mutex); | ||
| 902 | kfree(req); | ||
| 903 | break; | ||
| 904 | } | ||
| 905 | |||
| 720 | default: | 906 | default: |
| 721 | err = -ENOTTY; | 907 | err = -ENOTTY; |
| 722 | break; | 908 | break; |
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index 1fc32c863b78..274c67916b34 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h | |||
| @@ -131,6 +131,27 @@ struct ubi_ltree_entry { | |||
| 131 | struct rw_semaphore mutex; | 131 | struct rw_semaphore mutex; |
| 132 | }; | 132 | }; |
| 133 | 133 | ||
| 134 | /** | ||
| 135 | * struct ubi_rename_entry - volume re-name description data structure. | ||
| 136 | * @new_name_len: new volume name length | ||
| 137 | * @new_name: new volume name | ||
| 138 | * @remove: if not zero, this volume should be removed, not re-named | ||
| 139 | * @desc: descriptor of the volume | ||
| 140 | * @list: links re-name entries into a list | ||
| 141 | * | ||
| 142 | * This data structure is utilized in the multiple volume re-name code. Namely, | ||
| 143 | * UBI first creates a list of &struct ubi_rename_entry objects from the | ||
| 144 | * &struct ubi_rnvol_req request object, and then utilizes this list to do all | ||
| 145 | * the job. | ||
| 146 | */ | ||
| 147 | struct ubi_rename_entry { | ||
| 148 | int new_name_len; | ||
| 149 | char new_name[UBI_VOL_NAME_MAX + 1]; | ||
| 150 | int remove; | ||
| 151 | struct ubi_volume_desc *desc; | ||
| 152 | struct list_head list; | ||
| 153 | }; | ||
| 154 | |||
| 134 | struct ubi_volume_desc; | 155 | struct ubi_volume_desc; |
| 135 | 156 | ||
| 136 | /** | 157 | /** |
| @@ -206,7 +227,7 @@ struct ubi_volume { | |||
| 206 | int alignment; | 227 | int alignment; |
| 207 | int data_pad; | 228 | int data_pad; |
| 208 | int name_len; | 229 | int name_len; |
| 209 | char name[UBI_VOL_NAME_MAX+1]; | 230 | char name[UBI_VOL_NAME_MAX + 1]; |
| 210 | 231 | ||
| 211 | int upd_ebs; | 232 | int upd_ebs; |
| 212 | int ch_lnum; | 233 | int ch_lnum; |
| @@ -272,7 +293,7 @@ struct ubi_wl_entry; | |||
| 272 | * @vtbl_size: size of the volume table in bytes | 293 | * @vtbl_size: size of the volume table in bytes |
| 273 | * @vtbl: in-RAM volume table copy | 294 | * @vtbl: in-RAM volume table copy |
| 274 | * @volumes_mutex: protects on-flash volume table and serializes volume | 295 | * @volumes_mutex: protects on-flash volume table and serializes volume |
| 275 | * changes, like creation, deletion, update, resize | 296 | * changes, like creation, deletion, update, re-size and re-name |
| 276 | * | 297 | * |
| 277 | * @max_ec: current highest erase counter value | 298 | * @max_ec: current highest erase counter value |
| 278 | * @mean_ec: current mean erase counter value | 299 | * @mean_ec: current mean erase counter value |
| @@ -330,6 +351,8 @@ struct ubi_wl_entry; | |||
| 330 | * @peb_buf1: a buffer of PEB size used for different purposes | 351 | * @peb_buf1: a buffer of PEB size used for different purposes |
| 331 | * @peb_buf2: another buffer of PEB size used for different purposes | 352 | * @peb_buf2: another buffer of PEB size used for different purposes |
| 332 | * @buf_mutex: proptects @peb_buf1 and @peb_buf2 | 353 | * @buf_mutex: proptects @peb_buf1 and @peb_buf2 |
| 354 | * @ckvol_mutex: serializes static volume checking when opening | ||
| 355 | * @mult_mutex: serializes operations on multiple volumes, like re-nameing | ||
| 333 | * @dbg_peb_buf: buffer of PEB size used for debugging | 356 | * @dbg_peb_buf: buffer of PEB size used for debugging |
| 334 | * @dbg_buf_mutex: proptects @dbg_peb_buf | 357 | * @dbg_buf_mutex: proptects @dbg_peb_buf |
| 335 | */ | 358 | */ |
| @@ -410,6 +433,7 @@ struct ubi_device { | |||
| 410 | void *peb_buf2; | 433 | void *peb_buf2; |
| 411 | struct mutex buf_mutex; | 434 | struct mutex buf_mutex; |
| 412 | struct mutex ckvol_mutex; | 435 | struct mutex ckvol_mutex; |
| 436 | struct mutex mult_mutex; | ||
| 413 | #ifdef CONFIG_MTD_UBI_DEBUG | 437 | #ifdef CONFIG_MTD_UBI_DEBUG |
| 414 | void *dbg_peb_buf; | 438 | void *dbg_peb_buf; |
| 415 | struct mutex dbg_buf_mutex; | 439 | struct mutex dbg_buf_mutex; |
| @@ -426,12 +450,15 @@ extern struct mutex ubi_devices_mutex; | |||
| 426 | /* vtbl.c */ | 450 | /* vtbl.c */ |
| 427 | int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, | 451 | int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, |
| 428 | struct ubi_vtbl_record *vtbl_rec); | 452 | struct ubi_vtbl_record *vtbl_rec); |
| 453 | int ubi_vtbl_rename_volumes(struct ubi_device *ubi, | ||
| 454 | struct list_head *rename_list); | ||
| 429 | int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si); | 455 | int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si); |
| 430 | 456 | ||
| 431 | /* vmt.c */ | 457 | /* vmt.c */ |
| 432 | int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req); | 458 | int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req); |
| 433 | int ubi_remove_volume(struct ubi_volume_desc *desc); | 459 | int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl); |
| 434 | int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs); | 460 | int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs); |
| 461 | int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list); | ||
| 435 | int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol); | 462 | int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol); |
| 436 | void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol); | 463 | void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol); |
| 437 | 464 | ||
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 2cd886a5adac..4be4014c70df 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c | |||
| @@ -402,13 +402,14 @@ out_unlock: | |||
| 402 | /** | 402 | /** |
| 403 | * ubi_remove_volume - remove volume. | 403 | * ubi_remove_volume - remove volume. |
| 404 | * @desc: volume descriptor | 404 | * @desc: volume descriptor |
| 405 | * @no_vtbl: do not change volume table if not zero | ||
| 405 | * | 406 | * |
| 406 | * This function removes volume described by @desc. The volume has to be opened | 407 | * This function removes volume described by @desc. The volume has to be opened |
| 407 | * in "exclusive" mode. Returns zero in case of success and a negative error | 408 | * in "exclusive" mode. Returns zero in case of success and a negative error |
| 408 | * code in case of failure. The caller has to have the @ubi->volumes_mutex | 409 | * code in case of failure. The caller has to have the @ubi->volumes_mutex |
| 409 | * locked. | 410 | * locked. |
| 410 | */ | 411 | */ |
| 411 | int ubi_remove_volume(struct ubi_volume_desc *desc) | 412 | int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl) |
| 412 | { | 413 | { |
| 413 | struct ubi_volume *vol = desc->vol; | 414 | struct ubi_volume *vol = desc->vol; |
| 414 | struct ubi_device *ubi = vol->ubi; | 415 | struct ubi_device *ubi = vol->ubi; |
| @@ -437,9 +438,11 @@ int ubi_remove_volume(struct ubi_volume_desc *desc) | |||
| 437 | if (err) | 438 | if (err) |
| 438 | goto out_err; | 439 | goto out_err; |
| 439 | 440 | ||
| 440 | err = ubi_change_vtbl_record(ubi, vol_id, NULL); | 441 | if (!no_vtbl) { |
| 441 | if (err) | 442 | err = ubi_change_vtbl_record(ubi, vol_id, NULL); |
| 442 | goto out_err; | 443 | if (err) |
| 444 | goto out_err; | ||
| 445 | } | ||
| 443 | 446 | ||
| 444 | for (i = 0; i < vol->reserved_pebs; i++) { | 447 | for (i = 0; i < vol->reserved_pebs; i++) { |
| 445 | err = ubi_eba_unmap_leb(ubi, vol, i); | 448 | err = ubi_eba_unmap_leb(ubi, vol, i); |
| @@ -465,7 +468,8 @@ int ubi_remove_volume(struct ubi_volume_desc *desc) | |||
| 465 | ubi->vol_count -= 1; | 468 | ubi->vol_count -= 1; |
| 466 | spin_unlock(&ubi->volumes_lock); | 469 | spin_unlock(&ubi->volumes_lock); |
| 467 | 470 | ||
| 468 | err = paranoid_check_volumes(ubi); | 471 | if (!no_vtbl) |
| 472 | err = paranoid_check_volumes(ubi); | ||
| 469 | return err; | 473 | return err; |
| 470 | 474 | ||
| 471 | out_err: | 475 | out_err: |
| @@ -602,6 +606,44 @@ out_free: | |||
| 602 | } | 606 | } |
| 603 | 607 | ||
| 604 | /** | 608 | /** |
| 609 | * ubi_rename_volumes - re-name UBI volumes. | ||
| 610 | * @ubi: UBI device description object | ||
| 611 | * @renam_list: list of &struct ubi_rename_entry objects | ||
| 612 | * | ||
| 613 | * This function re-names or removes volumes specified in the re-name list. | ||
| 614 | * Returns zero in case of success and a negative error code in case of | ||
| 615 | * failure. | ||
| 616 | */ | ||
| 617 | int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list) | ||
| 618 | { | ||
| 619 | int err; | ||
| 620 | struct ubi_rename_entry *re; | ||
| 621 | |||
| 622 | err = ubi_vtbl_rename_volumes(ubi, rename_list); | ||
| 623 | if (err) | ||
| 624 | return err; | ||
| 625 | |||
| 626 | list_for_each_entry(re, rename_list, list) { | ||
| 627 | if (re->remove) { | ||
| 628 | err = ubi_remove_volume(re->desc, 1); | ||
| 629 | if (err) | ||
| 630 | break; | ||
| 631 | } else { | ||
| 632 | struct ubi_volume *vol = re->desc->vol; | ||
| 633 | |||
| 634 | spin_lock(&ubi->volumes_lock); | ||
| 635 | vol->name_len = re->new_name_len; | ||
| 636 | memcpy(vol->name, re->new_name, re->new_name_len + 1); | ||
| 637 | spin_unlock(&ubi->volumes_lock); | ||
| 638 | } | ||
| 639 | } | ||
| 640 | |||
| 641 | if (!err) | ||
| 642 | paranoid_check_volumes(ubi); | ||
| 643 | return err; | ||
| 644 | } | ||
| 645 | |||
| 646 | /** | ||
| 605 | * ubi_add_volume - add volume. | 647 | * ubi_add_volume - add volume. |
| 606 | * @ubi: UBI device description object | 648 | * @ubi: UBI device description object |
| 607 | * @vol: volume description object | 649 | * @vol: volume description object |
| @@ -826,10 +868,9 @@ static int paranoid_check_volume(struct ubi_device *ubi, int vol_id) | |||
| 826 | 868 | ||
| 827 | fail: | 869 | fail: |
| 828 | ubi_err("paranoid check failed for volume %d", vol_id); | 870 | ubi_err("paranoid check failed for volume %d", vol_id); |
| 829 | if (vol) { | 871 | if (vol) |
| 830 | ubi_dbg_dump_vol_info(vol); | 872 | ubi_dbg_dump_vol_info(vol); |
| 831 | ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); | 873 | ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); |
| 832 | } | ||
| 833 | spin_unlock(&ubi->volumes_lock); | 874 | spin_unlock(&ubi->volumes_lock); |
| 834 | return -EINVAL; | 875 | return -EINVAL; |
| 835 | } | 876 | } |
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 05fb72fd268f..23c5376234b2 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c | |||
| @@ -115,6 +115,57 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, | |||
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | /** | 117 | /** |
| 118 | * ubi_vtbl_rename_volumes - rename UBI volumes in the volume table. | ||
| 119 | * @ubi: UBI device description object | ||
| 120 | * @renam_list: list of &struct ubi_rename_entry objects | ||
| 121 | * | ||
| 122 | * This function re-names multiple volumes specified in @req in the volume | ||
| 123 | * table. Returns zero in case of success and a negative error code in case of | ||
| 124 | * failure. | ||
| 125 | */ | ||
| 126 | int ubi_vtbl_rename_volumes(struct ubi_device *ubi, | ||
| 127 | struct list_head *rename_list) | ||
| 128 | { | ||
| 129 | int i, err; | ||
| 130 | struct ubi_rename_entry *re; | ||
| 131 | struct ubi_volume *layout_vol; | ||
| 132 | |||
| 133 | list_for_each_entry(re, rename_list, list) { | ||
| 134 | uint32_t crc; | ||
| 135 | struct ubi_volume *vol = re->desc->vol; | ||
| 136 | struct ubi_vtbl_record *vtbl_rec = &ubi->vtbl[vol->vol_id]; | ||
| 137 | |||
| 138 | if (re->remove) { | ||
| 139 | memcpy(vtbl_rec, &empty_vtbl_record, | ||
| 140 | sizeof(struct ubi_vtbl_record)); | ||
| 141 | continue; | ||
| 142 | } | ||
| 143 | |||
| 144 | vtbl_rec->name_len = cpu_to_be16(re->new_name_len); | ||
| 145 | memcpy(vtbl_rec->name, re->new_name, re->new_name_len); | ||
| 146 | memset(vtbl_rec->name + re->new_name_len, 0, | ||
| 147 | UBI_VOL_NAME_MAX + 1 - re->new_name_len); | ||
| 148 | crc = crc32(UBI_CRC32_INIT, vtbl_rec, | ||
| 149 | UBI_VTBL_RECORD_SIZE_CRC); | ||
| 150 | vtbl_rec->crc = cpu_to_be32(crc); | ||
| 151 | } | ||
| 152 | |||
| 153 | layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; | ||
| 154 | for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { | ||
| 155 | err = ubi_eba_unmap_leb(ubi, layout_vol, i); | ||
| 156 | if (err) | ||
| 157 | return err; | ||
| 158 | |||
| 159 | err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0, | ||
| 160 | ubi->vtbl_size, UBI_LONGTERM); | ||
| 161 | if (err) | ||
| 162 | return err; | ||
| 163 | } | ||
| 164 | |||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | |||
| 168 | /** | ||
| 118 | * vtbl_check - check if volume table is not corrupted and contains sensible | 169 | * vtbl_check - check if volume table is not corrupted and contains sensible |
| 119 | * data. | 170 | * data. |
| 120 | * @ubi: UBI device description object | 171 | * @ubi: UBI device description object |
diff --git a/include/mtd/ubi-user.h b/include/mtd/ubi-user.h index a7421f130cc0..e8e57c3dfcdb 100644 --- a/include/mtd/ubi-user.h +++ b/include/mtd/ubi-user.h | |||
| @@ -58,6 +58,13 @@ | |||
| 58 | * device should be used. A &struct ubi_rsvol_req object has to be properly | 58 | * device should be used. A &struct ubi_rsvol_req object has to be properly |
| 59 | * filled and a pointer to it has to be passed to the IOCTL. | 59 | * filled and a pointer to it has to be passed to the IOCTL. |
| 60 | * | 60 | * |
| 61 | * UBI volumes re-name | ||
| 62 | * ~~~~~~~~~~~~~~~~~~~ | ||
| 63 | * | ||
| 64 | * To re-name several volumes atomically at one go, the %UBI_IOCRNVOL command | ||
| 65 | * of the UBI character device should be used. A &struct ubi_rnvol_req object | ||
| 66 | * has to be properly filled and a pointer to it has to be passed to the IOCTL. | ||
| 67 | * | ||
| 61 | * UBI volume update | 68 | * UBI volume update |
| 62 | * ~~~~~~~~~~~~~~~~~ | 69 | * ~~~~~~~~~~~~~~~~~ |
| 63 | * | 70 | * |
| @@ -104,6 +111,8 @@ | |||
| 104 | #define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t) | 111 | #define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t) |
| 105 | /* Re-size an UBI volume */ | 112 | /* Re-size an UBI volume */ |
| 106 | #define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) | 113 | #define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) |
| 114 | /* Re-name volumes */ | ||
| 115 | #define UBI_IOCRNVOL _IOW(UBI_IOC_MAGIC, 3, struct ubi_rnvol_req) | ||
| 107 | 116 | ||
| 108 | /* IOCTL commands of the UBI control character device */ | 117 | /* IOCTL commands of the UBI control character device */ |
| 109 | 118 | ||
| @@ -128,6 +137,9 @@ | |||
| 128 | /* Maximum MTD device name length supported by UBI */ | 137 | /* Maximum MTD device name length supported by UBI */ |
| 129 | #define MAX_UBI_MTD_NAME_LEN 127 | 138 | #define MAX_UBI_MTD_NAME_LEN 127 |
| 130 | 139 | ||
| 140 | /* Maximum amount of UBI volumes that can be re-named at one go */ | ||
| 141 | #define UBI_MAX_RNVOL 32 | ||
| 142 | |||
| 131 | /* | 143 | /* |
| 132 | * UBI data type hint constants. | 144 | * UBI data type hint constants. |
| 133 | * | 145 | * |
| @@ -189,7 +201,7 @@ struct ubi_attach_req { | |||
| 189 | int32_t ubi_num; | 201 | int32_t ubi_num; |
| 190 | int32_t mtd_num; | 202 | int32_t mtd_num; |
| 191 | int32_t vid_hdr_offset; | 203 | int32_t vid_hdr_offset; |
| 192 | uint8_t padding[12]; | 204 | int8_t padding[12]; |
| 193 | }; | 205 | }; |
| 194 | 206 | ||
| 195 | /** | 207 | /** |
| @@ -251,6 +263,48 @@ struct ubi_rsvol_req { | |||
| 251 | } __attribute__ ((packed)); | 263 | } __attribute__ ((packed)); |
| 252 | 264 | ||
| 253 | /** | 265 | /** |
| 266 | * struct ubi_rnvol_req - volumes re-name request. | ||
| 267 | * @count: count of volumes to re-name | ||
| 268 | * @padding1: reserved for future, not used, has to be zeroed | ||
| 269 | * @vol_id: ID of the volume to re-name | ||
| 270 | * @name_len: name length | ||
| 271 | * @padding2: reserved for future, not used, has to be zeroed | ||
| 272 | * @name: new volume name | ||
| 273 | * | ||
| 274 | * UBI allows to re-name up to %32 volumes at one go. The count of volumes to | ||
| 275 | * re-name is specified in the @count field. The ID of the volumes to re-name | ||
| 276 | * and the new names are specified in the @vol_id and @name fields. | ||
| 277 | * | ||
| 278 | * The UBI volume re-name operation is atomic, which means that should power cut | ||
| 279 | * happen, the volumes will have either old name or new name. So the possible | ||
| 280 | * use-cases of this command is atomic upgrade. Indeed, to upgrade, say, volumes | ||
| 281 | * A and B one may create temporary volumes %A1 and %B1 with the new contents, | ||
| 282 | * then atomically re-name A1->A and B1->B, in which case old %A and %B will | ||
| 283 | * be removed. | ||
| 284 | * | ||
| 285 | * If it is not desirable to remove old A and B, the re-name request has to | ||
| 286 | * contain 4 entries: A1->A, A->A1, B1->B, B->B1, in which case old A1 and B1 | ||
| 287 | * become A and B, and old A and B will become A1 and B1. | ||
| 288 | * | ||
| 289 | * It is also OK to request: A1->A, A1->X, B1->B, B->Y, in which case old A1 | ||
| 290 | * and B1 become A and B, and old A and B become X and Y. | ||
| 291 | * | ||
| 292 | * In other words, in case of re-naming into an existing volume name, the | ||
| 293 | * existing volume is removed, unless it is re-named as well at the same | ||
| 294 | * re-name request. | ||
| 295 | */ | ||
| 296 | struct ubi_rnvol_req { | ||
| 297 | int32_t count; | ||
| 298 | int8_t padding1[12]; | ||
| 299 | struct { | ||
| 300 | int32_t vol_id; | ||
| 301 | int16_t name_len; | ||
| 302 | int8_t padding2[2]; | ||
| 303 | char name[UBI_MAX_VOLUME_NAME + 1]; | ||
| 304 | } ents[UBI_MAX_RNVOL]; | ||
| 305 | } __attribute__ ((packed)); | ||
| 306 | |||
| 307 | /** | ||
| 254 | * struct ubi_leb_change_req - a data structure used in atomic logical | 308 | * struct ubi_leb_change_req - a data structure used in atomic logical |
| 255 | * eraseblock change requests. | 309 | * eraseblock change requests. |
| 256 | * @lnum: logical eraseblock number to change | 310 | * @lnum: logical eraseblock number to change |
| @@ -261,8 +315,8 @@ struct ubi_rsvol_req { | |||
| 261 | struct ubi_leb_change_req { | 315 | struct ubi_leb_change_req { |
| 262 | int32_t lnum; | 316 | int32_t lnum; |
| 263 | int32_t bytes; | 317 | int32_t bytes; |
| 264 | uint8_t dtype; | 318 | int8_t dtype; |
| 265 | uint8_t padding[7]; | 319 | int8_t padding[7]; |
| 266 | } __attribute__ ((packed)); | 320 | } __attribute__ ((packed)); |
| 267 | 321 | ||
| 268 | #endif /* __UBI_USER_H__ */ | 322 | #endif /* __UBI_USER_H__ */ |
