Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/common/rangeset.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 * rangeset.c
3
 * 
4
 * Creation, maintenance and automatic destruction of per-domain sets of
5
 * numeric ranges.
6
 * 
7
 * Copyright (c) 2005, K A Fraser
8
 */
9
10
#include <xen/sched.h>
11
#include <xen/errno.h>
12
#include <xen/rangeset.h>
13
#include <xsm/xsm.h>
14
15
/* An inclusive range [s,e] and pointer to next range in ascending order. */
16
struct range {
17
    struct list_head list;
18
    unsigned long s, e;
19
};
20
21
struct rangeset {
22
    /* Owning domain and threaded list of rangesets. */
23
    struct list_head rangeset_list;
24
    struct domain   *domain;
25
26
    /* Ordered list of ranges contained in this set, and protecting lock. */
27
    struct list_head range_list;
28
29
    /* Number of ranges that can be allocated */
30
    long             nr_ranges;
31
    rwlock_t         lock;
32
33
    /* Pretty-printing name. */
34
    char             name[32];
35
36
    /* RANGESETF flags. */
37
    unsigned int     flags;
38
};
39
40
/*****************************
41
 * Private range functions hide the underlying linked-list implemnetation.
42
 */
43
44
/* Find highest range lower than or containing s. NULL if no such range. */
45
static struct range *find_range(
46
    struct rangeset *r, unsigned long s)
47
2.44M
{
48
2.44M
    struct range *x = NULL, *y;
49
2.44M
50
2.44M
    list_for_each_entry ( y, &r->range_list, list )
51
7.48M
    {
52
7.48M
        if ( y->s > s )
53
946k
            break;
54
6.54M
        x = y;
55
6.54M
    }
56
2.44M
57
2.44M
    return x;
58
2.44M
}
59
60
/* Return the lowest range in the set r, or NULL if r is empty. */
61
static struct range *first_range(
62
    struct rangeset *r)
63
935
{
64
935
    if ( list_empty(&r->range_list) )
65
225
        return NULL;
66
710
    return list_entry(r->range_list.next, struct range, list);
67
935
}
68
69
/* Return range following x in ascending order, or NULL if x is the highest. */
70
static struct range *next_range(
71
    struct rangeset *r, struct range *x)
72
388
{
73
388
    if ( x->list.next == &r->range_list )
74
323
        return NULL;
75
65
    return list_entry(x->list.next, struct range, list);
76
388
}
77
78
/* Insert range y after range x in r. Insert as first range if x is NULL. */
79
static void insert_range(
80
    struct rangeset *r, struct range *x, struct range *y)
81
341
{
82
341
    list_add(&y->list, (x != NULL) ? &x->list : &r->range_list);
83
341
}
84
85
/* Remove a range from its list and free it. */
86
static void destroy_range(
87
    struct rangeset *r, struct range *x)
88
318
{
89
318
    r->nr_ranges++;
90
318
91
318
    list_del(&x->list);
92
318
    xfree(x);
93
318
}
94
95
/* Allocate a new range */
96
static struct range *alloc_range(
97
    struct rangeset *r)
98
341
{
99
341
    struct range *x;
100
341
101
341
    if ( r->nr_ranges == 0 )
102
0
        return NULL;
103
341
104
341
    x = xmalloc(struct range);
105
341
    if ( x )
106
341
        --r->nr_ranges;
107
341
108
341
    return x;
109
341
}
110
111
/*****************************
112
 * Core public functions
113
 */
114
115
int rangeset_add_range(
116
    struct rangeset *r, unsigned long s, unsigned long e)
