vbdev_lvol: external snapshot rpc interface
Add RPC interfaces for creation of esnap clone lvols. This also exercises esnap clone creation and various operations involving snapshots and clones of esnap clones to ensure that bdev_get_bdevs reports state correctly. Change-Id: Ib87d01026ef6e45203c4d9451759885a7be02d87 Signed-off-by: Mike Gerdts <mgerdts@nvidia.com> Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14978 Reviewed-by: Michal Berger <michal.berger@intel.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
aa209d4ecb
commit
68cde3b770
673
doc/img/lvol_esnap_clone.svg
Normal file
673
doc/img/lvol_esnap_clone.svg
Normal file
@ -0,0 +1,673 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="181.24mm"
|
||||
height="79.375mm"
|
||||
version="1.1"
|
||||
viewBox="0 0 181.24 79.375"
|
||||
id="svg172"
|
||||
sodipodi:docname="lvol_esnap_clone.svg"
|
||||
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<sodipodi:namedview
|
||||
id="namedview174"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="mm"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.7926966"
|
||||
inkscape:cx="338.59607"
|
||||
inkscape:cy="148.93764"
|
||||
inkscape:window-width="1351"
|
||||
inkscape:window-height="930"
|
||||
inkscape:window-x="762"
|
||||
inkscape:window-y="134"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g170" />
|
||||
<title
|
||||
id="title2">Thin Provisioning</title>
|
||||
<defs
|
||||
id="defs28">
|
||||
<marker
|
||||
id="marker2036"
|
||||
overflow="visible"
|
||||
orient="auto">
|
||||
<path
|
||||
transform="matrix(-.4 0 0 -.4 -4 0)"
|
||||
d="m0 0 5-5-17.5 5 17.5 5z"
|
||||
fill-rule="evenodd"
|
||||
stroke="#000"
|
||||
stroke-width="1pt"
|
||||
id="path4" />
|
||||
</marker>
|
||||
<marker
|
||||
id="marker1960"
|
||||
overflow="visible"
|
||||
orient="auto">
|
||||
<path
|
||||
transform="matrix(-.4 0 0 -.4 -4 0)"
|
||||
d="m0 0 5-5-17.5 5 17.5 5z"
|
||||
fill-rule="evenodd"
|
||||
stroke="#000"
|
||||
stroke-width="1pt"
|
||||
id="path7" />
|
||||
</marker>
|
||||
<marker
|
||||
id="marker1890"
|
||||
overflow="visible"
|
||||
orient="auto">
|
||||
<path
|
||||
transform="matrix(-.4 0 0 -.4 -4 0)"
|
||||
d="m0 0 5-5-17.5 5 17.5 5z"
|
||||
fill-rule="evenodd"
|
||||
stroke="#000"
|
||||
stroke-width="1pt"
|
||||
id="path10" />
|
||||
</marker>
|
||||
<marker
|
||||
id="marker1826"
|
||||
overflow="visible"
|
||||
orient="auto">
|
||||
<path
|
||||
transform="matrix(-.4 0 0 -.4 -4 0)"
|
||||
d="m0 0 5-5-17.5 5 17.5 5z"
|
||||
fill-rule="evenodd"
|
||||
stroke="#000"
|
||||
stroke-width="1pt"
|
||||
id="path13" />
|
||||
</marker>
|
||||
<marker
|
||||
id="marker1816"
|
||||
overflow="visible"
|
||||
orient="auto">
|
||||
<path
|
||||
transform="matrix(-.4 0 0 -.4 -4 0)"
|
||||
d="m0 0 5-5-17.5 5 17.5 5z"
|
||||
fill-rule="evenodd"
|
||||
stroke="#000"
|
||||
stroke-width="1pt"
|
||||
id="path16" />
|
||||
</marker>
|
||||
<marker
|
||||
id="Arrow1Mend"
|
||||
overflow="visible"
|
||||
orient="auto">
|
||||
<path
|
||||
transform="matrix(-.4 0 0 -.4 -4 0)"
|
||||
d="m0 0 5-5-17.5 5 17.5 5z"
|
||||
fill-rule="evenodd"
|
||||
stroke="#000"
|
||||
stroke-width="1pt"
|
||||
id="path19" />
|
||||
</marker>
|
||||
<marker
|
||||
id="marker11771-4-9"
|
||||
overflow="visible"
|
||||
orient="auto">
|
||||
<path
|
||||
transform="matrix(-.4 0 0 -.4 -4 0)"
|
||||
d="m0 0 5-5-17.5 5 17.5 5z"
|
||||
fill="#f00"
|
||||
fill-rule="evenodd"
|
||||
stroke="#ff2a2a"
|
||||
stroke-width="1pt"
|
||||
id="path22" />
|
||||
</marker>
|
||||
<marker
|
||||
id="marker1826-2-4-7-1-7"
|
||||
overflow="visible"
|
||||
orient="auto">
|
||||
<path
|
||||
transform="matrix(-.4 0 0 -.4 -4 0)"
|
||||
d="m0 0 5-5-17.5 5 17.5 5z"
|
||||
fill="#00f"
|
||||
fill-rule="evenodd"
|
||||
stroke="#00f"
|
||||
stroke-width="1pt"
|
||||
id="path25" />
|
||||
</marker>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata30">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Thin Provisioning</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(2.6458 2.3956)"
|
||||
id="g34">
|
||||
<rect
|
||||
x="-2.6458"
|
||||
y="-2.3956"
|
||||
width="181.24"
|
||||
height="79.375"
|
||||
fill="#fffffe"
|
||||
stroke-width=".26458"
|
||||
id="rect32" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(-3.9688 -4.6356)"
|
||||
id="g170">
|
||||
<g
|
||||
stroke="#000"
|
||||
id="g52">
|
||||
<g
|
||||
stroke-width=".26458"
|
||||
id="g48">
|
||||
<rect
|
||||
x="44.979"
|
||||
y="32.417"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="none"
|
||||
stroke-dasharray="0.52916663, 0.52916663"
|
||||
id="rect36" />
|
||||
<rect
|
||||
x="67.469"
|
||||
y="32.417"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="#d7d7f4"
|
||||
id="rect38" />
|
||||
<rect
|
||||
x="89.958"
|
||||
y="32.417"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="#d7d7f4"
|
||||
id="rect40" />
|
||||
<rect
|
||||
x="112.45"
|
||||
y="32.417"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="none"
|
||||
stroke-dasharray="0.52916663, 0.52916663"
|
||||
id="rect42" />
|
||||
<rect
|
||||
x="134.94"
|
||||
y="32.417"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="none"
|
||||
stroke-dasharray="0.52916663, 0.52916663"
|
||||
id="rect44" />
|
||||
<rect
|
||||
x="157.43"
|
||||
y="32.417"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="#d7d7f4"
|
||||
id="rect46" />
|
||||
</g>
|
||||
<rect
|
||||
x="44.979"
|
||||
y="46.969"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="#f4d7d7"
|
||||
stroke-dasharray="0.52999997, 0.26499999"
|
||||
stroke-width=".265"
|
||||
id="rect50" />
|
||||
</g>
|
||||
<text
|
||||
x="56.412949"
|
||||
y="51.598957"
|
||||
fill="#000000"
|
||||
font-family="sans-serif"
|
||||
font-size="10.583px"
|
||||
letter-spacing="0px"
|
||||
stroke-width="0.26458"
|
||||
word-spacing="0px"
|
||||
style="line-height:1.25"
|
||||
xml:space="preserve"
|
||||
id="text56"><tspan
|
||||
x="56.412949"
|
||||
y="51.598957"
|
||||
font-family="sans-serif"
|
||||
font-size="3.5278px"
|
||||
stroke-width="0.26458"
|
||||
text-align="center"
|
||||
text-anchor="middle"
|
||||
style="font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
|
||||
id="tspan54">26f9a7...</tspan></text>
|
||||
<rect
|
||||
x="67.469"
|
||||
y="46.969"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="#f4d7d7"
|
||||
stroke="#000"
|
||||
stroke-dasharray="0.52999997, 0.26499999"
|
||||
stroke-width=".265"
|
||||
id="rect58" />
|
||||
<text
|
||||
x="78.902527"
|
||||
y="51.598961"
|
||||
fill="#000000"
|
||||
font-family="sans-serif"
|
||||
font-size="10.583px"
|
||||
letter-spacing="0px"
|
||||
stroke-width="0.26458"
|
||||
word-spacing="0px"
|
||||
style="line-height:1.25"
|
||||
xml:space="preserve"
|
||||
id="text62"><tspan
|
||||
x="78.902527"
|
||||
y="51.598961"
|
||||
font-family="sans-serif"
|
||||
font-size="3.5278px"
|
||||
stroke-width="0.26458"
|
||||
text-align="center"
|
||||
text-anchor="middle"
|
||||
style="font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
|
||||
id="tspan60">b44ab3...</tspan></text>
|
||||
<rect
|
||||
x="89.958"
|
||||
y="46.969"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="#f4d7d7"
|
||||
stroke="#000"
|
||||
stroke-dasharray="0.52999997, 0.26499999"
|
||||
stroke-width=".265"
|
||||
id="rect64" />
|
||||
<text
|
||||
x="101.39211"
|
||||
y="51.598961"
|
||||
fill="#000000"
|
||||
font-family="sans-serif"
|
||||
font-size="10.583px"
|
||||
letter-spacing="0px"
|
||||
stroke-width="0.26458"
|
||||
word-spacing="0px"
|
||||
style="line-height:1.25"
|
||||
xml:space="preserve"
|
||||
id="text68"><tspan
|
||||
x="101.39211"
|
||||
y="51.598961"
|
||||
font-family="sans-serif"
|
||||
font-size="3.5278px"
|
||||
stroke-width="0.26458"
|
||||
text-align="center"
|
||||
text-anchor="middle"
|
||||
style="font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
|
||||
id="tspan66">ee5593...</tspan></text>
|
||||
<rect
|
||||
x="112.45"
|
||||
y="46.969"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="#f4d7d7"
|
||||
stroke="#000"
|
||||
stroke-dasharray="0.52999997, 0.26499999"
|
||||
stroke-width=".265"
|
||||
id="rect70" />
|
||||
<text
|
||||
x="123.88169"
|
||||
y="51.598961"
|
||||
fill="#000000"
|
||||
font-family="sans-serif"
|
||||
font-size="10.583px"
|
||||
letter-spacing="0px"
|
||||
stroke-width="0.26458"
|
||||
word-spacing="0px"
|
||||
style="line-height:1.25"
|
||||
xml:space="preserve"
|
||||
id="text74"><tspan
|
||||
x="123.88169"
|
||||
y="51.598961"
|
||||
font-family="sans-serif"
|
||||
font-size="3.5278px"
|
||||
stroke-width="0.26458"
|
||||
text-align="center"
|
||||
text-anchor="middle"
|
||||
style="font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
|
||||
id="tspan72">7a3bfe...</tspan></text>
|
||||
<rect
|
||||
x="134.94"
|
||||
y="46.969"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="#f4d7d7"
|
||||
stroke="#000"
|
||||
stroke-dasharray="0.52999997, 0.26499999"
|
||||
stroke-width=".265"
|
||||
id="rect76" />
|
||||
<text
|
||||
x="146.37128"
|
||||
y="51.598957"
|
||||
fill="#000000"
|
||||
font-family="sans-serif"
|
||||
font-size="10.583px"
|
||||
letter-spacing="0px"
|
||||
stroke-width="0.26458"
|
||||
word-spacing="0px"
|
||||
style="line-height:1.25"
|
||||
xml:space="preserve"
|
||||
id="text80"><tspan
|
||||
x="146.37128"
|
||||
y="51.598957"
|
||||
font-family="sans-serif"
|
||||
font-size="3.5278px"
|
||||
stroke-width="0.26458"
|
||||
text-align="center"
|
||||
text-anchor="middle"
|
||||
style="font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
|
||||
id="tspan78">8f4e15...</tspan></text>
|
||||
<rect
|
||||
x="157.43"
|
||||
y="46.969"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
fill="#f4d7d7"
|
||||
stroke="#000"
|
||||
stroke-dasharray="0.52999997, 0.26499999"
|
||||
stroke-width=".265"
|
||||
id="rect82" />
|
||||
<g
|
||||
font-family="sans-serif"
|
||||
letter-spacing="0px"
|
||||
stroke-width=".26458"
|
||||
word-spacing="0px"
|
||||
id="g98">
|
||||
<text
|
||||
x="168.86086"
|
||||
y="51.598961"
|
||||
font-size="10.583px"
|
||||
style="line-height:1.25"
|
||||
xml:space="preserve"
|
||||
id="text86"><tspan
|
||||
x="168.86086"
|
||||
y="51.598961"
|
||||
font-family="sans-serif"
|
||||
font-size="3.5278px"
|
||||
stroke-width="0.26458"
|
||||
text-align="center"
|
||||
text-anchor="middle"
|
||||
style="font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
|
||||
id="tspan84">40c285...</tspan></text>
|
||||
<text
|
||||
x="6.6430736"
|
||||
y="51.680019"
|
||||
font-size="3.5278px"
|
||||
style="line-height:1.25;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
|
||||
xml:space="preserve"
|
||||
id="text90"><tspan
|
||||
x="6.6430736"
|
||||
y="51.680019"
|
||||
stroke-width="0.26458"
|
||||
id="tspan88">read-only bdev</tspan></text>
|
||||
<text
|
||||
x="6.6296382"
|
||||
y="12.539818"
|
||||
font-size="3.5278px"
|
||||
style="line-height:1.25;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
|
||||
xml:space="preserve"
|
||||
id="text96"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan436"
|
||||
x="6.6296382"
|
||||
y="12.539818">esnap clone</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="6.6296382"
|
||||
y="16.949568"
|
||||
id="tspan440">Volume</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan438"
|
||||
x="6.6296382"
|
||||
y="21.359318" /></text>
|
||||
</g>
|
||||
<g
|
||||
stroke="#000"
|
||||
id="g118">
|
||||
<path
|
||||
d="m6.6146 24.479 173.3 1e-6"
|
||||
fill="none"
|
||||
stroke-dasharray="1.59, 1.59"
|
||||
stroke-width=".265"
|
||||
id="path100" />
|
||||
<g
|
||||
fill="#f4d7d7"
|
||||
stroke-dasharray="0.52916663, 0.26458332"
|
||||
stroke-width=".26458"
|
||||
id="g108">
|
||||
<rect
|
||||
x="44.979"
|
||||
y="9.9271"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
id="rect102" />
|
||||
<rect
|
||||
x="112.45"
|
||||
y="9.9271"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
id="rect104" />
|
||||
<rect
|
||||
x="134.94"
|
||||
y="9.9271"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
id="rect106" />
|
||||
</g>
|
||||
<g
|
||||
fill="#d7d7f4"
|
||||
stroke-width=".26458"
|
||||
id="g116">
|
||||
<rect
|
||||
x="67.469"
|
||||
y="9.9271"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
id="rect110" />
|
||||
<rect
|
||||
x="89.958"
|
||||
y="9.9271"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
id="rect112" />
|
||||
<rect
|
||||
x="157.43"
|
||||
y="9.9271"
|
||||
width="22.49"
|
||||
height="6.6146"
|
||||
id="rect114" />
|
||||
</g>
|
||||
</g>
|
||||
<text
|
||||
x="6.614583"
|
||||
y="37.708332"
|
||||
fill="#000000"
|
||||
font-family="sans-serif"
|
||||
font-size="3.5278px"
|
||||
letter-spacing="0px"
|
||||
stroke-width=".26458"
|
||||
word-spacing="0px"
|
||||
style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25"
|
||||
xml:space="preserve"
|
||||
id="text122"><tspan
|
||||
x="6.614583"
|
||||
y="37.708332"
|
||||
stroke-width=".26458"
|
||||
id="tspan120">active clusters</tspan></text>
|
||||
<rect
|
||||
x="37.042"
|
||||
y="7.2812"
|
||||
width="145.52"
|
||||
height="11.906"
|
||||
ry="1.3229"
|
||||
fill="none"
|
||||
stroke="#999"
|
||||
stroke-width=".5"
|
||||
id="rect124" />
|
||||
<rect
|
||||
x="37.042"
|
||||
y="29.771"
|
||||
width="145.52"
|
||||
height="26.458"
|
||||
ry="1.3229"
|
||||
fill="none"
|
||||
stroke="#999"
|
||||
stroke-width=".5"
|
||||
id="rect126" />
|
||||
<g
|
||||
fill="#00f"
|
||||
stroke="#00f"
|
||||
id="g144">
|
||||
<g
|
||||
stroke-width=".26458"
|
||||
id="g140">
|
||||
<path
|
||||
d="m78.052 16.542v15.875"
|
||||
marker-end="url(#marker1960)"
|
||||
id="path128" />
|
||||
<path
|
||||
d="m55.562 16.542v30.427"
|
||||
marker-end="url(#marker2036)"
|
||||
id="path130" />
|
||||
<path
|
||||
d="m100.54 16.542v15.875"
|
||||
marker-end="url(#marker1890)"
|
||||
id="path132" />
|
||||
<path
|
||||
d="m169.33 16.542v15.875"
|
||||
marker-end="url(#Arrow1Mend)"
|
||||
id="path134" />
|
||||
<path
|
||||
d="m124.35 16.542v30.427"
|
||||
marker-end="url(#marker1826)"
|
||||
id="path136" />
|
||||
<path
|
||||
d="m146.84 16.542v30.427"
|
||||
marker-end="url(#marker1816)"
|
||||
id="path138" />
|
||||
</g>
|
||||
<path
|
||||
d="m132.29 61.521 10.583 1e-5"
|
||||
marker-end="url(#marker1826-2-4-7-1-7)"
|
||||
stroke-width=".265"
|
||||
id="path142" />
|
||||
</g>
|
||||
<path
|
||||
d="m132.29 66.813h10.583"
|
||||
fill="#f00"
|
||||
marker-end="url(#marker11771-4-9)"
|
||||
stroke="#ff2a2a"
|
||||
stroke-width=".265"
|
||||
id="path146" />
|
||||
<g
|
||||
stroke-width=".26458"
|
||||
id="g162">
|
||||
<text
|
||||
x="145.52083"
|
||||
y="62.843975"
|
||||
fill="#000000"
|
||||
font-family="sans-serif"
|
||||
font-size="3.5278px"
|
||||
letter-spacing="0px"
|
||||
word-spacing="0px"
|
||||
style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25"
|
||||
xml:space="preserve"
|
||||
id="text150"><tspan
|
||||
x="145.52083"
|
||||
y="62.843975"
|
||||
font-family="sans-serif"
|
||||
font-size="2.8222px"
|
||||
stroke-width=".26458"
|
||||
style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal"
|
||||
id="tspan148">read</tspan></text>
|
||||
<text
|
||||
x="145.52083"
|
||||
y="68.135651"
|
||||
fill="#000000"
|
||||
font-family="sans-serif"
|
||||
font-size="3.5278px"
|
||||
letter-spacing="0px"
|
||||
word-spacing="0px"
|
||||
style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25"
|
||||
xml:space="preserve"
|
||||
id="text154"><tspan
|
||||
x="145.52083"
|
||||
y="68.135651"
|
||||
font-family="sans-serif"
|
||||
font-size="2.8222px"
|
||||
stroke-width=".26458"
|
||||
style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal"
|
||||
id="tspan152">allocate and copy cluster</tspan></text>
|
||||
<rect
|
||||
x="132.29"
|
||||
y="70.781"
|
||||
width="10.583"
|
||||
height="2.6458"
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-dasharray="0.52916664, 0.52916664"
|
||||
id="rect156" />
|
||||
<text
|
||||
x="145.52083"
|
||||
y="73.427307"
|
||||
fill="#000000"
|
||||
font-family="sans-serif"
|
||||
font-size="3.5278px"
|
||||
letter-spacing="0px"
|
||||
word-spacing="0px"
|
||||
style="line-height:1.25;font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
|
||||
xml:space="preserve"
|
||||
id="text160"><tspan
|
||||
x="145.52083"
|
||||
y="73.427307"
|
||||
font-family="sans-serif"
|
||||
font-size="2.8222px"
|
||||
stroke-width="0.26458"
|
||||
style="font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal"
|
||||
id="tspan158">external snapshot cluster</tspan></text>
|
||||
</g>
|
||||
<rect
|
||||
x="132.29"
|
||||
y="76.073"
|
||||
width="10.583"
|
||||
height="2.6458"
|
||||
fill="none"
|
||||
stroke="#000"
|
||||
stroke-width=".265"
|
||||
id="rect164" />
|
||||
<text
|
||||
x="145.52083"
|
||||
y="78.718971"
|
||||
fill="#000000"
|
||||
font-family="sans-serif"
|
||||
font-size="3.5278px"
|
||||
letter-spacing="0px"
|
||||
stroke-width=".26458"
|
||||
word-spacing="0px"
|
||||
style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;line-height:1.25"
|
||||
xml:space="preserve"
|
||||
id="text168"><tspan
|
||||
x="145.52083"
|
||||
y="78.718971"
|
||||
font-family="sans-serif"
|
||||
font-size="2.8222px"
|
||||
stroke-width=".26458"
|
||||
style="font-feature-settings:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal"
|
||||
id="tspan166">allocated cluster</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 19 KiB |
@ -9636,6 +9636,55 @@ Example response:
|
||||
}
|
||||
~~~
|
||||
|
||||
### bdev_lvol_clone_bdev {#rpc_bdev_lvol_clone_bdev}
|
||||
|
||||
Create a logical volume based on an external snapshot bdev. The external snapshot bdev
|
||||
is a bdev that will not be written to by any consumer and must not be an lvol in the
|
||||
lvstore as the clone.
|
||||
|
||||
Regardless of whether the bdev is specified by name or UUID, the bdev UUID will be stored
|
||||
in the logical volume's metadata for use while the lvolstore is loading. For this reason,
|
||||
it is important that the bdev chosen has a static UUID.
|
||||
|
||||
#### Parameters
|
||||
|
||||
Name | Optional | Type | Description
|
||||
----------------------- | -------- | ----------- | -----------
|
||||
bdev | Required | string | Name or UUID for bdev that acts as the external snapshot
|
||||
lvs_name | Required | string | logical volume store name
|
||||
clone_name | Required | string | Name for the logical volume to create
|
||||
|
||||
#### Response
|
||||
|
||||
UUID of the created logical volume clone is returned.
|
||||
|
||||
#### Example
|
||||
|
||||
Example request:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "bdev_lvol_clone_bdev",
|
||||
"id": 1,
|
||||
"params": {
|
||||
"bdev_uuid": "e4b40d8b-f623-416d-8234-baf5a4c83cbd",
|
||||
"lvs_name": "lvs1",
|
||||
"clone_name": "clone2"
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Example response:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": "336f662b-08e5-4006-8e06-e2023f7f9886"
|
||||
}
|
||||
~~~
|
||||
|
||||
### bdev_lvol_rename {#rpc_bdev_lvol_rename}
|
||||
|
||||
Rename a logical volume. New name will rename only the alias of the logical volume.
|
||||
|
16
doc/lvol.md
16
doc/lvol.md
@ -74,6 +74,18 @@ A snapshot can be removed only if there is a single clone on top of it. The rela
|
||||
The cluster map of clone and snapshot will be merged and entries for unallocated clusters in the clone will be updated with
|
||||
addresses from the snapshot cluster map. The entire operation modifies metadata only - no data is copied during this process.
|
||||
|
||||
### External Snapshots
|
||||
|
||||
With the external snapshots feature, clones can be made of any bdev. These clones are commonly called *esnap clones*.
|
||||
Esnap clones work very similarly to thin provisioning. Rather than the back device being an zeroes device, the external snapshot
|
||||
bdev is used as the back device.
|
||||
|
||||

