diff options
Diffstat (limited to 'litmus/reservations/alloc.c')
-rw-r--r-- | litmus/reservations/alloc.c | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/litmus/reservations/alloc.c b/litmus/reservations/alloc.c new file mode 100644 index 000000000000..1f93f223f504 --- /dev/null +++ b/litmus/reservations/alloc.c | |||
@@ -0,0 +1,143 @@ | |||
1 | #include <linux/slab.h> | ||
2 | #include <asm/uaccess.h> | ||
3 | |||
4 | #include <litmus/rt_param.h> | ||
5 | |||
6 | #include <litmus/reservations/alloc.h> | ||
7 | #include <litmus/reservations/polling.h> | ||
8 | #include <litmus/reservations/table-driven.h> | ||
9 | |||
10 | |||
11 | long alloc_polling_reservation( | ||
12 | int res_type, | ||
13 | struct reservation_config *config, | ||
14 | struct reservation **_res) | ||
15 | { | ||
16 | struct polling_reservation *pres; | ||
17 | int use_edf = config->priority == LITMUS_NO_PRIORITY; | ||
18 | int periodic = res_type == PERIODIC_POLLING; | ||
19 | |||
20 | if (config->polling_params.budget > | ||
21 | config->polling_params.period) { | ||
22 | printk(KERN_ERR "invalid polling reservation (%u): " | ||
23 | "budget > period\n", config->id); | ||
24 | return -EINVAL; | ||
25 | } | ||
26 | if (config->polling_params.budget > | ||
27 | config->polling_params.relative_deadline | ||
28 | && config->polling_params.relative_deadline) { | ||
29 | printk(KERN_ERR "invalid polling reservation (%u): " | ||
30 | "budget > deadline\n", config->id); | ||
31 | return -EINVAL; | ||
32 | } | ||
33 | if (config->polling_params.offset > | ||
34 | config->polling_params.period) { | ||
35 | printk(KERN_ERR "invalid polling reservation (%u): " | ||
36 | "offset > period\n", config->id); | ||
37 | return -EINVAL; | ||
38 | } | ||
39 | |||
40 | /* XXX: would be nice to use a core-local allocation. */ | ||
41 | pres = kzalloc(sizeof(*pres), GFP_KERNEL); | ||
42 | if (!pres) | ||
43 | return -ENOMEM; | ||
44 | |||
45 | polling_reservation_init(pres, use_edf, periodic, | ||
46 | config->polling_params.budget, | ||
47 | config->polling_params.period, | ||
48 | config->polling_params.relative_deadline, | ||
49 | config->polling_params.offset); | ||
50 | pres->res.id = config->id; | ||
51 | if (!use_edf) | ||
52 | pres->res.priority = config->priority; | ||
53 | |||
54 | *_res = &pres->res; | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | |||
59 | #define MAX_INTERVALS 1024 | ||
60 | |||
61 | long alloc_table_driven_reservation( | ||
62 | struct reservation_config *config, | ||
63 | struct reservation **_res) | ||
64 | { | ||
65 | struct table_driven_reservation *td_res = NULL; | ||
66 | struct lt_interval *slots = NULL; | ||
67 | size_t slots_size; | ||
68 | unsigned int i, num_slots; | ||
69 | long err = -EINVAL; | ||
70 | void *mem; | ||
71 | |||
72 | if (!config->table_driven_params.num_intervals) { | ||
73 | printk(KERN_ERR "invalid table-driven reservation (%u): " | ||
74 | "no intervals\n", config->id); | ||
75 | return -EINVAL; | ||
76 | } | ||
77 | |||
78 | if (config->table_driven_params.num_intervals > MAX_INTERVALS) { | ||
79 | printk(KERN_ERR "invalid table-driven reservation (%u): " | ||
80 | "too many intervals (max: %d)\n", config->id, MAX_INTERVALS); | ||
81 | return -EINVAL; | ||
82 | } | ||
83 | |||
84 | num_slots = config->table_driven_params.num_intervals; | ||
85 | slots_size = sizeof(slots[0]) * num_slots; | ||
86 | |||
87 | mem = kzalloc(sizeof(*td_res) + slots_size, GFP_KERNEL); | ||
88 | if (!mem) { | ||
89 | return -ENOMEM; | ||
90 | } else { | ||
91 | slots = mem + sizeof(*td_res); | ||
92 | td_res = mem; | ||
93 | err = copy_from_user(slots, | ||
94 | config->table_driven_params.intervals, slots_size); | ||
95 | } | ||
96 | |||
97 | if (!err) { | ||
98 | /* sanity checks */ | ||
99 | for (i = 0; !err && i < num_slots; i++) | ||
100 | if (slots[i].end <= slots[i].start) { | ||
101 | printk(KERN_ERR | ||
102 | "invalid table-driven reservation (%u): " | ||
103 | "invalid interval %u => [%llu, %llu]\n", | ||
104 | config->id, i, | ||
105 | slots[i].start, slots[i].end); | ||
106 | err = -EINVAL; | ||
107 | } | ||
108 | |||
109 | for (i = 0; !err && i + 1 < num_slots; i++) | ||
110 | if (slots[i + 1].start <= slots[i].end) { | ||
111 | printk(KERN_ERR | ||
112 | "invalid table-driven reservation (%u): " | ||
113 | "overlapping intervals %u, %u\n", | ||
114 | config->id, i, i + 1); | ||
115 | err = -EINVAL; | ||
116 | } | ||
117 | |||
118 | if (slots[num_slots - 1].end > | ||
119 | config->table_driven_params.major_cycle_length) { | ||
120 | printk(KERN_ERR | ||
121 | "invalid table-driven reservation (%u): last " | ||
122 | "interval ends past major cycle %llu > %llu\n", | ||
123 | config->id, | ||
124 | slots[num_slots - 1].end, | ||
125 | config->table_driven_params.major_cycle_length); | ||
126 | err = -EINVAL; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | if (err) { | ||
131 | kfree(td_res); | ||
132 | } else { | ||
133 | table_driven_reservation_init(td_res, | ||
134 | config->table_driven_params.major_cycle_length, | ||
135 | slots, num_slots); | ||
136 | td_res->res.id = config->id; | ||
137 | td_res->res.priority = config->priority; | ||
138 | *_res = &td_res->res; | ||
139 | } | ||
140 | |||
141 | return err; | ||
142 | } | ||
143 | |||