117
379
{
118
379
    struct range *x, *y;
119
379
    int rc = 0;
120
379
121
379
    ASSERT(s <= e);
122
379
123
379
    write_lock(&r->lock);
124
379
125
379
    x = find_range(r, s);
126
379
    y = find_range(r, e);
127
379
128
379
    if ( x == y )
129
379
    {
130
379
        if ( (x == NULL) || ((x->e < s) && ((x->e + 1) != s)) )
131
289
        {
132
289
            x = alloc_range(r);
133
289
            if ( x == NULL )
134
0
            {
135
0
                rc = -ENOMEM;
136
0
                goto out;
137
0
            }
138
289
139
289
            x->s = s;
140
289
            x->e = e;
141
289
142
289
            insert_range(r, y, x);
143
289
        }
144
90
        else if ( x->e < e )
145
42
            x->e = e;
146
379
    }
147
379
    else
148
0
    {
149
0
        if ( x == NULL )
150
0
        {
151
0
            x = first_range(r);
152
0
            x->s = s;
153
0
        }
154
0
        else if ( (x->e < s) && ((x->e + 1) != s) )
155
0
        {
156
0
            x = next_range(r, x);
157
0
            x->s = s;
158
0
        }
159
0
        
160
0
        x->e = (y->e > e) ? y->e : e;
161
0
162
0
        for ( ; ; )
163
0
        {
164
0
            y = next_range(r, x);
165
0
            if ( (y == NULL) || (y->e > x->e) )
166
0
                break;
167
0
            destroy_range(r, y);
168
0
        }
169
0
    }
170
379
171
379
    y = next_range(r, x);
172
379
    if ( (y != NULL) && ((x->e + 1) == y->s) )
173
0
    {
174
0
        x->e = y->e;
175
0
        destroy_range(r, y);
176
0
    }
177
379
178
379
 out:
179
379
    write_unlock(&r->lock);
180
379
    return rc;
181
379
}
182
183
int rangeset_remove_range(
184
    struct rangeset *r, unsigned long s, unsigned long e)
185
120
{
186
120
    struct range *x, *y, *t;
187
120
    int rc = 0;
188
120
189
120
    ASSERT(s <= e);
190
120
191
120
    write_lock(&r->lock);
192
120
193
120
    x = find_range(r, s);
194
120
    y = find_range(r, e);
195
120
196
120
    if ( x == y )
197
119
    {
198
119
        if ( (x == NULL) || (x->e < s) )
199
12
            goto out;
200
119
201
107
        if ( (x->s < s) && (x->e > e) )
202
52
        {
203
52
            y = alloc_range(r);
204
52
            if ( y == NULL )
205
0
            {
206
0
                rc = -ENOMEM;
207
0
                goto out;
208
0
            }
209
52
210
52
            y->s = e + 1;
211
52
            y->e = x->e;
212
52
            x->e = s - 1;
213
52
214
52
            insert_range(r, x, y);
215
52
        }
216
55
        else if ( (x->s == s) && (x->e <= e) )
217
0
            destroy_range(r, x);
218
55
        else if ( x->s == s )
219
44
            x->s = e + 1;
220
11
        else if ( x->e <= e )
221
11
            x->e = s - 1;
222
107
    }
223
120
    else
224
1
    {
225
1
        if ( x == NULL )
226
0
            x = first_range(r);
227
1
228
1
        if ( x->s < s )
229
1
        {
230
1
            x->e = s - 1;
231
1
            x = next_range(r, x);
232
1
        }
233
1
234
1
        while ( x != y )
235
0
        {
236
0
            t = x;
237
0
            x = next_range(r, x);
238
0
            destroy_range(r, t);
239
0
        }
240
1
241
1
        x->s = e + 1;
242
1
        if ( x->s > x->e )
243
0
            destroy_range(r, x);
244
1
    }
245
120
246
120
 out:
247
120
    write_unlock(&r->lock);
248
120
    return rc;
249
120
}
250
251
bool_t rangeset_contains_range(
252
    struct rangeset *r, unsigned long s, unsigned long e)
253
578k
{
254
578k
    struct range *x;
255
578k
    bool_t contains;
256
578k
257
578k
    ASSERT(s <= e);
258
578k
259
578k
    read_lock(&r->lock);
260
578k
    x = find_range(r, s);
261
575k
    contains = (x && (x->e >= e));
262
578k
    read_unlock(&r->lock);
263
578k
264
578k
    return contains;
265
578k
}
266
267
bool_t rangeset_overlaps_range(
268
    struct rangeset *r, unsigned long s, unsigned long e)