|
||||
|
||||
A bdev that is used as an external snapshot cannot be opened for writing by anything else so long as an esnap clone exists.
|
||||
|
||||
A bdev may have multiple esnap clones and esnap clones can themselves be snapshotted and cloned.
|
||||
|
||||
### Inflation {#lvol_inflation}
|
||||
|
||||
Blobs can be inflated to copy data from backing devices (e.g. snapshots) and allocate all remaining clusters. As a result of this
|
||||
@ -155,6 +167,10 @@ bdev_lvol_clone [-h] snapshot_name clone_name
|
||||
Create a clone with clone_name of a given lvol snapshot.
|
||||
optional arguments:
|
||||
-h, --help show help
|
||||
bdev_lvol_clone_bdev [-h] bdev_name_or_uuid lvs_name clone_name
|
||||
Create a clone with clone_name of a bdev. The bdev must not be an lvol in the lvs_name lvstore.
|
||||
optional arguments:
|
||||
-h, --help show help
|
||||
bdev_lvol_rename [-h] old_name new_name
|
||||
Change lvol bdev name
|
||||
optional arguments:
|
||||
|
@ -1150,7 +1150,7 @@ ignore_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, voi
|
||||
}
|
||||
|
||||
void
|
||||
vbdev_lvol_create_bdev_clone(const char *esnap_uuid,
|
||||
vbdev_lvol_create_bdev_clone(const char *esnap_name,
|
||||
struct spdk_lvol_store *lvs, const char *clone_name,
|
||||
spdk_lvol_op_with_handle_complete cb_fn, void *cb_arg)
|
||||
{
|
||||
@ -1158,7 +1158,6 @@ vbdev_lvol_create_bdev_clone(const char *esnap_uuid,
|
||||
struct spdk_bdev_desc *desc;
|
||||
struct spdk_bdev *bdev;
|
||||
char bdev_uuid[SPDK_UUID_STRING_LEN];
|
||||
struct spdk_uuid uuid;
|
||||
uint64_t sz;
|
||||
int rc;
|
||||
|
||||
@ -1168,16 +1167,9 @@ vbdev_lvol_create_bdev_clone(const char *esnap_uuid,
|
||||
return;
|
||||
}
|
||||
|
||||
rc = spdk_uuid_parse(&uuid, esnap_uuid);
|
||||
rc = spdk_bdev_open_ext(esnap_name, false, ignore_bdev_event_cb, NULL, &desc);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("Invalid UUID '%s'\n", esnap_uuid);
|
||||
cb_fn(cb_arg, NULL, -EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = spdk_bdev_open_ext(esnap_uuid, false, ignore_bdev_event_cb, NULL, &desc);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("bdev '%s' could not be opened: error %d\n", esnap_uuid, rc);
|
||||
SPDK_ERRLOG("bdev '%s' could not be opened: error %d\n", esnap_name, rc);
|
||||
cb_fn(cb_arg, NULL, rc);
|
||||
return;
|
||||
}
|
||||
@ -1186,20 +1178,12 @@ vbdev_lvol_create_bdev_clone(const char *esnap_uuid,
|
||||
rc = spdk_uuid_fmt_lower(bdev_uuid, sizeof(bdev_uuid), spdk_bdev_get_uuid(bdev));
|
||||
if (rc != 0) {
|
||||
spdk_bdev_close(desc);
|
||||
SPDK_ERRLOG("bdev %s: unable to parse UUID\n", esnap_uuid);
|
||||
SPDK_ERRLOG("bdev %s: unable to parse UUID\n", esnap_name);
|
||||
assert(false);
|
||||
cb_fn(cb_arg, NULL, -ENODEV);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Verify the bdev name or alias isn't a UUID that is different from the bdev's UUID. */
|
||||
if (spdk_uuid_compare(&uuid, spdk_bdev_get_uuid(bdev)) != 0) {
|
||||
spdk_bdev_close(desc);
|
||||
SPDK_ERRLOG("bdev with name or alias %s has UUID %s\n", esnap_uuid, bdev_uuid);
|
||||
cb_fn(cb_arg, NULL, -EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
req = calloc(1, sizeof(*req));
|
||||
if (req == NULL) {
|
||||
spdk_bdev_close(desc);
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (C) 2017 Intel Corporation.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "spdk/rpc.h"
|
||||
@ -540,6 +541,89 @@ cleanup:
|
||||
|
||||
SPDK_RPC_REGISTER("bdev_lvol_clone", rpc_bdev_lvol_clone, SPDK_RPC_RUNTIME)
|
||||
|
||||
struct rpc_bdev_lvol_clone_bdev {
|
||||
/* name or UUID. Whichever is used, the UUID will be stored in the lvol's metadata. */
|
||||
char *bdev_name;
|
||||
char *lvs_name;
|
||||
char *clone_name;
|
||||
};
|
||||
|
||||
static void
|
||||
free_rpc_bdev_lvol_clone_bdev(struct rpc_bdev_lvol_clone_bdev *req)
|
||||
{
|
||||
free(req->bdev_name);
|
||||
free(req->lvs_name);
|
||||
free(req->clone_name);
|
||||
}
|
||||
|
||||
static const struct spdk_json_object_decoder rpc_bdev_lvol_clone_bdev_decoders[] = {
|
||||
{
|
||||
"bdev", offsetof(struct rpc_bdev_lvol_clone_bdev, bdev_name),
|
||||
spdk_json_decode_string, false
|
||||
},
|
||||
{
|
||||
"lvs_name", offsetof(struct rpc_bdev_lvol_clone_bdev, lvs_name),
|
||||
spdk_json_decode_string, false
|
||||
},
|
||||
{
|
||||
"clone_name", offsetof(struct rpc_bdev_lvol_clone_bdev, clone_name),
|
||||
spdk_json_decode_string, false
|
||||
},
|
||||
};
|
||||
|
||||
static void
|
||||
rpc_bdev_lvol_clone_bdev(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params)
|
||||
{
|
||||
struct rpc_bdev_lvol_clone_bdev req = {};
|
||||
struct spdk_bdev *bdev;
|
||||
struct spdk_lvol_store *lvs = NULL;
|
||||
struct spdk_lvol *lvol;
|
||||
int rc;
|
||||
|
||||
SPDK_INFOLOG(lvol_rpc, "Cloning bdev\n");
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_bdev_lvol_clone_bdev_decoders,
|
||||
SPDK_COUNTOF(rpc_bdev_lvol_clone_bdev_decoders), &req)) {
|
||||
SPDK_INFOLOG(lvol_rpc, "spdk_json_decode_object failed\n");
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
|
||||
"spdk_json_decode_object failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = vbdev_get_lvol_store_by_uuid_xor_name(NULL, req.lvs_name, &lvs);
|
||||
if (rc != 0) {
|
||||
SPDK_INFOLOG(lvol_rpc, "lvs_name '%s' not found\n", req.lvs_name);
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
||||
"lvs does not exist");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bdev = spdk_bdev_get_by_name(req.bdev_name);
|
||||
if (bdev == NULL) {
|
||||
SPDK_INFOLOG(lvol_rpc, "bdev '%s' does not exist\n", req.bdev_name);
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
||||
"bdev does not exist");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
lvol = vbdev_lvol_get_from_bdev(bdev);
|
||||
if (lvol != NULL && lvol->lvol_store == lvs) {
|
||||
SPDK_INFOLOG(lvol_rpc, "bdev '%s' is an lvol in lvstore '%s\n", req.bdev_name,
|
||||
req.lvs_name);
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
||||
"bdev is an lvol in same lvs as clone; "
|
||||
"use bdev_lvol_clone instead");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
vbdev_lvol_create_bdev_clone(req.bdev_name, lvs, req.clone_name,
|
||||
rpc_bdev_lvol_clone_cb, request);
|
||||
cleanup:
|
||||
free_rpc_bdev_lvol_clone_bdev(&req);
|
||||
}
|
||||
|
||||
SPDK_RPC_REGISTER("bdev_lvol_clone_bdev", rpc_bdev_lvol_clone_bdev, SPDK_RPC_RUNTIME)
|
||||
|
||||
struct rpc_bdev_lvol_rename {
|
||||
char *old_name;
|
||||
char *new_name;
|
||||
|
@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Copyright (C) 2017 Intel Corporation.
|
||||
# All rights reserved.
|
||||
# Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
|
||||
def bdev_lvol_create_lvstore(client, bdev_name, lvs_name, cluster_sz=None,
|
||||
@ -122,6 +123,30 @@ def bdev_lvol_clone(client, snapshot_name, clone_name):
|
||||
return client.call('bdev_lvol_clone', params)
|
||||
|
||||
|
||||
def bdev_lvol_clone_bdev(client, bdev, lvs_name, clone_name):
|
||||
"""Create a logical volume based on a snapshot.
|
||||
|
||||
Regardless of whether the bdev is specified by name or UUID, the bdev UUID
|
||||
will be stored in the logical volume's metadata for use while the lvolstore
|
||||
is loading. For this reason, it is important that the bdev chosen has a
|
||||
static UUID.
|
||||
|
||||
Args:
|
||||
bdev: bdev to clone; must not be an lvol in same lvstore as clone
|
||||
lvs_name: name of logical volume store to use
|
||||
clone_name: name of logical volume to create
|
||||
|
||||
Returns:
|
||||
Name of created logical volume clone.
|
||||
"""
|
||||
params = {
|
||||
'bdev': bdev,
|
||||
'lvs_name': lvs_name,
|
||||
'clone_name': clone_name
|
||||
}
|
||||
return client.call('bdev_lvol_clone_bdev', params)
|
||||
|
||||
|
||||
def bdev_lvol_rename(client, old_name, new_name):
|
||||
"""Rename a logical volume.
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Copyright (C) 2016 Intel Corporation
|
||||
# All rights reserved.
|
||||
# Copyright (c) 2022 Dell Inc, or its subsidiaries.
|
||||
# Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
#
|
||||
|
||||
import logging
|
||||
@ -1966,6 +1967,19 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
|
||||
p.add_argument('clone_name', help='lvol clone name')
|
||||
p.set_defaults(func=bdev_lvol_clone)
|
||||
|
||||
def bdev_lvol_clone_bdev(args):
|
||||
print_json(rpc.lvol.bdev_lvol_clone_bdev(args.client,
|
||||
bdev=args.bdev,
|
||||
lvs_name=args.lvs_name,
|
||||
clone_name=args.clone_name))
|
||||
|
||||
p = subparsers.add_parser('bdev_lvol_clone_bdev',
|
||||
help='Create a clone of a non-lvol bdev')
|
||||
p.add_argument('bdev', help='bdev to clone')
|
||||
p.add_argument('lvs_name', help='logical volume store name')
|
||||
p.add_argument('clone_name', help='lvol clone name')
|
||||
p.set_defaults(func=bdev_lvol_clone_bdev)
|
||||
|
||||
def bdev_lvol_rename(args):
|
||||
rpc.lvol.bdev_lvol_rename(args.client,
|
||||
old_name=args.old_name,
|
||||
|
@ -609,6 +609,12 @@ function rpc_cmd_simple_data_json() {
|
||||
"num_blocks"
|
||||
"uuid"
|
||||
"product_name"
|
||||
"supported_io_types.read"
|
||||
"supported_io_types.write"
|
||||
"driver_specific.lvol.clone"
|
||||
"driver_specific.lvol.base_snapshot"
|
||||
"driver_specific.lvol.esnap_clone"
|
||||
"driver_specific.lvol.external_snapshot_name"
|
||||
)
|
||||
|
||||
[[ -v $elems ]] || return 1
|
||||
|
232
test/lvol/external_snapshot.sh
Executable file
232
test/lvol/external_snapshot.sh
Executable file
@ -0,0 +1,232 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
#
|
||||
testdir=$(readlink -f "$(dirname "$0")")
|
||||
rootdir=$(readlink -f "$testdir/../..")
|
||||
source "$rootdir/test/common/autotest_common.sh"
|
||||
source "$rootdir/test/lvol/common.sh"
|
||||
source "$rootdir/test/bdev/nbd_common.sh"
|
||||
|
||||
set -u
|
||||
|
||||
g_nbd_dev=INVALID
|
||||
g_cluster_size=INVALID
|
||||
g_block_size=INVALID
|
||||
|
||||
function test_esnap_reload() {
|
||||
local bs_dev esnap_dev
|
||||
local block_size=512
|
||||
local esnap_size_mb=1
|
||||
local lvs_cluster_size=$((16 * 1024))
|
||||
local lvs_uuid esnap_uuid eclone_uuid snap_uuid clone_uuid uuid
|
||||
local aio_bdev=test_esnap_reload_aio0
|
||||
|
||||
# Create the lvstore on an aio device. Can't use malloc because we need to remove
|
||||
# the device and re-add it to trigger an lvstore unload and then load.
|
||||
rm -f $testdir/aio_bdev_0
|
||||
truncate -s "${AIO_SIZE_MB}M" $testdir/aio_bdev_0
|
||||
bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
|
||||
lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore -c "$lvs_cluster_size" "$bs_dev" lvs_test)
|
||||
|
||||
# Create a bdev that will be the external snapshot
|
||||
esnap_uuid=e4b40d8b-f623-416d-8234-baf5a4c83cbd
|
||||
esnap_dev=$(rpc_cmd bdev_malloc_create -u "$esnap_uuid" "$esnap_size_mb" "$block_size")
|
||||
eclone_uuid=$(rpc_cmd bdev_lvol_clone_bdev "$esnap_uuid" lvs_test "eclone1")
|
||||
|
||||
# Unload the lvstore
|
||||
rpc_cmd bdev_aio_delete "$aio_bdev"
|
||||
NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
|
||||
|
||||
# Load the lvstore, expect to see eclone1 again
|
||||
bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
|
||||
lvs_uuid=$(rpc_cmd bdev_lvol_get_lvstores -l lvs_test)
|
||||
uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/eclone1 | jq -r '.[].name')
|
||||
[[ "$uuid" == "$eclone_uuid" ]]
|
||||
|
||||
# Create a snapshot of the eclone, reload, and verify all is there.
|
||||
snap_uuid=$(rpc_cmd bdev_lvol_snapshot "$eclone_uuid" snap1)
|
||||
rpc_cmd bdev_aio_delete "$aio_bdev"
|
||||
NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
|
||||
bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
|
||||
lvs_uuid=$(rpc_cmd bdev_lvol_get_lvstores -l lvs_test)
|
||||
uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/eclone1 | jq -r '.[].name')
|
||||
[[ "$uuid" == "$eclone_uuid" ]]
|
||||
uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/snap1 | jq -r '.[].name')
|
||||
[[ "$uuid" == "$snap_uuid" ]]
|
||||
|
||||
# Create a clone of the snapshot, reload, and verify all is there.
|
||||
clone_uuid=$(rpc_cmd bdev_lvol_clone "$snap_uuid" clone1)
|
||||
rpc_cmd bdev_aio_delete "$aio_bdev"
|
||||
NOT rpc_cmd bdev_lvol_get_lvstores -l lvs_test
|
||||
bs_dev=$(rpc_cmd bdev_aio_create "$testdir/aio_bdev_0" "$aio_bdev" "$block_size")
|
||||
lvs_uuid=$(rpc_cmd bdev_lvol_get_lvstores -l lvs_test)
|
||||
uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/eclone1 | jq -r '.[].name')
|
||||
[[ "$uuid" == "$eclone_uuid" ]]
|
||||
uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/snap1 | jq -r '.[].name')
|
||||
[[ "$uuid" == "$snap_uuid" ]]
|
||||
uuid=$(rpc_cmd bdev_get_bdevs -b lvs_test/clone1 | jq -r '.[].name')
|
||||
[[ "$uuid" == "$clone_uuid" ]]
|
||||
|
||||
rpc_cmd bdev_lvol_delete "$clone_uuid"
|
||||
rpc_cmd bdev_lvol_delete "$snap_uuid"
|
||||
rpc_cmd bdev_lvol_delete "$eclone_uuid"
|
||||
rpc_cmd bdev_aio_delete "$aio_bdev"
|
||||
rpc_cmd bdev_malloc_delete "$esnap_dev"
|
||||
}
|
||||
|
||||
function log_jq_out() {
|
||||
local key
|
||||
|
||||
xtrace_disable
|
||||
|
||||
while read -r key; do
|
||||
printf '%50s = %s\n' "$key" "${jq_out[$key]}"
|
||||
done < <(printf '%s\n' "${!jq_out[@]}" | sort)
|
||||
|
||||
xtrace_restore
|
||||
}
|
||||
|
||||
function verify_clone() {
|
||||
local bdev=$1
|
||||
local parent=$2
|
||||
|
||||
rpc_cmd_simple_data_json bdev bdev_get_bdevs -b "$bdev"
|
||||
log_jq_out
|
||||
|
||||
[[ "${jq_out["supported_io_types.read"]}" == true ]]
|
||||
[[ "${jq_out["supported_io_types.write"]}" == true ]]
|
||||
[[ "${jq_out["driver_specific.lvol.clone"]}" == true ]]
|
||||
[[ "${jq_out["driver_specific.lvol.base_snapshot"]}" == "$parent" ]]
|
||||
[[ "${jq_out["driver_specific.lvol.esnap_clone"]}" == false ]]
|
||||
[[ "${jq_out["driver_specific.lvol.external_snapshot_name"]}" == null ]]
|
||||
}
|
||||
|
||||
function verify_esnap_clone() {
|
||||
local bdev=$1
|
||||
local parent=$2
|
||||
local writable=${3:-true}
|
||||
|
||||
rpc_cmd_simple_data_json bdev bdev_get_bdevs -b "$bdev"
|
||||
log_jq_out
|
||||
|
||||
[[ "${jq_out["supported_io_types.read"]}" == true ]]
|
||||
[[ "${jq_out["supported_io_types.write"]}" == "$writable" ]]
|
||||
[[ "${jq_out["driver_specific.lvol.esnap_clone"]}" == true ]]
|
||||
[[ "${jq_out["driver_specific.lvol.external_snapshot_name"]}" == "$parent" ]]
|
||||
}
|
||||
|
||||
function test_esnap_clones() {
|
||||
local bs_dev esnap_dev
|
||||
local block_size=512
|
||||
local lvs_size_mb=100
|
||||
local esnap_size_mb=1
|
||||
local lvs_cluster_size=$((16 * 1024))
|
||||
local lvs_uuid esnap_uuid
|
||||
local vol1_uuid vol2_uuid vol3_uuid vol3_uuid vol4_uuid vol5_uuid
|
||||
|
||||
# Create the lvstore on a malloc device.
|
||||
bs_dev=$(rpc_cmd bdev_malloc_create $lvs_size_mb $block_size)
|
||||
lvs_uuid=$(rpc_cmd bdev_lvol_create_lvstore -c "$lvs_cluster_size" "$bs_dev" lvs_test)
|
||||
|
||||
# Create a bdev that will be the external snapshot
|
||||
# State:
|
||||
# esnap1
|
||||
esnap_uuid=2abddd12-c08d-40ad-bccf-ab131586ee4c
|
||||
esnap_dev=$(rpc_cmd bdev_malloc_create -b esnap1 -u "$esnap_uuid" "$esnap_size_mb" \
|
||||
"$block_size")
|
||||
|
||||
# Create an esnap clone: vol1
|
||||
# New state:
|
||||
# esnap1 <-- vol1(rw)
|
||||
vol1_uuid=$(rpc_cmd bdev_lvol_clone_bdev "$esnap_uuid" lvs_test vol1)
|
||||
verify_esnap_clone "$vol1_uuid" "$esnap_uuid"
|
||||
|
||||
# Create a snapshot of the esnap clone: vol2
|
||||
# New state:
|
||||
# esnap1 <-- vol2(ro) <-- vol1(rw)
|
||||
vol2_uuid=$(rpc_cmd bdev_lvol_snapshot "$vol1_uuid" vol2)
|
||||
verify_esnap_clone "$vol2_uuid" "$esnap_uuid" false
|
||||
verify_clone "$vol1_uuid" vol2
|
||||
|
||||
# Delete vol2.
|
||||
# New state:
|
||||
# esnap1 <-- vol1(rw)
|
||||
rpc_cmd bdev_lvol_delete "$vol2_uuid"
|
||||
NOT rpc_cmd bdev_get_bdevs -b "$vol2_uuid"
|
||||
verify_esnap_clone "$vol1_uuid" "$esnap_uuid"
|
||||
vol2_uuid=
|
||||
|
||||
# Snapshot vol1: vol3
|
||||
# New state:
|
||||
# ensap1 <-- vol3(ro) <-- vol1(rw)
|
||||
vol3_uuid=$(rpc_cmd bdev_lvol_snapshot "$vol1_uuid" vol3)
|
||||
verify_esnap_clone "$vol3_uuid" "$esnap_uuid" false
|
||||
verify_clone "$vol1_uuid" vol3
|
||||
|
||||
# Delete vol1
|
||||
# New state:
|
||||
# esnap1 <-- vol3(ro)
|
||||
rpc_cmd bdev_lvol_delete $vol1_uuid
|
||||
NOT rpc_cmd bdev_get_bdevs -b $vol1_uuid
|
||||
verify_esnap_clone "$vol3_uuid" "$esnap_uuid" false
|
||||
vol1_uuid=
|
||||
|
||||
# Create clone of vol3: vol4
|
||||
# Verify vol3 is still a read-only esnap clone and vol4 is a normal clone.
|
||||
# New state:
|
||||
# ensap1 <-- vol3(ro) <-- vol4(rw)
|
||||
vol4_uuid=$(rpc_cmd bdev_lvol_clone "$vol3_uuid" vol4)
|
||||
rpc_cmd bdev_get_bdevs -b "$vol4_uuid"
|
||||
verify_esnap_clone "$vol3_uuid" "$esnap_uuid" false
|
||||
verify_clone "$vol4_uuid" vol3
|
||||
|
||||
# Create clone of vol3 (vol5).
|
||||
# New state:
|
||||
# ensap1 <-- vol3(ro) <-- vol4(rw)
|
||||
# `<-- vol5(rw)
|
||||
vol5_uuid=$(rpc_cmd bdev_lvol_clone "$vol3_uuid" vol5)
|
||||
verify_esnap_clone "$vol3_uuid" "$esnap_uuid" false
|
||||
verify_clone "$vol4_uuid" vol3
|
||||
verify_clone "$vol5_uuid" vol3
|
||||
|
||||
# Cannot delete vol3 because it has multiple clones
|
||||
NOT rpc_cmd bdev_lvol_delete "$vol3_uuid"
|
||||
|
||||
# Delete vol4
|
||||
# New state:
|
||||
# ensap1 <-- vol3(ro) <-- vol5(rw)
|
||||
rpc_cmd bdev_lvol_delete "$vol4_uuid"
|
||||
NOT rpc_cmd bdev_get_bdevs -b "$vol4_uuid"
|
||||
verify_esnap_clone "$vol3_uuid" "$esnap_uuid" false
|
||||
verify_clone "$vol5_uuid" vol3
|
||||
|
||||
# Delete vol3.
|
||||
# New state:
|
||||
# ensap1 <-- vol5(rw)
|
||||
rpc_cmd bdev_lvol_delete "$vol3_uuid"
|
||||
NOT rpc_cmd bdev_get_bdevs -b "$vol3_uuid"
|
||||
verify_esnap_clone "$vol5_uuid" "$esnap_uuid"
|
||||
|
||||
# Delete vol5.
|
||||
# New state:
|
||||
# esnap1
|
||||
rpc_cmd bdev_lvol_delete "$vol5_uuid"
|
||||
NOT rpc_cmd bdev_get_bdevs -b "$vol5_uuid"
|
||||
|
||||
rpc_cmd bdev_malloc_delete "$bs_dev"
|
||||
rpc_cmd bdev_malloc_delete "$esnap_dev"
|
||||
}
|
||||
|
||||
$SPDK_BIN_DIR/spdk_tgt &
|
||||
spdk_pid=$!
|
||||
trap 'killprocess "$spdk_pid"; rm -f "$testdir/aio_bdev_0"; exit 1' SIGINT SIGTERM SIGPIPE EXIT
|
||||
waitforlisten $spdk_pid
|
||||
modprobe nbd
|
||||
|
||||
run_test "test_esnap_reload" test_esnap_reload
|
||||
run_test "test_esnap_clones" test_esnap_clones
|
||||
|
||||
trap - SIGINT SIGTERM SIGPIPE EXIT
|
||||
killprocess $spdk_pid
|
||||
rm -f "$testdir/aio_bdev_0"
|
@ -19,6 +19,7 @@ run_test "lvol_snapshot_clone" $rootdir/test/lvol/snapshot_clone.sh
|
||||
run_test "lvol_rename" $rootdir/test/lvol/rename.sh
|
||||
run_test "lvol_provisioning" $rootdir/test/lvol/thin_provisioning.sh
|
||||
run_test "lvol_esnap" $rootdir/test/lvol/esnap/esnap
|
||||
run_test "lvol_external_snapshot" $rootdir/test/lvol/external_snapshot.sh
|
||||
timing_exit basic
|
||||
|
||||
timing_exit lvol
|
||||
|
@ -1826,7 +1826,7 @@ ut_lvol_esnap_clone_bad_args(void)
|
||||
struct spdk_bdev bdev = { 0 };
|
||||
struct spdk_lvol_store *lvs;
|
||||
const char *esnap_uuid = "255f4236-9427-42d0-a9d1-aa17f37dd8db";
|
||||
const char *name_uuid = "5c164b0a-93af-434f-ac35-51af59791f3b";
|
||||
const char *esnap_name = "esnap1";
|
||||
int rc;
|
||||
|
||||
/* Lvol store is successfully created */
|
||||
@ -1840,7 +1840,7 @@ ut_lvol_esnap_clone_bad_args(void)
|
||||
|
||||
rc = spdk_uuid_parse(&bdev.uuid, esnap_uuid);
|
||||
CU_ASSERT(rc == 0);
|
||||
bdev.name = strdup(name_uuid);
|
||||
bdev.name = strdup(esnap_name);
|
||||
SPDK_CU_ASSERT_FATAL(bdev.name != NULL);
|
||||
bdev.blocklen = 512;
|
||||
bdev.blockcnt = 8192;
|
||||
@ -1852,23 +1852,23 @@ ut_lvol_esnap_clone_bad_args(void)
|
||||
vbdev_lvol_create_bdev_clone(esnap_uuid, NULL, "clone1", vbdev_lvol_create_complete, NULL);
|
||||
CU_ASSERT(g_lvolerrno == -EINVAL);
|
||||
|
||||
/* Error when a uuid-like name is provided and that matches the bdev name but not uuid */
|
||||
g_lvolerrno = 0xbad;
|
||||
vbdev_lvol_create_bdev_clone(name_uuid, lvs, "clone1", vbdev_lvol_create_complete, NULL);
|
||||
CU_ASSERT(g_lvolerrno == -EINVAL);
|
||||
|
||||
/* Error when the bdev does not exist */
|
||||
g_base_bdev = NULL;
|
||||
g_lvolerrno = 0xbad;
|
||||
vbdev_lvol_create_bdev_clone(esnap_uuid, lvs, "clone1", vbdev_lvol_create_complete, NULL);
|
||||
CU_ASSERT(g_lvolerrno == -ENODEV);
|
||||
|
||||
/* Success when the stars all align. */
|
||||
/* Success when creating by bdev UUID */
|
||||
g_base_bdev = &bdev;
|
||||
g_lvolerrno = 0xbad;
|
||||
vbdev_lvol_create_bdev_clone(esnap_uuid, lvs, "clone1", vbdev_lvol_create_complete, NULL);
|
||||
CU_ASSERT(g_lvolerrno == 0);
|
||||
|
||||
/* Success when creating by bdev name */
|
||||
g_lvolerrno = 0xbad;
|
||||
vbdev_lvol_create_bdev_clone(esnap_name, lvs, "clone2", vbdev_lvol_create_complete, NULL);
|
||||
CU_ASSERT(g_lvolerrno == 0);
|
||||
|
||||
g_lvol_store = lvs;
|
||||
vbdev_lvs_destruct(g_lvol_store, lvol_store_op_complete, NULL);
|
||||
CU_ASSERT(g_lvserrno == 0);
|
||||
|
Loading…
Reference in New Issue
Block a user