summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Scherle2022-06-27 18:30:05 +0200
committerMichael Scherle2022-06-27 18:30:05 +0200
commit022d10cf036570d60410e9c51e626b4ffe73e003 (patch)
treefb4071841934db8865b94c4c0c533afd0507c6fb
parentchanged : to = in cow status (diff)
downloaddnbd3-022d10cf036570d60410e9c51e626b4ffe73e003.tar.gz
dnbd3-022d10cf036570d60410e9c51e626b4ffe73e003.tar.xz
dnbd3-022d10cf036570d60410e9c51e626b4ffe73e003.zip
redme expanded
-rw-r--r--src/fuse/cowDoc/img/readrequest.svg4
-rw-r--r--src/fuse/cowDoc/readme.md214
-rw-r--r--src/fuse/cowfile.c168
3 files changed, 291 insertions, 95 deletions
diff --git a/src/fuse/cowDoc/img/readrequest.svg b/src/fuse/cowDoc/img/readrequest.svg
new file mode 100644
index 0000000..a16f95c
--- /dev/null
+++ b/src/fuse/cowDoc/img/readrequest.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Do not edit this file with editors other than diagrams.net -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="719px" height="701px" viewBox="-0.5 -0.5 719 701" content="&lt;mxfile host=&quot;app.diagrams.net&quot; modified=&quot;2022-06-27T15:42:31.682Z&quot; agent=&quot;5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36 OPR/87.0.4390.45&quot; etag=&quot;_RkRrWUXEJff4oZ7Tmkg&quot; version=&quot;20.0.3&quot;&gt;&lt;diagram id=&quot;otKvBIWVLEUd5MDrhZ-X&quot; name=&quot;Page-1&quot;&gt;5VpZc5swEP4tffBjOiAO48fm6jHpTGfcmTSPspENLSAihI376yuBZA45NrGxoclMxmFXu5LY3W8lrRgZN2H2mcDY+45dFIyA5mYj43YEgG4CMOJ/mrspOOOJVTCWxHeFUMmY+n+RYGqCm/ouSmqCFOOA+nGdOcdRhOa0xoOE4HVdbIGD+qgxXCKFMZ3DQOU++i71Cq4DxiX/C/KXnhxZtydFSwilsHiTxIMuXldYxt3IuCEY0+IpzG5QwI0n7VLo3b/Qup0YQRFto4BW8ZRkP52Hr4+mt/LJ+ttmdqWbRTcrGKTijcVs6UaaALnMIoLEhHp4iSMY3JXca4LTyEV8HI1RpcwDxjFj6oz5G1G6Ee6FKcWM5dEwEK0LHFHRqPMuijnwgV98WcFKcErmaM8bGiJoIFkiukdusnUJi2WEQ0TJhukRFEDqr+rzgCKolls5ofqJELipCMTYj2hS6fkHZzABgQ/LFMEh0KHbNR+yh6JHSVWmVrJyP7/C54bicoKgm7/rc4oSqgRA6V7uq7XnUzSNYW71NUN93ZWQzIUnTbD15AoRirL9vlRtLxRMp24kabN1iUddgsyrYFHK7fJWxcJHGFBTLLiAQYLeGHLGLZEDToXOSc4Y70hgdsDme53EMKr5w35OebLNbXaV5Eb7xAR0Lc5yy8l29rTk/2cBnv9hAlyZ62uMhnxCTACGPO6LX5XMx58R2RFeLBJEq4pBMY6GIlc22oJ3X8y70FSx6OFwliaHcdgB8GQ22gKvLfKccyEPOIq3KUkHATxmU7L5JRpz4ol3/tGS5G0mBiuojaQyn27V2HNFi1GlEiekTocgd9qC3OwT5AZ4Fxm3rTOMF3B7GWeoGOw84354l/nWAkPLt7qKu6Hk2w5hN2kJO71X2BmT4ebA7eJXWe+easvd7sWvByca4xOdeNRBz9Tq0J40zuqK+AnStnVIfK/8eQ6davB2tmj8p9neaJ79Qe/Z3n4P2V6XZcSD6d7qM90Da7jpvg9v9HsAkdO8ZJlh+CmrdSnufClrV/nnbQHEagmQU/c1p/lBzVYhZoPy2xr2E6GML9Ai0hv+uXwhy2gbt/bZCllqEb6vpbbcu7+ucKWcAUQhSz5fuJDVtlp98qq+e1PduKOw9EbkFPMXSo3g6WB7DdSt2xvLg8Bs6WCn112bep86oDzYLDD1nweNYcbtsTmxy3hvW9Do5eK6me4OVCga4he55gZqyUHcc+fwS8qNdu/7EcvuHYfD/A7k2Eu1DnFotD2g9oLDMXgdEJvyl/ngRD08N5G4IDjk3kCEAWsAK+MAEKmebIXRXBypB4Wev9FpVgZsp6X9jvhIh5HlV3NFjJbfHhp3/wA=&lt;/diagram&gt;&lt;/mxfile&gt;" style="background-color: rgb(255, 255, 255);"><defs/><g><path d="M 520 50 L 520 130 L 446.37 130" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 441.12 130 L 448.12 126.5 L 446.37 130 L 448.12 133.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="460" y="10" width="120" height="40" rx="16.8" ry="16.8" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 30px; margin-left: 461px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">read request</div></div></div></foreignObject><text x="520" y="34" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">read request</text></switch></g><path d="M 200 490 L 200 523.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 200 528.88 L 196.5 521.88 L 200 523.63 L 203.5 521.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 510px; margin-left: 200px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">false</div></div></div></foreignObject><text x="200" y="513" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">false</text></switch></g><path d="M 200 410 L 260 450 L 200 490 L 140 450 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 450px; margin-left: 141px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><span style="font-size: 10px;">block == local &amp;&amp;<br />offset &lt; endoffset</span></div></div></div></foreignObject><text x="200" y="454" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">block == local &amp;&amp;...</text></switch></g><path d="M 620 450 L 640 450 L 640 340 L 626.37 340" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 621.12 340 L 628.12 336.5 L 626.37 340 L 628.12 343.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 395px; margin-left: 640px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">true</div></div></div></foreignObject><text x="640" y="398" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">true</text></switch></g><path d="M 560 490 L 560 523.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 560 528.88 L 556.5 521.88 L 560 523.63 L 563.5 521.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 510px; margin-left: 560px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">false</div></div></div></foreignObject><text x="560" y="513" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">false</text></switch></g><path d="M 560 410 L 620 450 L 560 490 L 500 450 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 450px; margin-left: 501px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><span style="font-size: 10px;">block != local &amp;&amp;<br />offset &lt; endoffset</span></div></div></div></foreignObject><text x="560" y="454" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">block != local &amp;&amp;...</text></switch></g><path d="M 380 170 L 380 203.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 380 208.88 L 376.5 201.88 L 380 203.63 L 383.5 201.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 190px; margin-left: 380px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">true</div></div></div></foreignObject><text x="380" y="193" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">true</text></switch></g><path d="M 380 90 L 380 60 L 20 60 L 20 620 L 380 620 L 380 643.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 380 648.88 L 376.5 641.88 L 380 643.63 L 383.5 641.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 340px; margin-left: 20px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">false</div></div></div></foreignObject><text x="20" y="343" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">false</text></switch></g><path d="M 380 90 L 440 130 L 380 170 L 320 130 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 130px; margin-left: 321px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><span style="font-size: 10px;">offset &lt; endoffset</span></div></div></div></foreignObject><text x="380" y="134" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">offset &lt; endoffset</text></switch></g><path d="M 320 250 L 200 250 L 200 303.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 200 308.88 L 196.5 301.88 L 200 303.63 L 203.5 301.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 250px; margin-left: 230px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">true</div></div></div></foreignObject><text x="230" y="253" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">true</text></switch></g><path d="M 440 250 L 560 250 L 560 303.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 560 308.88 L 556.5 301.88 L 560 303.63 L 563.5 301.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 250px; margin-left: 530px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">false</div></div></div></foreignObject><text x="530" y="253" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">false</text></switch></g><path d="M 380 210 L 440 250 L 380 290 L 320 250 Z" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 250px; margin-left: 321px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><span style="font-size: 10px;">block == local</span></div></div></div></foreignObject><text x="380" y="254" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">block == local</text></switch></g><path d="M 200 370 L 200 403.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 200 408.88 L 196.5 401.88 L 200 403.63 L 203.5 401.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="140" y="310" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 340px; margin-left: 141px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">move to next block</div></div></div></foreignObject><text x="200" y="344" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">move to next block</text></switch></g><path d="M 140 450 L 120 450 L 120 340 L 133.63 340" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 138.88 340 L 131.88 343.5 L 133.63 340 L 131.88 336.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 395px; margin-left: 120px;"><div data-drawio-colors="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 10px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; background-color: rgb(255, 255, 255); white-space: nowrap;">true</div></div></div></foreignObject><text x="120" y="398" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="10px" text-anchor="middle">true</text></switch></g><path d="M 560 370 L 560 403.63" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 560 408.88 L 556.5 401.88 L 560 403.63 L 563.5 401.88 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="500" y="310" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 340px; margin-left: 501px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">move to next block</div></div></div></foreignObject><text x="560" y="344" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">move to next block</text></switch></g><path d="M 140 560 L 60 560 L 60 130 L 313.63 130" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 318.88 130 L 311.88 133.5 L 313.63 130 L 311.88 126.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="140" y="530" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 560px; margin-left: 141px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">read blocks local</div></div></div></foreignObject><text x="200" y="564" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">read blocks local</text></switch></g><path d="M 620 560 L 700 560 L 700 130 L 446.37 130" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 441.12 130 L 448.12 126.5 L 446.37 130 L 448.12 133.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><rect x="500" y="530" width="120" height="60" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 560px; margin-left: 501px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">read blocks from server</div></div></div></foreignObject><text x="560" y="564" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">read blocks from ser...</text></switch></g><rect x="320" y="650" width="120" height="40" rx="16.8" ry="16.8" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 670px; margin-left: 321px;"><div data-drawio-colors="color: rgb(0, 0, 0); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">read done</div></div></div></foreignObject><text x="380" y="674" fill="rgb(0, 0, 0)" font-family="Helvetica" font-size="12px" text-anchor="middle">read done</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Text is not SVG - cannot display</text></a></switch></svg> \ No newline at end of file
diff --git a/src/fuse/cowDoc/readme.md b/src/fuse/cowDoc/readme.md
index 0c63e60..7fb487c 100644
--- a/src/fuse/cowDoc/readme.md
+++ b/src/fuse/cowDoc/readme.md
@@ -10,7 +10,8 @@
# Introduction
-This extension to the fuse dnbd3 client allows it to mount images writable. The changes to an writeable mounted image will be stored in a separate files (also called Copy on Write (Cow)) on the client computer. These changes are uploaded in the background to the cow server. Once the user unmounts the images all remaining changes will be uploaded. Then the image will be merged on the server (if set so in the startup parameters).
+This extension to the fuse dnbd3 client allows it to mount images writable. The changes to a writable mounted image will be stored in a separate file (also called Copy on Write (Cow)) on the client computer. These changes are uploaded in the background to the cow server. Once the user unmounts the images, all remaining changes will be uploaded. Then the image will be merged on the server (if set so in the startup parameters).
+
# Usage
@@ -18,23 +19,101 @@ This extension to the fuse dnbd3 client allows it to mount images writable. The
### New Parameters
- `-c <path>` Enables the cow functionality, the argument sets the path for the temporary `.meta` and `.data` file in which the writes are stored
- `-C <address>` sets the address of the cow server. The cow server is responsible for merging the original image with the changes from the client.
-- `-L <path>` Similar to `-c <path>` but instead of creating a new session it loads an existing from the given path.
+- `-L <path>` Similar to `-c <path>` but instead of creating a new session, it loads an existing from the given path.
- `-m` if set, the client will request a merge after the image is unmounted and all change are uploaded.
Example parameters for creating a new cow session:
```
-./dnbd3-fuse "/home/user/VMs/mount" -f -h localhost -i test -c "/home/user/temp" -C "192.168.178.20:5000"
+./dnbd3-fuse "/home/user/VMs/mount" -f -h localhost -i imagename -c "/home/user/temp" -C "192.168.178.20:5000"
```
# Implementation Details
+
+
+
+## Data strucure
+<!---
+Split into metadata and data
+
+!-->
+
+The datastructe is split in to main parts. The actual data from the write on the image and its corresponding metadata. Its also important to distinguish between a dnbd3 block which is 4096byte and and cow block which groups 320 dnbd3 blocks together. An cow block has an `cow_block_metadata_t` struct which holds the corresponding meta data. The metadata is used to determine if and block has bin written on, where this block is stored in the data file, when it was last modified and when it was uploaded. But more later.
+
+
+### Blockmetadata
+
+![Datastructure](img/Bild1.jpg)
+
+The data structure for storing metadata about blocks contains a Layer 1(L1) and a Layer 2 (L2). L1 contains pointers to the L2's.
+The whole L1 array is initialized at the beginning and cannot be resized, so the size of the L1 array limits the total size of the image.
+The L2's are dynamically created once needed. So at the beginning, all L1 pointer will be null. The L2's are arrays which contains 1024
+`cow_block_metadata_t` structs.
+
+```C
+typedef struct cow_block_metadata
+{
+ atomic_int_least64_t offset;
+ atomic_uint_least64_t timeChanged;
+ atomic_uint_least64_t timeUploaded;
+ atomic_char bitfield[40];
+} cow_block_metadata_t;
+```
+Each `cow_block_metadata_t` contains a 40 byte so 320 bit bitfield. The bitfield indicates whether the corresponding data contains data or not. For e.g. if the bitfield starts with 01.., the first 4096 contains not data and the next 4096 contain data.
+So each `cow_block_metadata_t` stores the metadata of up to 320*4096 byte if all bits are set to 1. The offset is the offset where in the data file is the corresponding data stored. The timeChanged property contains the unix when the block was last modified, and the timeUploaded property contains the unix time when the block was last uploaded. It's 0 if the block was never uploaded.
+
+
+The L2 arrays and `cow_block_metadata_t` are sorted to original Offsets. So the first L1 pointer, thus the first L2 array, addresses the first 1024 * 320 * 4096 Bytes (L2Size * bitfieldsize * DNBD3Blocksize) of Data and so on.
+
+
+So for example, to get the `cow_block_metadata_t` for offset 4033085440 you would take L1[3] since
+```
+4033085440 / ( COW_L2_STORAGE_CAPACITY ) ≈ 3.005
+```
+
+ Then you would take the fifth `cow_block_metadata_t` in the L2 array because of
+```
+(4033085440 mod COW_L2_STORAGE_CAPACITY) / COW_METADATA_STORAGE_CAPACITY
+```
+Where:
+```
+COW_L2_STORAGE_CAPACITY = 1024 * 320 * 4096
+COW_METADATA_STORAGE_CAPACITY = 320 * 4096
+```
+
+
+
+### Read Request
+
+
+
+For an read request, for every 4096byte block it will be checked if the block is already local on the computer (therefore was already written to before).
+If so it will be read from disk, otherwise it will be requested from the dnbd3 server. To increase performance, multiple following blocks are also local/non local like the block before will be combined to to one larger reads from disc respectively one larger request from the server.
+
+![readrequest](img/readrequest.svg)
+
+The graph shown above is somewhat simplified for better visibility. The reads from the server happen async. So it will not be waited for the server to respond, rather the it will move on with the next blocks. As soon as the respond from the server is finished, the data will be written in
+the fuse buffer. Each request to the dnbd3 server will increase the `workCounter` variable by one and every time a request is done it will be decreased by one. Once `workCounter` is 0 again, fuse_request will be returned.
+
+Also on the local side, it has to break the loop once the end of an `cow_block_metadata_t` is reached, since the next data offset of the next `cow_block_metadata_t` is very likely not directly after it in the data file.
+### Write Request
+
+
+For the write request, if the start or the end or the end does not align with a multiple of 4096, then the start and/or end block must be padded.
+Because every 4096byte block needs complete data, since if the bit in the bitfield for that block is set, all the data will be read locally.
+To pad the block, if its still in the range of the original image size, the missing bytes will be requested from the dnbd3 server. If its outside of the original image (because the image grown in size) then the missing bytes will be padded with 0.
+The write request will write compute the corresponding `cow_block_metadata_t` from the offset. If the corresponding `cow_block_metadata_t` does not exist yet it will be created. The data will be written in the data file, at the offset which is stored in the `cow_block_metadata_t`.
+Then the corresponding bit in the bitfields will be set and the `timeChanged` will be updated. If there is more data to write, the next `cow_block_metadata_t` will be computed and the steps above will be repeated.
+The `workCounter` variable is used here again to make sure that if padding was needed it is done before the fuse request returns.
+
+
## Files
-If a new CoW session is started, a new `meta`, `data` and `status.txt` file is created.
+If a new CoW session is started, a new `meta`, `data` and if set so in the Command line arguments a `status.txt` file is created.
### status.txt
-While the cow session ist active the file contains:
+While the cow session is active, the file contains:
```
uuid: <uuid>
@@ -43,7 +122,7 @@ state: active
- The `uuid` is the session uuid, which the cow server uses to identify the session.
-Once the user unmounts the image the file contains:
+Once the user unmounts the image, the file contains:
```
uid: <uuid>
@@ -56,36 +135,35 @@ totalBlocks: <number>
- `totalBlocks` is the total Number of Blocks which need to be uploaded.
-Once all blocks are uploaded the state will be set to `done`.
+Once all blocks are uploaded, the state will be set to `done`.
-### meta.dat
+### meta
The `meta` file contains the following header:
```C
// cowfile.h
-typedef struct __attribute__( ( packed ) ) cowfile_metadata_header
+typedef struct cowfile_metadata_header
{
- uint64_t magicValue; // 8byte
- atomic_uint_fast64_t imageSize; // 8byte
- int32_t version; // 4byte
- int32_t blocksize; // 4byte
- uint64_t originalImageSize; // 8byte
- uint64_t metaDataStart; // 8byte
- int32_t bitfieldSize; // 4byte
- int32_t nextL2; // 4byte
- atomic_size_t metadataFileSize; // 8byte
- atomic_size_t dataFileSize; // 8byte
- uint64_t maxImageSize; // 8byte
- uint64_t creationTime; // 8byte
- uuid_t uuid; // 16byte
- char imageName[200]; // 200byte
+ uint64_t magicValue; // 8byte
+ atomic_uint_least64_t imageSize; // 8byte
+ int32_t version; // 4byte
+ int32_t blocksize; // 4byte
+ uint64_t originalImageSize; // 8byte
+ uint64_t metaDataStart; // 8byte
+ int32_t bitfieldSize; // 4byte
+ int32_t nextL2; // 4byte
+ atomic_uint_least64_t metadataFileSize; // 8byte
+ atomic_uint_least64_t dataFileSize; // 8byte
+ uint64_t maxImageSize; // 8byte
+ uint64_t creationTime; // 8byte
+ char uuid[40]; // 40byte
+ char imageName[200]; // 200byte
} cowfile_metadata_header_t;
-
```
-
+After this header at byte 8192 starts the l1 and then the l2 data structure mentioned above.
### data
-The `data` files contains
+The `data` files contains the magicValue and at the 40 * 8 * 4096 Offset(capacity of one cowfile_metadata_header_t) starts the first block data.
@@ -96,13 +174,57 @@ The magic values in both files are used to ensure that a suitable file is read a
#define COW_FILE_META_MAGIC_VALUE ((uint64_t)0xEBE44D6E72F7825E) // Magic Value to recognize a Cow meta file
#define COW_FILE_DATA_MAGIC_VALUE ((uint64_t)0xEBE44D6E72F7825F) // Magic Value to recognize a Cow data file
```
-## Data strucure
-![Datastructure](img/Bild1.jpg)
+
+
+### Threads
+This extension uses two new threads:
+```
+tidCowUploader
+tidStatUpdater
+```
+```tidCowUploader``` is the thread that uploads blocks to the cow server.
+
+```tidStatUpdater``` updates the stats in stdout or the stats files
+(depending on parameters).
+
+### Locks
+
+This extension uses a new lock ```cow.l2CreateLock```. It is used when a new L2 array is allocated.
+
+
+
+### Config Variables
+The follwoing configuration variables have been added to ```config.h```.
+```c
+//config.h
+// +++++ COW +++++
+#define COW_BITFIELD_SIZE 40 // NEVER CHANGE THIS OR THE WORLD WILL ALSO END!
+#define COW_FILE_META_MAGIC_VALUE ((uint64_t)0xEBE44D6E72F7825E) // Magic Value to recognize a Cow meta file
+#define COW_FILE_DATA_MAGIC_VALUE ((uint64_t)0xEBE44D6E72F7825F) // Magic Value to recognize a Cow data file
+#define COW_MIN_UPLOAD_DELAY 60 // in seconds
+#define COW_STATS_UPDATE_TIME 5 // time in seconds the cow status files gets updated (while uploading blocks)
+#define COW_MAX_PARALLEL_UPLOADS 10 // maximum number of parallel uploads
+#define COW_MAX_PARALLEL_BACKGROUND_UPLOADS 2 // maximum number of parallel uploads while the image is still mounted
+#define COW_URL_STRING_SIZE 500 // Max string size for an url
+#define COW_SHOW_UL_SPEED 1 // enable display of ul speed in cow status file
+// +++++ COW API Endpoints +++++
+#define COW_API_CREATE "%s/api/File/Create"
+#define COW_API_UPDATE "%s/api/File/Update?guid=%s&BlockNumber=%lu"
+#define COW_API_START_MERGE "%s/api/File/StartMerge"
+```
+
+- ```COW_MIN_UPLOAD_DELAY``` defines the minimum time in seconds that must have elapsed since the last modification of a cow block before it is uploaded.
+
+- ```COW_STATS_UPDATE_TIME``` defines the update frequency in seconds of the stdout print/ stats file update. Setting this to low could impact the performance since it hast to loop over all blocks.
+- ```COW_MAX_PARALLEL_UPLOADS``` defines to maximal number of parallel block uploads. These number is used once the image hast been dismounted and the final blocks are uploaded
+- ```COW_MAX_PARALLEL_BACKGROUND_UPLOADS``` defines to maximal number of parallel block uploads. These number is used will the image is still mounted and the user is still using it.
+
# REST Api
To transfer the data to the cow server, the following rest api is used:
+
### /api/File/Create
#### POST
@@ -112,6 +234,9 @@ To transfer the data to the cow server, the following rest api is used:
| ---- | ----------- |
| 200 | Success |
+This request is used once a new cow session is created. The returned guid is used in all later requests to identify the session.
+
+
### /api/File/Update
#### POST
@@ -128,15 +253,27 @@ To transfer the data to the cow server, the following rest api is used:
| ---- | ----------- |
| 200 | Success |
+Used for uploading a block of data. The blocknumber is the absolute block number. The body contains an "application/octet-stream" where the first bytes are the bitfield directly followed by the actual blockdata.
+
### /api/File/StartMerge
+#### POST
+##### Responses
+
+| Code | Description |
+| ---- | ----------- |
+| 200 | Success |
+Used to start the merging on the server.
+
+### /api/File/GetTopModifiedBlocks
+
#### GET
##### Parameters
| Name | Located in | Description | Required | Schema |
| ---- | ---------- | ----------- | -------- | ---- |
| guid | query | | Yes | string (uuid) |
-| fileSize | query | | Yes | long |
+| amount | query | | Yes | integer |
##### Responses
@@ -144,7 +281,9 @@ To transfer the data to the cow server, the following rest api is used:
| ---- | ----------- |
| 200 | Success |
-### /api/File/Satus
+This request returns a list that contains Block Ids and the amount of times this block got uploaded, sorted by the amount of uploads. This is useful to adjusting the `COW_MIN_UPLOAD_DELAY`.
+
+### /api/File/Status
#### GET
##### Parameters
@@ -159,19 +298,28 @@ To transfer the data to the cow server, the following rest api is used:
| ---- | ----------- |
| 200 | Success |
-## Models
+Returns the SessionStatus Model, which gives information about the session.
+
+### Models
+
+#### BlockStatistics
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| blockNumber | integer | | Yes |
+| modifications | integer | | Yes |
#### SessionState
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
-| SessionState | string | | Yes |
+| SessionState | string | | |
#### SessionStatus
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
-| state | string | _Enum:_ `"Copying"`, `"Active"`, `"Merging"`, `"Done"` | Yes |
+| state | string | _Enum:_ `"Copying"`, `"Active"`, `"Merging"`, `"Done"`, `"Failed"` | Yes |
| imageName | string | | Yes |
| originalImageVersion | integer | | Yes |
| newImageVersion | integer | | Yes |
diff --git a/src/fuse/cowfile.c b/src/fuse/cowfile.c
index 947682f..e48f770 100644
--- a/src/fuse/cowfile.c
+++ b/src/fuse/cowfile.c
@@ -188,23 +188,6 @@ bool createSession( const char *imageName, uint16_t version )
return true;
}
-
-void print_bin( char a )
-{
- for ( int i = 0; i < 8; i++ ) {
- printf( "%d", !!( ( a << i ) & 0x80 ) );
- }
-}
-
-void print_bin_arr( char *ptr, int size )
-{
- for ( int i = 0; i < size; i++ ) {
- print_bin( ptr[i] );
- printf( " " );
- }
- printf( "\n" );
-}
-
/**
* @brief Implementation of CURLOPT_READFUNCTION, this function will first send the bitfield and
* then the block data in one bitstream. this function is usually called multiple times per block,
@@ -337,7 +320,7 @@ int progress_callback( void *clientp, __attribute__( ( unused ) ) curl_off_t dlT
}
/**
- * @brief
+ * @brief Updates the status to the stdout/statfile depending on the startup parameters.
*
* @param inQueue Blocks that have changes old enough to be uploaded.
* @param modified Blocks that have been changed but whose changes are not old enough to be uploaded.
@@ -378,7 +361,12 @@ void updateCowStatsFile( uint64_t inQueue, uint64_t modified, uint64_t idle, cha
}
}
-
+/**
+ * @brief Starts the upload of a given block
+ *
+ * @param cm Curl_multi
+ * @param curlUploadBlock cow_curl_read_upload_t containing the data for the block to upload
+ */
bool addUpload( CURLM *cm, cow_curl_read_upload_t *curlUploadBlock)
{
CURL *eh = curl_easy_init();
@@ -408,16 +396,28 @@ bool addUpload( CURLM *cm, cow_curl_read_upload_t *curlUploadBlock)
return true;
}
+/**
+ * @brief After an upload completes, either successful or unsuccessful this
+ * function cleans everything up. If unsuccessful and there are some tries left
+ * retries to upload the block.
+ *
+ * @param cm Curl_multi
+ * @param msg CURLMsg
+ * @return true returned if upload was successful or retries still possible
+ * @return false returned if upload was unsuccessful
+ */
bool finishUpload( CURLM *cm, CURLMsg *msg )
{
bool status = true;
cow_curl_read_upload_t *curlUploadBlock;
CURLcode res;
+ CURLcode res2;
res = curl_easy_getinfo( msg->easy_handle, CURLINFO_PRIVATE, &curlUploadBlock );
- if ( res != CURLE_OK ) {
- logadd( LOG_ERROR, "ERROR" );
- }
- if ( msg->msg != CURLMSG_DONE ) {
+
+ long http_code = 0;
+ res2 = curl_easy_getinfo( msg->easy_handle, CURLINFO_RESPONSE_CODE, &http_code );
+
+ if ( res != CURLE_OK || res2 != CURLE_OK || http_code != 200 ||msg->msg != CURLMSG_DONE ) {
curlUploadBlock->fails++;
logadd( LOG_ERROR, "COW_API_UPDATE failed %i/5: %s\n", curlUploadBlock->fails,
curl_easy_strerror( msg->data.result ) );
@@ -431,15 +431,6 @@ bool finishUpload( CURLM *cm, CURLMsg *msg )
goto CLEANUP;
}
-
- long http_code = 0;
- curl_easy_getinfo( msg->easy_handle, CURLINFO_RESPONSE_CODE, &http_code );
- if ( http_code != 200 ) {
- logadd( LOG_ERROR, "COW_API_UPDATE failed http: %ld\n", http_code );
- curl_easy_reset( curl );
- return false;
- }
-
// everything went ok, update timeUploaded
curlUploadBlock->block->timeUploaded = curlUploadBlock->time;
totalBlocksUploaded++;
@@ -451,7 +442,18 @@ CLEANUP:
return status;
}
-bool MessageHandler( CURLM *cm, int *activeUploads, bool breakIfNotMax, bool ignoreMinUploadDelay )
+/**
+ * @brief
+ *
+ * @param cm Curl_multi
+ * @param activeUploads ptr to integer which holds the number of current uploads
+ * @param breakIfNotMax will return as soon as there are not all upload slots used, so they can be filled up.
+ * @param foregroundUpload used to determine the number of max uploads. If true COW_MAX_PARALLEL_UPLOADS will be the limit,
+ * else COW_MAX_PARALLEL_BACKGROUND_UPLOADS.
+ * @return true returned if all upload's were successful
+ * @return false returned if one ore more upload's failed.
+ */
+bool MessageHandler( CURLM *cm, int *activeUploads, bool breakIfNotMax, bool foregroundUpload )
{
CURLMsg *msg;
int msgsLeft = -1;
@@ -464,10 +466,11 @@ bool MessageHandler( CURLM *cm, int *activeUploads, bool breakIfNotMax, bool ign
status = false;
}
}
- if ( breakIfNotMax && *activeUploads <= ( ignoreMinUploadDelay ? COW_MAX_PARALLEL_UPLOADS
+ if ( breakIfNotMax && *activeUploads <= ( foregroundUpload ? COW_MAX_PARALLEL_UPLOADS
: COW_MAX_PARALLEL_BACKGROUND_UPLOADS ) ) {
break;
}
+ // ony wait if there are active uploads
if ( *activeUploads ) {
curl_multi_wait( cm, NULL, 0, 1000, NULL );
}
@@ -479,7 +482,11 @@ bool MessageHandler( CURLM *cm, int *activeUploads, bool breakIfNotMax, bool ign
/**
* @brief loops through all blocks and uploads them.
*
- * @param lastLoop if set to true, all blocks which are not uploaded will be uploaded, ignoring their timeChanged
+ * @param ignoreMinUploadDelay If true uploads all blocks that have changes while
+ * ignoring COW_MIN_UPLOAD_DELAY
+ * @param cm Curl_multi
+ * @return true if all blocks uploaded successful
+ * @return false if one ore more blocks failed to upload
*/
bool uploaderLoop( bool ignoreMinUploadDelay, CURLM *cm )
{
@@ -526,7 +533,10 @@ DONE:
-
+/**
+ * @brief Computes the data for the status to the stdout/statfile every COW_STATS_UPDATE_TIME seconds.
+ *
+ */
void * cowfile_statUpdater(__attribute__( ( unused ) ) void *something ) {
uint64_t lastUpdateTime = time(NULL);
@@ -610,6 +620,13 @@ void *cowfile_uploader( __attribute__( ( unused ) ) void *something )
return NULL;
}
+/**
+ * @brief Create a Cow Stats File an inserts the session guid
+ *
+ * @param path where the file is created
+ * @return true
+ * @return false if failed to create or to write into the file
+ */
bool createCowStatsFile( char *path )
{
char pathStatus[strlen( path ) + 12];
@@ -741,13 +758,13 @@ bool cowfile_init( char *path, const char *image_Name, uint16_t imageVersion, at
pthread_create( &tidStatUpdater, NULL, &cowfile_statUpdater, NULL );
return true;
}
+
/**
* @brief loads an existing cow state from the meta & data files
*
* @param path where the meta & data file is located
* @param imageSizePtr
*/
-
bool cowfile_load( char *path, atomic_uint_fast64_t **imageSizePtr, char *serverAddress, int isForeground )
{
foreground = isForeground;
@@ -885,11 +902,10 @@ static void writeData( const char *buffer, ssize_t size, size_t netSize, cow_req
}
/**
- * @brief
+ * @brief Increases the metadata->dataFileSize by COW_METADATA_STORAGE_CAPACITY.
+ * The space is not reserved on disk.
*
- * @param block
- * @return true
- * @return false
+ * @param block for which the space should be reserved.
*/
static bool allocateMetaBlockData( cow_block_metadata_t *block )
{
@@ -937,6 +953,15 @@ static bool createL2Block( int l1Offset )
return true;
}
+/**
+ * @brief Is called once an fuse write request ist finished.
+ * Calls the corrsponding fuse reply depending on the type and
+ * success of the request.
+ *
+ * @param req fuse_req_t
+ * @param cowRequest
+ */
+
static void finishWriteRequest( fuse_req_t req, cow_request_t *cowRequest )
{
if ( cowRequest->errorCode != 0 ) {
@@ -958,6 +983,12 @@ static void finishWriteRequest( fuse_req_t req, cow_request_t *cowRequest )
free( cowRequest );
}
+/**
+ * @brief Called after the padding data was received from the dnbd3 server.
+ * The data from the write request will be combined witch the data from the server
+ * so that we get a full DNBD3_BLOCK and is then written on the disk.
+ * @param sRequest
+ */
static void writePaddedBlock( cow_sub_request_t *sRequest )
{
//copy write Data
@@ -973,9 +1004,10 @@ static void writePaddedBlock( cow_sub_request_t *sRequest )
free( sRequest );
}
-// TODO if > remote pad 0
/**
- * @brief
+ * @brief If an block does not start or finishes on an multiple of DNBD3_BLOCK_SIZE, the blocks needs to be
+ * padded. If this block is inside the original image size, the padding data will be read fro the server
+ * otherwise it will be padded with 0 since the it must be the block at the end of the image.
*
*/
static void padBlockFromRemote( fuse_req_t req, off_t offset, cow_request_t *cowRequest, const char *buffer,
@@ -1018,12 +1050,25 @@ static void padBlockFromRemote( fuse_req_t req, off_t offset, cow_request_t *cow
}
}
+/**
+ * @brief Will be called after a dnbd3_async_t is finished.
+ * Calls the corrsponding callback function, either writePaddedBlock or readRemoteData
+ * depending if the original fuse request was a write or read.
+ *
+ */
void cowfile_handleCallback( dnbd3_async_t *request )
{
cow_sub_request_t *sRequest = container_of( request, cow_sub_request_t, dRequest );
sRequest->callback( sRequest );
}
+
+/**
+ * @brief called once dnbd3_async_t is finished. Increases bytesWorkedOn by the number of bytes
+ * this request had. Also checks if it was the last dnbd3_async_t to finish the fuse request, if
+ * so replys to fuse and cleans up the request.
+ *
+ */
void readRemoteData( cow_sub_request_t *sRequest )
{
atomic_fetch_add( &sRequest->cowRequest->bytesWorkedOn, sRequest->dRequest.length );
@@ -1038,7 +1083,14 @@ void readRemoteData( cow_sub_request_t *sRequest )
}
-/// TODO move block padding in write
+/**
+ * @brief Implementation of a write request or an truncate.
+ *
+ * @param req fuse_req_t
+ * @param cowRequest
+ * @param offset Offset where the write starts,
+ * @param size Size of the write.
+ */
void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, size_t size )
{
if ( cowRequest->replyAttr ) {
@@ -1119,8 +1171,6 @@ void cowfile_write( fuse_req_t req, cow_request_t *cowRequest, off_t offset, siz
l1Offset++;
l2Offset = 0;
}
- // return to fuse either here or in remote reads/writes
- // increase file size if its now larger
if ( atomic_fetch_sub( &cowRequest->workCounter, 1 ) == 1 ) {
finishWriteRequest( req, cowRequest );
}
@@ -1156,25 +1206,14 @@ static void readRemote( fuse_req_t req, off_t offset, ssize_t size, char * buffe
}
}
-void byte_to_binary( atomic_char *a )
-{
- for ( int i = 0; i < 8; i++ ) {
- char tmp = *a;
- printf( "%d", !!( ( tmp << i ) & 0x80 ) );
- }
- printf( "\n" );
-}
-
-/*
-Maybe optimize that remote reads are done first
-*/
/**
- * @brief
+ * @brief Reads data at given offset. If the data are available locally,
+ * they are read locally, otherwise they are requested remotely.
*
- * @param req Fuse request
+ * @param req fuse_req_t
* @param size of date to read
- * @param offset
- * @return uint64_t
+ * @param offset offset where the read starts.
+ * @return uint64_t Number of bytes read.
*/
void cowfile_read( fuse_req_t req, size_t size, off_t offset )
{
@@ -1279,6 +1318,11 @@ fail:;
}
+/**
+ * @brief stops the StatUpdater and CowUploader threads
+ * and waits for them to finish, then cleans up curl.
+ *
+ */
void cowfile_close()
{
uploadLoop = false;