dll,fuse: allow dir buffer entry invalidation

The FUSE implementation of ReadDirectory issues readdir followed
by a slew of getattr. In the current implementation if a getattr fails
the whole readdir operation fails.

This commit adds the ability to invalidate individual entries in the
directory buffer. Entries for which getattr fails are now marked invalid
rather than fail the overall ReadDirectory operation.

See #292
This commit is contained in:
Bill Zissimopoulos 2020-04-13 15:52:03 -07:00
parent 42fd57904a
commit b4c39f656c
No known key found for this signature in database
GPG Key ID: 3D4F95D52C7B3EA3
4 changed files with 79 additions and 7 deletions

View File

@ -335,6 +335,18 @@ FSP_API VOID FspFileSystemReleaseDirectoryBuffer(PVOID *PDirBuffer)
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer; FSP_FILE_SYSTEM_DIRECTORY_BUFFER *DirBuffer = *PDirBuffer;
/* eliminate invalidated entries from the index */
PULONG Index = (PULONG)(DirBuffer->Buffer + DirBuffer->HiMark);
ULONG Count = (DirBuffer->Capacity - DirBuffer->HiMark) / sizeof(ULONG);
ULONG I, J;
for (I = Count - 1, J = Count; I < Count; I--)
{
if (FspFileSystemDirectoryBufferEntryInvalid == Index[I])
continue;
Index[--J] = Index[I];
}
DirBuffer->HiMark = (ULONG)((PUINT8)&Index[J] - DirBuffer->Buffer);
FspFileSystemSortDirectoryBuffer(DirBuffer); FspFileSystemSortDirectoryBuffer(DirBuffer);
ReleaseSRWLockExclusive(&DirBuffer->Lock); ReleaseSRWLockExclusive(&DirBuffer->Lock);

View File

@ -1866,7 +1866,8 @@ static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem,
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0, Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
&Uid, &Gid, &Mode, &DirInfo->FileInfo); &Uid, &Gid, &Mode, &DirInfo->FileInfo);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; /* mark the directory buffer entry as invalid */
*Index = FspFileSystemDirectoryBufferEntryInvalid;
if (0 != PosixPathEnd) if (0 != PosixPathEnd)
*PosixPathEnd = SavedPathChar; *PosixPathEnd = SavedPathChar;

View File

@ -66,6 +66,7 @@ PSID FspWksidGet(WELL_KNOWN_SID_TYPE WellKnownSidType);
PWSTR FspDiagIdent(VOID); PWSTR FspDiagIdent(VOID);
#define FspFileSystemDirectoryBufferEntryInvalid ((ULONG)-1)
VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer, VOID FspFileSystemPeekInDirectoryBuffer(PVOID *PDirBuffer,
PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount); PUINT8 *PBuffer, PULONG *PIndex, PULONG PCount);

View File

@ -145,7 +145,7 @@ static void dirbuf_dots_test(void)
FspFileSystemDeleteDirectoryBuffer(&DirBuffer); FspFileSystemDeleteDirectoryBuffer(&DirBuffer);
} }
static void dirbuf_fill_dotest(unsigned seed, ULONG Count) static void dirbuf_fill_dotest(unsigned seed, ULONG Count, ULONG InvalidCount)
{ {
PVOID DirBuffer = 0; PVOID DirBuffer = 0;
NTSTATUS Result; NTSTATUS Result;
@ -202,6 +202,51 @@ static void dirbuf_fill_dotest(unsigned seed, ULONG Count)
ASSERT(STATUS_SUCCESS == Result); ASSERT(STATUS_SUCCESS == Result);
} }
#if 1
{
ASSERT(Count > InvalidCount);
#if !defined(FspFileSystemDirectoryBufferEntryInvalid)
const ULONG FspFileSystemDirectoryBufferEntryInvalid = ((ULONG)-1);
#endif
typedef struct
{
SRWLOCK Lock;
ULONG Capacity, LoMark, HiMark;
PUINT8 Buffer;
} FSP_FILE_SYSTEM_DIRECTORY_BUFFER;
FSP_FILE_SYSTEM_DIRECTORY_BUFFER *PeekDirBuffer = DirBuffer;
PUINT8 PeekBuffer = PeekDirBuffer->Buffer;
PULONG PeekIndex = (PULONG)(PeekDirBuffer->Buffer + PeekDirBuffer->HiMark);
ULONG PeekCount = (PeekDirBuffer->Capacity - PeekDirBuffer->HiMark) / sizeof(ULONG);
ASSERT(Count == PeekCount);
for (ULONG I = 0; InvalidCount > I; I++)
{
for (;;)
{
N = rand() % PeekCount;
if (FspFileSystemDirectoryBufferEntryInvalid == PeekIndex[N])
continue;
DirInfo = (PVOID)(PeekBuffer + PeekIndex[N]);
memcpy(CurrFileName, DirInfo->FileNameBuf, DirInfo->Size - sizeof *DirInfo);
CurrFileName[(DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR)] = L'\0';
/* do not invalidate dot entries as they are used in testing below */
if (0 == wcscmp(CurrFileName, L".") || 0 == wcscmp(CurrFileName, L".."))
continue;
PeekIndex[N] = FspFileSystemDirectoryBufferEntryInvalid;
break;
}
}
Count -= InvalidCount;
}
#endif
FspFileSystemReleaseDirectoryBuffer(&DirBuffer); FspFileSystemReleaseDirectoryBuffer(&DirBuffer);
MarkerIndex = rand() % Count; MarkerIndex = rand() % Count;
@ -303,19 +348,32 @@ static void dirbuf_fill_test(void)
{ {
unsigned seed = (unsigned)time(0); unsigned seed = (unsigned)time(0);
dirbuf_fill_dotest(1485473509, 10); dirbuf_fill_dotest(1485473509, 10, 0);
dirbuf_fill_dotest(1485473509, 10, 3);
for (ULONG I = 0; 10000 > I; I++) for (ULONG I = 0; 10000 > I; I++)
dirbuf_fill_dotest(seed + I, 10); {
dirbuf_fill_dotest(seed + I, 10, 0);
dirbuf_fill_dotest(seed + I, 10, 3);
}
for (ULONG I = 0; 1000 > I; I++) for (ULONG I = 0; 1000 > I; I++)
dirbuf_fill_dotest(seed + I, 100); {
dirbuf_fill_dotest(seed + I, 100, 0);
dirbuf_fill_dotest(seed + I, 100, 30);
}
for (ULONG I = 0; 100 > I; I++) for (ULONG I = 0; 100 > I; I++)
dirbuf_fill_dotest(seed + I, 1000); {
dirbuf_fill_dotest(seed + I, 1000, 0);
dirbuf_fill_dotest(seed + I, 1000, 300);
}
for (ULONG I = 0; 10 > I; I++) for (ULONG I = 0; 10 > I; I++)
dirbuf_fill_dotest(seed + I, 10000); {
dirbuf_fill_dotest(seed + I, 10000, 0);
dirbuf_fill_dotest(seed + I, 10000, 3000);
}
} }
void dirbuf_tests(void) void dirbuf_tests(void)