Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

hyperv: Log hypercall status codes as strings

Introduce hv_status_printk() macros as a convenience to log hypercall
errors, formatting them with the status code (HV_STATUS_*) as a raw hex
value and also as a string, which saves some time while debugging.

Create a table of HV_STATUS_ codes with strings and mapped errnos, and
use it for hv_result_to_string() and hv_result_to_errno().

Use the new hv_status_printk()s in hv_proc.c, hyperv-iommu.c, and
irqdomain.c hypercalls to aid debugging in the root partition.

Signed-off-by: Nuno Das Neves <nunodasneves@linux.microsoft.com>
Reviewed-by: Stanislav Kinsburskii <skinsburskii@linux.microsoft.com>
Link: https://lore.kernel.org/r/1741980536-3865-2-git-send-email-nunodasneves@linux.microsoft.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>
Message-ID: <1741980536-3865-2-git-send-email-nunodasneves@linux.microsoft.com>

authored by

Nuno Das Neves and committed by
Wei Liu
3817854b e792d843

+118 -44
+3 -3
arch/x86/hyperv/irqdomain.c
··· 64 64 local_irq_restore(flags); 65 65 66 66 if (!hv_result_success(status)) 67 - pr_err("%s: hypercall failed, status %lld\n", __func__, status); 67 + hv_status_err(status, "\n"); 68 68 69 69 return hv_result(status); 70 70 } ··· 224 224 kfree(stored_entry); 225 225 226 226 if (status != HV_STATUS_SUCCESS) { 227 - pr_debug("%s: failed to unmap, status %lld", __func__, status); 227 + hv_status_debug(status, "failed to unmap\n"); 228 228 return; 229 229 } 230 230 } ··· 273 273 status = hv_unmap_msi_interrupt(dev, &old_entry); 274 274 275 275 if (status != HV_STATUS_SUCCESS) 276 - pr_err("%s: hypercall failed, status %lld\n", __func__, status); 276 + hv_status_err(status, "\n"); 277 277 } 278 278 279 279 static void hv_msi_free_irq(struct irq_domain *domain,
+95 -34
drivers/hv/hv_common.c
··· 684 684 } 685 685 EXPORT_SYMBOL_GPL(hv_tdx_hypercall); 686 686 687 - /* Convert a hypercall result into a linux-friendly error code. */ 688 - int hv_result_to_errno(u64 status) 689 - { 690 - /* hv_do_hypercall() may return U64_MAX, hypercalls aren't possible */ 691 - if (unlikely(status == U64_MAX)) 692 - return -EOPNOTSUPP; 693 - /* 694 - * A failed hypercall is usually only recoverable (or loggable) near 695 - * the call site where the HV_STATUS_* code is known. So the errno 696 - * it gets converted to is not too useful further up the stack. 697 - * Provide a few mappings that could be useful, and revert to -EIO 698 - * as a fallback. 699 - */ 700 - switch (hv_result(status)) { 701 - case HV_STATUS_SUCCESS: 702 - return 0; 703 - case HV_STATUS_INVALID_HYPERCALL_CODE: 704 - case HV_STATUS_INVALID_HYPERCALL_INPUT: 705 - case HV_STATUS_INVALID_PARAMETER: 706 - case HV_STATUS_INVALID_PARTITION_ID: 707 - case HV_STATUS_INVALID_VP_INDEX: 708 - case HV_STATUS_INVALID_PORT_ID: 709 - case HV_STATUS_INVALID_CONNECTION_ID: 710 - case HV_STATUS_INVALID_LP_INDEX: 711 - case HV_STATUS_INVALID_REGISTER_VALUE: 712 - return -EINVAL; 713 - case HV_STATUS_INSUFFICIENT_MEMORY: 714 - return -ENOMEM; 715 - default: 716 - break; 717 - } 718 - return -EIO; 719 - } 720 - 721 687 void hv_identify_partition_type(void) 722 688 { 723 689 /* Assume guest role */ ··· 706 740 pr_crit("Hyper-V: CONFIG_MSHV_ROOT not enabled!\n"); 707 741 } 708 742 } 743 + 744 + struct hv_status_info { 745 + char *string; 746 + int errno; 747 + u16 code; 748 + }; 749 + 750 + /* 751 + * Note on the errno mappings: 752 + * A failed hypercall is usually only recoverable (or loggable) near 753 + * the call site where the HV_STATUS_* code is known. So the errno 754 + * it gets converted to is not too useful further up the stack. 755 + * Provide a few mappings that could be useful, and revert to -EIO 756 + * as a fallback. 757 + */ 758 + static const struct hv_status_info hv_status_infos[] = { 759 + #define _STATUS_INFO(status, errno) { #status, (errno), (status) } 760 + _STATUS_INFO(HV_STATUS_SUCCESS, 0), 761 + _STATUS_INFO(HV_STATUS_INVALID_HYPERCALL_CODE, -EINVAL), 762 + _STATUS_INFO(HV_STATUS_INVALID_HYPERCALL_INPUT, -EINVAL), 763 + _STATUS_INFO(HV_STATUS_INVALID_ALIGNMENT, -EIO), 764 + _STATUS_INFO(HV_STATUS_INVALID_PARAMETER, -EINVAL), 765 + _STATUS_INFO(HV_STATUS_ACCESS_DENIED, -EIO), 766 + _STATUS_INFO(HV_STATUS_INVALID_PARTITION_STATE, -EIO), 767 + _STATUS_INFO(HV_STATUS_OPERATION_DENIED, -EIO), 768 + _STATUS_INFO(HV_STATUS_UNKNOWN_PROPERTY, -EIO), 769 + _STATUS_INFO(HV_STATUS_PROPERTY_VALUE_OUT_OF_RANGE, -EIO), 770 + _STATUS_INFO(HV_STATUS_INSUFFICIENT_MEMORY, -ENOMEM), 771 + _STATUS_INFO(HV_STATUS_INVALID_PARTITION_ID, -EINVAL), 772 + _STATUS_INFO(HV_STATUS_INVALID_VP_INDEX, -EINVAL), 773 + _STATUS_INFO(HV_STATUS_NOT_FOUND, -EIO), 774 + _STATUS_INFO(HV_STATUS_INVALID_PORT_ID, -EINVAL), 775 + _STATUS_INFO(HV_STATUS_INVALID_CONNECTION_ID, -EINVAL), 776 + _STATUS_INFO(HV_STATUS_INSUFFICIENT_BUFFERS, -EIO), 777 + _STATUS_INFO(HV_STATUS_NOT_ACKNOWLEDGED, -EIO), 778 + _STATUS_INFO(HV_STATUS_INVALID_VP_STATE, -EIO), 779 + _STATUS_INFO(HV_STATUS_NO_RESOURCES, -EIO), 780 + _STATUS_INFO(HV_STATUS_PROCESSOR_FEATURE_NOT_SUPPORTED, -EIO), 781 + _STATUS_INFO(HV_STATUS_INVALID_LP_INDEX, -EINVAL), 782 + _STATUS_INFO(HV_STATUS_INVALID_REGISTER_VALUE, -EINVAL), 783 + _STATUS_INFO(HV_STATUS_INVALID_LP_INDEX, -EIO), 784 + _STATUS_INFO(HV_STATUS_INVALID_REGISTER_VALUE, -EIO), 785 + _STATUS_INFO(HV_STATUS_OPERATION_FAILED, -EIO), 786 + _STATUS_INFO(HV_STATUS_TIME_OUT, -EIO), 787 + _STATUS_INFO(HV_STATUS_CALL_PENDING, -EIO), 788 + _STATUS_INFO(HV_STATUS_VTL_ALREADY_ENABLED, -EIO), 789 + #undef _STATUS_INFO 790 + }; 791 + 792 + static inline const struct hv_status_info *find_hv_status_info(u64 hv_status) 793 + { 794 + int i; 795 + u16 code = hv_result(hv_status); 796 + 797 + for (i = 0; i < ARRAY_SIZE(hv_status_infos); ++i) { 798 + const struct hv_status_info *info = &hv_status_infos[i]; 799 + 800 + if (info->code == code) 801 + return info; 802 + } 803 + 804 + return NULL; 805 + } 806 + 807 + /* Convert a hypercall result into a linux-friendly error code. */ 808 + int hv_result_to_errno(u64 status) 809 + { 810 + const struct hv_status_info *info; 811 + 812 + /* hv_do_hypercall() may return U64_MAX, hypercalls aren't possible */ 813 + if (unlikely(status == U64_MAX)) 814 + return -EOPNOTSUPP; 815 + 816 + info = find_hv_status_info(status); 817 + if (info) 818 + return info->errno; 819 + 820 + return -EIO; 821 + } 822 + EXPORT_SYMBOL_GPL(hv_result_to_errno); 823 + 824 + const char *hv_result_to_string(u64 status) 825 + { 826 + const struct hv_status_info *info; 827 + 828 + if (unlikely(status == U64_MAX)) 829 + return "Hypercall page missing!"; 830 + 831 + info = find_hv_status_info(status); 832 + if (info) 833 + return info->string; 834 + 835 + return "Unknown"; 836 + } 837 + EXPORT_SYMBOL_GPL(hv_result_to_string);
+5 -5
drivers/hv/hv_proc.c
··· 87 87 page_count, 0, input_page, NULL); 88 88 local_irq_restore(flags); 89 89 if (!hv_result_success(status)) { 90 - pr_err("Failed to deposit pages: %lld\n", status); 90 + hv_status_err(status, "\n"); 91 91 ret = hv_result_to_errno(status); 92 92 goto err_free_allocations; 93 93 } ··· 137 137 138 138 if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { 139 139 if (!hv_result_success(status)) { 140 - pr_err("%s: cpu %u apic ID %u, %lld\n", __func__, 141 - lp_index, apic_id, status); 140 + hv_status_err(status, "cpu %u apic ID: %u\n", 141 + lp_index, apic_id); 142 142 ret = hv_result_to_errno(status); 143 143 } 144 144 break; ··· 179 179 180 180 if (hv_result(status) != HV_STATUS_INSUFFICIENT_MEMORY) { 181 181 if (!hv_result_success(status)) { 182 - pr_err("%s: vcpu %u, lp %u, %lld\n", __func__, 183 - vp_index, flags, status); 182 + hv_status_err(status, "vcpu: %u, lp: %u\n", 183 + vp_index, flags); 184 184 ret = hv_result_to_errno(status); 185 185 } 186 186 break;
+2 -2
drivers/iommu/hyperv-iommu.c
··· 217 217 status = hv_unmap_ioapic_interrupt(ioapic_id, &entry); 218 218 219 219 if (status != HV_STATUS_SUCCESS) 220 - pr_debug("%s: unexpected unmap status %lld\n", __func__, status); 220 + hv_status_debug(status, "failed to unmap\n"); 221 221 222 222 data->entry.ioapic_rte.as_uint64 = 0; 223 223 data->entry.source = 0; /* Invalid source */ ··· 228 228 vector, &entry); 229 229 230 230 if (status != HV_STATUS_SUCCESS) { 231 - pr_err("%s: map hypercall failed, status %lld\n", __func__, status); 231 + hv_status_err(status, "map failed\n"); 232 232 return; 233 233 } 234 234
+13
include/asm-generic/mshyperv.h
··· 298 298 return __cpumask_to_vpset(vpset, cpus, func); 299 299 } 300 300 301 + #define _hv_status_fmt(fmt) "%s: Hyper-V status: %#x = %s: " fmt 302 + #define hv_status_printk(level, status, fmt, ...) \ 303 + do { \ 304 + u64 __status = (status); \ 305 + pr_##level(_hv_status_fmt(fmt), __func__, hv_result(__status), \ 306 + hv_result_to_string(__status), ##__VA_ARGS__); \ 307 + } while (0) 308 + #define hv_status_err(status, fmt, ...) \ 309 + hv_status_printk(err, status, fmt, ##__VA_ARGS__) 310 + #define hv_status_debug(status, fmt, ...) \ 311 + hv_status_printk(debug, status, fmt, ##__VA_ARGS__) 312 + 313 + const char *hv_result_to_string(u64 hv_status); 301 314 int hv_result_to_errno(u64 status); 302 315 void hyperv_report_panic(struct pt_regs *regs, long err, bool in_die); 303 316 bool hv_is_hyperv_initialized(void);