* Set an internal fail_point structure from a human-readable failpoint string * in a lock-safe manner. */
| 759 | * in a lock-safe manner. |
| 760 | */ |
| 761 | static int |
| 762 | fail_point_set(struct fail_point *fp, char *buf) |
| 763 | { |
| 764 | struct fail_point_entry *ent, *ent_next; |
| 765 | struct fail_point_setting *entries; |
| 766 | bool should_wake_paused; |
| 767 | bool should_truncate; |
| 768 | int error; |
| 769 | |
| 770 | error = 0; |
| 771 | should_wake_paused = false; |
| 772 | should_truncate = false; |
| 773 | |
| 774 | /* Parse new entries. */ |
| 775 | /** |
| 776 | * ref protects our new malloc'd stuff from being garbage collected |
| 777 | * before we link it. |
| 778 | */ |
| 779 | fail_point_setting_get_ref(fp); |
| 780 | entries = fail_point_setting_new(fp); |
| 781 | if (parse_fail_point(entries, buf) == NULL) { |
| 782 | STAILQ_REMOVE(&fp_setting_garbage, entries, |
| 783 | fail_point_setting, fs_garbage_link); |
| 784 | fail_point_setting_destroy(entries); |
| 785 | error = EINVAL; |
| 786 | goto end; |
| 787 | } |
| 788 | |
| 789 | /** |
| 790 | * Transfer the entries we are going to keep to a new list. |
| 791 | * Get rid of useless zero probability entries, and entries with hit |
| 792 | * count 0. |
| 793 | * If 'off' is present, and it has no hit count set, then all entries |
| 794 | * after it are discarded since they are unreachable. |
| 795 | */ |
| 796 | TAILQ_FOREACH_SAFE(ent, &entries->fp_entry_queue, fe_entries, ent_next) { |
| 797 | if (ent->fe_prob == 0 || ent->fe_count == 0) { |
| 798 | printf("Discarding entry which cannot execute %s\n", |
| 799 | fail_type_strings[ent->fe_type].name); |
| 800 | TAILQ_REMOVE(&entries->fp_entry_queue, ent, |
| 801 | fe_entries); |
| 802 | fp_free(ent); |
| 803 | continue; |
| 804 | } else if (should_truncate) { |
| 805 | printf("Discarding unreachable entry %s\n", |
| 806 | fail_type_strings[ent->fe_type].name); |
| 807 | TAILQ_REMOVE(&entries->fp_entry_queue, ent, |
| 808 | fe_entries); |
| 809 | fp_free(ent); |
| 810 | continue; |
| 811 | } |
| 812 | |
| 813 | if (ent->fe_type == FAIL_POINT_OFF) { |
| 814 | should_wake_paused = true; |
| 815 | if (ent->fe_count == FE_COUNT_UNTRACKED) { |
| 816 | should_truncate = true; |
| 817 | TAILQ_REMOVE(&entries->fp_entry_queue, ent, |
| 818 | fe_entries); |
no test coverage detected