Skip to content

Instantly share code, notes, and snippets.

@tonosaman
Last active April 25, 2019 18:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tonosaman/3288cf1995c343d1d886b26744b498ec to your computer and use it in GitHub Desktop.
Save tonosaman/3288cf1995c343d1d886b26744b498ec to your computer and use it in GitHub Desktop.
Xvisor Development › [PATCH] CORE: blockdev: Fix stack frame corruption

CORE: vmm_blockdev: Fix stack frame corruption

This patch fixes stack frame corruption caused by a race condition between issuer and worker on the request queue.

Patch

diff --git a/core/block/vmm_blockdev.c b/core/block/vmm_blockdev.c
index 0c8b488..d32d768 100644
--- a/core/block/vmm_blockdev.c
+++ b/core/block/vmm_blockdev.c
@@ -127,7 +127,6 @@ int vmm_blockdev_complete_request(struct vmm_request *r)
        vmm_spin_lock_irqsave(&rq->lock, flags);
        __blockdev_done_request(rq);
        vmm_spin_unlock_irqrestore(&rq->lock, flags);
-       r->bdev = NULL;
 
        return VMM_OK;
 }
@@ -149,7 +148,6 @@ int vmm_blockdev_fail_request(struct vmm_request *r)
        vmm_spin_lock_irqsave(&rq->lock, flags);
        __blockdev_done_request(rq);
        vmm_spin_unlock_irqrestore(&rq->lock, flags);
-       r->bdev = NULL;
 
        return VMM_OK;
 }
@@ -268,6 +266,7 @@ static void blockdev_rw_completed(struct vmm_request *req)
                return;
        }
 
+       req->bdev = NULL;
        rw->failed = FALSE;
        vmm_completion_complete(&rw->done);
 }
@@ -280,6 +279,7 @@ static void blockdev_rw_failed(struct vmm_request *req)
                return;
        }
 
+       req->bdev = NULL;
        rw->failed = TRUE;
        vmm_completion_complete(&rw->done);
 }

Sequence Diagram

Blockdev complete race condition

Edit@www.planttext.com

