Przeglądaj źródła

deploy: 738727bbcc81f8b053b5c0370c2f5d7454680e9e

jserv 2 lat temu
rodzic
commit
1fea22efa8
3 zmienionych plików z 777 dodań i 40 usunięć
  1. 280 20
      index.html
  2. 217 0
      lkmpg-for-ht.css
  3. 280 20
      lkmpg-for-ht.html

+ 280 - 20
index.html

@@ -18,7 +18,7 @@
 
 <h2 class='titleHead'>The Linux Kernel Module Programming Guide</h2>
 <div class='author'><span class='ecrm-1200'>Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, Jim Huang</span></div><br />
-<div class='date'><span class='ecrm-1200'>May 1, 2023</span></div>
+<div class='date'><span class='ecrm-1200'>May 2, 2023</span></div>
                                                                   
 
                                                                   
@@ -92,10 +92,11 @@
 <br />    <span class='sectionToc'>18 <a href='#standardizing-the-interfaces-the-device-model' id='QQ2-1-64'>Standardizing the interfaces: The Device Model</a></span>
 <br />    <span class='sectionToc'>19 <a href='#optimizations' id='QQ2-1-65'>Optimizations</a></span>
 <br />     <span class='subsectionToc'>19.1 <a href='#likely-and-unlikely-conditions' id='QQ2-1-66'>Likely and Unlikely conditions</a></span>
-<br />    <span class='sectionToc'>20 <a href='#common-pitfalls' id='QQ2-1-67'>Common Pitfalls</a></span>
-<br />     <span class='subsectionToc'>20.1 <a href='#using-standard-libraries' id='QQ2-1-68'>Using standard libraries</a></span>
-<br />     <span class='subsectionToc'>20.2 <a href='#disabling-interrupts' id='QQ2-1-69'>Disabling interrupts</a></span>
-<br />    <span class='sectionToc'>21 <a href='#where-to-go-from-here' id='QQ2-1-70'>Where To Go From Here?</a></span>
+<br />     <span class='subsectionToc'>19.2 <a href='#static-keys' id='QQ2-1-67'>Static keys</a></span>
+<br />    <span class='sectionToc'>20 <a href='#common-pitfalls' id='QQ2-1-68'>Common Pitfalls</a></span>
+<br />     <span class='subsectionToc'>20.1 <a href='#using-standard-libraries' id='QQ2-1-69'>Using standard libraries</a></span>
+<br />     <span class='subsectionToc'>20.2 <a href='#disabling-interrupts' id='QQ2-1-70'>Disabling interrupts</a></span>
+<br />    <span class='sectionToc'>21 <a href='#where-to-go-from-here' id='QQ2-1-71'>Where To Go From Here?</a></span>
    </div>
    <h3 class='sectionHead' id='introduction'><span class='titlemark'>1   </span> <a id='x1-10001'></a>Introduction</h3>
 <!-- l. 65 --><p class='noindent'>The Linux Kernel Module Programming Guide is a free book; you may reproduce
@@ -110,12 +111,12 @@ the provisions of the <a href='https://opensource.org/licenses/OSL-3.0'>Open Sof
 distribute this book free of charge or for a profit. No explicit permission is required
 from the author for reproduction of this book in any medium, physical or
 electronic.
-</p><!-- l. 72 --><p class='indent'>   Derivative works and translations of this document must be placed under the
-Open Software License, and the original copyright notice must remain intact. If you
-have contributed new material to this book, you must make the material and source
                                                                   
 
                                                                   
+</p><!-- l. 72 --><p class='indent'>   Derivative works and translations of this document must be placed under the
+Open Software License, and the original copyright notice must remain intact. If you
+have contributed new material to this book, you must make the material and source
 code available for your revisions. Please make revisions and updates available directly
 to the document maintainer, Jim Huang &lt;jserv@ccns.ncku.edu.tw&gt;. This will allow
 for the merging of updates and provide consistent revisions to the Linux
@@ -6498,30 +6499,289 @@ avoids flushing the processor pipeline. The opposite happens if you use the
                                                                   
 </p><!-- l. 2047 --><p class='noindent'>
 </p>
