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