Test passing sequential and random access hints to fopen and _open. Test that the underlying windows handle actually has the corresponding FILE_SEQUENTIAL_ONLY mode set correctly.
Signed-off-by: Luke Deller luke@deller.id.au --- dlls/msvcrt/tests/file.c | 124 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+)
diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c index fb242d81282..1cabc163a93 100644 --- a/dlls/msvcrt/tests/file.c +++ b/dlls/msvcrt/tests/file.c @@ -35,6 +35,7 @@ #include <process.h> #include <errno.h> #include <locale.h> +#include <winternl.h>
#define MSVCRT_FD_BLOCK_SIZE 32 typedef struct { @@ -2731,6 +2732,127 @@ static void test_lseek(void) DeleteFileA("_creat.tst"); }
+static BOOL has_sequential_hint(int fd) +{ + HANDLE handle; + FILE_MODE_INFORMATION mode_info; + IO_STATUS_BLOCK io; + NTSTATUS status; + + /* Check whether the file handle has the sequential access hint */ + handle = (HANDLE)_get_osfhandle(fd); + status = NtQueryInformationFile(handle, &io, &mode_info, sizeof(mode_info), + FileModeInformation); + ok(!status, "NtQueryInformationFile failed\n"); + return (mode_info.Mode & FILE_SEQUENTIAL_ONLY) != 0; +} + +static void test_fopen_hints(void) +{ + char *tempf; + FILE *fp; + int i; + + /* fopen modes to test */ + const char *fopen_modes[] = { + "rb", "rbS", "rbR", "rbSR", "rbRS" + }; + /* corresponding expected hints */ + BOOL expected_hints[][2] = { + /* expect_sequential, expect_random */ + {FALSE, FALSE}, + {TRUE, FALSE}, + {FALSE, TRUE}, + {TRUE, TRUE}, + {TRUE, TRUE}, + }; + + /* create a test file */ + tempf = _tempnam(".","wne"); + fp = fopen(tempf, "wb"); + ok(fp != NULL, "unable to create test file\n"); + fwrite("abc\n", 1, 4, fp); + fclose(fp); + + /* test fopen with each mode */ + for (i = 0; i < sizeof(fopen_modes)/sizeof(char*); ++i) + { + BOOL expect_sequential, has_sequential; + const char *mode = fopen_modes[i]; + expect_sequential = expected_hints[i][0]; + + fp = fopen(tempf, mode); + ok(fp != NULL, "unable to fopen test file with mode "%s"\n", mode); + + has_sequential = has_sequential_hint(_fileno(fp)); + todo_wine_if(expect_sequential) ok(has_sequential == expect_sequential, + "unexpected sequential hint %d for fopen mode "%s"\n", + has_sequential, mode); + + /* TODO: Somehow check whether the random access hint has been applied. + * Sadly NtQueryInformationFile does not expose this information. */ + + fclose(fp); + } + + unlink(tempf); + free(tempf); +} + +static void test_open_hints(void) +{ + char *tempf; + int fd; + int i; + + /* fopen modes to test */ + int open_flags[] = { + _O_RDONLY | _O_BINARY, + _O_RDONLY | _O_BINARY | _O_SEQUENTIAL, + _O_RDONLY | _O_BINARY | _O_RANDOM, + _O_RDONLY | _O_BINARY | _O_RANDOM | _O_SEQUENTIAL, + }; + /* corresponding expected hints */ + BOOL expected_hints[][2] = { + /* expect_sequential, expect_random */ + {FALSE, FALSE}, + {TRUE, FALSE}, + {FALSE, TRUE}, + {TRUE, TRUE}, + }; + + /* create a test file */ + tempf = _tempnam(".","wne"); + fd = _open(tempf, _O_CREAT | _O_WRONLY | _O_BINARY); + ok(fd != -1, "unable to create test file\n"); + _write(fd, "abc\n", 4); + _close(fd); + + /* test _open with each mode */ + for (i = 0; i < sizeof(open_flags)/sizeof(int); ++i) + { + BOOL expect_sequential, has_sequential; + int flags = open_flags[i]; + expect_sequential = expected_hints[i][0]; + + fd = open(tempf, flags); + ok(fd != -1, "unable to _open test file with flags %x\n", flags); + + has_sequential = has_sequential_hint(fd); + todo_wine_if(expect_sequential) ok(has_sequential == expect_sequential, + "unexpected sequential hint %d for _open flags %x\n", + has_sequential, flags); + + /* TODO: Somehow check whether the random access hint has been applied. + * Sadly NtQueryInformationFile does not expose this information. */ + + close(fd); + } + + unlink(tempf); + free(tempf); +} + START_TEST(file) { int arg_c; @@ -2803,6 +2925,8 @@ START_TEST(file) test_close(); test__creat(); test_lseek(); + test_fopen_hints(); + test_open_hints();
/* Wait for the (_P_NOWAIT) spawned processes to finish to make sure the report * file contains lines in the correct order
Translate access pattern hints supplied to fopen / _open into the corresponding attributes for the lower level CreateFileW call.
Signed-off-by: Luke Deller luke@deller.id.au --- dlls/msvcrt/file.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c index 6e955099090..716d397d246 100644 --- a/dlls/msvcrt/file.c +++ b/dlls/msvcrt/file.c @@ -22,8 +22,6 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * - * TODO - * Use the file flag hints O_SEQUENTIAL, O_RANDOM, O_SHORT_LIVED */
#include <direct.h> @@ -1609,8 +1607,10 @@ static int msvcrt_get_flags(const wchar_t* mode, int *open_flags, int* stream_fl case 'w': break; case 'S': + *open_flags |= _O_SEQUENTIAL; + break; case 'R': - FIXME("ignoring cache optimization flag: %c\n", mode[-1]); + *open_flags |= _O_RANDOM; break; default: ERR("incorrect mode flag: %c\n", mode[-1]); @@ -2269,6 +2269,13 @@ int CDECL _wsopen_dispatch( const wchar_t* path, int oflags, int shflags, int pm sharing |= FILE_SHARE_DELETE; }
+ if (oflags & _O_RANDOM) + attrib |= FILE_FLAG_RANDOM_ACCESS; + if (oflags & _O_SEQUENTIAL) + attrib |= FILE_FLAG_SEQUENTIAL_SCAN; + if (oflags & _O_SHORT_LIVED) + attrib |= FILE_ATTRIBUTE_TEMPORARY; + sa.nLength = sizeof( SECURITY_ATTRIBUTES ); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = !(oflags & _O_NOINHERIT);
Translate FILE_FLAG_SEQUENTIAL_SCAN into the corresponding flag for NtCreateFile options
Signed-off-by: Luke Deller luke@deller.id.au --- dlls/kernelbase/file.c | 3 +++ dlls/msvcrt/tests/file.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index e0a75c2ad08..d21ad299d1f 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -723,6 +723,8 @@ static UINT get_nt_file_options( DWORD attributes ) options |= FILE_SYNCHRONOUS_IO_NONALERT; if (attributes & FILE_FLAG_RANDOM_ACCESS) options |= FILE_RANDOM_ACCESS; + if (attributes & FILE_FLAG_SEQUENTIAL_SCAN) + options |= FILE_SEQUENTIAL_ONLY; if (attributes & FILE_FLAG_WRITE_THROUGH) options |= FILE_WRITE_THROUGH; return options; @@ -3227,6 +3229,7 @@ HANDLE WINAPI DECLSPEC_HOTPATCH OpenFileById( HANDLE handle, LPFILE_ID_DESCRIPTO if (flags & FILE_FLAG_NO_BUFFERING) options |= FILE_NO_INTERMEDIATE_BUFFERING; if (!(flags & FILE_FLAG_OVERLAPPED)) options |= FILE_SYNCHRONOUS_IO_NONALERT; if (flags & FILE_FLAG_RANDOM_ACCESS) options |= FILE_RANDOM_ACCESS; + if (flags & FILE_FLAG_SEQUENTIAL_SCAN) options |= FILE_SEQUENTIAL_ONLY; flags &= FILE_ATTRIBUTE_VALID_FLAGS;
objectName.Length = sizeof(ULONGLONG); diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c index 1cabc163a93..a866df515be 100644 --- a/dlls/msvcrt/tests/file.c +++ b/dlls/msvcrt/tests/file.c @@ -2785,7 +2785,7 @@ static void test_fopen_hints(void) ok(fp != NULL, "unable to fopen test file with mode "%s"\n", mode);
has_sequential = has_sequential_hint(_fileno(fp)); - todo_wine_if(expect_sequential) ok(has_sequential == expect_sequential, + ok(has_sequential == expect_sequential, "unexpected sequential hint %d for fopen mode "%s"\n", has_sequential, mode);
@@ -2839,7 +2839,7 @@ static void test_open_hints(void) ok(fd != -1, "unable to _open test file with flags %x\n", flags);
has_sequential = has_sequential_hint(fd); - todo_wine_if(expect_sequential) ok(has_sequential == expect_sequential, + ok(has_sequential == expect_sequential, "unexpected sequential hint %d for _open flags %x\n", has_sequential, flags);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=94920
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w7u_adm (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w7u_el (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w8 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w8adm (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w864 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064v1507 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064v1809 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064_tsign (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w864 (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064v1507 (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064v1809 (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064 (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064_2qxl (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064_tsign (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64 (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64_ar (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64_he (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64_ja (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64_zh_CN (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
Implement file access pattern hints for sequential or random file access using posix_fadvise if available. On Linux this will influence the kernel's readahead behaviour.
Signed-off-by: Luke Deller luke@deller.id.au --- v3: if both flags are set (which is contradictory) then ignore them --- server/fd.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/server/fd.c b/server/fd.c index b953da2ab85..b20fa97229c 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1892,6 +1892,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam int root_fd = -1; int rw_mode; char *path; + unsigned int cache_hint;
if (((options & FILE_DELETE_ON_CLOSE) && !(access & DELETE)) || ((options & FILE_DIRECTORY_FILE) && (flags & O_TRUNC))) @@ -2036,6 +2037,15 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam free( closed_fd ); fd->cacheable = 1; } + +#if _POSIX_C_SOURCE > 200112L + cache_hint = options & (FILE_SEQUENTIAL_ONLY | FILE_RANDOM_ACCESS); + if (cache_hint == FILE_SEQUENTIAL_ONLY) + posix_fadvise( fd->unix_fd, 0, 0, POSIX_FADV_SEQUENTIAL ); + else if (cache_hint == FILE_RANDOM_ACCESS) + posix_fadvise( fd->unix_fd, 0, 0, POSIX_FADV_RANDOM ); +#endif + if (root_fd != -1) fchdir( server_dir_fd ); /* go back to the server dir */ return fd;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=94918
Your paranoid android.
=== w7u_2qxl (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w7u_adm (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w7u_el (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w8 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w8adm (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w864 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064v1507 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064v1809 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064_tsign (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64 (32 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w864 (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064v1507 (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064v1809 (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064 (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064_2qxl (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w1064_tsign (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64 (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64_ar (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64_he (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64_ja (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"
=== w10pro64_zh_CN (64 bit report) ===
msvcrt: file.c:2788: Test failed: unexpected sequential hint 0 for fopen mode "rbRS"