269
1.86M
{
270
1.86M
    struct range *x;
271
1.86M
    bool_t overlaps;
272
1.86M
273
1.86M
    ASSERT(s <= e);
274
1.86M
275
1.86M
    read_lock(&r->lock);
276
1.86M
    x = find_range(r, e);
277
1.85M
    overlaps = (x && (s <= x->e));
278
1.86M
    read_unlock(&r->lock);
279
1.86M
280
1.86M
    return overlaps;
281
1.86M
}
282
283
int rangeset_report_ranges(
284
    struct rangeset *r, unsigned long s, unsigned long e,
285
    int (*cb)(unsigned long s, unsigned long e, void *), void *ctxt)
286
1
{
287
1
    struct range *x;
288
1
    int rc = 0;
289
1
290
1
    read_lock(&r->lock);
291
1
292
9
    for ( x = first_range(r); x && (x->s <= e) && !rc; x = next_range(r, x) )
293
8
        if ( x->e >= s )
294
8
            rc = cb(max(x->s, s), min(x->e, e), ctxt);
295
1
296
1
    read_unlock(&r->lock);
297
1
298
1
    return rc;
299
1
}
300
301
int rangeset_consume_ranges(
302
    struct rangeset *r,
303
    int (*cb)(unsigned long s, unsigned long e, void *, unsigned long *c),
304
    void *ctxt)
305
616
{
306
616
    int rc = 0;
307
616
308
616
    write_lock(&r->lock);
309
934
    while ( !rangeset_is_empty(r) )
310
709
    {
311
709
        unsigned long consumed = 0;
312
709
        struct range *x = first_range(r);
313
709
314
709
        rc = cb(x->s, x->e, ctxt, &consumed);
315
709
316
709
        ASSERT(consumed <= x->e - x->s + 1);
317
709
        x->s += consumed;
318
709
        if ( x->s > x->e )
319
318
            destroy_range(r, x);
320
709
321
709
        if ( rc )
322
391
            break;
323
709
    }
324
616
    write_unlock(&r->lock);
325
616
326
616
    return rc;
327
616
}
328
329
int rangeset_add_singleton(
330
    struct rangeset *r, unsigned long s)
331
93
{
332
93
    return rangeset_add_range(r, s, s);
333
93
}
334
335
int rangeset_remove_singleton(
336
    struct rangeset *r, unsigned long s)
337
0
{
338
0
    return rangeset_remove_range(r, s, s);
339
0
}
340
341
bool_t rangeset_contains_singleton(
342
    struct rangeset *r, unsigned long s)
343
578k
{
344
578k
    return rangeset_contains_range(r, s, s);
345
578k
}
346
347
bool_t rangeset_is_empty(
348
    const struct rangeset *r)
349
1.01k
{
350
1.01k
    return ((r == NULL) || list_empty(&r->range_list));
351
1.01k
}
352
353
struct rangeset *rangeset_new(
354
    struct domain *d, char *name, unsigned int flags)
355
238
{
356
238
    struct rangeset *r;
357
238
358
238
    r = xmalloc(struct rangeset);
359
238
    if ( r == NULL )
360
0
        return NULL;
361
238
362
238
    rwlock_init(&r->lock);
363
238
    INIT_LIST_HEAD(&r->range_list);
364
238
    r->nr_ranges = -1;
365
238
366
238
    BUG_ON(flags & ~RANGESETF_prettyprint_hex);
367
238
    r->flags = flags;
368
238
369
238
    if ( name != NULL )
370
13
    {
371
13
        safe_strcpy(r->name, name);
372
13
    }
373
238
    else
374
225
    {
375
225
        snprintf(r->name, sizeof(r->name), "(no name)");
376
225
    }
377
238
378
238
    if ( (r->domain = d) != NULL )
379
12
    {
380
12
        spin_lock(&d->rangesets_lock);
381
12
        list_add(&r->rangeset_list, &d->rangesets);
382
12
        spin_unlock(&d->rangesets_lock);
383
12
    }
384
238
385
238
    return r;
386
238
}
387
388
void rangeset_destroy(
389
    struct rangeset *r)
