linux/kernel/range.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Range add and subtract
   4 */
   5#include <linux/init.h>
   6#include <linux/minmax.h>
   7#include <linux/printk.h>
   8#include <linux/sort.h>
   9#include <linux/string.h>
  10#include <linux/range.h>
  11
  12int add_range(struct range *range, int az, int nr_range, u64 start, u64 end)
  13{
  14        if (start >= end)
  15                return nr_range;
  16
  17        /* Out of slots: */
  18        if (nr_range >= az)
  19                return nr_range;
  20
  21        range[nr_range].start = start;
  22        range[nr_range].end = end;
  23
  24        nr_range++;
  25
  26        return nr_range;
  27}
  28
  29int add_range_with_merge(struct range *range, int az, int nr_range,
  30                     u64 start, u64 end)
  31{
  32        int i;
  33
  34        if (start >= end)
  35                return nr_range;
  36
  37        /* get new start/end: */
  38        for (i = 0; i < nr_range; i++) {
  39                u64 common_start, common_end;
  40
  41                if (!range[i].end)
  42                        continue;
  43
  44                common_start = max(range[i].start, start);
  45                common_end = min(range[i].end, end);
  46                if (common_start > common_end)
  47                        continue;
  48
  49                /* new start/end, will add it back at last */
  50                start = min(range[i].start, start);
  51                end = max(range[i].end, end);
  52
  53                memmove(&range[i], &range[i + 1],
  54                        (nr_range - (i + 1)) * sizeof(range[i]));
  55                range[nr_range - 1].start = 0;
  56                range[nr_range - 1].end   = 0;
  57                nr_range--;
  58                i--;
  59        }
  60
  61        /* Need to add it: */
  62        return add_range(range, az, nr_range, start, end);
  63}
  64
  65void subtract_range(struct range *range, int az, u64 start, u64 end)
  66{
  67        int i, j;
  68
  69        if (start >= end)
  70                return;
  71
  72        for (j = 0; j < az; j++) {
  73                if (!range[j].end)
  74                        continue;
  75
  76                if (start <= range[j].start && end >= range[j].end) {
  77                        range[j].start = 0;
  78                        range[j].end = 0;
  79                        continue;
  80                }
  81
  82                if (start <= range[j].start && end < range[j].end &&
  83                    range[j].start < end) {
  84                        range[j].start = end;
  85                        continue;
  86                }
  87
  88
  89                if (start > range[j].start && end >= range[j].end &&
  90                    range[j].end > start) {
  91                        range[j].end = start;
  92                        continue;
  93                }
  94
  95                if (start > range[j].start && end < range[j].end) {
  96                        /* Find the new spare: */
  97                        for (i = 0; i < az; i++) {
  98                                if (range[i].end == 0)
  99                                        break;
 100                        }
 101                        if (i < az) {
 102                                range[i].end = range[j].end;
 103                                range[i].start = end;
 104                        } else {
 105                                pr_err("%s: run out of slot in ranges\n",
 106                                        __func__);
 107                        }
 108                        range[j].end = start;
 109                        continue;
 110                }
 111        }
 112}
 113
 114static int cmp_range(const void *x1, const void *x2)
 115{
 116        const struct range *r1 = x1;
 117        const struct range *r2 = x2;
 118
 119        if (r1->start < r2->start)
 120                return -1;
 121        if (r1->start > r2->start)
 122                return 1;
 123        return 0;
 124}
 125
 126int clean_sort_range(struct range *range, int az)
 127{
 128        int i, j, k = az - 1, nr_range = az;
 129
 130        for (i = 0; i < k; i++) {
 131                if (range[i].end)
 132                        continue;
 133                for (j = k; j > i; j--) {
 134                        if (range[j].end) {
 135                                k = j;
 136                                break;
 137                        }
 138                }
 139                if (j == i)
 140                        break;
 141                range[i].start = range[k].start;
 142                range[i].end   = range[k].end;
 143                range[k].start = 0;
 144                range[k].end   = 0;
 145                k--;
 146        }
 147        /* count it */
 148        for (i = 0; i < az; i++) {
 149                if (!range[i].end) {
 150                        nr_range = i;
 151                        break;
 152                }
 153        }
 154
 155        /* sort them */
 156        sort(range, nr_range, sizeof(struct range), cmp_range, NULL);
 157
 158        return nr_range;
 159}
 160
 161void sort_range(struct range *range, int nr_range)
 162{
 163        /* sort them */
 164        sort(range, nr_range, sizeof(struct range), cmp_range, NULL);
 165}
 166