diff options
Diffstat (limited to 'kernel/livepatch/shadow.c')
-rw-r--r-- | kernel/livepatch/shadow.c | 26 |
1 files changed, 18 insertions, 8 deletions
diff --git a/kernel/livepatch/shadow.c b/kernel/livepatch/shadow.c index b10a0bbb7f84..83958c814439 100644 --- a/kernel/livepatch/shadow.c +++ b/kernel/livepatch/shadow.c | |||
@@ -243,15 +243,26 @@ void *klp_shadow_get_or_alloc(void *obj, unsigned long id, | |||
243 | } | 243 | } |
244 | EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc); | 244 | EXPORT_SYMBOL_GPL(klp_shadow_get_or_alloc); |
245 | 245 | ||
246 | static void klp_shadow_free_struct(struct klp_shadow *shadow, | ||
247 | klp_shadow_dtor_t dtor) | ||
248 | { | ||
249 | hash_del_rcu(&shadow->node); | ||
250 | if (dtor) | ||
251 | dtor(shadow->obj, shadow->data); | ||
252 | kfree_rcu(shadow, rcu_head); | ||
253 | } | ||
254 | |||
246 | /** | 255 | /** |
247 | * klp_shadow_free() - detach and free a <obj, id> shadow variable | 256 | * klp_shadow_free() - detach and free a <obj, id> shadow variable |
248 | * @obj: pointer to parent object | 257 | * @obj: pointer to parent object |
249 | * @id: data identifier | 258 | * @id: data identifier |
259 | * @dtor: custom callback that can be used to unregister the variable | ||
260 | * and/or free data that the shadow variable points to (optional) | ||
250 | * | 261 | * |
251 | * This function releases the memory for this <obj, id> shadow variable | 262 | * This function releases the memory for this <obj, id> shadow variable |
252 | * instance, callers should stop referencing it accordingly. | 263 | * instance, callers should stop referencing it accordingly. |
253 | */ | 264 | */ |
254 | void klp_shadow_free(void *obj, unsigned long id) | 265 | void klp_shadow_free(void *obj, unsigned long id, klp_shadow_dtor_t dtor) |
255 | { | 266 | { |
256 | struct klp_shadow *shadow; | 267 | struct klp_shadow *shadow; |
257 | unsigned long flags; | 268 | unsigned long flags; |
@@ -263,8 +274,7 @@ void klp_shadow_free(void *obj, unsigned long id) | |||
263 | (unsigned long)obj) { | 274 | (unsigned long)obj) { |
264 | 275 | ||
265 | if (klp_shadow_match(shadow, obj, id)) { | 276 | if (klp_shadow_match(shadow, obj, id)) { |
266 | hash_del_rcu(&shadow->node); | 277 | klp_shadow_free_struct(shadow, dtor); |
267 | kfree_rcu(shadow, rcu_head); | ||
268 | break; | 278 | break; |
269 | } | 279 | } |
270 | } | 280 | } |
@@ -276,11 +286,13 @@ EXPORT_SYMBOL_GPL(klp_shadow_free); | |||
276 | /** | 286 | /** |
277 | * klp_shadow_free_all() - detach and free all <*, id> shadow variables | 287 | * klp_shadow_free_all() - detach and free all <*, id> shadow variables |
278 | * @id: data identifier | 288 | * @id: data identifier |
289 | * @dtor: custom callback that can be used to unregister the variable | ||
290 | * and/or free data that the shadow variable points to (optional) | ||
279 | * | 291 | * |
280 | * This function releases the memory for all <*, id> shadow variable | 292 | * This function releases the memory for all <*, id> shadow variable |
281 | * instances, callers should stop referencing them accordingly. | 293 | * instances, callers should stop referencing them accordingly. |
282 | */ | 294 | */ |
283 | void klp_shadow_free_all(unsigned long id) | 295 | void klp_shadow_free_all(unsigned long id, klp_shadow_dtor_t dtor) |
284 | { | 296 | { |
285 | struct klp_shadow *shadow; | 297 | struct klp_shadow *shadow; |
286 | unsigned long flags; | 298 | unsigned long flags; |
@@ -290,10 +302,8 @@ void klp_shadow_free_all(unsigned long id) | |||
290 | 302 | ||
291 | /* Delete all <*, id> from hash */ | 303 | /* Delete all <*, id> from hash */ |
292 | hash_for_each(klp_shadow_hash, i, shadow, node) { | 304 | hash_for_each(klp_shadow_hash, i, shadow, node) { |
293 | if (klp_shadow_match(shadow, shadow->obj, id)) { | 305 | if (klp_shadow_match(shadow, shadow->obj, id)) |
294 | hash_del_rcu(&shadow->node); | 306 | klp_shadow_free_struct(shadow, dtor); |
295 | kfree_rcu(shadow, rcu_head); | ||
296 | } | ||
297 | } | 307 | } |
298 | 308 | ||
299 | spin_unlock_irqrestore(&klp_shadow_lock, flags); | 309 | spin_unlock_irqrestore(&klp_shadow_lock, flags); |