diff options
author | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-07-13 14:47:47 -0400 |
---|---|---|
committer | Artem Bityutskiy <Artem.Bityutskiy@nokia.com> | 2008-07-24 06:34:46 -0400 |
commit | f40ac9cdf6991287f19bdafe9b0752ee40137908 (patch) | |
tree | a49120d5be3729feaa40880962f29e3679c1800e /drivers/mtd/ubi | |
parent | c8566350a3229ca505b84313c65d1403b4d0cbfc (diff) |
UBI: implement multiple volumes rename
Quite useful ioctl which allows to make atomic system upgrades.
The idea belongs to Richard Titmuss <richard_titmuss@logitech.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Diffstat (limited to 'drivers/mtd/ubi')
-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 |
5 files changed, 318 insertions, 12 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 |