10d9e8c0bSMaciej S. Szmigiero /* 20d9e8c0bSMaciej S. Szmigiero * QEMU Hyper-V Dynamic Memory Protocol driver 30d9e8c0bSMaciej S. Szmigiero * 40d9e8c0bSMaciej S. Szmigiero * Copyright (C) 2020-2023 Oracle and/or its affiliates. 50d9e8c0bSMaciej S. Szmigiero * 60d9e8c0bSMaciej S. Szmigiero * This work is licensed under the terms of the GNU GPL, version 2 or later. 70d9e8c0bSMaciej S. Szmigiero * See the COPYING file in the top-level directory. 80d9e8c0bSMaciej S. Szmigiero */ 90d9e8c0bSMaciej S. Szmigiero 10*05871c72SPeter Maydell #include "qemu/osdep.h" 110d9e8c0bSMaciej S. Szmigiero #include "hv-balloon-internal.h" 120d9e8c0bSMaciej S. Szmigiero #include "hv-balloon-page_range_tree.h" 130d9e8c0bSMaciej S. Szmigiero 140d9e8c0bSMaciej S. Szmigiero /* 150d9e8c0bSMaciej S. Szmigiero * temporarily avoid warnings about enhanced GTree API usage requiring a 160d9e8c0bSMaciej S. Szmigiero * too recent Glib version until GLIB_VERSION_MAX_ALLOWED finally reaches 170d9e8c0bSMaciej S. Szmigiero * the Glib version with this API 180d9e8c0bSMaciej S. Szmigiero */ 190d9e8c0bSMaciej S. Szmigiero #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 200d9e8c0bSMaciej S. Szmigiero 210d9e8c0bSMaciej S. Szmigiero /* PageRangeTree */ 220d9e8c0bSMaciej S. Szmigiero static gint page_range_tree_key_compare(gconstpointer leftp, 230d9e8c0bSMaciej S. Szmigiero gconstpointer rightp, 240d9e8c0bSMaciej S. Szmigiero gpointer user_data) 250d9e8c0bSMaciej S. Szmigiero { 260d9e8c0bSMaciej S. Szmigiero const uint64_t *left = leftp, *right = rightp; 270d9e8c0bSMaciej S. Szmigiero 280d9e8c0bSMaciej S. Szmigiero if (*left < *right) { 290d9e8c0bSMaciej S. Szmigiero return -1; 300d9e8c0bSMaciej S. Szmigiero } else if (*left > *right) { 310d9e8c0bSMaciej S. Szmigiero return 1; 320d9e8c0bSMaciej S. Szmigiero } else { /* *left == *right */ 330d9e8c0bSMaciej S. Szmigiero return 0; 340d9e8c0bSMaciej S. Szmigiero } 350d9e8c0bSMaciej S. Szmigiero } 360d9e8c0bSMaciej S. Szmigiero 370d9e8c0bSMaciej S. Szmigiero static GTreeNode *page_range_tree_insert_new(PageRangeTree tree, 380d9e8c0bSMaciej S. Szmigiero uint64_t start, uint64_t count) 390d9e8c0bSMaciej S. Szmigiero { 400d9e8c0bSMaciej S. Szmigiero uint64_t *key = g_malloc(sizeof(*key)); 410d9e8c0bSMaciej S. Szmigiero PageRange *range = g_malloc(sizeof(*range)); 420d9e8c0bSMaciej S. Szmigiero 430d9e8c0bSMaciej S. Szmigiero assert(count > 0); 440d9e8c0bSMaciej S. Szmigiero 450d9e8c0bSMaciej S. Szmigiero *key = range->start = start; 460d9e8c0bSMaciej S. Szmigiero range->count = count; 470d9e8c0bSMaciej S. Szmigiero 480d9e8c0bSMaciej S. Szmigiero return g_tree_insert_node(tree.t, key, range); 490d9e8c0bSMaciej S. Szmigiero } 500d9e8c0bSMaciej S. Szmigiero 510d9e8c0bSMaciej S. Szmigiero void hvb_page_range_tree_insert(PageRangeTree tree, 520d9e8c0bSMaciej S. Szmigiero uint64_t start, uint64_t count, 530d9e8c0bSMaciej S. Szmigiero uint64_t *dupcount) 540d9e8c0bSMaciej S. Szmigiero { 550d9e8c0bSMaciej S. Szmigiero GTreeNode *node; 560d9e8c0bSMaciej S. Szmigiero bool joinable; 570d9e8c0bSMaciej S. Szmigiero uint64_t intersection; 580d9e8c0bSMaciej S. Szmigiero PageRange *range; 590d9e8c0bSMaciej S. Szmigiero 600d9e8c0bSMaciej S. Szmigiero assert(!SUM_OVERFLOW_U64(start, count)); 610d9e8c0bSMaciej S. Szmigiero if (count == 0) { 620d9e8c0bSMaciej S. Szmigiero return; 630d9e8c0bSMaciej S. Szmigiero } 640d9e8c0bSMaciej S. Szmigiero 650d9e8c0bSMaciej S. Szmigiero node = g_tree_upper_bound(tree.t, &start); 660d9e8c0bSMaciej S. Szmigiero if (node) { 670d9e8c0bSMaciej S. Szmigiero node = g_tree_node_previous(node); 680d9e8c0bSMaciej S. Szmigiero } else { 690d9e8c0bSMaciej S. Szmigiero node = g_tree_node_last(tree.t); 700d9e8c0bSMaciej S. Szmigiero } 710d9e8c0bSMaciej S. Szmigiero 720d9e8c0bSMaciej S. Szmigiero if (node) { 730d9e8c0bSMaciej S. Szmigiero range = g_tree_node_value(node); 740d9e8c0bSMaciej S. Szmigiero assert(range); 750d9e8c0bSMaciej S. Szmigiero intersection = page_range_intersection_size(range, start, count); 760d9e8c0bSMaciej S. Szmigiero joinable = page_range_joinable_right(range, start, count); 770d9e8c0bSMaciej S. Szmigiero } 780d9e8c0bSMaciej S. Szmigiero 790d9e8c0bSMaciej S. Szmigiero if (!node || 800d9e8c0bSMaciej S. Szmigiero (!intersection && !joinable)) { 810d9e8c0bSMaciej S. Szmigiero /* 820d9e8c0bSMaciej S. Szmigiero * !node case: the tree is empty or the very first node in the tree 830d9e8c0bSMaciej S. Szmigiero * already has a higher key (the start of its range). 840d9e8c0bSMaciej S. Szmigiero * the other case: there is a gap in the tree between the new range 850d9e8c0bSMaciej S. Szmigiero * and the previous one. 860d9e8c0bSMaciej S. Szmigiero * anyway, let's just insert the new range into the tree. 870d9e8c0bSMaciej S. Szmigiero */ 880d9e8c0bSMaciej S. Szmigiero node = page_range_tree_insert_new(tree, start, count); 890d9e8c0bSMaciej S. Szmigiero assert(node); 900d9e8c0bSMaciej S. Szmigiero range = g_tree_node_value(node); 910d9e8c0bSMaciej S. Szmigiero assert(range); 920d9e8c0bSMaciej S. Szmigiero } else { 930d9e8c0bSMaciej S. Szmigiero /* 940d9e8c0bSMaciej S. Szmigiero * the previous range in the tree either partially covers the new 950d9e8c0bSMaciej S. Szmigiero * range or ends just at its beginning - extend it 960d9e8c0bSMaciej S. Szmigiero */ 970d9e8c0bSMaciej S. Szmigiero if (dupcount) { 980d9e8c0bSMaciej S. Szmigiero *dupcount += intersection; 990d9e8c0bSMaciej S. Szmigiero } 1000d9e8c0bSMaciej S. Szmigiero 1010d9e8c0bSMaciej S. Szmigiero count += start - range->start; 1020d9e8c0bSMaciej S. Szmigiero range->count = MAX(range->count, count); 1030d9e8c0bSMaciej S. Szmigiero } 1040d9e8c0bSMaciej S. Szmigiero 1050d9e8c0bSMaciej S. Szmigiero /* check next nodes for possible merging */ 1060d9e8c0bSMaciej S. Szmigiero for (node = g_tree_node_next(node); node; ) { 1070d9e8c0bSMaciej S. Szmigiero PageRange *rangecur; 1080d9e8c0bSMaciej S. Szmigiero 1090d9e8c0bSMaciej S. Szmigiero rangecur = g_tree_node_value(node); 1100d9e8c0bSMaciej S. Szmigiero assert(rangecur); 1110d9e8c0bSMaciej S. Szmigiero 1120d9e8c0bSMaciej S. Szmigiero intersection = page_range_intersection_size(rangecur, 1130d9e8c0bSMaciej S. Szmigiero range->start, range->count); 1140d9e8c0bSMaciej S. Szmigiero joinable = page_range_joinable_left(rangecur, 1150d9e8c0bSMaciej S. Szmigiero range->start, range->count); 1160d9e8c0bSMaciej S. Szmigiero if (!intersection && !joinable) { 1170d9e8c0bSMaciej S. Szmigiero /* the current node is disjoint */ 1180d9e8c0bSMaciej S. Szmigiero break; 1190d9e8c0bSMaciej S. Szmigiero } 1200d9e8c0bSMaciej S. Szmigiero 1210d9e8c0bSMaciej S. Szmigiero if (dupcount) { 1220d9e8c0bSMaciej S. Szmigiero *dupcount += intersection; 1230d9e8c0bSMaciej S. Szmigiero } 1240d9e8c0bSMaciej S. Szmigiero 1250d9e8c0bSMaciej S. Szmigiero count = rangecur->count + (rangecur->start - range->start); 1260d9e8c0bSMaciej S. Szmigiero range->count = MAX(range->count, count); 1270d9e8c0bSMaciej S. Szmigiero 1280d9e8c0bSMaciej S. Szmigiero /* the current node was merged in, remove it */ 1290d9e8c0bSMaciej S. Szmigiero start = rangecur->start; 1300d9e8c0bSMaciej S. Szmigiero node = g_tree_node_next(node); 1310d9e8c0bSMaciej S. Szmigiero /* no hinted removal in GTree... */ 1320d9e8c0bSMaciej S. Szmigiero g_tree_remove(tree.t, &start); 1330d9e8c0bSMaciej S. Szmigiero } 1340d9e8c0bSMaciej S. Szmigiero } 1350d9e8c0bSMaciej S. Szmigiero 1360d9e8c0bSMaciej S. Szmigiero bool hvb_page_range_tree_pop(PageRangeTree tree, PageRange *out, 1370d9e8c0bSMaciej S. Szmigiero uint64_t maxcount) 1380d9e8c0bSMaciej S. Szmigiero { 1390d9e8c0bSMaciej S. Szmigiero GTreeNode *node; 1400d9e8c0bSMaciej S. Szmigiero PageRange *range; 1410d9e8c0bSMaciej S. Szmigiero 1420d9e8c0bSMaciej S. Szmigiero node = g_tree_node_last(tree.t); 1430d9e8c0bSMaciej S. Szmigiero if (!node) { 1440d9e8c0bSMaciej S. Szmigiero return false; 1450d9e8c0bSMaciej S. Szmigiero } 1460d9e8c0bSMaciej S. Szmigiero 1470d9e8c0bSMaciej S. Szmigiero range = g_tree_node_value(node); 1480d9e8c0bSMaciej S. Szmigiero assert(range); 1490d9e8c0bSMaciej S. Szmigiero 1500d9e8c0bSMaciej S. Szmigiero out->start = range->start; 1510d9e8c0bSMaciej S. Szmigiero 1520d9e8c0bSMaciej S. Szmigiero /* can't modify range->start as it is the node key */ 1530d9e8c0bSMaciej S. Szmigiero if (range->count > maxcount) { 1540d9e8c0bSMaciej S. Szmigiero out->start += range->count - maxcount; 1550d9e8c0bSMaciej S. Szmigiero out->count = maxcount; 1560d9e8c0bSMaciej S. Szmigiero range->count -= maxcount; 1570d9e8c0bSMaciej S. Szmigiero } else { 1580d9e8c0bSMaciej S. Szmigiero out->count = range->count; 1590d9e8c0bSMaciej S. Szmigiero /* no hinted removal in GTree... */ 1600d9e8c0bSMaciej S. Szmigiero g_tree_remove(tree.t, &out->start); 1610d9e8c0bSMaciej S. Szmigiero } 1620d9e8c0bSMaciej S. Szmigiero 1630d9e8c0bSMaciej S. Szmigiero return true; 1640d9e8c0bSMaciej S. Szmigiero } 1650d9e8c0bSMaciej S. Szmigiero 1660d9e8c0bSMaciej S. Szmigiero bool hvb_page_range_tree_intree_any(PageRangeTree tree, 1670d9e8c0bSMaciej S. Szmigiero uint64_t start, uint64_t count) 1680d9e8c0bSMaciej S. Szmigiero { 1690d9e8c0bSMaciej S. Szmigiero GTreeNode *node; 1700d9e8c0bSMaciej S. Szmigiero 1710d9e8c0bSMaciej S. Szmigiero if (count == 0) { 1720d9e8c0bSMaciej S. Szmigiero return false; 1730d9e8c0bSMaciej S. Szmigiero } 1740d9e8c0bSMaciej S. Szmigiero 1750d9e8c0bSMaciej S. Szmigiero /* find the first node that can possibly intersect our range */ 1760d9e8c0bSMaciej S. Szmigiero node = g_tree_upper_bound(tree.t, &start); 1770d9e8c0bSMaciej S. Szmigiero if (node) { 1780d9e8c0bSMaciej S. Szmigiero /* 1790d9e8c0bSMaciej S. Szmigiero * a NULL node below means that the very first node in the tree 1800d9e8c0bSMaciej S. Szmigiero * already has a higher key (the start of its range). 1810d9e8c0bSMaciej S. Szmigiero */ 1820d9e8c0bSMaciej S. Szmigiero node = g_tree_node_previous(node); 1830d9e8c0bSMaciej S. Szmigiero } else { 1840d9e8c0bSMaciej S. Szmigiero /* a NULL node below means that the tree is empty */ 1850d9e8c0bSMaciej S. Szmigiero node = g_tree_node_last(tree.t); 1860d9e8c0bSMaciej S. Szmigiero } 1870d9e8c0bSMaciej S. Szmigiero /* node range start <= range start */ 1880d9e8c0bSMaciej S. Szmigiero 1890d9e8c0bSMaciej S. Szmigiero if (!node) { 1900d9e8c0bSMaciej S. Szmigiero /* node range start > range start */ 1910d9e8c0bSMaciej S. Szmigiero node = g_tree_node_first(tree.t); 1920d9e8c0bSMaciej S. Szmigiero } 1930d9e8c0bSMaciej S. Szmigiero 1940d9e8c0bSMaciej S. Szmigiero for ( ; node; node = g_tree_node_next(node)) { 1950d9e8c0bSMaciej S. Szmigiero PageRange *range = g_tree_node_value(node); 1960d9e8c0bSMaciej S. Szmigiero 1970d9e8c0bSMaciej S. Szmigiero assert(range); 1980d9e8c0bSMaciej S. Szmigiero /* 1990d9e8c0bSMaciej S. Szmigiero * if this node starts beyond or at the end of our range so does 2000d9e8c0bSMaciej S. Szmigiero * every next one 2010d9e8c0bSMaciej S. Szmigiero */ 2020d9e8c0bSMaciej S. Szmigiero if (range->start >= start + count) { 2030d9e8c0bSMaciej S. Szmigiero break; 2040d9e8c0bSMaciej S. Szmigiero } 2050d9e8c0bSMaciej S. Szmigiero 2060d9e8c0bSMaciej S. Szmigiero if (page_range_intersection_size(range, start, count) > 0) { 2070d9e8c0bSMaciej S. Szmigiero return true; 2080d9e8c0bSMaciej S. Szmigiero } 2090d9e8c0bSMaciej S. Szmigiero } 2100d9e8c0bSMaciej S. Szmigiero 2110d9e8c0bSMaciej S. Szmigiero return false; 2120d9e8c0bSMaciej S. Szmigiero } 2130d9e8c0bSMaciej S. Szmigiero 2140d9e8c0bSMaciej S. Szmigiero void hvb_page_range_tree_init(PageRangeTree *tree) 2150d9e8c0bSMaciej S. Szmigiero { 2160d9e8c0bSMaciej S. Szmigiero tree->t = g_tree_new_full(page_range_tree_key_compare, NULL, 2170d9e8c0bSMaciej S. Szmigiero g_free, g_free); 2180d9e8c0bSMaciej S. Szmigiero } 2190d9e8c0bSMaciej S. Szmigiero 2200d9e8c0bSMaciej S. Szmigiero void hvb_page_range_tree_destroy(PageRangeTree *tree) 2210d9e8c0bSMaciej S. Szmigiero { 2220d9e8c0bSMaciej S. Szmigiero /* g_tree_destroy() is not NULL-safe */ 2230d9e8c0bSMaciej S. Szmigiero if (!tree->t) { 2240d9e8c0bSMaciej S. Szmigiero return; 2250d9e8c0bSMaciej S. Szmigiero } 2260d9e8c0bSMaciej S. Szmigiero 2270d9e8c0bSMaciej S. Szmigiero g_tree_destroy(tree->t); 2280d9e8c0bSMaciej S. Szmigiero tree->t = NULL; 2290d9e8c0bSMaciej S. Szmigiero } 230