Display the source blob
Display the rendered blob
Raw
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="1378px" preserveAspectRatio="none" style="width:981px;height:1378px;" version="1.1" viewBox="0 0 981 1378" width="981px" zoomAndPan="magnify"><defs><filter height="300%" id="f18e5664g1tade" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter><filter height="1" id="b18e5664g1tade0" width="1" x="0" y="0"><feFlood flood-color="#D3D3D3" result="flood"/><feComposite in="SourceGraphic" in2="flood" operator="over"/></filter><filter height="1" id="b18e5664g1tade1" width="1" x="0" y="0"><feFlood flood-color="#FFFF00" result="flood"/><feComposite in="SourceGraphic" in2="flood" operator="over"/></filter></defs><g><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="156.6641" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="86" y="93.7266"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="125.5313" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="86" y="357.7891"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="156.6641" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="86" y="563.5859"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="319.3281" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="86" y="827.6484"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="231.9297" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="454" y="215.2578"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="361.4609" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="454" y="685.1172"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="184.6641" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="454" y="1111.8438"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="355.4609" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="877" y="127.8594"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="259.0625" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="877" y="597.7188"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="384.4609" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="877" y="928.0469"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 5.0,5.0;" x1="91" x2="91" y1="54.5938" y2="1321.5078"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 5.0,5.0;" x1="459" x2="459" y1="54.5938" y2="1321.5078"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 5.0,5.0;" x1="881.5" x2="881.5" y1="54.5938" y2="1321.5078"/><rect fill="#FEFECE" filter="url(#f18e5664g1tade)" height="46.5938" style="stroke: #A80036; stroke-width: 1.5;" width="124" x="27" y="3"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="110" x="34" y="24">«vcpu@hcpu1»</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="45" x="66.5" y="40.2969">mterm</text><rect fill="#FEFECE" filter="url(#f18e5664g1tade)" height="46.5938" style="stroke: #A80036; stroke-width: 1.5;" width="124" x="27" y="1320.5078"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="110" x="34" y="1341.5078">«vcpu@hcpu1»</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="45" x="66.5" y="1357.8047">mterm</text><rect fill="#FEFECE" filter="url(#f18e5664g1tade)" height="46.5938" style="stroke: #A80036; stroke-width: 1.5;" width="124" x="395" y="3"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="110" x="402" y="24">«vcpu@hcpu2»</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="43" x="435.5" y="40.2969">mmc0</text><rect fill="#FEFECE" filter="url(#f18e5664g1tade)" height="46.5938" style="stroke: #A80036; stroke-width: 1.5;" width="124" x="395" y="1320.5078"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="110" x="402" y="1341.5078">«vcpu@hcpu2»</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="43" x="435.5" y="1357.8047">mmc0</text><rect fill="#FEFECE" filter="url(#f18e5664g1tade)" height="46.5938" style="stroke: #A80036; stroke-width: 1.5;" width="161" x="799.5" y="3"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="147" x="806.5" y="24">«struct blockdev_rw»</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="16" x="872" y="40.2969">rw</text><rect fill="#FEFECE" filter="url(#f18e5664g1tade)" height="46.5938" style="stroke: #A80036; stroke-width: 1.5;" width="161" x="799.5" y="1320.5078"/><text fill="#000000" font-family="sans-serif" font-size="14" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="147" x="806.5" y="1341.5078">«struct blockdev_rw»</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="16" x="872" y="1357.8047">rw</text><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="156.6641" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="86" y="93.7266"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="125.5313" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="86" y="357.7891"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="156.6641" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="86" y="563.5859"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="319.3281" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="86" y="827.6484"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="231.9297" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="454" y="215.2578"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="361.4609" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="454" y="685.1172"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="184.6641" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="454" y="1111.8438"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="355.4609" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="877" y="127.8594"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="259.0625" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="877" y="597.7188"/><rect fill="#FFFFFF" filter="url(#f18e5664g1tade)" height="384.4609" style="stroke: #A80036; stroke-width: 1.0;" width="10" x="877" y="928.0469"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="91" x2="138" y1="80.7266" y2="80.7266"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="138" x2="138" y1="80.7266" y2="93.7266"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="97" x2="138" y1="93.7266" y2="93.7266"/><polygon fill="#A80036" points="107,89.7266,97,93.7266,107,97.7266,103,93.7266" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="137" x="103" y="75.6606">blockdev_rw_blocks()</text><polygon fill="#A80036" points="865,123.8594,875,127.8594,865,131.8594,869,127.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="871" y1="127.8594" y2="127.8594"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="24" x="103" y="122.7935">A1.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="131" y="122.7935"/><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="141" x="131" y="122.7935">struct blockdev_rw rw</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="176" x="276" y="122.7935">is allocated on stack frame.</text><polygon fill="#A80036" points="865,152.9922,875,156.9922,865,160.9922,869,156.9922" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="871" y1="156.9922" y2="156.9922"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="24" x="103" y="151.9263">A2.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="131" y="151.9263"/><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="128" x="131" y="151.9263">rw.req.bdev = bdev</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="5" x="263" y="151.9263">(</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="24" x="268" y="151.9263">B1.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="62" x="296" y="151.9263">uses this)</text><polygon fill="#A80036" points="865,182.125,875,186.125,865,190.125,869,186.125" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="871" y1="186.125" y2="186.125"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="24" x="103" y="181.0591">A3.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="131" y="181.0591"/><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="116" x="131" y="181.0591">bwork-&gt;d.rw.r = r</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="90" x="251" y="181.0591">(r is pointer to</text><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="41" x="345" y="181.0591">rw.req</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="5" x="386" y="181.0591">)</text><polygon fill="#A80036" points="442,211.2578,452,215.2578,442,219.2578,446,215.2578" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="448" y1="215.2578" y2="215.2578"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="24" x="103" y="210.1919">A4.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="131" y="210.1919"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="302" x="131" y="210.1919">vmm_completion_complete(&amp;wq-&gt;work_avail)</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="96" x2="138" y1="249.3906" y2="249.3906"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="138" x2="138" y1="249.3906" y2="262.3906"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="91" x2="138" y1="262.3906" y2="262.3906"/><polygon fill="#A80036" points="101,258.3906,91,262.3906,101,266.3906,97,262.3906" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="24" x="103" y="244.3247">A5.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="131" y="244.3247"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="218" x="131" y="244.3247">vmm_completion_wait(&amp;rw.done)</text><polygon fill="#A80036" points="865,282.5234,875,286.5234,865,290.5234,869,286.5234" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="464" x2="871" y1="286.5234" y2="286.5234"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="24" x="471" y="281.4575">B1.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="47" x="499" y="281.4575">refer to</text><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="53" x="550" y="281.4575">r-&gt;bdev</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="13" x="607" y="281.4575">@</text><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="231" x="620" y="281.4575">vmm_blockdev_complete_request()</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="464" x2="506" y1="315.6563" y2="315.6563"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="506" x2="506" y1="315.6563" y2="328.6563"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="465" x2="506" y1="328.6563" y2="328.6563"/><polygon fill="#A80036" points="475,324.6563,465,328.6563,475,332.6563,471,328.6563" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="24" x="471" y="310.5903">B2.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="499" y="310.5903"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="76" x="499" y="310.5903">brq-&gt;read()</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="13" x="579" y="310.5903">or</text><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="79" x="596" y="310.5903">brq-&gt;write()</text><polygon fill="#A80036" points="107,353.7891,97,357.7891,107,361.7891,103,357.7891" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="101" x2="453" y1="357.7891" y2="357.7891"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="24" x="113" y="352.7231">B3.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="141" y="352.7231"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="263" x="141" y="352.7231">vmm_completion_complete(&amp;rw-&gt;done)</text><polygon fill="#A80036" points="865,395.4883,875,399.4883,865,403.4883,869,399.4883" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="464" x2="871" y1="399.4883" y2="399.4883"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="24" x="471" y="394.4224">B4.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="499" y="394.4224"/><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="106" x="499" y="394.4224">r-&gt;bdev = NULL</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="13" x="609" y="394.4224">@</text><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="231" x="622" y="394.4224">vmm_blockdev_complete_request()</text><path d="M293,370.7891 L293,410.7891 L445,410.7891 L445,380.7891 L435,370.7891 L293,370.7891 " fill="#FBFB77" filter="url(#f18e5664g1tade)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M435,370.7891 L435,380.7891 L445,380.7891 L435,370.7891 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="107" x="304" y="387.856">critical section</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="131" x="299" y="402.9888">Nondestructive case</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="464" x2="506" y1="446.1875" y2="446.1875"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="506" x2="506" y1="446.1875" y2="459.1875"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="459" x2="506" y1="459.1875" y2="459.1875"/><polygon fill="#A80036" points="469,455.1875,459,459.1875,469,463.1875,465,459.1875" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="24" x="471" y="441.1216">B5.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="499" y="441.1216"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="269" x="499" y="441.1216">vmm_completion_wait(&amp;wq-&gt;work_avail)</text><polygon fill="#A80036" points="870,479.3203,880,483.3203,870,487.3203,874,483.3203" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="91" x2="876" y1="483.3203" y2="483.3203"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="153" x="98" y="478.2544">Discard the stack frame</text><line style="stroke: #A80036; stroke-width: 2.0;" x1="873" x2="891" y1="474.3203" y2="492.3203"/><line style="stroke: #A80036; stroke-width: 2.0;" x1="873" x2="891" y1="492.3203" y2="474.3203"/><rect fill="#EEEEEE" filter="url(#f18e5664g1tade)" height="3" style="stroke: #EEEEEE; stroke-width: 1.0;" width="966.5" x="3" y="511.8867"/><line style="stroke: #000000; stroke-width: 1.0;" x1="3" x2="969.5" y1="511.8867" y2="511.8867"/><line style="stroke: #000000; stroke-width: 1.0;" x1="3" x2="969.5" y1="514.8867" y2="514.8867"/><rect fill="#EEEEEE" filter="url(#f18e5664g1tade)" height="23.1328" style="stroke: #000000; stroke-width: 2.0;" width="208" x="382.25" y="501.3203"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="189" x="388.25" y="517.3872">Destructive case is below</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="91" x2="138" y1="550.5859" y2="550.5859"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="138" x2="138" y1="550.5859" y2="563.5859"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="97" x2="138" y1="563.5859" y2="563.5859"/><polygon fill="#A80036" points="107,559.5859,97,563.5859,107,567.5859,103,563.5859" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="137" x="103" y="545.52">blockdev_rw_blocks()</text><polygon fill="#A80036" points="865,593.7188,875,597.7188,865,601.7188,869,597.7188" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="871" y1="597.7188" y2="597.7188"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="103" y="592.6528">A01.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="140" y="592.6528"/><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="141" x="140" y="592.6528">struct blockdev_rw rw</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="176" x="285" y="592.6528">is allocated on stack frame.</text><polygon fill="#A80036" points="865,622.8516,875,626.8516,865,630.8516,869,626.8516" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="871" y1="626.8516" y2="626.8516"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="103" y="621.7856">A02.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="140" y="621.7856"/><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="128" x="140" y="621.7856">rw.req.bdev = bdev</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="5" x="272" y="621.7856">(</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="277" y="621.7856">B01.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="62" x="314" y="621.7856">uses this)</text><polygon fill="#A80036" points="865,651.9844,875,655.9844,865,659.9844,869,655.9844" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="871" y1="655.9844" y2="655.9844"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="103" y="650.9185">A03.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="140" y="650.9185"/><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="116" x="140" y="650.9185">bwork-&gt;d.rw.r = r</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="90" x="260" y="650.9185">(r is pointer to</text><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="41" x="354" y="650.9185">rw.req</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="5" x="395" y="650.9185">)</text><polygon fill="#A80036" points="442,681.1172,452,685.1172,442,689.1172,446,685.1172" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="448" y1="685.1172" y2="685.1172"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="103" y="680.0513">A04.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="140" y="680.0513"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="302" x="140" y="680.0513">vmm_completion_complete(&amp;wq-&gt;work_avail)</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="96" x2="138" y1="719.25" y2="719.25"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="138" x2="138" y1="719.25" y2="732.25"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="91" x2="138" y1="732.25" y2="732.25"/><polygon fill="#A80036" points="101,728.25,91,732.25,101,736.25,97,732.25" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="103" y="714.1841">A05.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="140" y="714.1841"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="218" x="140" y="714.1841">vmm_completion_wait(&amp;rw.done)</text><polygon fill="#A80036" points="865,752.3828,875,756.3828,865,760.3828,869,756.3828" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="464" x2="871" y1="756.3828" y2="756.3828"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="471" y="751.3169">B01.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="47" x="508" y="751.3169">refer to</text><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="53" x="559" y="751.3169">r-&gt;bdev</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="13" x="616" y="751.3169">@</text><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="231" x="629" y="751.3169">vmm_blockdev_complete_request()</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="464" x2="506" y1="785.5156" y2="785.5156"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="506" x2="506" y1="785.5156" y2="798.5156"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="465" x2="506" y1="798.5156" y2="798.5156"/><polygon fill="#A80036" points="475,794.5156,465,798.5156,475,802.5156,471,798.5156" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="471" y="780.4497">B02.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="508" y="780.4497"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="76" x="508" y="780.4497">brq-&gt;read()</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="13" x="588" y="780.4497">or</text><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="79" x="605" y="780.4497">brq-&gt;write()</text><polygon fill="#A80036" points="107,823.6484,97,827.6484,107,831.6484,103,827.6484" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="101" x2="453" y1="827.6484" y2="827.6484"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="113" y="822.5825">B03.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="150" y="822.5825"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="263" x="150" y="822.5825">vmm_completion_complete(&amp;rw-&gt;done)</text><polygon fill="#A80036" points="870,852.7813,880,856.7813,870,860.7813,874,856.7813" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="876" y1="856.7813" y2="856.7813"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="153" x="103" y="851.7153">Discard the stack frame</text><line style="stroke: #A80036; stroke-width: 2.0;" x1="873" x2="891" y1="847.7813" y2="865.7813"/><line style="stroke: #A80036; stroke-width: 2.0;" x1="873" x2="891" y1="865.7813" y2="847.7813"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="96" x2="138" y1="885.9141" y2="885.9141"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="138" x2="138" y1="885.9141" y2="898.9141"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="97" x2="138" y1="898.9141" y2="898.9141"/><polygon fill="#A80036" points="107,894.9141,97,898.9141,107,902.9141,103,898.9141" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="137" x="103" y="880.8481">blockdev_rw_blocks()</text><path d="M252,871.2813 L252,896.2813 L888,896.2813 L888,881.2813 L878,871.2813 L252,871.2813 " fill="#FBFB77" filter="url(#f18e5664g1tade)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M878,871.2813 L878,881.2813 L888,881.2813 L878,871.2813 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="357" x="258" y="888.3481">The stack frame is allocated at the same place because</text><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="137" x="619" y="888.3481">blockdev_rw_blocks()</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="113" x="760" y="888.3481">is called in a loop.</text><polygon fill="#A80036" points="865,924.0469,875,928.0469,865,932.0469,869,928.0469" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="871" y1="928.0469" y2="928.0469"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="103" y="922.981">A11.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="140" y="922.981"/><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="141" x="140" y="922.981">struct blockdev_rw rw</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="176" x="285" y="922.981">is allocated on stack frame.</text><polygon fill="#A80036" points="865,953.1797,875,957.1797,865,961.1797,869,957.1797" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="871" y1="957.1797" y2="957.1797"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="103" y="952.1138">A12.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="140" y="952.1138"/><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="128" x="140" y="952.1138">rw.req.bdev = bdev</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="5" x="272" y="952.1138">(</text><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="277" y="952.1138">B11.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="61" x="314" y="952.1138">uses this.</text><text fill="#000000" filter="url(#b18e5664g1tade1)" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="22" x="379" y="952.1138">But</text><text fill="#000000" filter="url(#b18e5664g1tade1)" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="405" y="952.1138">B04.</text><text fill="#000000" filter="url(#b18e5664g1tade1)" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="65" x="442" y="952.1138">overwrites</text><text fill="#000000" filter="url(#b18e5664g1tade1)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="34" x="511" y="952.1138">NULL</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="5" x="545" y="952.1138">)</text><polygon fill="#A80036" points="865,994.8789,875,998.8789,865,1002.8789,869,998.8789" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="464" x2="871" y1="998.8789" y2="998.8789"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="471" y="993.813">B04.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="508" y="993.813"/><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="106" x="508" y="993.813">r-&gt;bdev = NULL</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="13" x="618" y="993.813">@</text><a href="https://github.com/avpatel/xvisor-next/blob/e321d1a80f7bd60489b5d93802b4851b8f2e881e/core/block/vmm_blockdev.c#L130" target="_top" xlink:actuate="onRequest" xlink:show="new" xlink:title="https://github.com/avpatel/xvisor-next/blob/e321d1a80f7bd60489b5d93802b4851b8f2e881e/core/block/vmm_blockdev.c#L130" xlink:type="simple"><text fill="#0000FF" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="229" x="631" y="993.813">vmm_blockdev_complete_request()</text></a><path d="M307,970.1797 L307,1010.1797 L445,1010.1797 L445,980.1797 L435,970.1797 L307,970.1797 " fill="#FBFB77" filter="url(#f18e5664g1tade)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M435,970.1797 L435,980.1797 L445,980.1797 L435,970.1797 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" textLength="107" x="318" y="987.2466">critical section</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="107" x="313" y="1002.3794">Destructive case</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="464" x2="506" y1="1045.5781" y2="1045.5781"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="506" x2="506" y1="1045.5781" y2="1058.5781"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="459" x2="506" y1="1058.5781" y2="1058.5781"/><polygon fill="#A80036" points="469,1054.5781,459,1058.5781,469,1062.5781,465,1058.5781" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="471" y="1040.5122">B05.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="508" y="1040.5122"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="269" x="508" y="1040.5122">vmm_completion_wait(&amp;wq-&gt;work_avail)</text><polygon fill="#A80036" points="865,1078.7109,875,1082.7109,865,1086.7109,869,1082.7109" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="871" y1="1082.7109" y2="1082.7109"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="103" y="1077.645">A13.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="140" y="1077.645"/><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="116" x="140" y="1077.645">bwork-&gt;d.rw.r = r</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="90" x="260" y="1077.645">(r is pointer to</text><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="41" x="354" y="1077.645">rw.req</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="5" x="395" y="1077.645">)</text><polygon fill="#A80036" points="442,1107.8438,452,1111.8438,442,1115.8438,446,1111.8438" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="96" x2="448" y1="1111.8438" y2="1111.8438"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="103" y="1106.7778">A14.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="140" y="1106.7778"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="302" x="140" y="1106.7778">vmm_completion_complete(&amp;wq-&gt;work_avail)</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="96" x2="138" y1="1145.9766" y2="1145.9766"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="138" x2="138" y1="1145.9766" y2="1158.9766"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="91" x2="138" y1="1158.9766" y2="1158.9766"/><polygon fill="#A80036" points="101,1154.9766,91,1158.9766,101,1162.9766,97,1158.9766" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="103" y="1140.9106">A15.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="140" y="1140.9106"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="218" x="140" y="1140.9106">vmm_completion_wait(&amp;rw.done)</text><path d="M8,1166.9766 L8,1191.9766 L170,1191.9766 L170,1176.9766 L160,1166.9766 L8,1166.9766 " fill="#FBFB77" filter="url(#f18e5664g1tade)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M160,1166.9766 L160,1176.9766 L170,1176.9766 L160,1166.9766 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="141" x="14" y="1184.0435">Keep waiting forever...</text><polygon fill="#A80036" points="865,1218.2422,875,1222.2422,865,1226.2422,869,1222.2422" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.0; stroke-dasharray: 2.0,2.0;" x1="464" x2="871" y1="1222.2422" y2="1222.2422"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="471" y="1217.1763">B11.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="47" x="508" y="1217.1763">refer to</text><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="53" x="559" y="1217.1763">r-&gt;bdev</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="13" x="616" y="1217.1763">@</text><a href="https://github.com/avpatel/xvisor-next/blob/e321d1a80f7bd60489b5d93802b4851b8f2e881e/core/block/vmm_blockdev.c#L120" target="_top" xlink:actuate="onRequest" xlink:show="new" xlink:title="https://github.com/avpatel/xvisor-next/blob/e321d1a80f7bd60489b5d93802b4851b8f2e881e/core/block/vmm_blockdev.c#L120" xlink:type="simple"><text fill="#0000FF" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="229" x="629" y="1217.1763">vmm_blockdev_complete_request()</text></a><path d="M380,1235.2422 L380,1260.2422 L956,1260.2422 L956,1245.2422 L946,1235.2422 L380,1235.2422 " fill="#FBFB77" filter="url(#f18e5664g1tade)" style="stroke: #A80036; stroke-width: 1.0;"/><path d="M946,1235.2422 L946,1245.2422 L956,1245.2422 L946,1235.2422 " fill="#FBFB77" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="231" x="386" y="1252.3091">vmm_blockdev_complete_request()</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="46" x="621" y="1252.3091">returns</text><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="99" x="671" y="1252.3091">VMM_EINVALID</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="54" x="774" y="1252.3091">because</text><text fill="#000000" filter="url(#b18e5664g1tade0)" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="53" x="832" y="1252.3091">r-&gt;bdev</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="52" x="889" y="1252.3091">is NULL.</text><line style="stroke: #A80036; stroke-width: 1.0;" x1="464" x2="506" y1="1295.5078" y2="1295.5078"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="506" x2="506" y1="1295.5078" y2="1308.5078"/><line style="stroke: #A80036; stroke-width: 1.0;" x1="459" x2="506" y1="1308.5078" y2="1308.5078"/><polygon fill="#A80036" points="469,1304.5078,459,1308.5078,469,1312.5078,465,1308.5078" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacingAndGlyphs" text-decoration="underline" textLength="33" x="471" y="1290.4419">B12.</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="0" x="508" y="1290.4419"/><text fill="#000000" font-family="sans-serif" font-size="13" font-style="italic" lengthAdjust="spacingAndGlyphs" textLength="269" x="508" y="1290.4419">vmm_completion_wait(&amp;wq-&gt;work_avail)</text><!--
@startuml
participant "mterm" as cpuA <<vcpu@hcpu1>>
participant "mmc0" as cpuB <<vcpu@hcpu2>>
participant "rw" as req <<struct blockdev_rw>>
cpuA -> cpuA : //blockdev_rw_blocks()//
activate cpuA
cpuA - -> req : **__A1.__** <back:lightgray>//struct blockdev_rw rw//</back> is allocated on stack frame.
activate req
cpuA - -> req : **__A2.__** <back:lightgray>//rw.req.bdev = bdev//</back> (**__B1.__** uses this)
cpuA - -> req : **__A3.__** <back:lightgray>//bwork->d.rw.r = r//</back> (r is pointer to //rw.req//)
cpuA - -> cpuB : **__A4.__** //vmm_completion_complete(&wq->work_avail)//
activate cpuB
cpuA -> cpuA : **__A5.__** //vmm_completion_wait(&rw.done)//
deactivate cpuA
cpuB - -> req : **__B1.__** refer to <back:lightgray>//r->bdev//</back> @//vmm_blockdev_complete_request()//
cpuB -> cpuB : **__B2.__** //brq->read()// or //brq->write()//
cpuB - -> cpuA : **__B3.__** //vmm_completion_complete(&rw->done)//
activate cpuA
cpuB - -> req : **__B4.__** <back:lightgray>//r->bdev = NULL//</back> @//vmm_blockdev_complete_request()//
note left
** critical section **
Nondestructive case
end note
cpuB -> cpuB : **__B5.__** //vmm_completion_wait(&wq->work_avail)//
deactivate cpuB
cpuA - -> req : Discard the stack frame
destroy req
deactivate cpuA
participant "mterm" as cpuA <<vcpu@hcpu1>>
participant "mmc0" as cpuB <<vcpu@hcpu2>>
participant "rw" as req <<struct blockdev_rw>>
== Destructive case is below ==
cpuA -> cpuA : //blockdev_rw_blocks()//
activate cpuA
cpuA - -> req : **__A01.__** <back:lightgray>//struct blockdev_rw rw//</back> is allocated on stack frame.
activate req
cpuA - -> req : **__A02.__** <back:lightgray>//rw.req.bdev = bdev//</back> (**__B01.__** uses this)
cpuA - -> req : **__A03.__** <back:lightgray>//bwork->d.rw.r = r//</back> (r is pointer to //rw.req//)
cpuA - -> cpuB : **__A04.__** //vmm_completion_complete(&wq->work_avail)//
activate cpuB
cpuA -> cpuA : **__A05.__** //vmm_completion_wait(&rw.done)//
deactivate cpuA
cpuB - -> req : **__B01.__** refer to <back:lightgray>//r->bdev//</back> @//vmm_blockdev_complete_request()//
cpuB -> cpuB : **__B02.__** //brq->read()// or //brq->write()//
cpuB - -> cpuA : **__B03.__** //vmm_completion_complete(&rw->done)//
activate cpuA
cpuA - -> req : Discard the stack frame
destroy req
cpuA -> cpuA : //blockdev_rw_blocks()//
note right
The stack frame is allocated at the same place because //blockdev_rw_blocks()// is called in a loop.
end note
cpuA - -> req : **__A11.__** <back:lightgray>//struct blockdev_rw rw//</back> is allocated on stack frame.
activate req
cpuA - -> req : **__A12.__** <back:lightgray>//rw.req.bdev = bdev//</back> (**__B11.__** uses this. <back:yellow>But **__B04.__** overwrites //NULL//</back>)
cpuB - -> req : **__B04.__** <back:lightgray>//r->bdev = NULL//</back> @[[https://github.com/avpatel/xvisor-next/blob/e321d1a80f7bd60489b5d93802b4851b8f2e881e/core/block/vmm_blockdev.c#L130 vmm_blockdev_complete_request()]]
note left
** critical section **
Destructive case
end note
cpuB -> cpuB : **__B05.__** //vmm_completion_wait(&wq->work_avail)//
deactivate cpuB
cpuA - -> req : **__A13.__** <back:lightgray>//bwork->d.rw.r = r//</back> (r is pointer to //rw.req//)
cpuA - -> cpuB : **__A14.__** //vmm_completion_complete(&wq->work_avail)//
activate cpuB
cpuA -> cpuA : **__A15.__** //vmm_completion_wait(&rw.done)//
deactivate cpuA
note over cpuA: Keep waiting forever...
cpuB - -> req : **__B11.__** refer to <back:lightgray>//r->bdev//</back> @[[https://github.com/avpatel/xvisor-next/blob/e321d1a80f7bd60489b5d93802b4851b8f2e881e/core/block/vmm_blockdev.c#L120 vmm_blockdev_complete_request()]]
note over cpuB, req
//vmm_blockdev_complete_request()// returns <back:lightgray>//VMM_EINVALID//</back> because <back:lightgray>//r->bdev//</back> is NULL.
end note
cpuB -> cpuB : **__B12.__** //vmm_completion_wait(&wq->work_avail)//
deactivate cpuB
@enduml
PlantUML version 1.2019.05(Sat Apr 20 16:45:36 UTC 2019)
(GPL source distribution)
Java Runtime: Java(TM) SE Runtime Environment
JVM: Java HotSpot(TM) 64-Bit Server VM
Java Version: 1.7.0_25-b15
Operating System: Linux
Default Encoding: UTF-8
Language: en
Country: US
--></g></svg>
@tonosaman
Copy link
Author

