From: Vibhav Pant vibhavp@gmail.com
--- configure | 10 ++++++ configure.ac | 1 + dlls/ntdll/unix/virtual.c | 75 +++++++++++++++++++++++++++++++-------- include/config.h.in | 3 ++ 4 files changed, 75 insertions(+), 14 deletions(-)
diff --git a/configure b/configure index 50567d732cd..b04ecb4f13c 100755 --- a/configure +++ b/configure @@ -21065,6 +21065,16 @@ then : printf "%s\n" "#define HAVE_REQUEST_SENSE 1" >>confdefs.h
+fi + +ac_fn_c_check_type "$LINENO" "struct pm_scan_arg" "ac_cv_type_struct_pm_scan_arg" "#include <linux/fs.h> +" +if test "x$ac_cv_type_struct_pm_scan_arg" = xyes +then : + +printf "%s\n" "#define HAVE_STRUCT_PM_SCAN_ARG 1" >>confdefs.h + + fi
diff --git a/configure.ac b/configure.ac index e4c6e98fd5c..ca94668b008 100644 --- a/configure.ac +++ b/configure.ac @@ -2119,6 +2119,7 @@ dnl **** Check for types ****
AC_C_INLINE AC_CHECK_TYPES([request_sense],,,[#include <linux/cdrom.h>]) +AC_CHECK_TYPES([struct pm_scan_arg],,,[#include <linux/fs.h>])
AC_CHECK_TYPES([struct xinpgen],,, [#include <sys/types.h> diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 2c3742ef0d5..0c7afe9c714 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 HAVE_STRUCT_PM_SCAN_ARG +#include <linux/fs.h> +#include <sys/ioctl.h> +#endif
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -5351,6 +5355,7 @@ static void fill_working_set_info( struct fill_working_set_info_data *d, struct } #else static int pagemap_fd = -2; +static BOOL pagemap_ioctl_avail = TRUE;
struct fill_working_set_info_data { @@ -5396,26 +5401,68 @@ static void fill_working_set_info( struct fill_working_set_info_data *d, struct page = (UINT_PTR)ref[i].addr >> page_shift; p = &info[ref[i].orig_index];
- assert(page >= d->buffer_start); - if (page >= d->buffer_start + d->buffer_len) + if (pagemap_ioctl_avail) + { + UINT_PTR addr = page; + struct page_region output_buf; + int count; + struct pm_scan_arg scan_arg = { + .size = sizeof( scan_arg ), + .flags = 0, + .start = addr, + .end = addr + page_size, + .vec = (UINT_PTR)&output_buf, + .vec_len = 1, + .max_pages = 1, + .category_inverted = 0, + .category_mask = PAGE_IS_PRESENT, + .category_anyof_mask = PAGE_IS_HUGE | PAGE_IS_PRESENT | PAGE_IS_FILE, + .return_mask = PAGE_IS_HUGE | PAGE_IS_PRESENT | PAGE_IS_FILE, + }; + memset( &output_buf, 0, sizeof( output_buf ) ); + count = ioctl( pagemap_fd, PAGEMAP_SCAN, &scan_arg ); + if (count == -1) + { + WARN( "ioctl(PAGEMAP_SCAN, %p) failed: '%s'\n", (void *)addr, strerror( errno ) ); + pagemap_ioctl_avail = FALSE; + continue; + } + else if (count > 0) + { + assert( output_buf.start <= addr && output_buf.end > addr ); + p->VirtualAttributes.Valid = !(vprot & VPROT_GUARD) && (vprot & 0x0f) && + (output_buf.categories & PAGE_IS_PRESENT); + p->VirtualAttributes.Shared = + !is_view_valloc( view ) && (output_buf.categories & PAGE_IS_FILE); + p->VirtualAttributes.LargePage = p->VirtualAttributes.Valid && + (output_buf.categories & PAGE_IS_HUGE) && + (view->protect & SEC_LARGE_PAGES); + if (p->VirtualAttributes.LargePage) p->VirtualAttributes.Locked = TRUE; + } + } + if (!pagemap_ioctl_avail) { - d->buffer_start = page; - len = min( sizeof(d->pm_buffer), (d->end_page - page) * sizeof(pagemap) ); - if (pagemap_fd != -1) + assert(page >= d->buffer_start); + if (page >= d->buffer_start + d->buffer_len) { - d->buffer_len = pread( pagemap_fd, d->pm_buffer, len, page * sizeof(pagemap) ); - if (d->buffer_len != len) + d->buffer_start = page; + len = min( sizeof(d->pm_buffer), (d->end_page - page) * sizeof(pagemap) ); + if (pagemap_fd != -1) { - d->buffer_len = max( d->buffer_len, 0 ); - memset( d->pm_buffer + d->buffer_len / sizeof(pagemap), 0, len - d->buffer_len ); + d->buffer_len = pread( pagemap_fd, d->pm_buffer, len, page * sizeof(pagemap) ); + if (d->buffer_len != len) + { + d->buffer_len = max( d->buffer_len, 0 ); + memset( d->pm_buffer + d->buffer_len / sizeof(pagemap), 0, len - d->buffer_len ); + } } + d->buffer_len = len / sizeof(pagemap); } - d->buffer_len = len / sizeof(pagemap); - } - pagemap = d->pm_buffer[page - d->buffer_start]; + pagemap = d->pm_buffer[page - d->buffer_start];
- p->VirtualAttributes.Valid = !(vprot & VPROT_GUARD) && (vprot & 0x0f) && (pagemap >> 63); - p->VirtualAttributes.Shared = !is_view_valloc( view ) && ((pagemap >> 61) & 1); + p->VirtualAttributes.Valid = !(vprot & VPROT_GUARD) && (vprot & 0x0f) && (pagemap >> 63); + p->VirtualAttributes.Shared = !is_view_valloc( view ) && ((pagemap >> 61) & 1); + } if (p->VirtualAttributes.Shared && p->VirtualAttributes.Valid) p->VirtualAttributes.ShareCount = 1; /* FIXME */ if (p->VirtualAttributes.Valid) diff --git a/include/config.h.in b/include/config.h.in index bbd5a57a280..54816765623 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -432,6 +432,9 @@ /* Define to 1 if `mt_gstat' is a member of `struct mtget'. */ #undef HAVE_STRUCT_MTGET_MT_GSTAT
+/* Define to 1 if the system has the type `struct pm_scan_arg'. */ +#undef HAVE_STRUCT_PM_SCAN_ARG + /* Define to 1 if `sin6_scope_id' is a member of `struct sockaddr_in6'. */ #undef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID