Skip to content

Commit 043f409

Browse files
committed
[Filestore] Validate iovec address ranges in use
1 parent 7987365 commit 043f409

File tree

4 files changed

+144
-1
lines changed

4 files changed

+144
-1
lines changed

cloud/filestore/libs/server/server.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ NProto::TError TryAdjustIovecOffsets(
505505
iovec.SetBase(offset + reinterpret_cast<ui64>(metadata.Address));
506506
}
507507

508-
return {};
508+
return state->LockAddressRanges(regionId, iovecs);
509509
}
510510

511511
////////////////////////////////////////////////////////////////////////////////
@@ -763,6 +763,18 @@ class TRequestHandler final
763763
[=, this] (const auto& response) {
764764
Y_UNUSED(response);
765765

766+
if constexpr (
767+
(std::is_same_v<TRequest, NProto::TWriteDataRequest> ||
768+
std::is_same_v<TRequest, NProto::TReadDataRequest>) &&
769+
std::is_same_v<TAppContext, TFileStoreContext>)
770+
{
771+
if (AppCtx.State && Request->IovecsSize() > 0) {
772+
AppCtx.State->ReleaseAddressRanges(
773+
Request->GetRegionId(),
774+
Request->GetIovecs());
775+
}
776+
}
777+
766778
if (AtomicCas(&RequestState, ExecutionCompleted, ExecutingRequest)) {
767779
// will be processed on executor thread
768780
EnqueueCompletion(ExecCtx.CompletionQueue.get(), tag);

cloud/filestore/libs/server/server_memory_state.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,59 @@ TResultOrError<TMmapRegionMetadata> TServerState::GetMmapRegion(ui64 mmapId)
145145
return it->second.ToMetadata();
146146
}
147147

148+
NProto::TError TServerState::LockAddressRanges(
149+
ui64 mmapId,
150+
const google::protobuf::RepeatedPtrField<NProto::TIovec>& iovecs)
151+
{
152+
TLightWriteGuard guard(StateLock);
153+
auto it = MmapRegions.find(mmapId);
154+
if (it == MmapRegions.end()) {
155+
return MakeError(
156+
E_TRANSPORT_ERROR,
157+
Sprintf("Mmap region not found: %lu", mmapId));
158+
}
159+
160+
NKikimr::TIntervalSet<ui64> addressRanges;
161+
162+
for (const auto& iovec: iovecs) {
163+
addressRanges.Add(iovec.GetBase(), iovec.GetBase() + iovec.GetLength());
164+
}
165+
166+
if (addressRanges & it->second.GetLockedAddressRanges()) {
167+
return MakeError(
168+
E_TRANSPORT_ERROR,
169+
Sprintf(
170+
"Address ranges from the mmap region %lu are already in use",
171+
mmapId));
172+
}
173+
174+
it->second.GetLockedAddressRanges().Add(addressRanges);
175+
return {};
176+
}
177+
178+
NProto::TError TServerState::ReleaseAddressRanges(
179+
ui64 mmapId,
180+
const google::protobuf::RepeatedPtrField<NProto::TIovec>& iovecs)
181+
{
182+
TLightWriteGuard guard(StateLock);
183+
auto it = MmapRegions.find(mmapId);
184+
if (it == MmapRegions.end()) {
185+
return MakeError(
186+
E_TRANSPORT_ERROR,
187+
Sprintf("Mmap region not found: %lu", mmapId));
188+
}
189+
190+
NKikimr::TIntervalSet<ui64> addressRanges;
191+
192+
for (const auto& iovec: iovecs) {
193+
it->second.GetLockedAddressRanges().Subtract(
194+
iovec.GetBase(),
195+
iovec.GetBase() + iovec.GetLength());
196+
}
197+
198+
return {};
199+
}
200+
148201
NProto::TError TServerState::PingMmapRegion(ui64 mmapId)
149202
{
150203
TLightWriteGuard guard(StateLock);

cloud/filestore/libs/server/server_memory_state.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
#include <util/system/file.h>
1212
#include <util/system/spinlock.h>
1313

14+
#include <cloud/filestore/public/api/protos/data.pb.h>
15+
16+
#include <contrib/ydb/core/util/interval_set.h>
17+
1418
#include <tuple>
1519
#include <unordered_map>
1620
#include <utility>
@@ -63,8 +67,13 @@ struct TMmapRegion
6367
Metadata.LatestActivityTimestamp = TInstant::Now();
6468
}
6569

70+
NKikimr::TIntervalSet<ui64>& GetLockedAddressRanges() {
71+
return LockedAddressRanges;
72+
}
73+
6674
private:
6775
TMmapRegionMetadata Metadata;
76+
NKikimr::TIntervalSet<ui64> LockedAddressRanges;
6877
};
6978