tonosaman commented Apr 25, 2019

Investigation tools

run-qemu.sh

#!/bin/sh                                                                                                                                                                 
~/github/qemu-3.1.0/aarch64-softmmu/qemu-system-aarch64 \
 -gdb tcp::9000 -S -semihosting \
 -nodefaults -nographic -monitor none -serial stdio -usb \
 -M raspi3 \
 -kernel build/vmm.bin \
 -drive if=sd,format=raw,file=mmc0.img \
 -dtb build/arch/arm/board/generic/dts/broadcom/bcm2837-rpi-3-b.dtb

dlist.gdb

define dlist
  set $offset = 0
  if $argc > 1
    set $offset = (int)$arg1
  end
  printf "---> entries of (struct dlist*)%p\n", &$arg0
  set $cur = $arg0.next
  set $i = 0
  while $cur != &$arg0
    if $argc > 2
      eval $arg2, (void*)$cur - $offset
    else
      printf "dlist@%d = (struct ???*)%p\n", $i++, (void*)$cur - $offset
    end
    set $cur = $cur.next
  end
  printf "<--- end of dlist\n"
end

document dlist
dlist <dlist> [<dlist offset in target structure>] [<eval format string>]
usage: dlist 'core/vmm_workqueue.c'::wqctrl 8
usage: dlist $wqctl->wq_list 8
usage: dlist $wqctl->wq_list 8 "p (struct vmm_work*)%p"

