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. */
find_range(struct rangeset * r,unsigned long s)45 static struct range *find_range(
46     struct rangeset *r, unsigned long s)
47 {
48     struct range *x = NULL, *y;
49 
50     list_for_each_entry ( y, &r->range_list, list )
51     {
52         if ( y->s > s )
53             break;
54         x = y;
55     }
56 
57     return x;
58 }
59 
60 /* Return the lowest range in the set r, or NULL if r is empty. */
first_range(struct rangeset * r)61 static struct range *first_range(
62     struct rangeset *r)
63 {
64     if ( list_empty(&r->range_list) )
65         return NULL;
66     return list_entry(r->range_list.next, struct range, list);
67 }
68 
69 /* Return range following x in ascending order, or NULL if x is the highest. */
next_range(struct rangeset * r,struct range * x)70 static struct range *next_range(
71     struct rangeset *r, struct range *x)
72 {
73     if ( x->list.next == &r->range_list )
74         return NULL;
75     return list_entry(x->list.next, struct range, list);
76 }
77 
78 /* Insert range y after range x in r. Insert as first range if x is NULL. */
insert_range(struct rangeset * r,struct range * x,struct range * y)79 static void insert_range(
80     struct rangeset *r, struct range *x, struct range *y)
81 {
82     list_add(&y->list, (x != NULL) ? &x->list : &r->range_list);
83 }
84 
85 /* Remove a range from its list and free it. */
destroy_range(struct rangeset * r,struct range * x)86 static void destroy_range(
87     struct rangeset *r, struct range *x)
88 {
89     r->nr_ranges++;
90 
91     list_del(&x->list);
92     xfree(x);
93 }
94 
95 /* Allocate a new range */
alloc_range(struct rangeset * r)96 static struct range *alloc_range(
97     struct rangeset *r)
98 {
99     struct range *x;
100 
101     if ( r->nr_ranges == 0 )
102         return NULL;
103 
104     x = xmalloc(struct range);
105     if ( x )
106         --r->nr_ranges;
107 
108     return x;
109 }
110 
111 /*****************************
112  * Core public functions
113  */
114 
rangeset_add_range(struct rangeset * r,unsigned long s,unsigned long e)115 int rangeset_add_range(
116     struct rangeset *r, unsigned long s, unsigned long e)
117 {
118     struct range *x, *y;
119     int rc = 0;
120 
121     ASSERT(s <= e);
122 
123     write_lock(&r->lock);
124 
125     x = find_range(r, s);
126     y = find_range(r, e);
127 
128     if ( x == y )
129     {
130         if ( (x == NULL) || ((x->e < s) && ((x->e + 1) != s)) )
131         {
132             x = alloc_range(r);
133             if ( x == NULL )
134             {
135                 rc = -ENOMEM;
136                 goto out;
137             }
138 
139             x->s = s;
140             x->e = e;
141 
142             insert_range(r, y, x);
143         }
144         else if ( x->e < e )
145             x->e = e;
146     }
147     else
148     {
149         if ( x == NULL )
150         {
151             x = first_range(r);
152             x->s = s;
153         }
154         else if ( (x->e < s) && ((x->e + 1) != s) )
155         {
156             x = next_range(r, x);
157             x->s = s;
158         }
159 
160         x->e = (y->e > e) ? y->e : e;
161 
162         for ( ; ; )
163         {
164             y = next_range(r, x);
165             if ( (y == NULL) || (y->e > x->e) )
166                 break;
167             destroy_range(r, y);
168         }
169     }
170 
171     y = next_range(r, x);
172     if ( (y != NULL) && ((x->e + 1) == y->s) )
173     {
174         x->e = y->e;
175         destroy_range(r, y);
176     }
177 
178  out:
179     write_unlock(&r->lock);
180     return rc;
181 }
182 
rangeset_remove_range(struct rangeset * r,unsigned long s,unsigned long e)183 int rangeset_remove_range(
184     struct rangeset *r, unsigned long s, unsigned long e)
185 {
186     struct range *x, *y, *t;
187     int rc = 0;
188 
189     ASSERT(s <= e);
190 
191     write_lock(&r->lock);
192 
193     x = find_range(r, s);
194     y = find_range(r, e);
195 
196     if ( x == y )
197     {
198         if ( (x == NULL) || (x->e < s) )
199             goto out;
200 
201         if ( (x->s < s) && (x->e > e) )
202         {
203             y = alloc_range(r);
204             if ( y == NULL )
205             {
206                 rc = -ENOMEM;
207                 goto out;
208             }
209 
210             y->s = e + 1;
211             y->e = x->e;
212             x->e = s - 1;
213 
214             insert_range(r, x, y);
215         }
216         else if ( (x->s == s) && (x->e <= e) )
217             destroy_range(r, x);
218         else if ( x->s == s )
219             x->s = e + 1;
220         else if ( x->e <= e )
221             x->e = s - 1;
222     }
223     else
224     {
225         if ( x == NULL )
226             x = first_range(r);
227 
228         if ( x->s < s )
229         {
230             x->e = s - 1;
231             x = next_range(r, x);
232         }
233 
234         while ( x != y )
235         {
236             t = x;
237             x = next_range(r, x);
238             destroy_range(r, t);
239         }
240 
241         x->s = e + 1;
242         if ( x->s > x->e )
243             destroy_range(r, x);
244     }
245 
246  out:
247     write_unlock(&r->lock);
248     return rc;
249 }
250 
rangeset_contains_range(struct rangeset * r,unsigned long s,unsigned long e)251 bool_t rangeset_contains_range(
252     struct rangeset *r, unsigned long s, unsigned long e)
253 {
254     struct range *x;
255     bool_t contains;
256 
257     ASSERT(s <= e);
258 
259     if ( !r )
260         return false;
261 
262     read_lock(&r->lock);
263     x = find_range(r, s);
264     contains = (x && (x->e >= e));
265     read_unlock(&r->lock);
266 
267     return contains;
268 }
269 
rangeset_overlaps_range(struct rangeset * r,unsigned long s,unsigned long e)270 bool_t rangeset_overlaps_range(
271     struct rangeset *r, unsigned long s, unsigned long e)
272 {
273     struct range *x;
274     bool_t overlaps;
275 
276     ASSERT(s <= e);
277 
278     if ( !r )
279         return false;
280 
281     read_lock(&r->lock);
282     x = find_range(r, e);
283     overlaps = (x && (s <= x->e));
284     read_unlock(&r->lock);
285 
286     return overlaps;
287 }
288 
rangeset_report_ranges(struct rangeset * r,unsigned long s,unsigned long e,int (* cb)(unsigned long s,unsigned long e,void *),void * ctxt)289 int rangeset_report_ranges(
290     struct rangeset *r, unsigned long s, unsigned long e,
291     int (*cb)(unsigned long s, unsigned long e, void *), void *ctxt)
292 {
293     struct range *x;
294     int rc = 0;
295 
296     read_lock(&r->lock);
297 
298     for ( x = first_range(r); x && (x->s <= e) && !rc; x = next_range(r, x) )
299         if ( x->e >= s )
300             rc = cb(max(x->s, s), min(x->e, e), ctxt);
301 
302     read_unlock(&r->lock);
303 
304     return rc;
305 }
306 
rangeset_claim_range(struct rangeset * r,unsigned long size,unsigned long * s)307 int rangeset_claim_range(struct rangeset *r, unsigned long size,
308                          unsigned long *s)
309 {
310     struct range *prev, *next;
311     unsigned long start = 0;
312 
313     write_lock(&r->lock);
314 
315     for ( prev = NULL, next = first_range(r);
316           next;
317           prev = next, next = next_range(r, next) )
318     {
319         if ( (next->s - start) >= size )
320             goto insert;
321 
322         if ( next->e == ~0UL )
323             goto out;
324 
325         start = next->e + 1;
326     }
327 
328     if ( (~0UL - start) + 1 >= size )
329         goto insert;
330 
331  out:
332     write_unlock(&r->lock);
333     return -ENOSPC;
334 
335  insert:
336     if ( unlikely(!prev) )
337     {
338         next = alloc_range(r);
339         if ( !next )
340         {
341             write_unlock(&r->lock);
342             return -ENOMEM;
343         }
344 
345         next->s = start;
346         next->e = start + size - 1;
347         insert_range(r, prev, next);
348     }
349     else
350         prev->e += size;
351 
352     write_unlock(&r->lock);
353 
354     *s = start;
355 
356     return 0;
357 }
358 
rangeset_consume_ranges(struct rangeset * r,int (* cb)(unsigned long s,unsigned long e,void *,unsigned long * c),void * ctxt)359 int rangeset_consume_ranges(struct rangeset *r,
360                             int (*cb)(unsigned long s, unsigned long e, void *,
361                                       unsigned long *c),
362                             void *ctxt)
363 {
364     int rc = 0;
365 
366     write_lock(&r->lock);
367     while ( !rangeset_is_empty(r) )
368     {
369         unsigned long consumed = 0;
370         struct range *x = first_range(r);
371 
372         rc = cb(x->s, x->e, ctxt, &consumed);
373 
374         ASSERT(consumed <= x->e - x->s + 1);
375         x->s += consumed;
376         if ( x->s > x->e )
377             destroy_range(r, x);
378 
379         if ( rc )
380             break;
381     }
382     write_unlock(&r->lock);
383 
384     return rc;
385 }
386 
merge(unsigned long s,unsigned long e,void * data)387 static int merge(unsigned long s, unsigned long e, void *data)
388 {
389     struct rangeset *r = data;
390 
391     return rangeset_add_range(r, s, e);
392 }
393 
rangeset_merge(struct rangeset * r1,struct rangeset * r2)394 int rangeset_merge(struct rangeset *r1, struct rangeset *r2)
395 {
396     return rangeset_report_ranges(r2, 0, ~0ul, merge, r1);
397 }
398 
rangeset_add_singleton(struct rangeset * r,unsigned long s)399 int rangeset_add_singleton(
400     struct rangeset *r, unsigned long s)
401 {
402     return rangeset_add_range(r, s, s);
403 }
404 
rangeset_remove_singleton(struct rangeset * r,unsigned long s)405 int rangeset_remove_singleton(
406     struct rangeset *r, unsigned long s)
407 {
408     return rangeset_remove_range(r, s, s);
409 }
410 
rangeset_contains_singleton(struct rangeset * r,unsigned long s)411 bool_t rangeset_contains_singleton(
412     struct rangeset *r, unsigned long s)
413 {
414     return rangeset_contains_range(r, s, s);
415 }
416 
rangeset_is_empty(const struct rangeset * r)417 bool_t rangeset_is_empty(
418     const struct rangeset *r)
419 {
420     return ((r == NULL) || list_empty(&r->range_list));
421 }
422 
rangeset_new(struct domain * d,char * name,unsigned int flags)423 struct rangeset *rangeset_new(
424     struct domain *d, char *name, unsigned int flags)
425 {
426     struct rangeset *r;
427 
428     r = xmalloc(struct rangeset);
429     if ( r == NULL )
430         return NULL;
431 
432     rwlock_init(&r->lock);
433     INIT_LIST_HEAD(&r->range_list);
434     r->nr_ranges = -1;
435 
436     BUG_ON(flags & ~RANGESETF_prettyprint_hex);
437     r->flags = flags;
438 
439     if ( name != NULL )
440     {
441         safe_strcpy(r->name, name);
442     }
443     else
444     {
445         snprintf(r->name, sizeof(r->name), "(no name)");
446     }
447 
448     if ( (r->domain = d) != NULL )
449     {
450         spin_lock(&d->rangesets_lock);
451         list_add(&r->rangeset_list, &d->rangesets);
452         spin_unlock(&d->rangesets_lock);
453     }
454 
455     return r;
456 }
457 
rangeset_destroy(struct rangeset * r)458 void rangeset_destroy(
459     struct rangeset *r)
460 {
461     struct range *x;
462 
463     if ( r == NULL )
464         return;
465 
466     if ( r->domain != NULL )
467     {
468         spin_lock(&r->domain->rangesets_lock);
469         list_del(&r->rangeset_list);
470         spin_unlock(&r->domain->rangesets_lock);
471     }
472 
473     while ( (x = first_range(r)) != NULL )
474         destroy_range(r, x);
475 
476     xfree(r);
477 }
478 
rangeset_limit(struct rangeset * r,unsigned int limit)479 void rangeset_limit(
480     struct rangeset *r, unsigned int limit)
481 {
482     r->nr_ranges = limit;
483 }
484 
rangeset_domain_initialise(struct domain * d)485 void rangeset_domain_initialise(
486     struct domain *d)
487 {
488     INIT_LIST_HEAD(&d->rangesets);
489     spin_lock_init(&d->rangesets_lock);
490 }
491 
rangeset_domain_destroy(struct domain * d)492 void rangeset_domain_destroy(
493     struct domain *d)
494 {
495     struct rangeset *r;
496 
497     if ( list_head_is_null(&d->rangesets) )
498         return;
499 
500     while ( !list_empty(&d->rangesets) )
501     {
502         r = list_entry(d->rangesets.next, struct rangeset, rangeset_list);
503 
504         BUG_ON(r->domain != d);
505         r->domain = NULL;
506         list_del(&r->rangeset_list);
507 
508         rangeset_destroy(r);
509     }
510 }
511 
rangeset_swap(struct rangeset * a,struct rangeset * b)512 void rangeset_swap(struct rangeset *a, struct rangeset *b)
513 {
514     LIST_HEAD(tmp);
515 
516     if ( a < b )
517     {
518         write_lock(&a->lock);
519         write_lock(&b->lock);
520     }
521     else
522     {
523         write_lock(&b->lock);
524         write_lock(&a->lock);
525     }
526 
527     list_splice_init(&a->range_list, &tmp);
528     list_splice_init(&b->range_list, &a->range_list);
529     list_splice(&tmp, &b->range_list);
530 
531     write_unlock(&a->lock);
532     write_unlock(&b->lock);
533 }
534 
535 /*****************************
536  * Pretty-printing functions
537  */
538 
print_limit(struct rangeset * r,unsigned long s)539 static void print_limit(struct rangeset *r, unsigned long s)
540 {
541     printk((r->flags & RANGESETF_prettyprint_hex) ? "%lx" : "%lu", s);
542 }
543 
rangeset_printk(struct rangeset * r)544 static void rangeset_printk(struct rangeset *r)
545 {
546     int nr_printed = 0;
547     struct range *x;
548 
549     read_lock(&r->lock);
550 
551     printk("%-10s {", r->name);
552 
553     for ( x = first_range(r); x != NULL; x = next_range(r, x) )
554     {
555         if ( nr_printed++ )
556             printk(",");
557         printk(" ");
558         print_limit(r, x->s);
559         if ( x->s != x->e )
560         {
561             printk("-");
562             print_limit(r, x->e);
563         }
564     }
565 
566     printk(" }");
567 
568     read_unlock(&r->lock);
569 }
570 
rangeset_domain_printk(struct domain * d)571 void rangeset_domain_printk(
572     struct domain *d)
573 {
574     struct rangeset *r;
575 
576     printk("Rangesets belonging to domain %u:\n", d->domain_id);
577 
578     spin_lock(&d->rangesets_lock);
579 
580     if ( list_empty(&d->rangesets) )
581         printk("    None\n");
582 
583     list_for_each_entry ( r, &d->rangesets, rangeset_list )
584     {
585         printk("    ");
586         rangeset_printk(r);
587         printk("\n");
588     }
589 
590     spin_unlock(&d->rangesets_lock);
591 }
592 
593 /*
594  * Local variables:
595  * mode: C
596  * c-file-style: "BSD"
597  * c-basic-offset: 4
598  * tab-width: 4
599  * indent-tabs-mode: nil
600  * End:
601  */
602