]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | /* |
2 | * Copyright(c) 2012-2018 Intel Corporation | |
3 | * SPDX-License-Identifier: BSD-3-Clause-Clear | |
4 | */ | |
5 | ||
6 | #include "ocf/ocf.h" | |
7 | #include "ocf_mngt_common.h" | |
8 | #include "../ocf_priv.h" | |
9 | #include "../metadata/metadata.h" | |
10 | #include "../engine/cache_engine.h" | |
11 | #include "../utils/utils_part.h" | |
12 | #include "../eviction/ops.h" | |
13 | #include "ocf_env.h" | |
14 | ||
15 | static uint64_t _ocf_mngt_count_parts_min_size(struct ocf_cache *cache) | |
16 | { | |
17 | struct ocf_user_part *part; | |
18 | ocf_part_id_t part_id; | |
19 | uint64_t count = 0; | |
20 | ||
21 | for_each_part(cache, part, part_id) { | |
22 | if (ocf_part_is_valid(part)) | |
23 | count += part->config->min_size; | |
24 | } | |
25 | ||
26 | return count; | |
27 | } | |
28 | ||
29 | int ocf_mngt_add_partition_to_cache(struct ocf_cache *cache, | |
30 | ocf_part_id_t part_id, const char *name, uint32_t min_size, | |
31 | uint32_t max_size, uint8_t priority, bool valid) | |
32 | { | |
33 | uint32_t size; | |
34 | ||
35 | if (!name) | |
36 | return -OCF_ERR_INVAL; | |
37 | ||
38 | if (part_id >= OCF_IO_CLASS_MAX) | |
39 | return -OCF_ERR_INVAL; | |
40 | ||
41 | if (cache->user_parts[part_id].config->flags.valid) | |
42 | return -OCF_ERR_INVAL; | |
43 | ||
44 | if (max_size > PARTITION_SIZE_MAX) | |
45 | return -OCF_ERR_INVAL; | |
46 | ||
47 | if (env_strnlen(name, OCF_IO_CLASS_NAME_MAX) >= | |
48 | OCF_IO_CLASS_NAME_MAX) { | |
49 | ocf_cache_log(cache, log_info, | |
50 | "Name of the partition is too long\n"); | |
51 | return -OCF_ERR_INVAL; | |
52 | } | |
53 | ||
54 | size = sizeof(cache->user_parts[part_id].config->name); | |
55 | if (env_strncpy(cache->user_parts[part_id].config->name, size, name, size)) | |
56 | return -OCF_ERR_INVAL; | |
57 | ||
58 | cache->user_parts[part_id].config->min_size = min_size; | |
59 | cache->user_parts[part_id].config->max_size = max_size; | |
60 | cache->user_parts[part_id].config->priority = priority; | |
61 | cache->user_parts[part_id].config->cache_mode = ocf_cache_mode_max; | |
62 | ||
63 | ocf_part_set_valid(cache, part_id, valid); | |
64 | ocf_lst_add(&cache->lst_part, part_id); | |
65 | ocf_part_sort(cache); | |
66 | ||
67 | cache->user_parts[part_id].config->flags.added = 1; | |
68 | ||
69 | return 0; | |
70 | } | |
71 | ||
72 | static int _ocf_mngt_set_partition_size(struct ocf_cache *cache, | |
73 | ocf_part_id_t part_id, uint32_t min, uint32_t max) | |
74 | { | |
75 | struct ocf_user_part *part = &cache->user_parts[part_id]; | |
76 | ||
77 | if (min > max) | |
78 | return -OCF_ERR_INVAL; | |
79 | ||
80 | if (_ocf_mngt_count_parts_min_size(cache) + min | |
81 | >= cache->device->collision_table_entries) { | |
82 | /* Illegal configuration in which sum of all min_sizes exceeds | |
83 | * cache size. | |
84 | */ | |
85 | return -OCF_ERR_INVAL; | |
86 | } | |
87 | ||
88 | if (max > PARTITION_SIZE_MAX) | |
89 | max = PARTITION_SIZE_MAX; | |
90 | ||
91 | part->config->min_size = min; | |
92 | part->config->max_size = max; | |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
97 | static int _ocf_mngt_io_class_configure(ocf_cache_t cache, | |
98 | const struct ocf_mngt_io_class_config *cfg) | |
99 | { | |
100 | int result = -1; | |
101 | struct ocf_user_part *dest_part; | |
102 | ||
103 | ocf_part_id_t part_id = cfg->class_id; | |
104 | const char *name = cfg->name; | |
105 | int16_t prio = cfg->prio; | |
106 | ocf_cache_mode_t cache_mode = cfg->cache_mode; | |
107 | uint32_t min = cfg->min_size; | |
108 | uint32_t max = cfg->max_size; | |
109 | ||
110 | OCF_CHECK_NULL(cache->device); | |
111 | ||
112 | dest_part = &cache->user_parts[part_id]; | |
113 | ||
114 | if (!ocf_part_is_added(dest_part)) { | |
115 | ocf_cache_log(cache, log_info, "Setting IO class, id: %u, " | |
116 | "name: '%s' [ ERROR ]\n", part_id, dest_part->config->name); | |
117 | return -OCF_ERR_INVAL; | |
118 | } | |
119 | ||
f67539c2 TL |
120 | if (!name[0]) |
121 | return -OCF_ERR_INVAL; | |
9f95a23c TL |
122 | |
123 | if (part_id == PARTITION_DEFAULT) { | |
124 | /* Special behavior for default partition */ | |
125 | ||
126 | /* Try set partition size */ | |
127 | if (_ocf_mngt_set_partition_size(cache, part_id, min, max)) { | |
128 | ocf_cache_log(cache, log_info, | |
129 | "Setting IO class size, id: %u, name: '%s' " | |
130 | "[ ERROR ]\n", part_id, dest_part->config->name); | |
131 | return -OCF_ERR_INVAL; | |
132 | } | |
133 | ocf_part_set_prio(cache, dest_part, prio); | |
134 | dest_part->config->cache_mode = cache_mode; | |
135 | ||
136 | ocf_cache_log(cache, log_info, | |
137 | "Updating unclassified IO class, id: " | |
138 | "%u [ OK ]\n", part_id); | |
139 | ||
140 | return 0; | |
141 | } | |
142 | ||
143 | /* Setting */ | |
144 | result = env_strncpy(dest_part->config->name, | |
145 | sizeof(dest_part->config->name), name, | |
146 | sizeof(dest_part->config->name)); | |
147 | if (result) | |
148 | return result; | |
149 | ||
150 | /* Try set partition size */ | |
151 | if (_ocf_mngt_set_partition_size(cache, part_id, min, max)) { | |
152 | ocf_cache_log(cache, log_info, | |
153 | "Setting IO class size, id: %u, name: '%s' " | |
154 | "[ ERROR ]\n", part_id, dest_part->config->name); | |
155 | return -OCF_ERR_INVAL; | |
156 | } | |
157 | ||
158 | if (ocf_part_is_valid(dest_part)) { | |
159 | /* Updating existing */ | |
160 | ocf_cache_log(cache, log_info, "Updating existing IO " | |
161 | "class, id: %u, name: '%s' [ OK ]\n", | |
162 | part_id, dest_part->config->name); | |
163 | } else { | |
164 | /* Adding new */ | |
165 | ocf_part_set_valid(cache, part_id, true); | |
166 | ||
167 | ocf_cache_log(cache, log_info, "Adding new IO class, " | |
168 | "id: %u, name: '%s' [ OK ]\n", part_id, | |
169 | dest_part->config->name); | |
170 | } | |
171 | ||
172 | ocf_part_set_prio(cache, dest_part, prio); | |
173 | dest_part->config->cache_mode = cache_mode; | |
174 | ||
175 | return result; | |
176 | } | |
177 | ||
f67539c2 | 178 | static void _ocf_mngt_io_class_remove(ocf_cache_t cache, |
9f95a23c TL |
179 | const struct ocf_mngt_io_class_config *cfg) |
180 | { | |
181 | struct ocf_user_part *dest_part; | |
182 | ocf_part_id_t part_id = cfg->class_id; | |
9f95a23c TL |
183 | |
184 | dest_part = &cache->user_parts[part_id]; | |
185 | ||
186 | OCF_CHECK_NULL(cache->device); | |
187 | ||
188 | if (part_id == PARTITION_DEFAULT) { | |
189 | ocf_cache_log(cache, log_info, | |
190 | "Cannot remove unclassified IO class, " | |
191 | "id: %u [ ERROR ]\n", part_id); | |
f67539c2 | 192 | return; |
9f95a23c TL |
193 | } |
194 | ||
f67539c2 | 195 | if (!ocf_part_is_valid(dest_part)) { |
9f95a23c | 196 | /* Does not exist */ |
f67539c2 | 197 | return; |
9f95a23c TL |
198 | } |
199 | ||
f67539c2 TL |
200 | |
201 | ocf_part_set_valid(cache, part_id, false); | |
202 | ||
203 | ocf_cache_log(cache, log_info, | |
204 | "Removing IO class, id: %u [ OK ]\n", part_id); | |
9f95a23c TL |
205 | } |
206 | ||
207 | static int _ocf_mngt_io_class_edit(ocf_cache_t cache, | |
208 | const struct ocf_mngt_io_class_config *cfg) | |
209 | { | |
f67539c2 | 210 | int result = 0; |
9f95a23c | 211 | |
f67539c2 | 212 | if (cfg->name) |
9f95a23c | 213 | result = _ocf_mngt_io_class_configure(cache, cfg); |
f67539c2 TL |
214 | else |
215 | _ocf_mngt_io_class_remove(cache, cfg); | |
9f95a23c TL |
216 | |
217 | return result; | |
218 | } | |
219 | ||
220 | static int _ocf_mngt_io_class_validate_cfg(ocf_cache_t cache, | |
221 | const struct ocf_mngt_io_class_config *cfg) | |
222 | { | |
223 | if (cfg->class_id >= OCF_IO_CLASS_MAX) | |
224 | return -OCF_ERR_INVAL; | |
225 | ||
226 | /* Name set to null means particular io_class should be removed */ | |
227 | if (!cfg->name) | |
228 | return 0; | |
229 | ||
9f95a23c TL |
230 | if (cfg->cache_mode < ocf_cache_mode_none || |
231 | cfg->cache_mode > ocf_cache_mode_max) { | |
232 | return -OCF_ERR_INVAL; | |
233 | } | |
234 | ||
235 | if (!ocf_part_is_name_valid(cfg->name)) { | |
236 | ocf_cache_log(cache, log_info, | |
237 | "The name of the partition is not valid\n"); | |
238 | return -OCF_ERR_INVAL; | |
239 | } | |
240 | ||
241 | if (!ocf_part_is_prio_valid(cfg->prio)) { | |
242 | ocf_cache_log(cache, log_info, | |
243 | "Invalid value of the partition priority\n"); | |
244 | return -OCF_ERR_INVAL; | |
245 | } | |
246 | ||
247 | return 0; | |
248 | } | |
249 | ||
250 | int ocf_mngt_cache_io_classes_configure(ocf_cache_t cache, | |
251 | const struct ocf_mngt_io_classes_config *cfg) | |
252 | { | |
253 | struct ocf_user_part *old_config; | |
254 | int result; | |
255 | int i; | |
256 | ||
257 | OCF_CHECK_NULL(cache); | |
258 | OCF_CHECK_NULL(cfg); | |
259 | ||
260 | for (i = 0; i < OCF_IO_CLASS_MAX; i++) { | |
261 | result = _ocf_mngt_io_class_validate_cfg(cache, &cfg->config[i]); | |
262 | if (result) | |
263 | return result; | |
264 | } | |
265 | ||
266 | old_config = env_malloc(sizeof(cache->user_parts), ENV_MEM_NORMAL); | |
267 | if (!old_config) | |
268 | return -OCF_ERR_NO_MEM; | |
269 | ||
f67539c2 | 270 | ocf_metadata_start_exclusive_access(&cache->metadata.lock); |
9f95a23c | 271 | |
f67539c2 TL |
272 | result = env_memcpy(old_config, sizeof(cache->user_parts), |
273 | cache->user_parts, sizeof(cache->user_parts)); | |
9f95a23c TL |
274 | if (result) |
275 | goto out_cpy; | |
276 | ||
277 | for (i = 0; i < OCF_IO_CLASS_MAX; i++) { | |
278 | result = _ocf_mngt_io_class_edit(cache, &cfg->config[i]); | |
f67539c2 | 279 | if (result) { |
9f95a23c TL |
280 | ocf_cache_log(cache, log_err, |
281 | "Failed to set new io class config\n"); | |
282 | goto out_edit; | |
283 | } | |
284 | } | |
285 | ||
286 | ocf_part_sort(cache); | |
287 | ||
288 | out_edit: | |
289 | if (result) { | |
f67539c2 TL |
290 | ENV_BUG_ON(env_memcpy(cache->user_parts, sizeof(cache->user_parts), |
291 | old_config, sizeof(cache->user_parts))); | |
9f95a23c TL |
292 | } |
293 | ||
294 | out_cpy: | |
f67539c2 | 295 | ocf_metadata_end_exclusive_access(&cache->metadata.lock); |
9f95a23c TL |
296 | env_free(old_config); |
297 | ||
298 | return result; | |
299 | } |