How to calculate the <dlist offset in target structure>:
  (gdb) p/a &$wqctl->wq_list
  $2 = 0x101f1008 <wqctrl+8>
  (gdb) p/a &((struct vmm_workqueue_ctrl *)0)->wq_list
  $1 = 0x8
  (gdb) info symbol &$wqctl->wq_list
  wqctrl + 8 in section .bss
These results implies 8.
end

# @note mterm vcpu is assigned to hcpu0, and priority is VMM_VCPU_DEF_PRIORITY==3.
define stat_mterm
  set $schedp0 = (struct vmm_scheduler_ctrl*)((void*)&percpu_sched + __percpu_offset[0])
  set $schedp0rq = (struct vmm_schedalgo_rq*)$schedp0->rq
  if $schedp0rq->list[3].next == &$schedp0rq->list[3]
    if $schedp0->current_vcpu->name[0] == 'm' && $schedp0->current_vcpu->name[1] == 't' && $schedp0->current_vcpu->name[2] == 'e' && $schedp0->current_vcpu->name[3] == 'r' && $schedp0->current_vcpu->name[4] == 'm'
      printf "mterm is current_vcpu [#####]: "
    else
      printf "mterm vcpu is unreachable from schedp [?????]: "
    end
  else
    printf "mterm exists in rq [@@@@@]: "
  end
  printf "$schedp0=%p $schedp0rq=%p $schedp0->current_vcpu=%p{state=%d}\n", $schedp0, $schedp0rq, $schedp0->current_vcpu, $schedp0->current_vcpu->state.counter
  if $schedp0rq->list[3].next != &$schedp0rq->list[3]
    dlist $schedp0rq->list[3] 0 "p (struct vmm_schedalgo_rq_entry*)%p"
  end
