brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · 7a7098b Raw
227 lines · plain
1================2Shadow Variables3================4 5Shadow variables are a simple way for livepatch modules to associate6additional "shadow" data with existing data structures.  Shadow data is7allocated separately from parent data structures, which are left8unmodified.  The shadow variable API described in this document is used9to allocate/add and remove/free shadow variables to/from their parents.10 11The implementation introduces a global, in-kernel hashtable that12associates pointers to parent objects and a numeric identifier of the13shadow data.  The numeric identifier is a simple enumeration that may be14used to describe shadow variable version, class or type, etc.  More15specifically, the parent pointer serves as the hashtable key while the16numeric id subsequently filters hashtable queries.  Multiple shadow17variables may attach to the same parent object, but their numeric18identifier distinguishes between them.19 20 211. Brief API summary22====================23 24(See the full API usage docbook notes in livepatch/shadow.c.)25 26A hashtable references all shadow variables.  These references are27stored and retrieved through a <obj, id> pair.28 29* The klp_shadow variable data structure encapsulates both tracking30  meta-data and shadow-data:31 32  - meta-data33 34    - obj - pointer to parent object35    - id - data identifier36 37  - data[] - storage for shadow data38 39It is important to note that the klp_shadow_alloc() and40klp_shadow_get_or_alloc() are zeroing the variable by default.41They also allow to call a custom constructor function when a non-zero42value is needed. Callers should provide whatever mutual exclusion43is required.44 45Note that the constructor is called under klp_shadow_lock spinlock. It allows46to do actions that can be done only once when a new variable is allocated.47 48* klp_shadow_get() - retrieve a shadow variable data pointer49  - search hashtable for <obj, id> pair50 51* klp_shadow_alloc() - allocate and add a new shadow variable52  - search hashtable for <obj, id> pair53 54  - if exists55 56    - WARN and return NULL57 58  - if <obj, id> doesn't already exist59 60    - allocate a new shadow variable61    - initialize the variable using a custom constructor and data when provided62    - add <obj, id> to the global hashtable63 64* klp_shadow_get_or_alloc() - get existing or alloc a new shadow variable65  - search hashtable for <obj, id> pair66 67  - if exists68 69    - return existing shadow variable70 71  - if <obj, id> doesn't already exist72 73    - allocate a new shadow variable74    - initialize the variable using a custom constructor and data when provided75    - add <obj, id> pair to the global hashtable76 77* klp_shadow_free() - detach and free a <obj, id> shadow variable78  - find and remove a <obj, id> reference from global hashtable79 80    - if found81 82      - call destructor function if defined83      - free shadow variable84 85* klp_shadow_free_all() - detach and free all <_, id> shadow variables86  - find and remove any <_, id> references from global hashtable87 88    - if found89 90      - call destructor function if defined91      - free shadow variable92 93 942. Use cases95============96 97(See the example shadow variable livepatch modules in samples/livepatch/98for full working demonstrations.)99 100For the following use-case examples, consider commit 1d147bfa6429101("mac80211: fix AP powersave TX vs.  wakeup race"), which added a102spinlock to net/mac80211/sta_info.h :: struct sta_info.  Each use-case103example can be considered a stand-alone livepatch implementation of this104fix.105 106 107Matching parent's lifecycle108---------------------------109 110If parent data structures are frequently created and destroyed, it may111be easiest to align their shadow variables lifetimes to the same112allocation and release functions.  In this case, the parent data113structure is typically allocated, initialized, then registered in some114manner.  Shadow variable allocation and setup can then be considered115part of the parent's initialization and should be completed before the116parent "goes live" (ie, any shadow variable get-API requests are made117for this <obj, id> pair.)118 119For commit 1d147bfa6429, when a parent sta_info structure is allocated,120allocate a shadow copy of the ps_lock pointer, then initialize it::121 122  #define PS_LOCK 1123  struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,124				  const u8 *addr, gfp_t gfp)125  {126	struct sta_info *sta;127	spinlock_t *ps_lock;128 129	/* Parent structure is created */130	sta = kzalloc(sizeof(*sta) + hw->sta_data_size, gfp);131 132	/* Attach a corresponding shadow variable, then initialize it */133	ps_lock = klp_shadow_alloc(sta, PS_LOCK, sizeof(*ps_lock), gfp,134				   NULL, NULL);135	if (!ps_lock)136		goto shadow_fail;137	spin_lock_init(ps_lock);138	...139 140When requiring a ps_lock, query the shadow variable API to retrieve one141for a specific struct sta_info:::142 143  void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)144  {145	spinlock_t *ps_lock;146 147	/* sync with ieee80211_tx_h_unicast_ps_buf */148	ps_lock = klp_shadow_get(sta, PS_LOCK);149	if (ps_lock)150		spin_lock(ps_lock);151	...152 153When the parent sta_info structure is freed, first free the shadow154variable::155 156  void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)157  {158	klp_shadow_free(sta, PS_LOCK, NULL);159	kfree(sta);160	...161 162 163In-flight parent objects164------------------------165 166Sometimes it may not be convenient or possible to allocate shadow167variables alongside their parent objects.  Or a livepatch fix may168require shadow variables for only a subset of parent object instances.169In these cases, the klp_shadow_get_or_alloc() call can be used to attach170shadow variables to parents already in-flight.171 172For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is173inside ieee80211_sta_ps_deliver_wakeup()::174 175  int ps_lock_shadow_ctor(void *obj, void *shadow_data, void *ctor_data)176  {177	spinlock_t *lock = shadow_data;178 179	spin_lock_init(lock);180	return 0;181  }182 183  #define PS_LOCK 1184  void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)185  {186	spinlock_t *ps_lock;187 188	/* sync with ieee80211_tx_h_unicast_ps_buf */189	ps_lock = klp_shadow_get_or_alloc(sta, PS_LOCK,190			sizeof(*ps_lock), GFP_ATOMIC,191			ps_lock_shadow_ctor, NULL);192 193	if (ps_lock)194		spin_lock(ps_lock);195	...196 197This usage will create a shadow variable, only if needed, otherwise it198will use one that was already created for this <obj, id> pair.199 200Like the previous use-case, the shadow spinlock needs to be cleaned up.201A shadow variable can be freed just before its parent object is freed,202or even when the shadow variable itself is no longer required.203 204 205Other use-cases206---------------207 208Shadow variables can also be used as a flag indicating that a data209structure was allocated by new, livepatched code.  In this case, it210doesn't matter what data value the shadow variable holds, its existence211suggests how to handle the parent object.212 213 2143. References215=============216 217* https://github.com/dynup/kpatch218 219  The livepatch implementation is based on the kpatch version of shadow220  variables.221 222* http://files.mkgnu.net/files/dynamos/doc/papers/dynamos_eurosys_07.pdf223 224  Dynamic and Adaptive Updates of Non-Quiescent Subsystems in Commodity225  Operating System Kernels (Kritis Makris, Kyung Dong Ryu 2007) presented226  a datatype update technique called "shadow data structures".227