-   <h3 class='sectionHead' id='common-pitfalls'><span class='titlemark'>20   </span> <a id='x1-6800020'></a>Common Pitfalls</h3>
-<!-- l. 2050 --><p class='noindent'>
+   <h4 class='subsectionHead' id='static-keys'><span class='titlemark'>19.2   </span> <a id='x1-6800019.2'></a>Static keys</h4>
+<!-- l. 2049 --><p class='noindent'>Static keys allow us to enable or disable kernel code paths based on the runtime state
+of key. Its APIs have been available since 2010 (most architectures are already
+supported), use self-modifying code to eliminate the overhead of cache and branch
+prediction. The most typical use case of static keys is for performance-sensitive kernel
+code, such as tracepoints, context switching, networking, etc. These hot paths of the
+kernel often contain branches and can be optimized easily using this technique.
+Before we can use static keys in the kernel, we need to make sure that gcc supports
+<code> <span id='textcolor3472'><span class='ectt-1000'>asm</span></span><span class='ectt-1000'> </span><span id='textcolor3473'><span class='ectt-1000'>goto</span></span>
+</code> inline assembly, and the following kernel configurations are set:
+</p><!-- l. 1 --><p class='indent'>
+</p>
+   <pre class='fancyvrb' id='fancyvrb99'><a id='x1-68006r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>CONFIG_JUMP_LABEL=y</span> 
+<a id='x1-68008r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>CONFIG_HAVE_ARCH_JUMP_LABEL=y</span> 
+<a id='x1-68010r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'>CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y</span></pre>
+<!-- l. 2059 --><p class='indent'>   To declare a static key, we need to define a global variable using the
+<code> <span class='ectt-1000'>DEFINE_STATIC_KEY_FALSE</span>
+</code> or <code>  <span class='ectt-1000'>DEFINE_STATIC_KEY_TRUE</span>
+</code> macro defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/jump_label.h'>include/linux/jump_label.h</a>. This macro initializes the key with
+the given initial value, which is either false or true, respectively. For example, to
+declare a static key with an initial value of false, we can use the following
+code:
+</p><!-- l. 1 --><p class='indent'>
+</p>
+   <pre class='fancyvrb' id='fancyvrb100'><a id='x1-68015r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>DEFINE_STATIC_KEY_FALSE(fkey);</span></pre>
+<!-- l. 2066 --><p class='indent'>   Once the static key has been declared, we need to add branching code to the
+module that uses the static key. For example, the code includes a fastpath, where a
+no-op instruction will be generated at compile time as the key is initialized to false
+and the branch is unlikely to be taken.
+</p><!-- l. 1 --><p class='indent'>
+</p>
+   <pre class='fancyvrb' id='fancyvrb101'><a id='x1-68021r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>pr_info(</span><span id='textcolor3474'><span class='ectt-0800'>"fastpath 1</span></span><span id='textcolor3475'><span class='ectt-0800'>\n</span></span><span id='textcolor3476'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68023r2'></a><span class='ecrm-0500'>2</span><span id='textcolor3477'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (static_branch_unlikely(&amp;fkey))</span> 
+<a id='x1-68025r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'>    pr_alert(</span><span id='textcolor3478'><span class='ectt-0800'>"do unlikely thing</span></span><span id='textcolor3479'><span class='ectt-0800'>\n</span></span><span id='textcolor3480'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68027r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'>pr_info(</span><span id='textcolor3481'><span class='ectt-0800'>"fastpath 2</span></span><span id='textcolor3482'><span class='ectt-0800'>\n</span></span><span id='textcolor3483'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span></pre>
+<!-- l. 2076 --><p class='indent'>   If the key is enabled at runtime by calling
+<code> <span class='ectt-1000'>static_branch_enable(&amp;fkey)</span>
+</code>, the fastpath will be patched with an unconditional jump instruction to the slowpath
+code <code>  <span class='ectt-1000'>pr_alert</span>
+</code>, so the branch will always be taken until the key is disabled again.
+</p><!-- l. 2078 --><p class='indent'>   The following kernel module derived from <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>chardev.c</span></span></span>, demostrates how the static
+key works.
+</p><!-- l. 1 --><p class='indent'>
+</p>
+   <pre class='fancyvrb' id='fancyvrb102'><a id='x1-68031r1'></a><span class='ecrm-0500'>1</span><span id='textcolor3484'><span class='ectt-0800'>/*</span></span> 
+<a id='x1-68033r2'></a><span class='ecrm-0500'>2</span><span id='textcolor3485'><span class='ectt-0800'> * static_key.c</span></span> 
+<a id='x1-68035r3'></a><span class='ecrm-0500'>3</span><span id='textcolor3486'><span class='ectt-0800'> */</span></span> 
+<a id='x1-68037r4'></a><span class='ecrm-0500'>4</span> 
+<a id='x1-68039r5'></a><span class='ecrm-0500'>5</span><span id='textcolor3487'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3488'><span class='ectt-0800'>&lt;linux/atomic.h&gt;</span></span> 
+<a id='x1-68041r6'></a><span class='ecrm-0500'>6</span><span id='textcolor3489'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3490'><span class='ectt-0800'>&lt;linux/device.h&gt;</span></span> 
+<a id='x1-68043r7'></a><span class='ecrm-0500'>7</span><span id='textcolor3491'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3492'><span class='ectt-0800'>&lt;linux/fs.h&gt;</span></span> 
+<a id='x1-68045r8'></a><span class='ecrm-0500'>8</span><span id='textcolor3493'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3494'><span class='ectt-0800'>&lt;linux/kernel.h&gt; /* for sprintf() */</span></span> 
+<a id='x1-68047r9'></a><span class='ecrm-0500'>9</span><span id='textcolor3495'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3496'><span class='ectt-0800'>&lt;linux/module.h&gt;</span></span> 
+<a id='x1-68049r10'></a><span class='ecrm-0500'>10</span><span id='textcolor3497'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3498'><span class='ectt-0800'>&lt;linux/printk.h&gt;</span></span> 
+<a id='x1-68051r11'></a><span class='ecrm-0500'>11</span><span id='textcolor3499'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3500'><span class='ectt-0800'>&lt;linux/types.h&gt;</span></span> 
+<a id='x1-68053r12'></a><span class='ecrm-0500'>12</span><span id='textcolor3501'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3502'><span class='ectt-0800'>&lt;linux/uaccess.h&gt; /* for get_user and put_user */</span></span> 
+<a id='x1-68055r13'></a><span class='ecrm-0500'>13</span> 
+<a id='x1-68057r14'></a><span class='ecrm-0500'>14</span><span id='textcolor3503'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3504'><span class='ectt-0800'>&lt;asm/errno.h&gt;</span></span> 
+<a id='x1-68059r15'></a><span class='ecrm-0500'>15</span> 
+<a id='x1-68061r16'></a><span class='ecrm-0500'>16</span><span id='textcolor3505'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3506'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor3507'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3508'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file);</span> 
+<a id='x1-68063r17'></a><span class='ecrm-0500'>17</span><span id='textcolor3509'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3510'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor3511'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3512'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file);</span> 
+<a id='x1-68065r18'></a><span class='ecrm-0500'>18</span><span id='textcolor3513'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3514'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor3515'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor3516'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf, </span><span id='textcolor3517'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count,</span> 
+<a id='x1-68067r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'>                           loff_t *ppos);</span> 
+<a id='x1-68069r20'></a><span class='ecrm-0500'>20</span><span id='textcolor3518'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3519'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor3520'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor3521'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3522'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf,</span> 
+<a id='x1-68071r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>                            </span><span id='textcolor3523'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count, loff_t *ppos);</span> 
+<a id='x1-68073r22'></a><span class='ecrm-0500'>22</span> 
+<a id='x1-68075r23'></a><span class='ecrm-0500'>23</span><span id='textcolor3524'><span class='ectt-0800'>#define SUCCESS 0</span></span> 
+<a id='x1-68077r24'></a><span class='ecrm-0500'>24</span><span id='textcolor3525'><span class='ectt-0800'>#define DEVICE_NAME "key_state"</span></span> 
+<a id='x1-68079r25'></a><span class='ecrm-0500'>25</span><span id='textcolor3526'><span class='ectt-0800'>#define BUF_LEN 10</span></span> 
+<a id='x1-68081r26'></a><span class='ecrm-0500'>26</span> 
+<a id='x1-68083r27'></a><span class='ecrm-0500'>27</span><span id='textcolor3527'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3528'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> major;</span> 
+<a id='x1-68085r28'></a><span class='ecrm-0500'>28</span> 
+<a id='x1-68087r29'></a><span class='ecrm-0500'>29</span><span id='textcolor3529'><span class='ectt-0800'>enum</span></span><span class='ectt-0800'> {</span> 
+<a id='x1-68089r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'>    CDEV_NOT_USED = 0,</span> 
+<a id='x1-68091r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'>    CDEV_EXCLUSIVE_OPEN = 1,</span> 
+<a id='x1-68093r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'>};</span> 
+<a id='x1-68095r33'></a><span class='ecrm-0500'>33</span> 
+<a id='x1-68097r34'></a><span class='ecrm-0500'>34</span><span id='textcolor3530'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);</span> 
+<a id='x1-68099r35'></a><span class='ecrm-0500'>35</span> 
+<a id='x1-68101r36'></a><span class='ecrm-0500'>36</span><span id='textcolor3531'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3532'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> msg[BUF_LEN + 1];</span> 
+<a id='x1-68103r37'></a><span class='ecrm-0500'>37</span> 
+<a id='x1-68105r38'></a><span class='ecrm-0500'>38</span><span id='textcolor3533'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3534'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *cls;</span> 
+<a id='x1-68107r39'></a><span class='ecrm-0500'>39</span> 
+<a id='x1-68109r40'></a><span class='ecrm-0500'>40</span><span id='textcolor3535'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DEFINE_STATIC_KEY_FALSE(fkey);</span> 
+<a id='x1-68111r41'></a><span class='ecrm-0500'>41</span> 
+<a id='x1-68113r42'></a><span class='ecrm-0500'>42</span><span id='textcolor3536'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3537'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations chardev_fops = {</span> 
+<a id='x1-68115r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'>    .owner = THIS_MODULE,</span> 
+<a id='x1-68117r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>    .open = device_open,</span> 
+<a id='x1-68119r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'>    .release = device_release,</span> 
+<a id='x1-68121r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'>    .read = device_read,</span> 
+<a id='x1-68123r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'>    .write = device_write,</span> 
+<a id='x1-68125r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'>};</span> 
+<a id='x1-68127r49'></a><span class='ecrm-0500'>49</span> 
+<a id='x1-68129r50'></a><span class='ecrm-0500'>50</span><span id='textcolor3538'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3539'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init chardev_init(</span><span id='textcolor3540'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span> 
+<a id='x1-68131r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'>{</span> 
+<a id='x1-68133r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'>    major = register_chrdev(0, DEVICE_NAME, &amp;chardev_fops);</span> 
+<a id='x1-68135r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'>    </span><span id='textcolor3541'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (major &lt; 0) {</span> 
+<a id='x1-68137r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'>        pr_alert(</span><span id='textcolor3542'><span class='ectt-0800'>"Registering char device failed with %d</span></span><span id='textcolor3543'><span class='ectt-0800'>\n</span></span><span id='textcolor3544'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, major);</span> 
+<a id='x1-68139r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'>        </span><span id='textcolor3545'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> major;</span> 
+<a id='x1-68141r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'>    }</span> 
+<a id='x1-68143r57'></a><span class='ecrm-0500'>57</span> 
+<a id='x1-68145r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'>    pr_info(</span><span id='textcolor3546'><span class='ectt-0800'>"I was assigned major number %d</span></span><span id='textcolor3547'><span class='ectt-0800'>\n</span></span><span id='textcolor3548'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, major);</span> 
+<a id='x1-68147r59'></a><span class='ecrm-0500'>59</span> 
+<a id='x1-68149r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'>    cls = class_create(THIS_MODULE, DEVICE_NAME);</span> 
+<a id='x1-68151r61'></a><span class='ecrm-0500'>61</span> 
+<a id='x1-68153r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'>    device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);</span> 
+<a id='x1-68155r63'></a><span class='ecrm-0500'>63</span> 
+<a id='x1-68157r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>    pr_info(</span><span id='textcolor3549'><span class='ectt-0800'>"Device created on /dev/%s</span></span><span id='textcolor3550'><span class='ectt-0800'>\n</span></span><span id='textcolor3551'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DEVICE_NAME);</span> 
+<a id='x1-68159r65'></a><span class='ecrm-0500'>65</span> 
+<a id='x1-68161r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'>    </span><span id='textcolor3552'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span> 
+<a id='x1-68163r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>}</span> 
+<a id='x1-68165r68'></a><span class='ecrm-0500'>68</span> 
+<a id='x1-68167r69'></a><span class='ecrm-0500'>69</span><span id='textcolor3553'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3554'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit chardev_exit(</span><span id='textcolor3555'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span> 
+<a id='x1-68169r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>{</span> 
+<a id='x1-68171r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'>    device_destroy(cls, MKDEV(major, 0));</span> 
+<a id='x1-68173r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'>    class_destroy(cls);</span> 
+<a id='x1-68175r73'></a><span class='ecrm-0500'>73</span> 
+<a id='x1-68177r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'>    </span><span id='textcolor3556'><span class='ectt-0800'>/* Unregister the device */</span></span> 
+<a id='x1-68179r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'>    unregister_chrdev(major, DEVICE_NAME);</span> 
+<a id='x1-68181r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'>}</span> 
+<a id='x1-68183r77'></a><span class='ecrm-0500'>77</span> 
+<a id='x1-68185r78'></a><span class='ecrm-0500'>78</span><span id='textcolor3557'><span class='ectt-0800'>/* Methods */</span></span> 
+<a id='x1-68187r79'></a><span class='ecrm-0500'>79</span> 
+<a id='x1-68189r80'></a><span class='ecrm-0500'>80</span><span id='textcolor3558'><span class='ectt-0800'>/**</span></span> 
+<a id='x1-68191r81'></a><span class='ecrm-0500'>81</span><span id='textcolor3559'><span class='ectt-0800'> * Called when a process tried to open the device file, like</span></span> 
+<a id='x1-68193r82'></a><span class='ecrm-0500'>82</span><span id='textcolor3560'><span class='ectt-0800'> * cat /dev/key_state</span></span> 
+<a id='x1-68195r83'></a><span class='ecrm-0500'>83</span><span id='textcolor3561'><span class='ectt-0800'> */</span></span> 
+<a id='x1-68197r84'></a><span class='ecrm-0500'>84</span><span id='textcolor3562'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3563'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor3564'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3565'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span> 
+<a id='x1-68199r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'>{</span> 
+<a id='x1-68201r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'>    </span><span id='textcolor3566'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (atomic_cmpxchg(&amp;already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))</span> 
+<a id='x1-68203r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'>        </span><span id='textcolor3567'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EBUSY;</span> 
+<a id='x1-68205r88'></a><span class='ecrm-0500'>88</span> 
+<a id='x1-68207r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'>    sprintf(msg, static_key_enabled(&amp;fkey) ? </span><span id='textcolor3568'><span class='ectt-0800'>"enabled</span></span><span id='textcolor3569'><span class='ectt-0800'>\n</span></span><span id='textcolor3570'><span class='ectt-0800'>"</span></span><span class='ectt-0800'> : </span><span id='textcolor3571'><span class='ectt-0800'>"disabled</span></span><span id='textcolor3572'><span class='ectt-0800'>\n</span></span><span id='textcolor3573'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68209r90'></a><span class='ecrm-0500'>90</span> 
+<a id='x1-68211r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'>    pr_info(</span><span id='textcolor3574'><span class='ectt-0800'>"fastpath 1</span></span><span id='textcolor3575'><span class='ectt-0800'>\n</span></span><span id='textcolor3576'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68213r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'>    </span><span id='textcolor3577'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (static_branch_unlikely(&amp;fkey))</span> 
+<a id='x1-68215r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'>        pr_alert(</span><span id='textcolor3578'><span class='ectt-0800'>"do unlikely thing</span></span><span id='textcolor3579'><span class='ectt-0800'>\n</span></span><span id='textcolor3580'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68217r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'>    pr_info(</span><span id='textcolor3581'><span class='ectt-0800'>"fastpath 2</span></span><span id='textcolor3582'><span class='ectt-0800'>\n</span></span><span id='textcolor3583'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68219r95'></a><span class='ecrm-0500'>95</span> 
+<a id='x1-68221r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'>    try_module_get(THIS_MODULE);</span> 
+<a id='x1-68223r97'></a><span class='ecrm-0500'>97</span> 
+<a id='x1-68225r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'>    </span><span id='textcolor3584'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span> 
+<a id='x1-68227r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'>}</span> 
+<a id='x1-68229r100'></a><span class='ecrm-0500'>100</span> 
+<a id='x1-68231r101'></a><span class='ecrm-0500'>101</span><span id='textcolor3585'><span class='ectt-0800'>/**</span></span> 
+<a id='x1-68233r102'></a><span class='ecrm-0500'>102</span><span id='textcolor3586'><span class='ectt-0800'> * Called when a process closes the device file</span></span> 
+<a id='x1-68235r103'></a><span class='ecrm-0500'>103</span><span id='textcolor3587'><span class='ectt-0800'> */</span></span> 
+<a id='x1-68237r104'></a><span class='ecrm-0500'>104</span><span id='textcolor3588'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3589'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor3590'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3591'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span> 
+<a id='x1-68239r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'>{</span> 
+<a id='x1-68241r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'>    </span><span id='textcolor3592'><span class='ectt-0800'>/* We are now ready for our next caller. */</span></span> 
+<a id='x1-68243r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'>    atomic_set(&amp;already_open, CDEV_NOT_USED);</span> 
+<a id='x1-68245r108'></a><span class='ecrm-0500'>108</span> 
+<a id='x1-68247r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'>    </span><span id='textcolor3593'><span class='ectt-0800'>/**</span></span> 
+<a id='x1-68249r110'></a><span class='ecrm-0500'>110</span><span id='textcolor3594'><span class='ectt-0800'>     * Decrement the usage count, or else once you opened the file, you will</span></span> 
+<a id='x1-68251r111'></a><span class='ecrm-0500'>111</span><span id='textcolor3595'><span class='ectt-0800'>     * never get rid of the module.</span></span> 
+<a id='x1-68253r112'></a><span class='ecrm-0500'>112</span><span id='textcolor3596'><span class='ectt-0800'>     */</span></span> 
+<a id='x1-68255r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'>    module_put(THIS_MODULE);</span> 
+<a id='x1-68257r114'></a><span class='ecrm-0500'>114</span> 
+<a id='x1-68259r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'>    </span><span id='textcolor3597'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span> 
+<a id='x1-68261r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'>}</span> 
+<a id='x1-68263r117'></a><span class='ecrm-0500'>117</span> 
+<a id='x1-68265r118'></a><span class='ecrm-0500'>118</span><span id='textcolor3598'><span class='ectt-0800'>/**</span></span> 
+<a id='x1-68267r119'></a><span class='ecrm-0500'>119</span><span id='textcolor3599'><span class='ectt-0800'> * Called when a process, which already opened the dev file, attempts to</span></span> 
+<a id='x1-68269r120'></a><span class='ecrm-0500'>120</span><span id='textcolor3600'><span class='ectt-0800'> * read from it.</span></span> 
+<a id='x1-68271r121'></a><span class='ecrm-0500'>121</span><span id='textcolor3601'><span class='ectt-0800'> */</span></span> 
+<a id='x1-68273r122'></a><span class='ecrm-0500'>122</span><span id='textcolor3602'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3603'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor3604'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor3605'><span class='ectt-0800'>/* see include/linux/fs.h */</span></span> 
+<a id='x1-68275r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'>                           </span><span id='textcolor3606'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer, </span><span id='textcolor3607'><span class='ectt-0800'>/* buffer to fill with data */</span></span> 
+<a id='x1-68277r124'></a><span class='ecrm-0500'>124</span><span class='ectt-0800'>                           </span><span id='textcolor3608'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, </span><span id='textcolor3609'><span class='ectt-0800'>/* length of the buffer */</span></span> 
+<a id='x1-68279r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'>                           loff_t *offset)</span> 
+<a id='x1-68281r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'>{</span> 
+<a id='x1-68283r127'></a><span class='ecrm-0500'>127</span><span class='ectt-0800'>    </span><span id='textcolor3610'><span class='ectt-0800'>/* Number of the bytes actually written to the buffer */</span></span> 
+<a id='x1-68285r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'>    </span><span id='textcolor3611'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> bytes_read = 0;</span> 
+<a id='x1-68287r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'>    </span><span id='textcolor3612'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3613'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *msg_ptr = msg;</span> 
+<a id='x1-68289r130'></a><span class='ecrm-0500'>130</span> 
+<a id='x1-68291r131'></a><span class='ecrm-0500'>131</span><span class='ectt-0800'>    </span><span id='textcolor3614'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!*(msg_ptr + *offset)) { </span><span id='textcolor3615'><span class='ectt-0800'>/* We are at the end of the message */</span></span> 
+<a id='x1-68293r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'>        *offset = 0; </span><span id='textcolor3616'><span class='ectt-0800'>/* reset the offset */</span></span> 
+<a id='x1-68295r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'>        </span><span id='textcolor3617'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0; </span><span id='textcolor3618'><span class='ectt-0800'>/* signify end of file */</span></span> 
+<a id='x1-68297r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'>    }</span> 
+<a id='x1-68299r135'></a><span class='ecrm-0500'>135</span> 
+<a id='x1-68301r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'>    msg_ptr += *offset;</span> 
+<a id='x1-68303r137'></a><span class='ecrm-0500'>137</span> 
+<a id='x1-68305r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'>    </span><span id='textcolor3619'><span class='ectt-0800'>/* Actually put the date into the buffer */</span></span> 
+<a id='x1-68307r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'>    </span><span id='textcolor3620'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (length &amp;&amp; *msg_ptr) {</span> 
+<a id='x1-68309r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'>        </span><span id='textcolor3621'><span class='ectt-0800'>/**</span></span> 
+<a id='x1-68311r141'></a><span class='ecrm-0500'>141</span><span id='textcolor3622'><span class='ectt-0800'>         * The buffer is in the user data segment, not the kernel</span></span> 
+<a id='x1-68313r142'></a><span class='ecrm-0500'>142</span><span id='textcolor3623'><span class='ectt-0800'>         * segment so "*" assignment won</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t work. We have to use</span></span> 
+<a id='x1-68315r143'></a><span class='ecrm-0500'>143</span><span id='textcolor3624'><span class='ectt-0800'>         * put_user which copies data from the kernel data segment to</span></span> 
+<a id='x1-68317r144'></a><span class='ecrm-0500'>144</span><span id='textcolor3625'><span class='ectt-0800'>         * the user data segment.</span></span> 
+<a id='x1-68319r145'></a><span class='ecrm-0500'>145</span><span id='textcolor3626'><span class='ectt-0800'>         */</span></span> 
+<a id='x1-68321r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'>        put_user(*(msg_ptr++), buffer++);</span> 
+<a id='x1-68323r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'>        length--;</span> 
+<a id='x1-68325r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'>        bytes_read++;</span> 
+<a id='x1-68327r149'></a><span class='ecrm-0500'>149</span><span class='ectt-0800'>    }</span> 
+<a id='x1-68329r150'></a><span class='ecrm-0500'>150</span> 
+<a id='x1-68331r151'></a><span class='ecrm-0500'>151</span><span class='ectt-0800'>    *offset += bytes_read;</span> 
+<a id='x1-68333r152'></a><span class='ecrm-0500'>152</span> 
+<a id='x1-68335r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'>    </span><span id='textcolor3627'><span class='ectt-0800'>/* Most read functions return the number of bytes put into the buffer. */</span></span> 
+<a id='x1-68337r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'>    </span><span id='textcolor3628'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> bytes_read;</span> 
+<a id='x1-68339r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'>}</span> 
+<a id='x1-68341r156'></a><span class='ecrm-0500'>156</span> 
+<a id='x1-68343r157'></a><span class='ecrm-0500'>157</span><span id='textcolor3629'><span class='ectt-0800'>/* Called when a process writes to dev file; echo "enable" &gt; /dev/key_state */</span></span> 
+<a id='x1-68345r158'></a><span class='ecrm-0500'>158</span><span id='textcolor3630'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3631'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor3632'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor3633'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3634'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span> 
+<a id='x1-68347r159'></a><span class='ecrm-0500'>159</span><span class='ectt-0800'>                            </span><span id='textcolor3635'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, loff_t *offset)</span> 
+<a id='x1-68349r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'>{</span> 
+<a id='x1-68351r161'></a><span class='ecrm-0500'>161</span><span class='ectt-0800'>    </span><span id='textcolor3636'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> command[10];</span> 
+<a id='x1-68353r162'></a><span class='ecrm-0500'>162</span> 
+<a id='x1-68355r163'></a><span class='ecrm-0500'>163</span><span class='ectt-0800'>    </span><span id='textcolor3637'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (length &gt; 10) {</span> 
+<a id='x1-68357r164'></a><span class='ecrm-0500'>164</span><span class='ectt-0800'>        pr_err(</span><span id='textcolor3638'><span class='ectt-0800'>"command exceeded 10 char</span></span><span id='textcolor3639'><span class='ectt-0800'>\n</span></span><span id='textcolor3640'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68359r165'></a><span class='ecrm-0500'>165</span><span class='ectt-0800'>        </span><span id='textcolor3641'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EINVAL;</span> 
+<a id='x1-68361r166'></a><span class='ecrm-0500'>166</span><span class='ectt-0800'>    }</span> 
+<a id='x1-68363r167'></a><span class='ecrm-0500'>167</span> 
+<a id='x1-68365r168'></a><span class='ecrm-0500'>168</span><span class='ectt-0800'>    </span><span id='textcolor3642'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_from_user(command, buffer, length))</span> 
+<a id='x1-68367r169'></a><span class='ecrm-0500'>169</span><span class='ectt-0800'>        </span><span id='textcolor3643'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EFAULT;</span> 
+<a id='x1-68369r170'></a><span class='ecrm-0500'>170</span> 
+<a id='x1-68371r171'></a><span class='ecrm-0500'>171</span><span class='ectt-0800'>    </span><span id='textcolor3644'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (strncmp(command, </span><span id='textcolor3645'><span class='ectt-0800'>"enable"</span></span><span class='ectt-0800'>, strlen(</span><span id='textcolor3646'><span class='ectt-0800'>"enable"</span></span><span class='ectt-0800'>)) == 0)</span> 
+<a id='x1-68373r172'></a><span class='ecrm-0500'>172</span><span class='ectt-0800'>        static_branch_enable(&amp;fkey);</span> 
+<a id='x1-68375r173'></a><span class='ecrm-0500'>173</span><span class='ectt-0800'>    </span><span id='textcolor3647'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> </span><span id='textcolor3648'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (strncmp(command, </span><span id='textcolor3649'><span class='ectt-0800'>"disable"</span></span><span class='ectt-0800'>, strlen(</span><span id='textcolor3650'><span class='ectt-0800'>"disable"</span></span><span class='ectt-0800'>)) == 0)</span> 
+<a id='x1-68377r174'></a><span class='ecrm-0500'>174</span><span class='ectt-0800'>        static_branch_disable(&amp;fkey);</span> 
+<a id='x1-68379r175'></a><span class='ecrm-0500'>175</span><span class='ectt-0800'>    </span><span id='textcolor3651'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> {</span> 
+<a id='x1-68381r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'>        pr_err(</span><span id='textcolor3652'><span class='ectt-0800'>"Invalid command: %s</span></span><span id='textcolor3653'><span class='ectt-0800'>\n</span></span><span id='textcolor3654'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, command);</span> 
+<a id='x1-68383r177'></a><span class='ecrm-0500'>177</span><span class='ectt-0800'>        </span><span id='textcolor3655'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EINVAL;</span> 
+<a id='x1-68385r178'></a><span class='ecrm-0500'>178</span><span class='ectt-0800'>    }</span> 
+<a id='x1-68387r179'></a><span class='ecrm-0500'>179</span> 
+<a id='x1-68389r180'></a><span class='ecrm-0500'>180</span><span class='ectt-0800'>    </span><span id='textcolor3656'><span class='ectt-0800'>/* Again, return the number of input characters used. */</span></span> 
+<a id='x1-68391r181'></a><span class='ecrm-0500'>181</span><span class='ectt-0800'>    </span><span id='textcolor3657'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> length;</span> 
+<a id='x1-68393r182'></a><span class='ecrm-0500'>182</span><span class='ectt-0800'>}</span> 
+<a id='x1-68395r183'></a><span class='ecrm-0500'>183</span> 
+<a id='x1-68397r184'></a><span class='ecrm-0500'>184</span><span class='ectt-0800'>module_init(chardev_init);</span> 
+<a id='x1-68399r185'></a><span class='ecrm-0500'>185</span><span class='ectt-0800'>module_exit(chardev_exit);</span> 
+<a id='x1-68401r186'></a><span class='ecrm-0500'>186</span> 
+<a id='x1-68403r187'></a><span class='ecrm-0500'>187</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor3658'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
+                                                                  
+
+                                                                  
+<!-- l. 2082 --><p class='indent'>   To check the state of the static key, we can use the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev/key_state</span></span></span>
+interface.
+</p><!-- l. 1 --><p class='indent'>
+</p>
+   <pre class='fancyvrb' id='fancyvrb103'><a id='x1-68406r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>cat /dev/key_state</span></pre>
+<!-- l. 2088 --><p class='indent'>   This will display the current state of the key, which is disabled by default.
+</p><!-- l. 2090 --><p class='indent'>   To change the state of the static key, we can perform a write operation on the
+file:
+</p><!-- l. 1 --><p class='indent'>
 </p>
-   <h4 class='subsectionHead' id='using-standard-libraries'><span class='titlemark'>20.1   </span> <a id='x1-6900020.1'></a>Using standard libraries</h4>
-<!-- l. 2052 --><p class='noindent'>You can not do that. In a kernel module, you can only use kernel functions which are
+   <pre class='fancyvrb' id='fancyvrb104'><a id='x1-68409r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>echo enable &gt; /dev/key_state</span></pre>
+<!-- l. 2096 --><p class='indent'>   This will enable the static key, causing the code path to switch from the fastpath
+to the slowpath.
+</p><!-- l. 2098 --><p class='indent'>   In some cases, the key is enabled or disabled at initialization and never changed,
+we can declare a static key as read-only, which means that it can only be toggled in
+the module init function. To declare a read-only static key, we can use the
+<code> <span class='ectt-1000'>DEFINE_STATIC_KEY_FALSE_RO</span>
+</code> or <code>  <span class='ectt-1000'>DEFINE_STATIC_KEY_TRUE_RO</span>
+</code> macro instead. Attempts to change the key at runtime will result in a page fault. For
+more information, see <a href='https://www.kernel.org/doc/Documentation/static-keys.txt'>Static keys</a>
+</p><!-- l. 2101 --><p class='noindent'>
+</p>
+   <h3 class='sectionHead' id='common-pitfalls'><span class='titlemark'>20   </span> <a id='x1-6900020'></a>Common Pitfalls</h3>
+<!-- l. 2104 --><p class='noindent'>
+</p>
+   <h4 class='subsectionHead' id='using-standard-libraries'><span class='titlemark'>20.1   </span> <a id='x1-7000020.1'></a>Using standard libraries</h4>
+<!-- l. 2106 --><p class='noindent'>You can not do that. In a kernel module, you can only use kernel functions which are
 the functions you can see in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span>.
-</p><!-- l. 2055 --><p class='noindent'>
+</p><!-- l. 2109 --><p class='noindent'>
 </p>
-   <h4 class='subsectionHead' id='disabling-interrupts'><span class='titlemark'>20.2   </span> <a id='x1-7000020.2'></a>Disabling interrupts</h4>
-<!-- l. 2057 --><p class='noindent'>You might need to do this for a short time and that is OK, but if you do not enable
+   <h4 class='subsectionHead' id='disabling-interrupts'><span class='titlemark'>20.2   </span> <a id='x1-7100020.2'></a>Disabling interrupts</h4>
+<!-- l. 2111 --><p class='noindent'>You might need to do this for a short time and that is OK, but if you do not enable
 them afterwards, your system will be stuck and you will have to power it
 off.
-</p><!-- l. 2059 --><p class='noindent'>
+                                                                  
+
+                                                                  
+</p><!-- l. 2113 --><p class='noindent'>
 </p>
-   <h3 class='sectionHead' id='where-to-go-from-here'><span class='titlemark'>21   </span> <a id='x1-7100021'></a>Where To Go From Here?</h3>
-<!-- l. 2061 --><p class='noindent'>For people seriously interested in kernel programming, I recommend <a href='https://kernelnewbies.org'>kernelnewbies.org</a>
+   <h3 class='sectionHead' id='where-to-go-from-here'><span class='titlemark'>21   </span> <a id='x1-7200021'></a>Where To Go From Here?</h3>
+<!-- l. 2115 --><p class='noindent'>For people seriously interested in kernel programming, I recommend <a href='https://kernelnewbies.org'>kernelnewbies.org</a>
 and the <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation'>Documentation</a> subdirectory within the kernel source code which is not
 always easy to understand but can be a starting point for further investigation. Also,
 as Linus Torvalds said, the best way to learn the kernel is to read the source code
 yourself.
-</p><!-- l. 2064 --><p class='indent'>   If you would like to contribute to this guide or notice anything glaringly wrong,
+</p><!-- l. 2118 --><p class='indent'>   If you would like to contribute to this guide or notice anything glaringly wrong,
 please create an issue at <a class='url' href='https://github.com/sysprog21/lkmpg'><span class='ectt-1000'>https://github.com/sysprog21/lkmpg</span></a>. Your pull requests
 will be appreciated.
-</p><!-- l. 2067 --><p class='indent'>   Happy hacking!
+</p><!-- l. 2121 --><p class='indent'>   Happy hacking!
 </p>
    <div class='footnotes'><!-- l. 1803 --><p class='indent'>     <span class='footnote-mark'><a href='#fn1x0-bk' id='fn1x0'><sup class='textsuperscript'>1</sup></a></span><span class='ecrm-0800'>The goal of threaded interrupts is to push more of the work to separate threads, so that the
 </span><span class='ecrm-0800'>minimum needed for acknowledging an interrupt is reduced, and therefore the time spent handling

+ 217 - 0
lkmpg-for-ht.css

@@ -4172,5 +4172,222 @@ pre#fancyvrb98{ border-bottom: solid 0.4pt; }
 pre#fancyvrb98{ border-right: solid 0.4pt; }
 span#textcolor3470{color:rgb(0,0,255)}
 span#textcolor3471{color:rgb(0,0,255)}
+span#textcolor3472{color:rgb(0,0,255)}
+span#textcolor3473{color:rgb(0,0,255)}
+pre#fancyvrb99{padding:5.69054pt;}
+pre#fancyvrb99{ border-top: solid 0.4pt; }
+pre#fancyvrb99{ border-left: solid 0.4pt; }
+pre#fancyvrb99{ border-bottom: solid 0.4pt; }
+pre#fancyvrb99{ border-right: solid 0.4pt; }
+pre#fancyvrb100{padding:5.69054pt;}
+pre#fancyvrb100{ border-top: solid 0.4pt; }
+pre#fancyvrb100{ border-left: solid 0.4pt; }
+pre#fancyvrb100{ border-bottom: solid 0.4pt; }
+pre#fancyvrb100{ border-right: solid 0.4pt; }
+pre#fancyvrb101{padding:5.69054pt;}
+pre#fancyvrb101{ border-top: solid 0.4pt; }
+pre#fancyvrb101{ border-left: solid 0.4pt; }
+pre#fancyvrb101{ border-bottom: solid 0.4pt; }
+pre#fancyvrb101{ border-right: solid 0.4pt; }
+span#textcolor3474{color:rgb(163,20,20)}
+span#textcolor3475{color:rgb(163,20,20)}
+span#textcolor3476{color:rgb(163,20,20)}
+span#textcolor3477{color:rgb(0,0,255)}
+span#textcolor3478{color:rgb(163,20,20)}
+span#textcolor3479{color:rgb(163,20,20)}
+span#textcolor3480{color:rgb(163,20,20)}
+span#textcolor3481{color:rgb(163,20,20)}
+span#textcolor3482{color:rgb(163,20,20)}
+span#textcolor3483{color:rgb(163,20,20)}
+pre#fancyvrb102{padding:5.69054pt;}
+pre#fancyvrb102{ border-top: solid 0.4pt; }
+pre#fancyvrb102{ border-left: solid 0.4pt; }
+pre#fancyvrb102{ border-bottom: solid 0.4pt; }
+pre#fancyvrb102{ border-right: solid 0.4pt; }
+span#textcolor3484{color:rgb(0,127,0)}
+span#textcolor3485{color:rgb(0,127,0)}
+span#textcolor3486{color:rgb(0,127,0)}
+span#textcolor3487{color:rgb(0,0,255)}
+span#textcolor3488{color:rgb(0,127,0)}
+span#textcolor3489{color:rgb(0,0,255)}
+span#textcolor3490{color:rgb(0,127,0)}
+span#textcolor3491{color:rgb(0,0,255)}
+span#textcolor3492{color:rgb(0,127,0)}
+span#textcolor3493{color:rgb(0,0,255)}
+span#textcolor3494{color:rgb(0,127,0)}
+span#textcolor3495{color:rgb(0,0,255)}
+span#textcolor3496{color:rgb(0,127,0)}
+span#textcolor3497{color:rgb(0,0,255)}
+span#textcolor3498{color:rgb(0,127,0)}
+span#textcolor3499{color:rgb(0,0,255)}
+span#textcolor3500{color:rgb(0,127,0)}
+span#textcolor3501{color:rgb(0,0,255)}
+span#textcolor3502{color:rgb(0,127,0)}
+span#textcolor3503{color:rgb(0,0,255)}
+span#textcolor3504{color:rgb(0,127,0)}
+span#textcolor3505{color:rgb(0,0,255)}
+span#textcolor3506{color:rgb(43,145,175)}
+span#textcolor3507{color:rgb(0,0,255)}
+span#textcolor3508{color:rgb(0,0,255)}
+span#textcolor3509{color:rgb(0,0,255)}
+span#textcolor3510{color:rgb(43,145,175)}
+span#textcolor3511{color:rgb(0,0,255)}
+span#textcolor3512{color:rgb(0,0,255)}
+span#textcolor3513{color:rgb(0,0,255)}
+span#textcolor3514{color:rgb(43,145,175)}
+span#textcolor3515{color:rgb(0,0,255)}
+span#textcolor3516{color:rgb(43,145,175)}
+span#textcolor3517{color:rgb(43,145,175)}
+span#textcolor3518{color:rgb(0,0,255)}
+span#textcolor3519{color:rgb(43,145,175)}
+span#textcolor3520{color:rgb(0,0,255)}
+span#textcolor3521{color:rgb(0,0,255)}
+span#textcolor3522{color:rgb(43,145,175)}
+span#textcolor3523{color:rgb(43,145,175)}
+span#textcolor3524{color:rgb(0,0,255)}
+span#textcolor3525{color:rgb(0,0,255)}
+span#textcolor3526{color:rgb(0,0,255)}
+span#textcolor3527{color:rgb(0,0,255)}
+span#textcolor3528{color:rgb(43,145,175)}
+span#textcolor3529{color:rgb(0,0,255)}
+span#textcolor3530{color:rgb(0,0,255)}
+span#textcolor3531{color:rgb(0,0,255)}
+span#textcolor3532{color:rgb(43,145,175)}
+span#textcolor3533{color:rgb(0,0,255)}
+span#textcolor3534{color:rgb(0,0,255)}
+span#textcolor3535{color:rgb(0,0,255)}
+span#textcolor3536{color:rgb(0,0,255)}
+span#textcolor3537{color:rgb(0,0,255)}
+span#textcolor3538{color:rgb(0,0,255)}
+span#textcolor3539{color:rgb(43,145,175)}
+span#textcolor3540{color:rgb(43,145,175)}
+span#textcolor3541{color:rgb(0,0,255)}
+span#textcolor3542{color:rgb(163,20,20)}
+span#textcolor3543{color:rgb(163,20,20)}
+span#textcolor3544{color:rgb(163,20,20)}
+span#textcolor3545{color:rgb(0,0,255)}
+span#textcolor3546{color:rgb(163,20,20)}
+span#textcolor3547{color:rgb(163,20,20)}
+span#textcolor3548{color:rgb(163,20,20)}
+span#textcolor3549{color:rgb(163,20,20)}
+span#textcolor3550{color:rgb(163,20,20)}
+span#textcolor3551{color:rgb(163,20,20)}
+span#textcolor3552{color:rgb(0,0,255)}
+span#textcolor3553{color:rgb(0,0,255)}
+span#textcolor3554{color:rgb(43,145,175)}
+span#textcolor3555{color:rgb(43,145,175)}
+span#textcolor3556{color:rgb(0,127,0)}
+span#textcolor3557{color:rgb(0,127,0)}
+span#textcolor3558{color:rgb(0,127,0)}
+span#textcolor3559{color:rgb(0,127,0)}
+span#textcolor3560{color:rgb(0,127,0)}
+span#textcolor3561{color:rgb(0,127,0)}
+span#textcolor3562{color:rgb(0,0,255)}
+span#textcolor3563{color:rgb(43,145,175)}
+span#textcolor3564{color:rgb(0,0,255)}
+span#textcolor3565{color:rgb(0,0,255)}
+span#textcolor3566{color:rgb(0,0,255)}
+span#textcolor3567{color:rgb(0,0,255)}
+span#textcolor3568{color:rgb(163,20,20)}
+span#textcolor3569{color:rgb(163,20,20)}
+span#textcolor3570{color:rgb(163,20,20)}
+span#textcolor3571{color:rgb(163,20,20)}
+span#textcolor3572{color:rgb(163,20,20)}
+span#textcolor3573{color:rgb(163,20,20)}
+span#textcolor3574{color:rgb(163,20,20)}
+span#textcolor3575{color:rgb(163,20,20)}
+span#textcolor3576{color:rgb(163,20,20)}
+span#textcolor3577{color:rgb(0,0,255)}
+span#textcolor3578{color:rgb(163,20,20)}
+span#textcolor3579{color:rgb(163,20,20)}
+span#textcolor3580{color:rgb(163,20,20)}
+span#textcolor3581{color:rgb(163,20,20)}
+span#textcolor3582{color:rgb(163,20,20)}
+span#textcolor3583{color:rgb(163,20,20)}
+span#textcolor3584{color:rgb(0,0,255)}
+span#textcolor3585{color:rgb(0,127,0)}
+span#textcolor3586{color:rgb(0,127,0)}
+span#textcolor3587{color:rgb(0,127,0)}
+span#textcolor3588{color:rgb(0,0,255)}
+span#textcolor3589{color:rgb(43,145,175)}
+span#textcolor3590{color:rgb(0,0,255)}
+span#textcolor3591{color:rgb(0,0,255)}
+span#textcolor3592{color:rgb(0,127,0)}
+span#textcolor3593{color:rgb(0,127,0)}
+span#textcolor3594{color:rgb(0,127,0)}
+span#textcolor3595{color:rgb(0,127,0)}
+span#textcolor3596{color:rgb(0,127,0)}
+span#textcolor3597{color:rgb(0,0,255)}
+span#textcolor3598{color:rgb(0,127,0)}
+span#textcolor3599{color:rgb(0,127,0)}
+span#textcolor3600{color:rgb(0,127,0)}
+span#textcolor3601{color:rgb(0,127,0)}
+span#textcolor3602{color:rgb(0,0,255)}
+span#textcolor3603{color:rgb(43,145,175)}
+span#textcolor3604{color:rgb(0,0,255)}
+span#textcolor3605{color:rgb(0,127,0)}
+span#textcolor3606{color:rgb(43,145,175)}
+span#textcolor3607{color:rgb(0,127,0)}
+span#textcolor3608{color:rgb(43,145,175)}
+span#textcolor3609{color:rgb(0,127,0)}
+span#textcolor3610{color:rgb(0,127,0)}
+span#textcolor3611{color:rgb(43,145,175)}
+span#textcolor3612{color:rgb(0,0,255)}
+span#textcolor3613{color:rgb(43,145,175)}
+span#textcolor3614{color:rgb(0,0,255)}
+span#textcolor3615{color:rgb(0,127,0)}
+span#textcolor3616{color:rgb(0,127,0)}
+span#textcolor3617{color:rgb(0,0,255)}
+span#textcolor3618{color:rgb(0,127,0)}
+span#textcolor3619{color:rgb(0,127,0)}
+span#textcolor3620{color:rgb(0,0,255)}
+span#textcolor3621{color:rgb(0,127,0)}
+span#textcolor3622{color:rgb(0,127,0)}
+span#textcolor3623{color:rgb(0,127,0)}
+span#textcolor3624{color:rgb(0,127,0)}
+span#textcolor3625{color:rgb(0,127,0)}
+span#textcolor3626{color:rgb(0,127,0)}
+span#textcolor3627{color:rgb(0,127,0)}
+span#textcolor3628{color:rgb(0,0,255)}
+span#textcolor3629{color:rgb(0,127,0)}
+span#textcolor3630{color:rgb(0,0,255)}
+span#textcolor3631{color:rgb(43,145,175)}
+span#textcolor3632{color:rgb(0,0,255)}
+span#textcolor3633{color:rgb(0,0,255)}
+span#textcolor3634{color:rgb(43,145,175)}
+span#textcolor3635{color:rgb(43,145,175)}
+span#textcolor3636{color:rgb(43,145,175)}
+span#textcolor3637{color:rgb(0,0,255)}
+span#textcolor3638{color:rgb(163,20,20)}
+span#textcolor3639{color:rgb(163,20,20)}
+span#textcolor3640{color:rgb(163,20,20)}
+span#textcolor3641{color:rgb(0,0,255)}
+span#textcolor3642{color:rgb(0,0,255)}
+span#textcolor3643{color:rgb(0,0,255)}
+span#textcolor3644{color:rgb(0,0,255)}
+span#textcolor3645{color:rgb(163,20,20)}
+span#textcolor3646{color:rgb(163,20,20)}
+span#textcolor3647{color:rgb(0,0,255)}
+span#textcolor3648{color:rgb(0,0,255)}
+span#textcolor3649{color:rgb(163,20,20)}
+span#textcolor3650{color:rgb(163,20,20)}
+span#textcolor3651{color:rgb(0,0,255)}
+span#textcolor3652{color:rgb(163,20,20)}
+span#textcolor3653{color:rgb(163,20,20)}
+span#textcolor3654{color:rgb(163,20,20)}
+span#textcolor3655{color:rgb(0,0,255)}
+span#textcolor3656{color:rgb(0,127,0)}
+span#textcolor3657{color:rgb(0,0,255)}
+span#textcolor3658{color:rgb(163,20,20)}
+pre#fancyvrb103{padding:5.69054pt;}
+pre#fancyvrb103{ border-top: solid 0.4pt; }
+pre#fancyvrb103{ border-left: solid 0.4pt; }
+pre#fancyvrb103{ border-bottom: solid 0.4pt; }
+pre#fancyvrb103{ border-right: solid 0.4pt; }
+pre#fancyvrb104{padding:5.69054pt;}
+pre#fancyvrb104{ border-top: solid 0.4pt; }
+pre#fancyvrb104{ border-left: solid 0.4pt; }
+pre#fancyvrb104{ border-bottom: solid 0.4pt; }
+pre#fancyvrb104{ border-right: solid 0.4pt; }
 /* end css.sty */
 

+ 280 - 20
lkmpg-for-ht.html

@@ -18,7 +18,7 @@
 
 <h2 class='titleHead'>The Linux Kernel Module Programming Guide</h2>
 <div class='author'><span class='ecrm-1200'>Peter Jay Salzman, Michael Burian, Ori Pomerantz, Bob Mottram, Jim Huang</span></div><br />
-<div class='date'><span class='ecrm-1200'>May 1, 2023</span></div>
+<div class='date'><span class='ecrm-1200'>May 2, 2023</span></div>
                                                                   
 
                                                                   
@@ -92,10 +92,11 @@
 <br />    <span class='sectionToc'>18 <a href='#standardizing-the-interfaces-the-device-model' id='QQ2-1-64'>Standardizing the interfaces: The Device Model</a></span>
 <br />    <span class='sectionToc'>19 <a href='#optimizations' id='QQ2-1-65'>Optimizations</a></span>
 <br />     <span class='subsectionToc'>19.1 <a href='#likely-and-unlikely-conditions' id='QQ2-1-66'>Likely and Unlikely conditions</a></span>
-<br />    <span class='sectionToc'>20 <a href='#common-pitfalls' id='QQ2-1-67'>Common Pitfalls</a></span>
-<br />     <span class='subsectionToc'>20.1 <a href='#using-standard-libraries' id='QQ2-1-68'>Using standard libraries</a></span>
-<br />     <span class='subsectionToc'>20.2 <a href='#disabling-interrupts' id='QQ2-1-69'>Disabling interrupts</a></span>
-<br />    <span class='sectionToc'>21 <a href='#where-to-go-from-here' id='QQ2-1-70'>Where To Go From Here?</a></span>
+<br />     <span class='subsectionToc'>19.2 <a href='#static-keys' id='QQ2-1-67'>Static keys</a></span>
+<br />    <span class='sectionToc'>20 <a href='#common-pitfalls' id='QQ2-1-68'>Common Pitfalls</a></span>
+<br />     <span class='subsectionToc'>20.1 <a href='#using-standard-libraries' id='QQ2-1-69'>Using standard libraries</a></span>
+<br />     <span class='subsectionToc'>20.2 <a href='#disabling-interrupts' id='QQ2-1-70'>Disabling interrupts</a></span>
+<br />    <span class='sectionToc'>21 <a href='#where-to-go-from-here' id='QQ2-1-71'>Where To Go From Here?</a></span>
    </div>
    <h3 class='sectionHead' id='introduction'><span class='titlemark'>1   </span> <a id='x1-10001'></a>Introduction</h3>
 <!-- l. 65 --><p class='noindent'>The Linux Kernel Module Programming Guide is a free book; you may reproduce
@@ -110,12 +111,12 @@ the provisions of the <a href='https://opensource.org/licenses/OSL-3.0'>Open Sof
 distribute this book free of charge or for a profit. No explicit permission is required
 from the author for reproduction of this book in any medium, physical or
 electronic.
-</p><!-- l. 72 --><p class='indent'>   Derivative works and translations of this document must be placed under the
-Open Software License, and the original copyright notice must remain intact. If you
-have contributed new material to this book, you must make the material and source
                                                                   
 
                                                                   
+</p><!-- l. 72 --><p class='indent'>   Derivative works and translations of this document must be placed under the
+Open Software License, and the original copyright notice must remain intact. If you
+have contributed new material to this book, you must make the material and source
 code available for your revisions. Please make revisions and updates available directly
 to the document maintainer, Jim Huang &lt;jserv@ccns.ncku.edu.tw&gt;. This will allow
 for the merging of updates and provide consistent revisions to the Linux
@@ -6498,30 +6499,289 @@ avoids flushing the processor pipeline. The opposite happens if you use the
                                                                   
 </p><!-- l. 2047 --><p class='noindent'>
 </p>
-   <h3 class='sectionHead' id='common-pitfalls'><span class='titlemark'>20   </span> <a id='x1-6800020'></a>Common Pitfalls</h3>
-<!-- l. 2050 --><p class='noindent'>
+   <h4 class='subsectionHead' id='static-keys'><span class='titlemark'>19.2   </span> <a id='x1-6800019.2'></a>Static keys</h4>
+<!-- l. 2049 --><p class='noindent'>Static keys allow us to enable or disable kernel code paths based on the runtime state
+of key. Its APIs have been available since 2010 (most architectures are already
+supported), use self-modifying code to eliminate the overhead of cache and branch
+prediction. The most typical use case of static keys is for performance-sensitive kernel
+code, such as tracepoints, context switching, networking, etc. These hot paths of the
+kernel often contain branches and can be optimized easily using this technique.
+Before we can use static keys in the kernel, we need to make sure that gcc supports
+<code> <span id='textcolor3472'><span class='ectt-1000'>asm</span></span><span class='ectt-1000'> </span><span id='textcolor3473'><span class='ectt-1000'>goto</span></span>
+</code> inline assembly, and the following kernel configurations are set:
+</p><!-- l. 1 --><p class='indent'>
+</p>
+   <pre class='fancyvrb' id='fancyvrb99'><a id='x1-68006r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>CONFIG_JUMP_LABEL=y</span> 
+<a id='x1-68008r2'></a><span class='ecrm-0500'>2</span><span class='ectt-0800'>CONFIG_HAVE_ARCH_JUMP_LABEL=y</span> 
+<a id='x1-68010r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'>CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y</span></pre>
+<!-- l. 2059 --><p class='indent'>   To declare a static key, we need to define a global variable using the
+<code> <span class='ectt-1000'>DEFINE_STATIC_KEY_FALSE</span>
+</code> or <code>  <span class='ectt-1000'>DEFINE_STATIC_KEY_TRUE</span>
+</code> macro defined in <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/include/linux/jump_label.h'>include/linux/jump_label.h</a>. This macro initializes the key with
+the given initial value, which is either false or true, respectively. For example, to
+declare a static key with an initial value of false, we can use the following
+code:
+</p><!-- l. 1 --><p class='indent'>
+</p>
+   <pre class='fancyvrb' id='fancyvrb100'><a id='x1-68015r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>DEFINE_STATIC_KEY_FALSE(fkey);</span></pre>
+<!-- l. 2066 --><p class='indent'>   Once the static key has been declared, we need to add branching code to the
+module that uses the static key. For example, the code includes a fastpath, where a
+no-op instruction will be generated at compile time as the key is initialized to false
+and the branch is unlikely to be taken.
+</p><!-- l. 1 --><p class='indent'>
+</p>
+   <pre class='fancyvrb' id='fancyvrb101'><a id='x1-68021r1'></a><span class='ecrm-0500'>1</span><span class='ectt-0800'>pr_info(</span><span id='textcolor3474'><span class='ectt-0800'>"fastpath 1</span></span><span id='textcolor3475'><span class='ectt-0800'>\n</span></span><span id='textcolor3476'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68023r2'></a><span class='ecrm-0500'>2</span><span id='textcolor3477'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (static_branch_unlikely(&amp;fkey))</span> 
+<a id='x1-68025r3'></a><span class='ecrm-0500'>3</span><span class='ectt-0800'>    pr_alert(</span><span id='textcolor3478'><span class='ectt-0800'>"do unlikely thing</span></span><span id='textcolor3479'><span class='ectt-0800'>\n</span></span><span id='textcolor3480'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68027r4'></a><span class='ecrm-0500'>4</span><span class='ectt-0800'>pr_info(</span><span id='textcolor3481'><span class='ectt-0800'>"fastpath 2</span></span><span id='textcolor3482'><span class='ectt-0800'>\n</span></span><span id='textcolor3483'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span></pre>
+<!-- l. 2076 --><p class='indent'>   If the key is enabled at runtime by calling
+<code> <span class='ectt-1000'>static_branch_enable(&amp;fkey)</span>
+</code>, the fastpath will be patched with an unconditional jump instruction to the slowpath
+code <code>  <span class='ectt-1000'>pr_alert</span>
+</code>, so the branch will always be taken until the key is disabled again.
+</p><!-- l. 2078 --><p class='indent'>   The following kernel module derived from <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>chardev.c</span></span></span>, demostrates how the static
+key works.
+</p><!-- l. 1 --><p class='indent'>
+</p>
+   <pre class='fancyvrb' id='fancyvrb102'><a id='x1-68031r1'></a><span class='ecrm-0500'>1</span><span id='textcolor3484'><span class='ectt-0800'>/*</span></span> 
+<a id='x1-68033r2'></a><span class='ecrm-0500'>2</span><span id='textcolor3485'><span class='ectt-0800'> * static_key.c</span></span> 
+<a id='x1-68035r3'></a><span class='ecrm-0500'>3</span><span id='textcolor3486'><span class='ectt-0800'> */</span></span> 
+<a id='x1-68037r4'></a><span class='ecrm-0500'>4</span> 
+<a id='x1-68039r5'></a><span class='ecrm-0500'>5</span><span id='textcolor3487'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3488'><span class='ectt-0800'>&lt;linux/atomic.h&gt;</span></span> 
+<a id='x1-68041r6'></a><span class='ecrm-0500'>6</span><span id='textcolor3489'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3490'><span class='ectt-0800'>&lt;linux/device.h&gt;</span></span> 
+<a id='x1-68043r7'></a><span class='ecrm-0500'>7</span><span id='textcolor3491'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3492'><span class='ectt-0800'>&lt;linux/fs.h&gt;</span></span> 
+<a id='x1-68045r8'></a><span class='ecrm-0500'>8</span><span id='textcolor3493'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3494'><span class='ectt-0800'>&lt;linux/kernel.h&gt; /* for sprintf() */</span></span> 
+<a id='x1-68047r9'></a><span class='ecrm-0500'>9</span><span id='textcolor3495'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3496'><span class='ectt-0800'>&lt;linux/module.h&gt;</span></span> 
+<a id='x1-68049r10'></a><span class='ecrm-0500'>10</span><span id='textcolor3497'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3498'><span class='ectt-0800'>&lt;linux/printk.h&gt;</span></span> 
+<a id='x1-68051r11'></a><span class='ecrm-0500'>11</span><span id='textcolor3499'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3500'><span class='ectt-0800'>&lt;linux/types.h&gt;</span></span> 
+<a id='x1-68053r12'></a><span class='ecrm-0500'>12</span><span id='textcolor3501'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3502'><span class='ectt-0800'>&lt;linux/uaccess.h&gt; /* for get_user and put_user */</span></span> 
+<a id='x1-68055r13'></a><span class='ecrm-0500'>13</span> 
+<a id='x1-68057r14'></a><span class='ecrm-0500'>14</span><span id='textcolor3503'><span class='ectt-0800'>#include</span></span><span class='ectt-0800'> </span><span id='textcolor3504'><span class='ectt-0800'>&lt;asm/errno.h&gt;</span></span> 
+<a id='x1-68059r15'></a><span class='ecrm-0500'>15</span> 
+<a id='x1-68061r16'></a><span class='ecrm-0500'>16</span><span id='textcolor3505'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3506'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor3507'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3508'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file);</span> 
+<a id='x1-68063r17'></a><span class='ecrm-0500'>17</span><span id='textcolor3509'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3510'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor3511'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3512'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file);</span> 
+<a id='x1-68065r18'></a><span class='ecrm-0500'>18</span><span id='textcolor3513'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3514'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor3515'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor3516'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf, </span><span id='textcolor3517'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count,</span> 
+<a id='x1-68067r19'></a><span class='ecrm-0500'>19</span><span class='ectt-0800'>                           loff_t *ppos);</span> 
+<a id='x1-68069r20'></a><span class='ecrm-0500'>20</span><span id='textcolor3518'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3519'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor3520'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file, </span><span id='textcolor3521'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3522'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buf,</span> 
+<a id='x1-68071r21'></a><span class='ecrm-0500'>21</span><span class='ectt-0800'>                            </span><span id='textcolor3523'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> count, loff_t *ppos);</span> 
+<a id='x1-68073r22'></a><span class='ecrm-0500'>22</span> 
+<a id='x1-68075r23'></a><span class='ecrm-0500'>23</span><span id='textcolor3524'><span class='ectt-0800'>#define SUCCESS 0</span></span> 
+<a id='x1-68077r24'></a><span class='ecrm-0500'>24</span><span id='textcolor3525'><span class='ectt-0800'>#define DEVICE_NAME "key_state"</span></span> 
+<a id='x1-68079r25'></a><span class='ecrm-0500'>25</span><span id='textcolor3526'><span class='ectt-0800'>#define BUF_LEN 10</span></span> 
+<a id='x1-68081r26'></a><span class='ecrm-0500'>26</span> 
+<a id='x1-68083r27'></a><span class='ecrm-0500'>27</span><span id='textcolor3527'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3528'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> major;</span> 
+<a id='x1-68085r28'></a><span class='ecrm-0500'>28</span> 
+<a id='x1-68087r29'></a><span class='ecrm-0500'>29</span><span id='textcolor3529'><span class='ectt-0800'>enum</span></span><span class='ectt-0800'> {</span> 
+<a id='x1-68089r30'></a><span class='ecrm-0500'>30</span><span class='ectt-0800'>    CDEV_NOT_USED = 0,</span> 
+<a id='x1-68091r31'></a><span class='ecrm-0500'>31</span><span class='ectt-0800'>    CDEV_EXCLUSIVE_OPEN = 1,</span> 
+<a id='x1-68093r32'></a><span class='ecrm-0500'>32</span><span class='ectt-0800'>};</span> 
+<a id='x1-68095r33'></a><span class='ecrm-0500'>33</span> 
+<a id='x1-68097r34'></a><span class='ecrm-0500'>34</span><span id='textcolor3530'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);</span> 
+<a id='x1-68099r35'></a><span class='ecrm-0500'>35</span> 
+<a id='x1-68101r36'></a><span class='ecrm-0500'>36</span><span id='textcolor3531'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3532'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> msg[BUF_LEN + 1];</span> 
+<a id='x1-68103r37'></a><span class='ecrm-0500'>37</span> 
+<a id='x1-68105r38'></a><span class='ecrm-0500'>38</span><span id='textcolor3533'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3534'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> class *cls;</span> 
+<a id='x1-68107r39'></a><span class='ecrm-0500'>39</span> 
+<a id='x1-68109r40'></a><span class='ecrm-0500'>40</span><span id='textcolor3535'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> DEFINE_STATIC_KEY_FALSE(fkey);</span> 
+<a id='x1-68111r41'></a><span class='ecrm-0500'>41</span> 
+<a id='x1-68113r42'></a><span class='ecrm-0500'>42</span><span id='textcolor3536'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3537'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file_operations chardev_fops = {</span> 
+<a id='x1-68115r43'></a><span class='ecrm-0500'>43</span><span class='ectt-0800'>    .owner = THIS_MODULE,</span> 
+<a id='x1-68117r44'></a><span class='ecrm-0500'>44</span><span class='ectt-0800'>    .open = device_open,</span> 
+<a id='x1-68119r45'></a><span class='ecrm-0500'>45</span><span class='ectt-0800'>    .release = device_release,</span> 
+<a id='x1-68121r46'></a><span class='ecrm-0500'>46</span><span class='ectt-0800'>    .read = device_read,</span> 
+<a id='x1-68123r47'></a><span class='ecrm-0500'>47</span><span class='ectt-0800'>    .write = device_write,</span> 
+<a id='x1-68125r48'></a><span class='ecrm-0500'>48</span><span class='ectt-0800'>};</span> 
+<a id='x1-68127r49'></a><span class='ecrm-0500'>49</span> 
+<a id='x1-68129r50'></a><span class='ecrm-0500'>50</span><span id='textcolor3538'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3539'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> __init chardev_init(</span><span id='textcolor3540'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span> 
+<a id='x1-68131r51'></a><span class='ecrm-0500'>51</span><span class='ectt-0800'>{</span> 
+<a id='x1-68133r52'></a><span class='ecrm-0500'>52</span><span class='ectt-0800'>    major = register_chrdev(0, DEVICE_NAME, &amp;chardev_fops);</span> 
+<a id='x1-68135r53'></a><span class='ecrm-0500'>53</span><span class='ectt-0800'>    </span><span id='textcolor3541'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (major &lt; 0) {</span> 
+<a id='x1-68137r54'></a><span class='ecrm-0500'>54</span><span class='ectt-0800'>        pr_alert(</span><span id='textcolor3542'><span class='ectt-0800'>"Registering char device failed with %d</span></span><span id='textcolor3543'><span class='ectt-0800'>\n</span></span><span id='textcolor3544'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, major);</span> 
+<a id='x1-68139r55'></a><span class='ecrm-0500'>55</span><span class='ectt-0800'>        </span><span id='textcolor3545'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> major;</span> 
+<a id='x1-68141r56'></a><span class='ecrm-0500'>56</span><span class='ectt-0800'>    }</span> 
+<a id='x1-68143r57'></a><span class='ecrm-0500'>57</span> 
+<a id='x1-68145r58'></a><span class='ecrm-0500'>58</span><span class='ectt-0800'>    pr_info(</span><span id='textcolor3546'><span class='ectt-0800'>"I was assigned major number %d</span></span><span id='textcolor3547'><span class='ectt-0800'>\n</span></span><span id='textcolor3548'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, major);</span> 
+<a id='x1-68147r59'></a><span class='ecrm-0500'>59</span> 
+<a id='x1-68149r60'></a><span class='ecrm-0500'>60</span><span class='ectt-0800'>    cls = class_create(THIS_MODULE, DEVICE_NAME);</span> 
+<a id='x1-68151r61'></a><span class='ecrm-0500'>61</span> 
+<a id='x1-68153r62'></a><span class='ecrm-0500'>62</span><span class='ectt-0800'>    device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);</span> 
+<a id='x1-68155r63'></a><span class='ecrm-0500'>63</span> 
+<a id='x1-68157r64'></a><span class='ecrm-0500'>64</span><span class='ectt-0800'>    pr_info(</span><span id='textcolor3549'><span class='ectt-0800'>"Device created on /dev/%s</span></span><span id='textcolor3550'><span class='ectt-0800'>\n</span></span><span id='textcolor3551'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, DEVICE_NAME);</span> 
+<a id='x1-68159r65'></a><span class='ecrm-0500'>65</span> 
+<a id='x1-68161r66'></a><span class='ecrm-0500'>66</span><span class='ectt-0800'>    </span><span id='textcolor3552'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span> 
+<a id='x1-68163r67'></a><span class='ecrm-0500'>67</span><span class='ectt-0800'>}</span> 
+<a id='x1-68165r68'></a><span class='ecrm-0500'>68</span> 
+<a id='x1-68167r69'></a><span class='ecrm-0500'>69</span><span id='textcolor3553'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3554'><span class='ectt-0800'>void</span></span><span class='ectt-0800'> __exit chardev_exit(</span><span id='textcolor3555'><span class='ectt-0800'>void</span></span><span class='ectt-0800'>)</span> 
+<a id='x1-68169r70'></a><span class='ecrm-0500'>70</span><span class='ectt-0800'>{</span> 
+<a id='x1-68171r71'></a><span class='ecrm-0500'>71</span><span class='ectt-0800'>    device_destroy(cls, MKDEV(major, 0));</span> 
+<a id='x1-68173r72'></a><span class='ecrm-0500'>72</span><span class='ectt-0800'>    class_destroy(cls);</span> 
+<a id='x1-68175r73'></a><span class='ecrm-0500'>73</span> 
+<a id='x1-68177r74'></a><span class='ecrm-0500'>74</span><span class='ectt-0800'>    </span><span id='textcolor3556'><span class='ectt-0800'>/* Unregister the device */</span></span> 
+<a id='x1-68179r75'></a><span class='ecrm-0500'>75</span><span class='ectt-0800'>    unregister_chrdev(major, DEVICE_NAME);</span> 
+<a id='x1-68181r76'></a><span class='ecrm-0500'>76</span><span class='ectt-0800'>}</span> 
+<a id='x1-68183r77'></a><span class='ecrm-0500'>77</span> 
+<a id='x1-68185r78'></a><span class='ecrm-0500'>78</span><span id='textcolor3557'><span class='ectt-0800'>/* Methods */</span></span> 
+<a id='x1-68187r79'></a><span class='ecrm-0500'>79</span> 
+<a id='x1-68189r80'></a><span class='ecrm-0500'>80</span><span id='textcolor3558'><span class='ectt-0800'>/**</span></span> 
+<a id='x1-68191r81'></a><span class='ecrm-0500'>81</span><span id='textcolor3559'><span class='ectt-0800'> * Called when a process tried to open the device file, like</span></span> 
+<a id='x1-68193r82'></a><span class='ecrm-0500'>82</span><span id='textcolor3560'><span class='ectt-0800'> * cat /dev/key_state</span></span> 
+<a id='x1-68195r83'></a><span class='ecrm-0500'>83</span><span id='textcolor3561'><span class='ectt-0800'> */</span></span> 
+<a id='x1-68197r84'></a><span class='ecrm-0500'>84</span><span id='textcolor3562'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3563'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_open(</span><span id='textcolor3564'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3565'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span> 
+<a id='x1-68199r85'></a><span class='ecrm-0500'>85</span><span class='ectt-0800'>{</span> 
+<a id='x1-68201r86'></a><span class='ecrm-0500'>86</span><span class='ectt-0800'>    </span><span id='textcolor3566'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (atomic_cmpxchg(&amp;already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN))</span> 
+<a id='x1-68203r87'></a><span class='ecrm-0500'>87</span><span class='ectt-0800'>        </span><span id='textcolor3567'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EBUSY;</span> 
+<a id='x1-68205r88'></a><span class='ecrm-0500'>88</span> 
+<a id='x1-68207r89'></a><span class='ecrm-0500'>89</span><span class='ectt-0800'>    sprintf(msg, static_key_enabled(&amp;fkey) ? </span><span id='textcolor3568'><span class='ectt-0800'>"enabled</span></span><span id='textcolor3569'><span class='ectt-0800'>\n</span></span><span id='textcolor3570'><span class='ectt-0800'>"</span></span><span class='ectt-0800'> : </span><span id='textcolor3571'><span class='ectt-0800'>"disabled</span></span><span id='textcolor3572'><span class='ectt-0800'>\n</span></span><span id='textcolor3573'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68209r90'></a><span class='ecrm-0500'>90</span> 
+<a id='x1-68211r91'></a><span class='ecrm-0500'>91</span><span class='ectt-0800'>    pr_info(</span><span id='textcolor3574'><span class='ectt-0800'>"fastpath 1</span></span><span id='textcolor3575'><span class='ectt-0800'>\n</span></span><span id='textcolor3576'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68213r92'></a><span class='ecrm-0500'>92</span><span class='ectt-0800'>    </span><span id='textcolor3577'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (static_branch_unlikely(&amp;fkey))</span> 
+<a id='x1-68215r93'></a><span class='ecrm-0500'>93</span><span class='ectt-0800'>        pr_alert(</span><span id='textcolor3578'><span class='ectt-0800'>"do unlikely thing</span></span><span id='textcolor3579'><span class='ectt-0800'>\n</span></span><span id='textcolor3580'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68217r94'></a><span class='ecrm-0500'>94</span><span class='ectt-0800'>    pr_info(</span><span id='textcolor3581'><span class='ectt-0800'>"fastpath 2</span></span><span id='textcolor3582'><span class='ectt-0800'>\n</span></span><span id='textcolor3583'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68219r95'></a><span class='ecrm-0500'>95</span> 
+<a id='x1-68221r96'></a><span class='ecrm-0500'>96</span><span class='ectt-0800'>    try_module_get(THIS_MODULE);</span> 
+<a id='x1-68223r97'></a><span class='ecrm-0500'>97</span> 
+<a id='x1-68225r98'></a><span class='ecrm-0500'>98</span><span class='ectt-0800'>    </span><span id='textcolor3584'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span> 
+<a id='x1-68227r99'></a><span class='ecrm-0500'>99</span><span class='ectt-0800'>}</span> 
+<a id='x1-68229r100'></a><span class='ecrm-0500'>100</span> 
+<a id='x1-68231r101'></a><span class='ecrm-0500'>101</span><span id='textcolor3585'><span class='ectt-0800'>/**</span></span> 
+<a id='x1-68233r102'></a><span class='ecrm-0500'>102</span><span id='textcolor3586'><span class='ectt-0800'> * Called when a process closes the device file</span></span> 
+<a id='x1-68235r103'></a><span class='ecrm-0500'>103</span><span id='textcolor3587'><span class='ectt-0800'> */</span></span> 
+<a id='x1-68237r104'></a><span class='ecrm-0500'>104</span><span id='textcolor3588'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3589'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> device_release(</span><span id='textcolor3590'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> inode *inode, </span><span id='textcolor3591'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *file)</span> 
+<a id='x1-68239r105'></a><span class='ecrm-0500'>105</span><span class='ectt-0800'>{</span> 
+<a id='x1-68241r106'></a><span class='ecrm-0500'>106</span><span class='ectt-0800'>    </span><span id='textcolor3592'><span class='ectt-0800'>/* We are now ready for our next caller. */</span></span> 
+<a id='x1-68243r107'></a><span class='ecrm-0500'>107</span><span class='ectt-0800'>    atomic_set(&amp;already_open, CDEV_NOT_USED);</span> 
+<a id='x1-68245r108'></a><span class='ecrm-0500'>108</span> 
+<a id='x1-68247r109'></a><span class='ecrm-0500'>109</span><span class='ectt-0800'>    </span><span id='textcolor3593'><span class='ectt-0800'>/**</span></span> 
+<a id='x1-68249r110'></a><span class='ecrm-0500'>110</span><span id='textcolor3594'><span class='ectt-0800'>     * Decrement the usage count, or else once you opened the file, you will</span></span> 
+<a id='x1-68251r111'></a><span class='ecrm-0500'>111</span><span id='textcolor3595'><span class='ectt-0800'>     * never get rid of the module.</span></span> 
+<a id='x1-68253r112'></a><span class='ecrm-0500'>112</span><span id='textcolor3596'><span class='ectt-0800'>     */</span></span> 
+<a id='x1-68255r113'></a><span class='ecrm-0500'>113</span><span class='ectt-0800'>    module_put(THIS_MODULE);</span> 
+<a id='x1-68257r114'></a><span class='ecrm-0500'>114</span> 
+<a id='x1-68259r115'></a><span class='ecrm-0500'>115</span><span class='ectt-0800'>    </span><span id='textcolor3597'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> SUCCESS;</span> 
+<a id='x1-68261r116'></a><span class='ecrm-0500'>116</span><span class='ectt-0800'>}</span> 
+<a id='x1-68263r117'></a><span class='ecrm-0500'>117</span> 
+<a id='x1-68265r118'></a><span class='ecrm-0500'>118</span><span id='textcolor3598'><span class='ectt-0800'>/**</span></span> 
+<a id='x1-68267r119'></a><span class='ecrm-0500'>119</span><span id='textcolor3599'><span class='ectt-0800'> * Called when a process, which already opened the dev file, attempts to</span></span> 
+<a id='x1-68269r120'></a><span class='ecrm-0500'>120</span><span id='textcolor3600'><span class='ectt-0800'> * read from it.</span></span> 
+<a id='x1-68271r121'></a><span class='ecrm-0500'>121</span><span id='textcolor3601'><span class='ectt-0800'> */</span></span> 
+<a id='x1-68273r122'></a><span class='ecrm-0500'>122</span><span id='textcolor3602'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3603'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_read(</span><span id='textcolor3604'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor3605'><span class='ectt-0800'>/* see include/linux/fs.h */</span></span> 
+<a id='x1-68275r123'></a><span class='ecrm-0500'>123</span><span class='ectt-0800'>                           </span><span id='textcolor3606'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer, </span><span id='textcolor3607'><span class='ectt-0800'>/* buffer to fill with data */</span></span> 
+<a id='x1-68277r124'></a><span class='ecrm-0500'>124</span><span class='ectt-0800'>                           </span><span id='textcolor3608'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, </span><span id='textcolor3609'><span class='ectt-0800'>/* length of the buffer */</span></span> 
+<a id='x1-68279r125'></a><span class='ecrm-0500'>125</span><span class='ectt-0800'>                           loff_t *offset)</span> 
+<a id='x1-68281r126'></a><span class='ecrm-0500'>126</span><span class='ectt-0800'>{</span> 
+<a id='x1-68283r127'></a><span class='ecrm-0500'>127</span><span class='ectt-0800'>    </span><span id='textcolor3610'><span class='ectt-0800'>/* Number of the bytes actually written to the buffer */</span></span> 
+<a id='x1-68285r128'></a><span class='ecrm-0500'>128</span><span class='ectt-0800'>    </span><span id='textcolor3611'><span class='ectt-0800'>int</span></span><span class='ectt-0800'> bytes_read = 0;</span> 
+<a id='x1-68287r129'></a><span class='ecrm-0500'>129</span><span class='ectt-0800'>    </span><span id='textcolor3612'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3613'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> *msg_ptr = msg;</span> 
+<a id='x1-68289r130'></a><span class='ecrm-0500'>130</span> 
+<a id='x1-68291r131'></a><span class='ecrm-0500'>131</span><span class='ectt-0800'>    </span><span id='textcolor3614'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (!*(msg_ptr + *offset)) { </span><span id='textcolor3615'><span class='ectt-0800'>/* We are at the end of the message */</span></span> 
+<a id='x1-68293r132'></a><span class='ecrm-0500'>132</span><span class='ectt-0800'>        *offset = 0; </span><span id='textcolor3616'><span class='ectt-0800'>/* reset the offset */</span></span> 
+<a id='x1-68295r133'></a><span class='ecrm-0500'>133</span><span class='ectt-0800'>        </span><span id='textcolor3617'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> 0; </span><span id='textcolor3618'><span class='ectt-0800'>/* signify end of file */</span></span> 
+<a id='x1-68297r134'></a><span class='ecrm-0500'>134</span><span class='ectt-0800'>    }</span> 
+<a id='x1-68299r135'></a><span class='ecrm-0500'>135</span> 
+<a id='x1-68301r136'></a><span class='ecrm-0500'>136</span><span class='ectt-0800'>    msg_ptr += *offset;</span> 
+<a id='x1-68303r137'></a><span class='ecrm-0500'>137</span> 
+<a id='x1-68305r138'></a><span class='ecrm-0500'>138</span><span class='ectt-0800'>    </span><span id='textcolor3619'><span class='ectt-0800'>/* Actually put the date into the buffer */</span></span> 
+<a id='x1-68307r139'></a><span class='ecrm-0500'>139</span><span class='ectt-0800'>    </span><span id='textcolor3620'><span class='ectt-0800'>while</span></span><span class='ectt-0800'> (length &amp;&amp; *msg_ptr) {</span> 
+<a id='x1-68309r140'></a><span class='ecrm-0500'>140</span><span class='ectt-0800'>        </span><span id='textcolor3621'><span class='ectt-0800'>/**</span></span> 
+<a id='x1-68311r141'></a><span class='ecrm-0500'>141</span><span id='textcolor3622'><span class='ectt-0800'>         * The buffer is in the user data segment, not the kernel</span></span> 
+<a id='x1-68313r142'></a><span class='ecrm-0500'>142</span><span id='textcolor3623'><span class='ectt-0800'>         * segment so "*" assignment won</span><span class='tctt-0800'>'</span><span class='ectt-0800'>t work. We have to use</span></span> 
+<a id='x1-68315r143'></a><span class='ecrm-0500'>143</span><span id='textcolor3624'><span class='ectt-0800'>         * put_user which copies data from the kernel data segment to</span></span> 
+<a id='x1-68317r144'></a><span class='ecrm-0500'>144</span><span id='textcolor3625'><span class='ectt-0800'>         * the user data segment.</span></span> 
+<a id='x1-68319r145'></a><span class='ecrm-0500'>145</span><span id='textcolor3626'><span class='ectt-0800'>         */</span></span> 
+<a id='x1-68321r146'></a><span class='ecrm-0500'>146</span><span class='ectt-0800'>        put_user(*(msg_ptr++), buffer++);</span> 
+<a id='x1-68323r147'></a><span class='ecrm-0500'>147</span><span class='ectt-0800'>        length--;</span> 
+<a id='x1-68325r148'></a><span class='ecrm-0500'>148</span><span class='ectt-0800'>        bytes_read++;</span> 
+<a id='x1-68327r149'></a><span class='ecrm-0500'>149</span><span class='ectt-0800'>    }</span> 
+<a id='x1-68329r150'></a><span class='ecrm-0500'>150</span> 
+<a id='x1-68331r151'></a><span class='ecrm-0500'>151</span><span class='ectt-0800'>    *offset += bytes_read;</span> 
+<a id='x1-68333r152'></a><span class='ecrm-0500'>152</span> 
+<a id='x1-68335r153'></a><span class='ecrm-0500'>153</span><span class='ectt-0800'>    </span><span id='textcolor3627'><span class='ectt-0800'>/* Most read functions return the number of bytes put into the buffer. */</span></span> 
+<a id='x1-68337r154'></a><span class='ecrm-0500'>154</span><span class='ectt-0800'>    </span><span id='textcolor3628'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> bytes_read;</span> 
+<a id='x1-68339r155'></a><span class='ecrm-0500'>155</span><span class='ectt-0800'>}</span> 
+<a id='x1-68341r156'></a><span class='ecrm-0500'>156</span> 
+<a id='x1-68343r157'></a><span class='ecrm-0500'>157</span><span id='textcolor3629'><span class='ectt-0800'>/* Called when a process writes to dev file; echo "enable" &gt; /dev/key_state */</span></span> 
+<a id='x1-68345r158'></a><span class='ecrm-0500'>158</span><span id='textcolor3630'><span class='ectt-0800'>static</span></span><span class='ectt-0800'> </span><span id='textcolor3631'><span class='ectt-0800'>ssize_t</span></span><span class='ectt-0800'> device_write(</span><span id='textcolor3632'><span class='ectt-0800'>struct</span></span><span class='ectt-0800'> file *filp, </span><span id='textcolor3633'><span class='ectt-0800'>const</span></span><span class='ectt-0800'> </span><span id='textcolor3634'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> __user *buffer,</span> 
+<a id='x1-68347r159'></a><span class='ecrm-0500'>159</span><span class='ectt-0800'>                            </span><span id='textcolor3635'><span class='ectt-0800'>size_t</span></span><span class='ectt-0800'> length, loff_t *offset)</span> 
+<a id='x1-68349r160'></a><span class='ecrm-0500'>160</span><span class='ectt-0800'>{</span> 
+<a id='x1-68351r161'></a><span class='ecrm-0500'>161</span><span class='ectt-0800'>    </span><span id='textcolor3636'><span class='ectt-0800'>char</span></span><span class='ectt-0800'> command[10];</span> 
+<a id='x1-68353r162'></a><span class='ecrm-0500'>162</span> 
+<a id='x1-68355r163'></a><span class='ecrm-0500'>163</span><span class='ectt-0800'>    </span><span id='textcolor3637'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (length &gt; 10) {</span> 
+<a id='x1-68357r164'></a><span class='ecrm-0500'>164</span><span class='ectt-0800'>        pr_err(</span><span id='textcolor3638'><span class='ectt-0800'>"command exceeded 10 char</span></span><span id='textcolor3639'><span class='ectt-0800'>\n</span></span><span id='textcolor3640'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>);</span> 
+<a id='x1-68359r165'></a><span class='ecrm-0500'>165</span><span class='ectt-0800'>        </span><span id='textcolor3641'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EINVAL;</span> 
+<a id='x1-68361r166'></a><span class='ecrm-0500'>166</span><span class='ectt-0800'>    }</span> 
+<a id='x1-68363r167'></a><span class='ecrm-0500'>167</span> 
+<a id='x1-68365r168'></a><span class='ecrm-0500'>168</span><span class='ectt-0800'>    </span><span id='textcolor3642'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (copy_from_user(command, buffer, length))</span> 
+<a id='x1-68367r169'></a><span class='ecrm-0500'>169</span><span class='ectt-0800'>        </span><span id='textcolor3643'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EFAULT;</span> 
+<a id='x1-68369r170'></a><span class='ecrm-0500'>170</span> 
+<a id='x1-68371r171'></a><span class='ecrm-0500'>171</span><span class='ectt-0800'>    </span><span id='textcolor3644'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (strncmp(command, </span><span id='textcolor3645'><span class='ectt-0800'>"enable"</span></span><span class='ectt-0800'>, strlen(</span><span id='textcolor3646'><span class='ectt-0800'>"enable"</span></span><span class='ectt-0800'>)) == 0)</span> 
+<a id='x1-68373r172'></a><span class='ecrm-0500'>172</span><span class='ectt-0800'>        static_branch_enable(&amp;fkey);</span> 
+<a id='x1-68375r173'></a><span class='ecrm-0500'>173</span><span class='ectt-0800'>    </span><span id='textcolor3647'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> </span><span id='textcolor3648'><span class='ectt-0800'>if</span></span><span class='ectt-0800'> (strncmp(command, </span><span id='textcolor3649'><span class='ectt-0800'>"disable"</span></span><span class='ectt-0800'>, strlen(</span><span id='textcolor3650'><span class='ectt-0800'>"disable"</span></span><span class='ectt-0800'>)) == 0)</span> 
+<a id='x1-68377r174'></a><span class='ecrm-0500'>174</span><span class='ectt-0800'>        static_branch_disable(&amp;fkey);</span> 
+<a id='x1-68379r175'></a><span class='ecrm-0500'>175</span><span class='ectt-0800'>    </span><span id='textcolor3651'><span class='ectt-0800'>else</span></span><span class='ectt-0800'> {</span> 
+<a id='x1-68381r176'></a><span class='ecrm-0500'>176</span><span class='ectt-0800'>        pr_err(</span><span id='textcolor3652'><span class='ectt-0800'>"Invalid command: %s</span></span><span id='textcolor3653'><span class='ectt-0800'>\n</span></span><span id='textcolor3654'><span class='ectt-0800'>"</span></span><span class='ectt-0800'>, command);</span> 
+<a id='x1-68383r177'></a><span class='ecrm-0500'>177</span><span class='ectt-0800'>        </span><span id='textcolor3655'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> -EINVAL;</span> 
+<a id='x1-68385r178'></a><span class='ecrm-0500'>178</span><span class='ectt-0800'>    }</span> 
+<a id='x1-68387r179'></a><span class='ecrm-0500'>179</span> 
+<a id='x1-68389r180'></a><span class='ecrm-0500'>180</span><span class='ectt-0800'>    </span><span id='textcolor3656'><span class='ectt-0800'>/* Again, return the number of input characters used. */</span></span> 
+<a id='x1-68391r181'></a><span class='ecrm-0500'>181</span><span class='ectt-0800'>    </span><span id='textcolor3657'><span class='ectt-0800'>return</span></span><span class='ectt-0800'> length;</span> 
+<a id='x1-68393r182'></a><span class='ecrm-0500'>182</span><span class='ectt-0800'>}</span> 
+<a id='x1-68395r183'></a><span class='ecrm-0500'>183</span> 
+<a id='x1-68397r184'></a><span class='ecrm-0500'>184</span><span class='ectt-0800'>module_init(chardev_init);</span> 
+<a id='x1-68399r185'></a><span class='ecrm-0500'>185</span><span class='ectt-0800'>module_exit(chardev_exit);</span> 
+<a id='x1-68401r186'></a><span class='ecrm-0500'>186</span> 
+<a id='x1-68403r187'></a><span class='ecrm-0500'>187</span><span class='ectt-0800'>MODULE_LICENSE(</span><span id='textcolor3658'><span class='ectt-0800'>"GPL"</span></span><span class='ectt-0800'>);</span></pre>
+                                                                  
+
+                                                                  
+<!-- l. 2082 --><p class='indent'>   To check the state of the static key, we can use the <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/dev/key_state</span></span></span>
+interface.
+</p><!-- l. 1 --><p class='indent'>
+</p>
+   <pre class='fancyvrb' id='fancyvrb103'><a id='x1-68406r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>cat /dev/key_state</span></pre>
+<!-- l. 2088 --><p class='indent'>   This will display the current state of the key, which is disabled by default.
+</p><!-- l. 2090 --><p class='indent'>   To change the state of the static key, we can perform a write operation on the
+file:
+</p><!-- l. 1 --><p class='indent'>
 </p>
-   <h4 class='subsectionHead' id='using-standard-libraries'><span class='titlemark'>20.1   </span> <a id='x1-6900020.1'></a>Using standard libraries</h4>
-<!-- l. 2052 --><p class='noindent'>You can not do that. In a kernel module, you can only use kernel functions which are
+   <pre class='fancyvrb' id='fancyvrb104'><a id='x1-68409r1'></a><span class='ecrm-0500'>1</span><span class='ectt-1000'>echo enable &gt; /dev/key_state</span></pre>
+<!-- l. 2096 --><p class='indent'>   This will enable the static key, causing the code path to switch from the fastpath
+to the slowpath.
+</p><!-- l. 2098 --><p class='indent'>   In some cases, the key is enabled or disabled at initialization and never changed,
+we can declare a static key as read-only, which means that it can only be toggled in
+the module init function. To declare a read-only static key, we can use the
+<code> <span class='ectt-1000'>DEFINE_STATIC_KEY_FALSE_RO</span>
+</code> or <code>  <span class='ectt-1000'>DEFINE_STATIC_KEY_TRUE_RO</span>
+</code> macro instead. Attempts to change the key at runtime will result in a page fault. For
+more information, see <a href='https://www.kernel.org/doc/Documentation/static-keys.txt'>Static keys</a>
+</p><!-- l. 2101 --><p class='noindent'>
+</p>
+   <h3 class='sectionHead' id='common-pitfalls'><span class='titlemark'>20   </span> <a id='x1-6900020'></a>Common Pitfalls</h3>
+<!-- l. 2104 --><p class='noindent'>
+</p>
+   <h4 class='subsectionHead' id='using-standard-libraries'><span class='titlemark'>20.1   </span> <a id='x1-7000020.1'></a>Using standard libraries</h4>
+<!-- l. 2106 --><p class='noindent'>You can not do that. In a kernel module, you can only use kernel functions which are
 the functions you can see in <span class='obeylines-h'><span class='verb'><span class='ectt-1000'>/proc/kallsyms</span></span></span>.
-</p><!-- l. 2055 --><p class='noindent'>
+</p><!-- l. 2109 --><p class='noindent'>
 </p>
-   <h4 class='subsectionHead' id='disabling-interrupts'><span class='titlemark'>20.2   </span> <a id='x1-7000020.2'></a>Disabling interrupts</h4>
-<!-- l. 2057 --><p class='noindent'>You might need to do this for a short time and that is OK, but if you do not enable
+   <h4 class='subsectionHead' id='disabling-interrupts'><span class='titlemark'>20.2   </span> <a id='x1-7100020.2'></a>Disabling interrupts</h4>
+<!-- l. 2111 --><p class='noindent'>You might need to do this for a short time and that is OK, but if you do not enable
 them afterwards, your system will be stuck and you will have to power it
 off.
-</p><!-- l. 2059 --><p class='noindent'>
+                                                                  
+
+                                                                  
+</p><!-- l. 2113 --><p class='noindent'>
 </p>
-   <h3 class='sectionHead' id='where-to-go-from-here'><span class='titlemark'>21   </span> <a id='x1-7100021'></a>Where To Go From Here?</h3>
-<!-- l. 2061 --><p class='noindent'>For people seriously interested in kernel programming, I recommend <a href='https://kernelnewbies.org'>kernelnewbies.org</a>
+   <h3 class='sectionHead' id='where-to-go-from-here'><span class='titlemark'>21   </span> <a id='x1-7200021'></a>Where To Go From Here?</h3>
+<!-- l. 2115 --><p class='noindent'>For people seriously interested in kernel programming, I recommend <a href='https://kernelnewbies.org'>kernelnewbies.org</a>
 and the <a href='https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation'>Documentation</a> subdirectory within the kernel source code which is not
 always easy to understand but can be a starting point for further investigation. Also,
 as Linus Torvalds said, the best way to learn the kernel is to read the source code
 yourself.
-</p><!-- l. 2064 --><p class='indent'>   If you would like to contribute to this guide or notice anything glaringly wrong,
+</p><!-- l. 2118 --><p class='indent'>   If you would like to contribute to this guide or notice anything glaringly wrong,
 please create an issue at <a class='url' href='https://github.com/sysprog21/lkmpg'><span class='ectt-1000'>https://github.com/sysprog21/lkmpg</span></a>. Your pull requests
 will be appreciated.
-</p><!-- l. 2067 --><p class='indent'>   Happy hacking!
+</p><!-- l. 2121 --><p class='indent'>   Happy hacking!
 </p>
    <div class='footnotes'><!-- l. 1803 --><p class='indent'>     <span class='footnote-mark'><a href='#fn1x0-bk' id='fn1x0'><sup class='textsuperscript'>1</sup></a></span><span class='ecrm-0800'>The goal of threaded interrupts is to push more of the work to separate threads, so that the
 </span><span class='ecrm-0800'>minimum needed for acknowledging an interrupt is reduced, and therefore the time spent handling