static int hv_free_page_report()

in hv_balloon.c [1576:1620]


static int hv_free_page_report(struct page_reporting_dev_info *pr_dev_info,
		    struct scatterlist *sgl, unsigned int nents)
{
	unsigned long flags;
	struct hv_memory_hint *hint;
	int i;
	u64 status;
	struct scatterlist *sg;

	WARN_ON_ONCE(nents > HV_MEMORY_HINT_MAX_GPA_PAGE_RANGES);
	WARN_ON_ONCE(sgl->length < HV_MIN_PAGE_REPORTING_LEN);
	local_irq_save(flags);
	hint = *(struct hv_memory_hint **)this_cpu_ptr(hyperv_pcpu_input_arg);
	if (!hint) {
		local_irq_restore(flags);
		return -ENOSPC;
	}

	hint->type = HV_EXT_MEMORY_HEAT_HINT_TYPE_COLD_DISCARD;
	hint->reserved = 0;
	for_each_sg(sgl, sg, nents, i) {
		union hv_gpa_page_range *range;

		range = &hint->ranges[i];
		range->address_space = 0;
		/* page reporting only reports 2MB pages or higher */
		range->page.largepage = 1;
		range->page.additional_pages =
			(sg->length / HV_MIN_PAGE_REPORTING_LEN) - 1;
		range->page_size = HV_GPA_PAGE_RANGE_PAGE_SIZE_2MB;
		range->base_large_pfn =
			page_to_hvpfn(sg_page(sg)) >> HV_MIN_PAGE_REPORTING_ORDER;
	}

	status = hv_do_rep_hypercall(HV_EXT_CALL_MEMORY_HEAT_HINT, nents, 0,
				     hint, NULL);
	local_irq_restore(flags);
	if ((status & HV_HYPERCALL_RESULT_MASK) != HV_STATUS_SUCCESS) {
		pr_err("Cold memory discard hypercall failed with status %llx\n",
			status);
		return -EINVAL;
	}

	return 0;
}