end

# usage: stat_brwq $rw_done
define stat_brwq
  printf "(vmm_completion*)%p: wq.vcpu_count=%d\n", &$arg0, $arg0.wq.vcpu_count
  if $arg0.wq.vcpu_count > 0
    set $vcpu_off = (off_t)&((struct vmm_vcpu*)0)->wq_head
    dlist $arg0.wq.vcpu_list $vcpu_off "p (struct vmm_vcpu*)%p"
  end
end

define stat_mmc0
  set $wqctl=&'core/vmm_workqueue.c'::wqctrl
  set $cur = $wqctl.wq_list.next
  while $cur != &$wqctl.wq_list
    set $wq = (struct vmm_workqueue*)((void*)$cur - (off_t)&(((struct vmm_workqueue*)0)->head))
    set $wq_vcpu = $wq->thread->tvcpu
    if $wq_vcpu->name[0] == 'm' && $wq_vcpu->name[1] == 'm' && $wq_vcpu->name[2] == 'c' && $wq_vcpu->name[3] == '0'
      printf "mmc0: wq=%p {thread->vcpu=%p, work_list=%p, work_avail=%p}\n", $wq, $wq_vcpu, &$wq->work_list, &$wq->work_avail

      printf "### mmc0: foreach (struct blockrq_work*)wq->work_list ###\n"
      set $off_bw = (off_t)&((struct blockrq_work*)0)->work.head
      dlist $wq->work_list $off_bw "p *(struct blockrq_work*)%p"

      printf "### mmc0: (struct vmm_request*)bwork->d.rw.r @wq->work_list ###\n"
      dlist $wq->work_list $off_bw "p *((struct blockrq_work*)%p)->d.rw.r"

      printf "### mmc0: foreach (struct vmm_completion)wq.work_avail ### \n"
      stat_brwq $wq->work_avail

      set $cur = &$wqctl.wq_list
    else
      set $cur = $cur.next
    end
  end
