Skip to content

Commit 746cb28

Browse files
committed
librbd: fix split() for SparseExtent and SparseBufferlistExtent
SparseExtents and SparseBufferlist are typedefs for interval_map. In both cases, split() handler is broken: for the former the extent isn't actually split and for the latter incorrect bufferlist is attached to the split extent. Fortunately, both SnapshotDelta as produced by ObjectListSnapsRequest and SparseBufferlist used in a couple of places seem to be collections where only disjoint intervals are inserted and splitting doesn't occur (at least in the common case). But still, this is a landmine waiting for someone to step on it. Fixes: https://tracker.ceph.com/issues/64423 Signed-off-by: Ilya Dryomov <[email protected]>
1 parent bab43e8 commit 746cb28

File tree

2 files changed

+96
-4
lines changed

2 files changed

+96
-4
lines changed

src/librbd/io/Types.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,9 @@ struct SparseExtent {
179179
std::ostream& operator<<(std::ostream& os, const SparseExtent& state);
180180

181181
struct SparseExtentSplitMerge {
182-
SparseExtent split(uint64_t offset, uint64_t length, SparseExtent &se) const {
183-
return SparseExtent(se.state, se.length);
182+
SparseExtent split(uint64_t offset, uint64_t length,
183+
const SparseExtent& se) const {
184+
return SparseExtent(se.state, length);
184185
}
185186

186187
bool can_merge(const SparseExtent& left, const SparseExtent& right) const {
@@ -231,10 +232,10 @@ struct SparseBufferlistExtent : public SparseExtent {
231232

232233
struct SparseBufferlistExtentSplitMerge {
233234
SparseBufferlistExtent split(uint64_t offset, uint64_t length,
234-
SparseBufferlistExtent& sbe) const {
235+
const SparseBufferlistExtent& sbe) const {
235236
ceph::bufferlist bl;
236237
if (sbe.state == SPARSE_EXTENT_STATE_DATA) {
237-
bl.substr_of(bl, offset, length);
238+
bl.substr_of(sbe.bl, offset, length);
238239
}
239240
return SparseBufferlistExtent(sbe.state, length, std::move(bl));
240241
}

src/test/librbd/io/test_mock_ObjectRequest.cc

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,6 +2070,97 @@ TEST_F(TestMockIoObjectRequest, ListSnapsNoSnapsInSnapSet) {
20702070
EXPECT_EQ(expected_snapshot_delta, snapshot_delta);
20712071
}
20722072

2073+
TEST(SparseExtents, Split) {
2074+
SparseExtents extents;
2075+
extents.insert(50, 100, {SPARSE_EXTENT_STATE_DATA, 100});
2076+
extents.erase(80, 30);
2077+
extents.insert(45, 10, {SPARSE_EXTENT_STATE_ZEROED, 10});
2078+
extents.insert(140, 20, {SPARSE_EXTENT_STATE_DNE, 20});
2079+
extents.insert(125, 5, {SPARSE_EXTENT_STATE_ZEROED, 5});
2080+
2081+
SparseExtents expected_extents = {
2082+
{45, {10, {SPARSE_EXTENT_STATE_ZEROED, 10}}},
2083+
{55, {25, {SPARSE_EXTENT_STATE_DATA, 25}}},
2084+
{110, {15, {SPARSE_EXTENT_STATE_DATA, 15}}},
2085+
{125, {5, {SPARSE_EXTENT_STATE_ZEROED, 5}}},
2086+
{130, {10, {SPARSE_EXTENT_STATE_DATA, 10}}},
2087+
{140, {20, {SPARSE_EXTENT_STATE_DNE, 20}}}
2088+
};
2089+
EXPECT_EQ(expected_extents, extents);
2090+
}
2091+
2092+
TEST(SparseBufferlist, Split) {
2093+
bufferlist bl;
2094+
bl.append(std::string(5, '1'));
2095+
bl.append(std::string(25, '2'));
2096+
bl.append(std::string(30, '3'));
2097+
bl.append(std::string(15, '4'));
2098+
bl.append(std::string(5, '5'));
2099+
bl.append(std::string(10, '6'));
2100+
bl.append(std::string(10, '7'));
2101+
bufferlist expected_bl1;
2102+
expected_bl1.append(std::string(25, '2'));
2103+
bufferlist expected_bl2;
2104+
expected_bl2.append(std::string(15, '4'));
2105+
bufferlist expected_bl3;
2106+
expected_bl3.append(std::string(10, '6'));
2107+
2108+
SparseBufferlist extents;
2109+
extents.insert(50, 100, {SPARSE_EXTENT_STATE_DATA, 100, std::move(bl)});
2110+
extents.erase(80, 30);
2111+
extents.insert(45, 10, {SPARSE_EXTENT_STATE_ZEROED, 10});
2112+
extents.insert(140, 20, {SPARSE_EXTENT_STATE_DNE, 20});
2113+
extents.insert(125, 5, {SPARSE_EXTENT_STATE_ZEROED, 5});
2114+
2115+
SparseBufferlist expected_extents = {
2116+
{45, {10, {SPARSE_EXTENT_STATE_ZEROED, 10}}},
2117+
{55, {25, {SPARSE_EXTENT_STATE_DATA, 25, std::move(expected_bl1)}}},
2118+
{110, {15, {SPARSE_EXTENT_STATE_DATA, 15, std::move(expected_bl2)}}},
2119+
{125, {5, {SPARSE_EXTENT_STATE_ZEROED, 5}}},
2120+
{130, {10, {SPARSE_EXTENT_STATE_DATA, 10, std::move(expected_bl3)}}},
2121+
{140, {20, {SPARSE_EXTENT_STATE_DNE, 20}}}
2122+
};
2123+
EXPECT_EQ(expected_extents, extents);
2124+
}
2125+
2126+
TEST(SparseBufferlist, SplitData) {
2127+
bufferlist bl1;
2128+
bl1.append(std::string(100, '1'));
2129+
bufferlist bl2;
2130+
bl2.append(std::string(15, '2'));
2131+
bufferlist bl3;
2132+
bl3.append(std::string(40, '3'));
2133+
bufferlist bl4;
2134+
bl4.append(std::string(10, '4'));
2135+
bufferlist expected_bl1 = bl2;
2136+
bufferlist expected_bl2;
2137+
expected_bl2.append(std::string(35, '1'));
2138+
bufferlist expected_bl3 = bl4;
2139+
bufferlist expected_bl4;
2140+
expected_bl4.append(std::string(30, '1'));
2141+
bufferlist expected_bl5;
2142+
expected_bl5.append(std::string(5, '3'));
2143+
bufferlist expected_bl6;
2144+
expected_bl6.append(std::string(15, '3'));
2145+
2146+
SparseBufferlist extents;
2147+
extents.insert(50, 100, {SPARSE_EXTENT_STATE_DATA, 100, std::move(bl1)});
2148+
extents.insert(40, 15, {SPARSE_EXTENT_STATE_DATA, 15, std::move(bl2)});
2149+
extents.insert(130, 40, {SPARSE_EXTENT_STATE_DATA, 40, std::move(bl3)});
2150+
extents.erase(135, 20);
2151+
extents.insert(90, 10, {SPARSE_EXTENT_STATE_DATA, 10, std::move(bl4)});
2152+
2153+
SparseBufferlist expected_extents = {
2154+
{40, {15, {SPARSE_EXTENT_STATE_DATA, 15, std::move(expected_bl1)}}},
2155+
{55, {35, {SPARSE_EXTENT_STATE_DATA, 35, std::move(expected_bl2)}}},
2156+
{90, {10, {SPARSE_EXTENT_STATE_DATA, 10, std::move(expected_bl3)}}},
2157+
{100, {30, {SPARSE_EXTENT_STATE_DATA, 30, std::move(expected_bl4)}}},
2158+
{130, {5, {SPARSE_EXTENT_STATE_DATA, 5, std::move(expected_bl5)}}},
2159+
{155, {15, {SPARSE_EXTENT_STATE_DATA, 15, std::move(expected_bl6)}}}
2160+
};
2161+
EXPECT_EQ(expected_extents, extents);
2162+
}
2163+
20732164
} // namespace io
20742165
} // namespace librbd
20752166

0 commit comments

Comments
 (0)