Changeset 8b51009 in mainline for uspace/srv/bd/hr/util.c
- Timestamp:
- 2025-03-28T23:37:16Z (3 months ago)
- Children:
- 0437dd5
- Parents:
- 7bfe468
- git-author:
- Miroslav Cimerman <mc@…> (2025-03-28 23:25:57)
- git-committer:
- Miroslav Cimerman <mc@…> (2025-03-28 23:37:16)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/bd/hr/util.c
r7bfe468 r8b51009 41 41 #include <io/log.h> 42 42 #include <loc.h> 43 #include <mem.h> 43 44 #include <stdatomic.h> 44 45 #include <stdlib.h> 45 46 #include <stdio.h> 46 47 #include <str_error.h> 47 48 #include <vbd.h> 49 50 #include "io.h" 51 #include "superblock.h" 48 52 #include "util.h" 49 53 #include "var.h" … … 56 60 57 61 extern loc_srv_t *hr_srv; 62 extern list_t hr_volumes; 63 extern fibril_rwlock_t hr_volumes_lock; 64 65 errno_t hr_create_vol_struct(hr_volume_t **rvol, hr_level_t level) 66 { 67 errno_t rc; 68 69 hr_volume_t *vol = calloc(1, sizeof(hr_volume_t)); 70 if (vol == NULL) 71 return ENOMEM; 72 73 vol->level = level; 74 75 switch (level) { 76 case HR_LVL_1: 77 vol->hr_ops.create = hr_raid1_create; 78 vol->hr_ops.init = hr_raid1_init; 79 vol->hr_ops.status_event = hr_raid1_status_event; 80 vol->hr_ops.add_hotspare = hr_raid1_add_hotspare; 81 break; 82 case HR_LVL_0: 83 vol->hr_ops.create = hr_raid0_create; 84 vol->hr_ops.init = hr_raid0_init; 85 vol->hr_ops.status_event = hr_raid0_status_event; 86 break; 87 case HR_LVL_4: 88 vol->hr_ops.create = hr_raid5_create; 89 vol->hr_ops.init = hr_raid5_init; 90 vol->hr_ops.status_event = hr_raid5_status_event; 91 vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; 92 break; 93 case HR_LVL_5: 94 vol->hr_ops.create = hr_raid5_create; 95 vol->hr_ops.init = hr_raid5_init; 96 vol->hr_ops.status_event = hr_raid5_status_event; 97 vol->hr_ops.add_hotspare = hr_raid5_add_hotspare; 98 break; 99 default: 100 HR_DEBUG("unkown level: %d, aborting\n", vol->level); 101 rc = EINVAL; 102 goto error; 103 } 104 105 vol->fge = hr_fpool_create(16, 32, sizeof(hr_io_t)); 106 if (vol->fge == NULL) { 107 rc = ENOMEM; 108 goto error; 109 } 110 111 vol->status = HR_VOL_NONE; 112 113 for (size_t i = 0; i < HR_MAX_EXTENTS; ++i) 114 vol->extents[i].status = HR_EXT_MISSING; 115 116 for (size_t i = 0; i < HR_MAX_HOTSPARES; ++i) 117 vol->extents[i].status = HR_EXT_MISSING; 118 119 fibril_mutex_initialize(&vol->lock); /* XXX: will remove this */ 120 121 fibril_rwlock_initialize(&vol->extents_lock); 122 fibril_rwlock_initialize(&vol->states_lock); 123 124 fibril_mutex_initialize(&vol->hotspare_lock); 125 126 list_initialize(&vol->range_lock_list); 127 fibril_mutex_initialize(&vol->range_lock_list_lock); 128 129 atomic_init(&vol->rebuild_blk, 0); 130 atomic_init(&vol->state_dirty, false); 131 atomic_init(&vol->open_cnt, 0); 132 133 *rvol = vol; 134 135 return EOK; 136 error: 137 free(vol); 138 return rc; 139 } 140 141 void hr_destroy_vol_struct(hr_volume_t *vol) 142 { 143 if (vol == NULL) 144 return; 145 146 hr_fpool_destroy(vol->fge); 147 hr_fini_devs(vol); 148 free(vol->in_mem_md); 149 free(vol); 150 } 151 152 hr_volume_t *hr_get_volume(service_id_t svc_id) 153 { 154 HR_DEBUG("hr_get_volume(): (%" PRIun ")\n", svc_id); 155 156 hr_volume_t *rvol = NULL; 157 158 fibril_rwlock_read_lock(&hr_volumes_lock); 159 list_foreach(hr_volumes, lvolumes, hr_volume_t, iter) { 160 if (iter->svc_id == svc_id) { 161 rvol = iter; 162 break; 163 } 164 } 165 166 fibril_rwlock_read_unlock(&hr_volumes_lock); 167 return rvol; 168 } 169 170 errno_t hr_remove_volume(service_id_t svc_id) 171 { 172 HR_DEBUG("hr_remove_volume(): (%" PRIun ")\n", svc_id); 173 174 errno_t rc; 175 176 fibril_rwlock_write_lock(&hr_volumes_lock); 177 list_foreach(hr_volumes, lvolumes, hr_volume_t, vol) { 178 if (vol->svc_id == svc_id) { 179 int open_cnt = atomic_load_explicit(&vol->open_cnt, 180 memory_order_relaxed); 181 /* 182 * The "atomicity" of this if condition is provided 183 * by the write lock - no new bd connection can 184 * come, because we need to get the bd_srvs_t from 185 * volume, which we get from the list. 186 * (see hr_client_conn() in hr.c) 187 */ 188 if (open_cnt > 0) { 189 fibril_rwlock_write_unlock(&hr_volumes_lock); 190 return EBUSY; 191 } 192 list_remove(&vol->lvolumes); 193 fibril_rwlock_write_unlock(&hr_volumes_lock); 194 195 hr_destroy_vol_struct(vol); 196 197 rc = loc_service_unregister(hr_srv, svc_id); 198 return rc; 199 } 200 } 201 202 fibril_rwlock_write_unlock(&hr_volumes_lock); 203 return ENOENT; 204 } 58 205 59 206 errno_t hr_init_devs(hr_volume_t *vol) … … 419 566 } 420 567 568 struct svc_id_linked { 569 link_t link; 570 service_id_t svc_id; 571 hr_metadata_t *md; 572 bool inited; 573 bool md_present; 574 }; 575 576 static errno_t hr_add_svc_linked_to_list(list_t *list, service_id_t svc_id, 577 bool inited, hr_metadata_t *md) 578 { 579 errno_t rc = EOK; 580 struct svc_id_linked *to_add; 581 582 to_add = malloc(sizeof(struct svc_id_linked)); 583 if (to_add == NULL) { 584 rc = ENOMEM; 585 goto error; 586 } 587 to_add->svc_id = svc_id; 588 to_add->inited = inited; 589 590 if (md != NULL) { 591 to_add->md = malloc(sizeof(hr_metadata_t)); 592 if (to_add->md == NULL) { 593 rc = ENOMEM; 594 goto error; 595 } 596 to_add->md_present = true; 597 memcpy(to_add->md, md, sizeof(*md)); 598 } else { 599 to_add->md_present = false; 600 } 601 602 list_append(&to_add->link, list); 603 604 error: 605 return rc; 606 } 607 608 static void free_svc_id_linked(struct svc_id_linked *p) 609 { 610 if (p->md_present) 611 free(p->md); 612 free(p); 613 } 614 615 static void free_svc_id_list(list_t *list) 616 { 617 struct svc_id_linked *dev_id; 618 while (!list_empty(list)) { 619 dev_id = list_pop(list, struct svc_id_linked, link); 620 free_svc_id_linked(dev_id); 621 } 622 } 623 624 static errno_t hr_fill_disk_part_svcs_list(list_t *list) 625 { 626 errno_t rc; 627 size_t disk_count; 628 service_id_t *disk_svcs = NULL; 629 vbd_t *vbd = NULL; 630 631 rc = vbd_create(&vbd); 632 if (rc != EOK) 633 goto error; 634 635 rc = vbd_get_disks(vbd, &disk_svcs, &disk_count); 636 if (rc != EOK) 637 goto error; 638 639 for (size_t i = 0; i < disk_count; i++) { 640 vbd_disk_info_t disk_info; 641 rc = vbd_disk_info(vbd, disk_svcs[i], &disk_info); 642 if (rc != EOK) 643 goto error; 644 645 if (disk_info.ltype == lt_none) { 646 rc = hr_add_svc_linked_to_list(list, disk_svcs[i], false, NULL); 647 if (rc != EOK) 648 goto error; 649 } else { 650 size_t part_count; 651 service_id_t *part_ids = NULL; 652 rc = vbd_label_get_parts(vbd, disk_svcs[i], &part_ids, &part_count); 653 if (rc != EOK) 654 goto error; 655 656 for (size_t j = 0; j < part_count; j++) { 657 vbd_part_info_t part_info; 658 rc = vbd_part_get_info(vbd, part_ids[j], &part_info); 659 if (rc != EOK) { 660 free(part_ids); 661 goto error; 662 } 663 664 rc = hr_add_svc_linked_to_list(list, 665 part_info.svc_id, false, NULL); 666 if (rc != EOK) { 667 free(part_ids); 668 goto error; 669 } 670 } 671 672 free(part_ids); 673 } 674 } 675 676 free(disk_svcs); 677 vbd_destroy(vbd); 678 return EOK; 679 error: 680 free_svc_id_list(list); 681 if (disk_svcs != NULL) 682 free(disk_svcs); 683 vbd_destroy(vbd); 684 685 return rc; 686 } 687 688 static errno_t block_init_dev_list(list_t *list) 689 { 690 list_foreach_safe(*list, cur_link, next_link) { 691 struct svc_id_linked *iter; 692 iter = list_get_instance(cur_link, struct svc_id_linked, link); 693 694 if (iter->inited) 695 continue; 696 697 errno_t rc = block_init(iter->svc_id); 698 699 /* already used as an extent of active volume */ 700 /* XXX: figure out how it is with hotspares too */ 701 if (rc == EEXIST) { 702 list_remove(cur_link); 703 free_svc_id_linked(iter); 704 continue; 705 } 706 707 if (rc != EOK) 708 return rc; 709 710 iter->inited = true; 711 } 712 713 return EOK; 714 } 715 716 static void block_fini_dev_list(list_t *list) 717 { 718 list_foreach(*list, link, struct svc_id_linked, iter) { 719 if (iter->inited) { 720 block_fini(iter->svc_id); 721 iter->inited = false; 722 } 723 } 724 } 725 726 static errno_t hr_util_get_matching_md_svcs_list(list_t *rlist, list_t *devlist, 727 service_id_t svc_id, hr_metadata_t *md_main) 728 { 729 errno_t rc = EOK; 730 731 list_foreach(*devlist, link, struct svc_id_linked, iter) { 732 if (iter->svc_id == svc_id) 733 continue; 734 void *md_block; 735 hr_metadata_t md; 736 rc = hr_get_metadata_block(iter->svc_id, &md_block); 737 if (rc != EOK) 738 goto error; 739 hr_decode_metadata_from_block(md_block, &md); 740 741 free(md_block); 742 743 if (!hr_valid_md_magic(&md)) 744 continue; 745 746 if (memcmp(md_main->uuid, md.uuid, HR_UUID_LEN) != 0) 747 continue; 748 749 /* 750 * XXX: can I assume bsize and everything is fine when 751 * UUID matches? 752 */ 753 754 rc = hr_add_svc_linked_to_list(rlist, iter->svc_id, true, &md); 755 if (rc != EOK) 756 goto error; 757 } 758 759 return EOK; 760 error: 761 free_svc_id_list(rlist); 762 return rc; 763 } 764 765 static errno_t hr_util_assemble_from_matching_list(list_t *list) 766 { 767 HR_DEBUG("%s()", __func__); 768 769 errno_t rc = EOK; 770 771 hr_metadata_t *main_md = NULL; 772 size_t max_counter_val = 0; 773 774 list_foreach(*list, link, struct svc_id_linked, iter) { 775 hr_metadata_dump(iter->md); 776 if (iter->md->counter >= max_counter_val) { 777 max_counter_val = iter->md->counter; 778 main_md = iter->md; 779 } 780 } 781 782 assert(main_md != NULL); 783 784 hr_volume_t *vol; 785 rc = hr_create_vol_struct(&vol, (hr_level_t)main_md->level); 786 if (rc != EOK) 787 goto error; 788 789 vol->nblocks = main_md->nblocks; 790 vol->data_blkno = main_md->data_blkno; 791 vol->truncated_blkno = main_md->truncated_blkno; 792 vol->data_offset = main_md->data_offset; 793 vol->counter = main_md->counter; 794 vol->metadata_version = main_md->version; 795 vol->extent_no = main_md->extent_no; 796 vol->level = main_md->level; 797 vol->layout = main_md->layout; 798 vol->strip_size = main_md->strip_size; 799 vol->bsize = main_md->bsize; 800 memcpy(vol->devname, main_md->devname, HR_DEVNAME_LEN); 801 802 list_foreach(*list, link, struct svc_id_linked, iter) { 803 vol->extents[iter->md->index].svc_id = iter->svc_id; 804 if (iter->md->counter == max_counter_val) 805 vol->extents[iter->md->index].status = HR_EXT_ONLINE; 806 else 807 vol->extents[iter->md->index].status = HR_EXT_INVALID; 808 } 809 810 rc = vol->hr_ops.create(vol); 811 if (rc != EOK) 812 goto error; 813 814 fibril_rwlock_write_lock(&hr_volumes_lock); 815 816 list_foreach(hr_volumes, lvolumes, hr_volume_t, other) { 817 uint8_t *our_uuid = vol->in_mem_md->uuid; 818 uint8_t *other_uuid = other->in_mem_md->uuid; 819 if (memcmp(our_uuid, other_uuid, HR_UUID_LEN) == 0) { 820 rc = EEXIST; 821 fibril_rwlock_write_unlock(&hr_volumes_lock); 822 goto error; 823 } 824 } 825 826 /* 827 * XXX: register it here 828 * ... if it fails on EEXIST try different name... like + 1 on the end 829 */ 830 831 list_append(&vol->lvolumes, &hr_volumes); 832 833 fibril_rwlock_write_unlock(&hr_volumes_lock); 834 835 return EOK; 836 error: 837 hr_destroy_vol_struct(vol); 838 return rc; 839 } 840 841 errno_t hr_util_try_auto_assemble(size_t *rassembled_cnt) 842 { 843 HR_DEBUG("%s()", __func__); 844 845 /* 846 * scan partitions or disks: 847 * 848 * When we find a metadata block with valid 849 * magic, take UUID and try to find other matching 850 * UUIDs. 851 * 852 * We ignore extents that are a part of already 853 * active volumes. (even when the counter is lower 854 * on active volumes... XXX: use timestamp as initial counter value 855 * when assembling, or writing dirty metadata?) 856 */ 857 858 size_t asm_cnt = 0; 859 errno_t rc; 860 list_t dev_id_list; 861 862 list_initialize(&dev_id_list); 863 rc = hr_fill_disk_part_svcs_list(&dev_id_list); 864 if (rc != EOK) 865 goto error; 866 867 rc = block_init_dev_list(&dev_id_list); 868 if (rc != EOK) 869 goto error; 870 871 struct svc_id_linked *iter; 872 while (!list_empty(&dev_id_list)) { 873 iter = list_pop(&dev_id_list, struct svc_id_linked, link); 874 875 printf("svc_id: %lu\n", iter->svc_id); 876 877 void *metadata_block; 878 hr_metadata_t metadata; 879 880 rc = hr_get_metadata_block(iter->svc_id, &metadata_block); 881 if (rc != EOK) 882 goto error; 883 884 hr_decode_metadata_from_block(metadata_block, &metadata); 885 886 free(metadata_block); 887 888 if (!hr_valid_md_magic(&metadata)) { 889 printf("BAD magic\n"); 890 block_fini(iter->svc_id); 891 free_svc_id_linked(iter); 892 continue; 893 } 894 895 hr_metadata_dump(&metadata); 896 897 char *svc_name = NULL; 898 rc = loc_service_get_name(iter->svc_id, &svc_name); 899 if (rc != EOK) 900 goto error; 901 902 HR_DEBUG("found valid metadata on %s, " 903 "will try to match other extents\n", svc_name); 904 905 free(svc_name); 906 907 list_t matching_svcs_list; 908 list_initialize(&matching_svcs_list); 909 910 rc = hr_util_get_matching_md_svcs_list(&matching_svcs_list, 911 &dev_id_list, iter->svc_id, &metadata); 912 if (rc != EOK) 913 goto error; 914 915 /* add current iter to list as well */ 916 rc = hr_add_svc_linked_to_list(&matching_svcs_list, 917 iter->svc_id, true, &metadata); 918 if (rc != EOK) { 919 free_svc_id_list(&matching_svcs_list); 920 goto error; 921 } 922 923 /* remove matching list members from dev_id_list */ 924 list_foreach(matching_svcs_list, link, struct svc_id_linked, 925 iter2) { 926 printf("matching svc_id: %lu\n", iter2->svc_id); 927 struct svc_id_linked *to_remove; 928 list_foreach_safe(dev_id_list, cur_link, next_link) { 929 to_remove = list_get_instance(cur_link, 930 struct svc_id_linked, link); 931 if (to_remove->svc_id == iter2->svc_id) { 932 list_remove(cur_link); 933 free_svc_id_linked(to_remove); 934 } 935 } 936 } 937 938 rc = hr_util_assemble_from_matching_list(&matching_svcs_list); 939 switch (rc) { 940 case EOK: 941 asm_cnt++; 942 break; 943 case EEXIST: 944 /* 945 * A race is detected this way, because we don't want 946 * to hold the hr_volumes list lock for a long time, 947 * for all assembly attempts. XXX: discuss... 948 */ 949 rc = EOK; 950 break; 951 default: 952 block_fini_dev_list(&matching_svcs_list); 953 free_svc_id_list(&matching_svcs_list); 954 goto error; 955 } 956 957 free_svc_id_list(&matching_svcs_list); 958 } 959 960 error: 961 if (rassembled_cnt != NULL) 962 *rassembled_cnt = asm_cnt; 963 964 block_fini_dev_list(&dev_id_list); 965 free_svc_id_list(&dev_id_list); 966 967 return rc; 968 } 969 421 970 /** @} 422 971 */
Note:
See TracChangeset
for help on using the changeset viewer.