end

run-qemu.gdb

# usage: M-x gdb => ../gcc-linaro-5.3.1-2016.05-rc2-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gdb -i=mi -x run-qemu.gdb

source ./dlist.gdb

add-symbol-file build/vmm.elf 0x10000000

# NOTE: It is necessary to execute qemu as remote target in advance.
# % qemu-2.12.0/aarch64-softmmu/qemu-system-aarch64 -gdb tcp::9000 -S -semihosting -nodefaults -serial mon:stdio -nographic -M raspi3 -kernel build/vmm.bin -dtb bcm2837-r
target remote localhost:9000

# copy dtb (QEMU modified) from 0x8000000 to 0x800000
set $x0 = 0x800000
set $x1 = 0x8000000
set $x2 = 0x1000
call memcpy

# b core/vmm_workqueue.c:263
# commands
#   set $mmc0_host = (struct mmc_host*)((void*)mmc_host_list->next - (off_t)&((struct mmc_host*)0)->link)
#   if $mmc0_host->brq->wq == wq
#     printf "$mmc0_host->brq->wq = (struct vmm_workqueue*)%p ====\n", wq
#     set $off = (off_t)&((struct vmm_work*)0)->head
#     dlist wq->work_list $off "p *(struct vmm_work*)%p"
#   end
#   cont
# end