390
225
{
391
225
    struct range *x;
392
225
393
225
    if ( r == NULL )
394
0
        return;
395
225
396
225
    if ( r->domain != NULL )
397
0
    {
398
0
        spin_lock(&r->domain->rangesets_lock);
399
0
        list_del(&r->rangeset_list);
400
0
        spin_unlock(&r->domain->rangesets_lock);
401
0
    }
402
225
403
225
    while ( (x = first_range(r)) != NULL )
404
0
        destroy_range(r, x);
405
225
406
225
    xfree(r);
407
225
}
408
409
void rangeset_limit(
410
    struct rangeset *r, unsigned int limit)
411
0
{
412
0
    r->nr_ranges = limit;
413
0
}
414
415
void rangeset_domain_initialise(
416
    struct domain *d)
417
5
{
418
5
    INIT_LIST_HEAD(&d->rangesets);
419
5
    spin_lock_init(&d->rangesets_lock);
420
5
}
421
422
void rangeset_domain_destroy(
423
    struct domain *d)
424
0
{
425
0
    struct rangeset *r;
426
0
427
0
    while ( !list_empty(&d->rangesets) )
428
0
    {
429
0
        r = list_entry(d->rangesets.next, struct rangeset, rangeset_list);
430
0
431
0
        BUG_ON(r->domain != d);
432
0
        r->domain = NULL;
433
0
        list_del(&r->rangeset_list);
434
0
435
0
        rangeset_destroy(r);
436
0
    }
437
0
}
438
439
void rangeset_swap(struct rangeset *a, struct rangeset *b)
440
0
{
441
0
    LIST_HEAD(tmp);
442
0
443
0
    if ( a < b )
444
0
    {
445
0
        write_lock(&a->lock);
446
0
        write_lock(&b->lock);
447
0
    }
448
0
    else
449
0
    {
450
0
        write_lock(&b->lock);
451
0
        write_lock(&a->lock);
452
0
    }
453
0
454
0
    list_splice_init(&a->range_list, &tmp);
455
0
    list_splice_init(&b->range_list, &a->range_list);
456
0
    list_splice(&tmp, &b->range_list);
457
0
458
0
    write_unlock(&a->lock);
459
0
    write_unlock(&b->lock);
460
0
}
461
462
/*****************************
463
 * Pretty-printing functions
464
 */
465
466
static void print_limit(struct rangeset *r, unsigned long s)
467
0
{
468
0
    printk((r->flags & RANGESETF_prettyprint_hex) ? "%lx" : "%lu", s);
469
0
}
470
471
void rangeset_printk(
472
    struct rangeset *r)
473
0
{
474
0
    int nr_printed = 0;
475
0
    struct range *x;
476
0
477
0
    read_lock(&r->lock);
478
0
479
0
    printk("%-10s {", r->name);
480
0
481
0
    for ( x = first_range(r); x != NULL; x = next_range(r, x) )
482
0
    {
483
0
        if ( nr_printed++ )
484
0
            printk(",");
485
0
        printk(" ");
486
0
        print_limit(r, x->s);
487
0
        if ( x->s != x->e )
488
0
        {
489
0
            printk("-");
490
0
            print_limit(r, x->e);
491
0
        }
492
0
    }
493
0
494
0
    printk(" }");
495
0
496
0
    read_unlock(&r->lock);
497
0
}
498
499
void rangeset_domain_printk(
500
    struct domain *d)
501
0
{
502
0
    struct rangeset *r;
503
0
504
0
    printk("Rangesets belonging to domain %u:\n", d->domain_id);
505
0
506
0
    spin_lock(&d->rangesets_lock);
507
0
508
0
    if ( list_empty(&d->rangesets) )
509
0
        printk("    None\n");
510
0
511
0
    list_for_each_entry ( r, &d->rangesets, rangeset_list )
512
0
    {
513
0
        printk("    ");
514
0
        rangeset_printk(r);
515
0
        printk("\n");
516
0
    }
517
0
518
0
    spin_unlock(&d->rangesets_lock);
519
0
}
520
521
/*
522
 * Local variables:
523
 * mode: C
524
 * c-file-style: "BSD"
525
 * c-basic-offset: 4
526
 * tab-width: 4
527
 * indent-tabs-mode: nil
528
 * End:
529
 */