summaryrefslogtreecommitdiff
path: root/Documentation/livepatch
diff options
context:
space:
mode:
authorJoe Lawrence <joe.lawrence@redhat.com>2017-08-31 16:37:41 -0400
committerJiri Kosina <jkosina@suse.cz>2017-09-14 23:06:12 +0200
commit439e7271dc2b63de379e37971dc2f64d71e24f8a (patch)
treec3dd63d08e743a63936c24949b456d4522003022 /Documentation/livepatch
parentdcba71086e0d1abf4f00cd381530b11d0db7fa1d (diff)
downloadlwn-439e7271dc2b63de379e37971dc2f64d71e24f8a.tar.gz
lwn-439e7271dc2b63de379e37971dc2f64d71e24f8a.zip
livepatch: introduce shadow variable API
Add exported API for livepatch modules: klp_shadow_get() klp_shadow_alloc() klp_shadow_get_or_alloc() klp_shadow_free() klp_shadow_free_all() that implement "shadow" variables, which allow callers to associate new shadow fields to existing data structures. This is intended to be used by livepatch modules seeking to emulate additions to data structure definitions. See Documentation/livepatch/shadow-vars.txt for a summary of the new shadow variable API, including a few common use cases. See samples/livepatch/livepatch-shadow-* for example modules that demonstrate shadow variables. [jkosina@suse.cz: fix __klp_shadow_get_or_alloc() comment as spotted by Josh] Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Acked-by: Miroslav Benes <mbenes@suse.cz> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'Documentation/livepatch')
-rw-r--r--Documentation/livepatch/shadow-vars.txt192
1 files changed, 192 insertions, 0 deletions
diff --git a/Documentation/livepatch/shadow-vars.txt b/Documentation/livepatch/shadow-vars.txt
new file mode 100644
index 000000000000..e3ffc4301bfa
--- /dev/null
+++ b/Documentation/livepatch/shadow-vars.txt
@@ -0,0 +1,192 @@
+================
+Shadow Variables
+================
+
+Shadow variables are a simple way for livepatch modules to associate
+additional "shadow" data with existing data structures. Shadow data is
+allocated separately from parent data structures, which are left
+unmodified. The shadow variable API described in this document is used
+to allocate/attach and detach/release shadow variables to their parents.
+
+The implementation introduces a global, in-kernel hashtable that
+associates pointers to parent objects and a numeric identifier of the
+shadow data. The numeric identifier is a simple enumeration that may be
+used to describe shadow variable version, class or type, etc. More
+specifically, the parent pointer serves as the hashtable key while the
+numeric id subsequently filters hashtable queries. Multiple shadow
+variables may attach to the same parent object, but their numeric
+identifier distinguishes between them.
+
+
+1. Brief API summary
+====================
+
+(See the full API usage docbook notes in livepatch/shadow.c.)
+
+A hashtable references all shadow variables. These references are
+stored and retrieved through a <obj, id> pair.
+
+* The klp_shadow variable data structure encapsulates both tracking
+meta-data and shadow-data:
+ - meta-data
+ - obj - pointer to parent object
+ - id - data identifier
+ - data[] - storage for shadow data
+
+It is important to note that the klp_shadow_alloc() and
+klp_shadow_get_or_alloc() calls, described below, store a *copy* of the
+data that the functions are provided. Callers should provide whatever
+mutual exclusion is required of the shadow data.
+
+* klp_shadow_get() - retrieve a shadow variable data pointer
+ - search hashtable for <obj, id> pair
+
+* klp_shadow_alloc() - allocate and add a new shadow variable
+ - search hashtable for <obj, id> pair
+ - if exists
+ - WARN and return NULL
+ - if <obj, id> doesn't already exist
+ - allocate a new shadow variable
+ - copy data into the new shadow variable
+ - add <obj, id> to the global hashtable
+
+* klp_shadow_get_or_alloc() - get existing or alloc a new shadow variable
+ - search hashtable for <obj, id> pair
+ - if exists
+ - return existing shadow variable
+ - if <obj, id> doesn't already exist
+ - allocate a new shadow variable
+ - copy data into the new shadow variable
+ - add <obj, id> pair to the global hashtable
+
+* klp_shadow_free() - detach and free a <obj, id> shadow variable
+ - find and remove a <obj, id> reference from global hashtable
+ - if found, free shadow variable
+
+* klp_shadow_free_all() - detach and free all <*, id> shadow variables
+ - find and remove any <*, id> references from global hashtable
+ - if found, free shadow variable
+
+
+2. Use cases
+============
+
+(See the example shadow variable livepatch modules in samples/livepatch/
+for full working demonstrations.)
+
+For the following use-case examples, consider commit 1d147bfa6429
+("mac80211: fix AP powersave TX vs. wakeup race"), which added a
+spinlock to net/mac80211/sta_info.h :: struct sta_info. Each use-case
+example can be considered a stand-alone livepatch implementation of this
+fix.
+
+
+Matching parent's lifecycle
+---------------------------
+
+If parent data structures are frequently created and destroyed, it may
+be easiest to align their shadow variables lifetimes to the same
+allocation and release functions. In this case, the parent data
+structure is typically allocated, initialized, then registered in some
+manner. Shadow variable allocation and setup can then be considered
+part of the parent's initialization and should be completed before the
+parent "goes live" (ie, any shadow variable get-API requests are made
+for this <obj, id> pair.)
+
+For commit 1d147bfa6429, when a parent sta_info structure is allocated,
+allocate a shadow copy of the ps_lock pointer, then initialize it:
+
+#define PS_LOCK 1
+struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
+ const u8 *addr, gfp_t gfp)
+{
+ struct sta_info *sta;
+ spinlock_t *ps_lock;
+
+ /* Parent structure is created */
+ sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp);
+
+ /* Attach a corresponding shadow variable, then initialize it */
+ ps_lock = klp_shadow_alloc(sta, PS_LOCK, NULL, sizeof(ps_lock), gfp);
+ if (!ps_lock)
+ goto shadow_fail;
+ spin_lock_init(ps_lock);
+ ...
+
+When requiring a ps_lock, query the shadow variable API to retrieve one
+for a specific struct sta_info:
+
+void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
+{
+ spinlock_t *ps_lock;
+
+ /* sync with ieee80211_tx_h_unicast_ps_buf */
+ ps_lock = klp_shadow_get(sta, PS_LOCK);
+ if (ps_lock)
+ spin_lock(ps_lock);
+ ...
+
+When the parent sta_info structure is freed, first free the shadow
+variable:
+
+void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
+{
+ klp_shadow_free(sta, PS_LOCK);
+ kfree(sta);
+ ...
+
+
+In-flight parent objects
+------------------------
+
+Sometimes it may not be convenient or possible to allocate shadow
+variables alongside their parent objects. Or a livepatch fix may
+require shadow varibles to only a subset of parent object instances. In
+these cases, the klp_shadow_get_or_alloc() call can be used to attach
+shadow variables to parents already in-flight.
+
+For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is
+inside ieee80211_sta_ps_deliver_wakeup():
+
+#define PS_LOCK 1
+void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
+{
+ DEFINE_SPINLOCK(ps_lock_fallback);
+ spinlock_t *ps_lock;
+
+ /* sync with ieee80211_tx_h_unicast_ps_buf */
+ ps_lock = klp_shadow_get_or_alloc(sta, PS_LOCK,
+ &ps_lock_fallback, sizeof(ps_lock_fallback),
+ GFP_ATOMIC);
+ if (ps_lock)
+ spin_lock(ps_lock);
+ ...
+
+This usage will create a shadow variable, only if needed, otherwise it
+will use one that was already created for this <obj, id> pair.
+
+Like the previous use-case, the shadow spinlock needs to be cleaned up.
+A shadow variable can be freed just before its parent object is freed,
+or even when the shadow variable itself is no longer required.
+
+
+Other use-cases
+---------------
+
+Shadow variables can also be used as a flag indicating that a data
+structure was allocated by new, livepatched code. In this case, it
+doesn't matter what data value the shadow variable holds, its existence
+suggests how to handle the parent object.
+
+
+3. References
+=============
+
+* https://github.com/dynup/kpatch
+The livepatch implementation is based on the kpatch version of shadow
+variables.
+
+* http://files.mkgnu.net/files/dynamos/doc/papers/dynamos_eurosys_07.pdf
+Dynamic and Adaptive Updates of Non-Quiescent Subsystems in Commodity
+Operating System Kernels (Kritis Makris, Kyung Dong Ryu 2007) presented
+a datatype update technique called "shadow data structures".