From: Vibhav Pant vibhavp@gmail.com
On Linux (for now), virtual_get_min_large_page_size will iterate through /sys/kernel/mm/hugepages and return the minimum huge page size supported by the system. The exported function wine_unix_get_min_large_page_size is a wrapper around this function. --- dlls/ntdll/ntdll.spec | 3 ++ dlls/ntdll/ntsyscalls.h | 6 ++- dlls/ntdll/unix/unix_private.h | 1 + dlls/ntdll/unix/virtual.c | 74 ++++++++++++++++++++++++++++++++++ include/winternl.h | 2 + 5 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 3471905c762..07fc0150926 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1741,3 +1741,6 @@ # Filesystem @ stdcall -syscall wine_nt_to_unix_file_name(ptr ptr ptr long) @ stdcall -syscall wine_unix_to_nt_file_name(str ptr ptr) + +# Memory management +@ stdcall -syscall wine_unix_get_min_large_page_size(ptr) diff --git a/dlls/ntdll/ntsyscalls.h b/dlls/ntdll/ntsyscalls.h index 55e1436848b..8f7619a4866 100644 --- a/dlls/ntdll/ntsyscalls.h +++ b/dlls/ntdll/ntsyscalls.h @@ -242,7 +242,8 @@ SYSCALL_ENTRY( 0x00ee, NtWriteVirtualMemory, 20 ) \ SYSCALL_ENTRY( 0x00ef, NtYieldExecution, 0 ) \ SYSCALL_ENTRY( 0x00f0, wine_nt_to_unix_file_name, 16 ) \ - SYSCALL_ENTRY( 0x00f1, wine_unix_to_nt_file_name, 12 ) + SYSCALL_ENTRY( 0x00f1, wine_unix_get_min_large_page_size, 4 ) \ + SYSCALL_ENTRY( 0x00f2, wine_unix_to_nt_file_name, 12 )
#define ALL_SYSCALLS64 \ SYSCALL_ENTRY( 0x0000, NtAcceptConnectPort, 48 ) \ @@ -481,4 +482,5 @@ SYSCALL_ENTRY( 0x00e9, NtWriteVirtualMemory, 40 ) \ SYSCALL_ENTRY( 0x00ea, NtYieldExecution, 0 ) \ SYSCALL_ENTRY( 0x00eb, wine_nt_to_unix_file_name, 32 ) \ - SYSCALL_ENTRY( 0x00ec, wine_unix_to_nt_file_name, 24 ) + SYSCALL_ENTRY( 0x00ec, wine_unix_get_min_large_page_size, 8 ) \ + SYSCALL_ENTRY( 0x00ed, wine_unix_to_nt_file_name, 24 ) diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index b278ab8df84..80b366f8b74 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -256,6 +256,7 @@ extern void *anon_mmap_alloc( size_t size, int prot ); extern void virtual_init(void); extern ULONG_PTR get_system_affinity_mask(void); extern void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info, BOOL wow64 ); +extern NTSTATUS virtual_get_min_large_page_size( SIZE_T *size ); extern NTSTATUS virtual_map_builtin_module( HANDLE mapping, void **module, SIZE_T *size, SECTION_IMAGE_INFORMATION *info, ULONG_PTR limit_low, ULONG_PTR limit_high, WORD machine, BOOL prefer_native ); diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 4b23d9954df..d5c968866b8 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -63,6 +63,10 @@ # include <mach/mach_init.h> # include <mach/mach_vm.h> #endif +#ifdef __linux__ +#include <sys/types.h> +#include <dirent.h> +#endif
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -3394,6 +3398,76 @@ void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info, BOOL wow64 ) else info->HighestUserAddress = (char *)user_space_limit - 1; }
+NTSTATUS WINAPI wine_unix_get_min_large_page_size( SIZE_T *size ) +{ + return virtual_get_min_large_page_size( size ); +} + +NTSTATUS virtual_get_min_large_page_size( SIZE_T *size ) +{ +#ifdef __linux__ + DIR *sysfs_hugepages; + struct dirent *supported_size; + SIZE_T min_size; + SIZE_T total_supported_sizes = 0; +#endif + + if (size == NULL) + { + return STATUS_INVALID_PARAMETER; + } + +#ifdef __linux__ + errno = 0; + sysfs_hugepages = opendir( "/sys/kernel/mm/hugepages" ); + if (sysfs_hugepages == NULL) + { + switch (errno) + { + case ENOENT: /* No huge pages support */ + return STATUS_NOT_SUPPORTED; + case ENOMEM: + return STATUS_NO_MEMORY; + default: + return STATUS_INTERNAL_ERROR; + } + } + supported_size = readdir( sysfs_hugepages ); + while (supported_size != NULL) + { + SIZE_T page_size; + + /* Entries are of the form "hugepages-${size}kB" */ + if (strncmp( supported_size->d_name, "hugepages-", 10 ) != 0) + { + supported_size = readdir( sysfs_hugepages ); + continue; + } + page_size = strtol( &supported_size->d_name[10], NULL, 10 ); + if (page_size == 0 || page_size == LONG_MAX || page_size == LONG_MIN) + { + ERR( "could not parse page size from /sys/kernel/mm/hugepages entry %s\n", + supported_size->d_name ); + supported_size = readdir( sysfs_hugepages ); + continue; + } + page_size *= 1024; + min_size = ( total_supported_sizes == 0 ) ? page_size + : ( page_size < min_size ? page_size : min_size ); + total_supported_sizes++; + supported_size = readdir( sysfs_hugepages ); + } + + closedir(sysfs_hugepages); + if (total_supported_sizes == 0) + return STATUS_NOT_SUPPORTED; + *size = min_size; +#else /* __linux__ */ + *size = 2 * 1024 * 1024; +#endif /* !defined(__linux) */ + return STATUS_SUCCESS; +} +
/*********************************************************************** * virtual_map_builtin_module diff --git a/include/winternl.h b/include/winternl.h index 22cdceeaedb..72bdb2b1673 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -5148,6 +5148,8 @@ NTSYSAPI NTSTATUS WINAPI wine_nt_to_unix_file_name( const OBJECT_ATTRIBUTES *att UINT disposition ); NTSYSAPI NTSTATUS WINAPI wine_unix_to_nt_file_name( const char *name, WCHAR *buffer, ULONG *size );
+NTSYSAPI NTSTATUS WINAPI wine_unix_get_min_large_page_size( SIZE_T *size ); +
/*********************************************************************** * Inline functions