7079
class TServerState
@@ -86,6 +95,14 @@ class TServerState
8695

8796
NProto::TError PingMmapRegion(ui64 mmapId);
8897

98+
NProto::TError LockAddressRanges(
99+
ui64 mmapId,
100+
const google::protobuf::RepeatedPtrField<NProto::TIovec>& iovecs);
101+
102+
NProto::TError ReleaseAddressRanges(
103+
ui64 mmapId,
104+
const google::protobuf::RepeatedPtrField<NProto::TIovec>& iovecs);
105+
89106
private:
90107
TLightRWLock StateLock;
91108
std::unordered_map<ui64, TMmapRegion> MmapRegions;

cloud/filestore/libs/server/server_memory_state_ut.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,67 @@ Y_UNIT_TEST_SUITE(TServerStateTest)
278278
getResult.GetResult().LatestActivityTimestamp,
279279
oldTimestamp);
280280
}
281+
282+
Y_UNIT_TEST(ShouldRejectLockingIntersectingRegions)
283+
{
284+
TTestEnv env;
285+
TServerState state(env.GetBasePath());
286+
287+
const size_t fileSize = 4096;
288+
TString relativePath = env.CreateTestFile("test_file.dat", fileSize);
289+
290+
auto result = state.CreateMmapRegion(relativePath, fileSize);
291+
UNIT_ASSERT_C(!HasError(result), FormatError(result.GetError()));
292+
293+
const auto mmapInfo = result.ExtractResult();
294+
295+
google::protobuf::RepeatedPtrField<NProto::TIovec> iovecs;
296+
auto iovec = iovecs.Add();
297+
iovec->SetBase(0);
298+
iovec->SetLength(100);
299+
300+
iovec = iovecs.Add();
301+
iovec->SetBase(4000);
302+
iovec->SetLength(100);
303+
304+
result = state.LockAddressRanges(mmapInfo.Id, iovecs);
305+
UNIT_ASSERT_C(!HasError(result), FormatError(result.GetError()));
306+
307+
result = state.LockAddressRanges(mmapInfo.Id, iovecs);
308+
UNIT_ASSERT(HasError(result));
309+
310+
{
311+
google::protobuf::RepeatedPtrField<NProto::TIovec> iovecs;
312+
auto iovec = iovecs.Add();
313+
iovec->SetBase(50);
314+
iovec->SetLength(1000);
315+
316+
result = state.LockAddressRanges(mmapInfo.Id, iovecs);
317+
UNIT_ASSERT(HasError(result));
318+
}
319+
320+
{
321+
google::protobuf::RepeatedPtrField<NProto::TIovec> iovecs;
322+
auto iovec = iovecs.Add();
323+
iovec->SetBase(50);
324+
iovec->SetLength(10);
325+
326+
result = state.LockAddressRanges(mmapInfo.Id, iovecs);
327+
UNIT_ASSERT(HasError(result));
328+
}
329+
330+
state.ReleaseAddressRanges(mmapInfo.Id, iovecs);
331+
332+
{
333+
google::protobuf::RepeatedPtrField<NProto::TIovec> iovecs;
334+
auto iovec = iovecs.Add();
335+
iovec->SetBase(50);
336+
iovec->SetLength(10);
337+
338+
result = state.LockAddressRanges(mmapInfo.Id, iovecs);
339+
UNIT_ASSERT_C(!HasError(result), FormatError(result.GetError()));
340+
}
341+
}
281342
}
282343

283344
} // namespace NCloud::NFileStore::NServer

0 commit comments

Comments
 (0)