#????????	list_add_tail(&bwork->head, &brq->wq_pending_list);
# dlist $mmc0_host->brq->wq_pending_list


b vmm_blockdev.c:308
commands
  set $rw_done = &rw.done
  printf ">>>> &rw.done=%p, rw.req=", &rw.done
  p rw.req
  stat_mmc0
#  watch -l *&rw.req.bdev
#  commands
#    frame
#    cont
#  end
  cont
end

## vmm_workqueue_schedule_work@vmm_workqueue.c
b vmm_workqueue.c:258
commands
  set $wq_vcpu = wq->thread->tvcpu
  if $wq_vcpu->name[0] == 'm' && $wq_vcpu->name[1] == 'm' && $wq_vcpu->name[2] == 'c' && $wq_vcpu->name[3] == '0'
    set $bwork = (struct blockrq_work *)((void*)work - (off_t)&((struct blockrq_work*)0)->work)
    p *$bwork
    p *$bwork->d.rw.r
    if $bwork->is_rw && $bwork->d.rw.r.bdev == 0
      printf "************** ERROR: bdev=0 ***************\n"
    else
      cont
    end
  else
    cont
  end
end

b vmm_blockdev.c:310 if $rw_done == &rw.done
commands
  printf "<<<< &rw.done=%p, rw.req=", &rw.done
  p rw.req
  stat_mmc0
  cont
end

#### blockrq_rw_done() -> vmm_blockdev_complete_request(struct vmm_request *r) で r.bdev が 0
b vmm_blockdev.c:120
### blockdev_rw_blocks() -> vmm_blockdev_submit_request()@vmm_blockdev.c:158 -> __blockdev_make_request()@vmm_blockdev.c:64 でbdevに値がセットされる
b vmm_blockdev.c:87
commands
  printf "((struct vmm_request*)%p)->bdev=%p\n", r, r->bdev
  if r->bdev != 0
    cont
  else
    printf "r->bdev == 0 !!!!!!!!!!!!!!!!"
  end
end

### __blockdev_make_request()@vmm_blockdev.c:83 でエラー時 bdevが 0にされる
b vmm_blockdev.c:83
# 上書きされていたりする?チェック
set $prev_r_bdev = -1
b vmm_blockdev.c:64
commands
  if $prev_r_bdev == r->bdev && bdev == 0
    printf "************** ERROR: BAD OVERWRITE ***************\n"
  else
    set $prev_r_bdev = r->bdev
    printf "__blockdev_make_request(): ((struct vmm_request*)%p)->bdev=%p\n", r, r->bdev
    cont
  end
end


