1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * system_state.c - State of the system modified by livepatches 4 * 5 * Copyright (C) 2019 SUSE 6 */ 7 8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 10 #include <linux/livepatch.h> 11 #include "core.h" 12 #include "transition.h" 13 14 #define klp_for_each_state(patch, state) \ 15 for (state = patch->states; state && state->id; state++) 16 17 /** 18 * klp_get_state() - get information about system state modified by 19 * the given patch 20 * @patch: livepatch that modifies the given system state 21 * @id: custom identifier of the modified system state 22 * 23 * Checks whether the given patch modifies the given system state. 24 * 25 * The function can be called either from pre/post (un)patch 26 * callbacks or from the kernel code added by the livepatch. 27 * 28 * Return: pointer to struct klp_state when found, otherwise NULL. 29 */ 30 struct klp_state *klp_get_state(struct klp_patch *patch, unsigned long id) 31 { 32 struct klp_state *state; 33 34 klp_for_each_state(patch, state) { 35 if (state->id == id) 36 return state; 37 } 38 39 return NULL; 40 } 41 EXPORT_SYMBOL_GPL(klp_get_state); 42 43 /** 44 * klp_get_prev_state() - get information about system state modified by 45 * the already installed livepatches 46 * @id: custom identifier of the modified system state 47 * 48 * Checks whether already installed livepatches modify the given 49 * system state. 50 * 51 * The same system state can be modified by more non-cumulative 52 * livepatches. It is expected that the latest livepatch has 53 * the most up-to-date information. 54 * 55 * The function can be called only during transition when a new 56 * livepatch is being enabled or when such a transition is reverted. 57 * It is typically called only from from pre/post (un)patch 58 * callbacks. 59 * 60 * Return: pointer to the latest struct klp_state from already 61 * installed livepatches, NULL when not found. 62 */ 63 struct klp_state *klp_get_prev_state(unsigned long id) 64 { 65 struct klp_patch *patch; 66 struct klp_state *state, *last_state = NULL; 67 68 if (WARN_ON_ONCE(!klp_transition_patch)) 69 return NULL; 70 71 klp_for_each_patch(patch) { 72 if (patch == klp_transition_patch) 73 goto out; 74 75 state = klp_get_state(patch, id); 76 if (state) 77 last_state = state; 78 } 79 80 out: 81 return last_state; 82 } 83 EXPORT_SYMBOL_GPL(klp_get_prev_state); 84