# workqueue_main
b vmm_workqueue.c:317
commands
  set $bwork = (struct blockrq_work *)((void*)work - (off_t)&((struct blockrq_work*)0)->work)
  if wq->thread->tvcpu->name[0] == 'm' && wq->thread->tvcpu->name[1] == 'm' && wq->thread->tvcpu->name[2] == 'c'
    if $bwork->is_rw && $bwork->d.rw.r.bdev == 0
      printf "************** ERROR: bdev=0 ***************\n"
      printf "*(struct blockrq_work*)%p = ", $bwork
      p *$bwork
      printf "*(struct struct vmm_request*)%p = ", $bwork->d.rw.r
      p *$bwork->d.rw.r
    else
      cont
    end
  else
    cont
  end
end

#blockrq_work_func
b vmm_blockrq.c:201 if bwork->is_rw && bwork->d.rw.r.bdev == 0
commands
    printf "************** ERROR: bdev=0 ***************\n"
end
b vmm_blockrq.c:211 if bwork->d.rw.r.bdev == 0
commands
    printf "************** ERROR: bdev=0 ***************\n"
end
b vmm_blockrq.c:221 if bwork->d.rw.r.bdev == 0
commands
    printf "************** ERROR: bdev=0 ***************\n"
end

# blockrq_rw_done
b vmm_blockrq.c:188 if $rw_done == &((struct blockdev_rw*)r.priv)->done
commands
  printf "blockrq_rw_done(): ((struct vmm_request*)%p)->bdev=%p\n", r, r->bdev
  p *r
  printf "blockrq_rw_done(): rw.done=%p\n", &((struct blockdev_rw*)r->priv)->done
  if r->type == VMM_REQUEST_READ && r->bdev == 0
    printf "************** ERROR: r->bdev broken ***************\n"
  else
    cont
  end
end

# blockrq_dequeue_work(bwork) => list_del(bwork->head)
b vmm_blockdev_complete_request if $rw_done == &((struct blockdev_rw *)r->priv)->done
commands
  printf "vmm_blockdev_complete_request(): r->completed = %p = ", r->completed
  if r->completed == vmm_completion_complete
    printf "vmm_completion_complete\n"
  end
  if r->completed == blockdev_rw_completed
    printf "blockdev_rw_completed\n"
  end
  cont
end

b vmm_blockdev.c:130
commands
  printf "vmm_blockdev_complete_request(): r->bdev = %p => NULL", r->bdev
  cont
end

#  r->completed(vmm_request *r) -> blockdev_rw_completed(r) -> vmm_completion_complete(vmm_completion* cmpl=((blockdev_rw *)r->priv)->done) -> __vmm_waitqueue_wakefirst(&cmpl->wq) -> __vmm_waitqueue_wake(wq, vcpu)
b 'core/block/vmm_blockdev.c':blockdev_rw_completed if $rw_done == &((struct blockdev_rw *)req->priv)->done
commands
  printf "WAKEUP requester ===> *(struct completion*)%p = ", $rw_done
  p *$rw_done
  set $off = (off_t)&((struct vmm_vcpu*)0)->wq_head
  dlist $rw_done->wq.vcpu_list $off "p ((struct vmm_vcpu*)%p)->name"
  cont
end
b vmm_completion_complete if $rw_done == cmpl
commands
  cont
end

#  __blockdev_done_request((vmm_request_queue *)r->bdev->rq)
    b vmm_completion.c:89 if cmpl == $rw_done
    commands
      printf "!!!! &rw.done=0x%08x rw.done=", cmpl
      p/x *cmpl
      stat_mterm
      cont
    end

    b vmm_completion.c:91 if cmpl == $rw_done
    commands
      printf "__vmm_waitqueue_wakefirst(&cmpl->wq): rc=%d\n", rc
      stat_mterm
      cont
    end

b vmm_blockrq.c:83
commands
  printf "blockrq_queue_rw(): bowrk->is_rw = TRUE: wq_pending_list ... \n"
  set $off = (off_t)&((struct blockrq_work*)0)->head
  dlist brq->wq_pending_list $off "p *((struct blockrq_work*)%p)->d.rw.r"
  printf "blockrq_queue_rw(): (struct vmm_request*)bwork->d.rw.r @brq->wq->work_list ###\n"
  set $off_bw = (off_t)&((struct blockrq_work*)0)->work.head
  dlist brq->wq->work_list $off_bw "p *((struct blockrq_work*)%p)->d.rw.r"
  cont
end

b vmm_blockrq.c:115
commands
  printf "blockrq_queue_work(): bowrk->is_rw = FALSE: wq_pending_list ... \n"
  set $off = (off_t)&((struct blockrq_work*)0)->head
  dlist brq->wq_pending_list $off "p *((struct blockrq_work*)%p)->d.rw.r"
  printf "blockrq_queue_rw(): (struct vmm_request*)bwork->d.rw.r @brq->wq->work_list ###\n"
  set $off_bw = (off_t)&((struct blockrq_work*)0)->work.head
  dlist brq->wq->work_list $off_bw "p *((struct blockrq_work*)%p)->d.rw.r"
  cont
end

b vmm_scheduler.c:531
commands
  if vcpu->name[0] == 'm' && vcpu->name[1] == 'm' && vcpu->name[2] == 'c'
    printf "vmm_scheduler_switch(schedp, schedp->irq_regs): "
    p schedp->current_vcpu->name
    printf " -> "
    p vcpu->name
  else
    cont
  end
end


# ---- disable all break points until `XVisor# vfs guest_load` command input.
disable

# trap XVisor# vfs guest_load guest0 0x400a0000 /loader.bin
b cmd_vfs_load
commands
  enable
  cont
end

# set scheduler-locking on

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment