Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions include/os/windows/spl/sys/sysmacros.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ extern unsigned int num_ecores;
* swap priority is at 92. Most ZFS priorities should probably
* stay below this, but kmem_reap needs to be higher.
*/
#define minclsyspri 81 /* BASEPRI_KERNEL */
#define defclsyspri 81 /* BASEPRI_KERNEL */
#define maxclsyspri 89
#define minclsyspri 8 /* BASEPRI_KERNEL */
#define defclsyspri 8 /* BASEPRI_KERNEL */
#define maxclsyspri 12

#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20)
#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20)
Expand Down
2 changes: 2 additions & 0 deletions include/os/windows/zfs/sys/kstat_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ typedef struct windows_kstat {
kstat_named_t zfs_removal_suspend_progress;
kstat_named_t cpu_avx_supported;
kstat_named_t zvol_io_threads;
kstat_named_t zfs_prealloc_percent;
} windows_kstat_t;


Expand Down Expand Up @@ -261,6 +262,7 @@ extern int zfs_autoimport_disable;
extern int zfs_removal_suspend_progress;
extern int cpu_avx_supported;
extern int zvol_threads;
extern int zfs_prealloc_percent;

int kstat_windows_init(void *);
void kstat_windows_fini(void);
Expand Down
36 changes: 35 additions & 1 deletion module/os/windows/spl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,40 @@ wdk_add_library(splkern
${TMH_FILE_LIST}
)

target_include_directories(splkern BEFORE PUBLIC "${CMAKE_SOURCE_DIR}/include/os/windows/" PUBLIC "${CMAKE_SOURCE_DIR}/include/os/windows/spl")
# set(CMAKE_TOOLCHAIN_FILE $ENV{CMAKE_TOOLCHAIN_FILE})

target_include_directories(splkern BEFORE PUBLIC "${CMAKE_SOURCE_DIR}/include/os/windows/" PUBLIC "${CMAKE_SOURCE_DIR}/include/os/windows/spl")
find_program(MSVC_CL_EXECUTABLE cl.exe)
if(NOT MSVC_CL_EXECUTABLE)
message(FATAL_ERROR "MSVC_CL_EXECUTABLE is not set! Make sure to run CMake with a configured compiler.")
else()
message(STATUS "MSVC_CL_EXECUTABLE is set to: ${MSVC_CL_EXECUTABLE}")
endif()

find_program(MSVC_LIB_EXECUTABLE lib.exe)
if(NOT MSVC_LIB_EXECUTABLE)
message(FATAL_ERROR "MSVC lib.exe not found in PATH. Ensure you're using Visual Studio Command Prompt or MSVC toolchain.")
else()
message(STATUS "MSVC_LIB_EXECUTABLE is set to: ${MSVC_LIB_EXECUTABLE}")
endif()

set(CR_WRAPPERS_DIR "${CMAKE_BINARY_DIR}/module/os/windows/spl")
file(MAKE_DIRECTORY "${CR_WRAPPERS_DIR}")

set(CR_WRAPPERS_OBJ "${CR_WRAPPERS_DIR}/spl_cr_wrappers.obj")
set(CR_WRAPPERS_LIB "${CR_WRAPPERS_DIR}/spl_cr_wrappers.lib")

add_custom_command(
OUTPUT ${CR_WRAPPERS_LIB}
COMMAND ${MSVC_CL_EXECUTABLE} /nologo /c /Fo"${CR_WRAPPERS_OBJ}" ${CMAKE_SOURCE_DIR}/module/os/windows/spl/spl_cr_wrappers.c
COMMAND ${MSVC_LIB_EXECUTABLE} /nologo /OUT:${CR_WRAPPERS_LIB} /MACHINE:x64 ${CR_WRAPPERS_OBJ}
WORKING_DIRECTORY ${CR_WRAPPERS_DIR}
DEPENDS ${CMAKE_SOURCE_DIR}/module/os/windows/spl/spl_cr_wrappers.c
COMMENT "Building ${CR_WRAPPERS_LIB} in ${CR_WRAPPERS_DIR} using MSVC"
)

add_custom_target(cr_wrappers ALL DEPENDS ${CR_WRAPPERS_LIB})
add_library(spl_cr_wrappers STATIC IMPORTED GLOBAL)
set_target_properties(spl_cr_wrappers PROPERTIES
IMPORTED_LOCATION ${CR_WRAPPERS_LIB})

69 changes: 66 additions & 3 deletions module/os/windows/spl/spl-kmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ static volatile _Atomic int64_t spl_free = 0;
int64_t spl_free_delta_ema;

static boolean_t spl_event_thread_exit = FALSE;
static boolean_t spl_abd_prealloc_thread_exit = FALSE;
PKEVENT low_mem_event = NULL;

static volatile _Atomic int64_t spl_free_manual_pressure = 0;
Expand Down Expand Up @@ -131,6 +132,10 @@ extern uint64_t zfs_active_rwlock;
extern uint64_t total_memory;
extern uint64_t real_total_memory;

extern kmem_cache_t *abd_chunk_cache;
extern uint64_t zfs_arc_max;
extern int zfs_prealloc_percent;

#define MULT 1

static const char *KMEM_VA_PREFIX = "kmem_va";
Expand Down Expand Up @@ -4230,7 +4235,7 @@ spl_free_wrapper(void)
int64_t
spl_free_manual_pressure_wrapper(void)
{
return (spl_free_manual_pressure);
return (0);
}

uint64_t
Expand Down Expand Up @@ -4479,6 +4484,7 @@ spl_free_thread()
spl_vm_pressure_level != MAGIC_PRESSURE_UNAVAILABLE) {
/* there is pressure */
lowmem = true;
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "spl_vm_pressure_level: %lu\n",spl_vm_pressure_level));
new_spl_free = -(2LL * PAGE_SIZE * spl_vm_pages_wanted);
if (spl_vm_pressure_level > 1) {
emergency_lowmem = true;
Expand Down Expand Up @@ -4533,6 +4539,7 @@ spl_free_thread()
int64_t old_pressure = spl_free_manual_pressure;
new_spl_free -= old_pressure * 2LL;
lowmem = true;
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "spl_free_manual_pressure: %llu\n",spl_free_manual_pressure));
if (spl_free_fast_pressure) {
emergency_lowmem = true;
new_spl_free -= old_pressure * 4LL;
Expand Down Expand Up @@ -4630,6 +4637,7 @@ spl_free_thread()
new_spl_free += bminus;
lowmem = true;
emergency_lowmem = true;
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "spl_vm_pages_wanted %lu\n", spl_vm_pages_wanted));
// atomic swaps to set these variables used in arc.c
int64_t previous_highest_pressure = 0;
int64_t new_p = -bminus;
Expand All @@ -4650,6 +4658,7 @@ spl_free_thread()
new_spl_free -= bytes_wanted;
if (reserve_low && !early_lots_free) {
lowmem = true;
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "spl_vm_pages_wanted: %lu reserve_low: %lu early_lots_free: %lu\n", spl_vm_pages_wanted, reserve_low, early_lots_free));
if (recent_lowmem == 0) {
recent_lowmem = time_now;
}
Expand Down Expand Up @@ -4760,6 +4769,7 @@ spl_free_thread()
real_total_memory) > 75) {
new_spl_free -= total_mem_used / 32;
lowmem = true;
KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "segkmem_total_mem_allocated: %llu real_total_memory: %llu\n", segkmem_total_mem_allocated, real_total_memory));
}
}

Expand Down Expand Up @@ -4914,6 +4924,53 @@ spl_event_thread(void *notused)
thread_exit();
}

static void
spl_abd_prealloc_thread(void *notused)
{
NTSTATUS Status;

typedef struct abd_prealloc_node {
list_node_t node;
} abd_prealloc_node_t;

abd_prealloc_node_t *node;
list_t abd_prealloc_list;

KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "SPL: abd prealloc start segkmem_total_mem_allocated: %lld total_memory: %lld\n",
segkmem_total_mem_allocated, total_memory));

dprintf("SPL: beginning spl_abd_prealloc_thread() loop\n");

list_create(&abd_prealloc_list, sizeof (abd_prealloc_node_t), offsetof(abd_prealloc_node_t, node));

while (!spl_abd_prealloc_thread_exit) {

if (!abd_chunk_cache || !zfs_arc_max) {
delay(hz);
continue;
}

if (segkmem_total_mem_allocated >=
(zfs_arc_max * zfs_prealloc_percent) / 100) {
break;
}

node = (abd_prealloc_node_t *)kmem_cache_alloc(abd_chunk_cache, KM_SLEEP);
list_insert_tail(&abd_prealloc_list, node);
}

while ((node = list_remove_head(&abd_prealloc_list)) != NULL) {
kmem_cache_free(abd_chunk_cache, node);
}

spl_abd_prealloc_thread_exit = FALSE;
dprintf("SPL: %s thread_exit\n", __func__);

KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "SPL: abd prealloc done segkmem_total_mem_allocated: %lld total_memory: %lld zfs_arc_max: %llu zfs_prealloc_percent: %d%\n",
segkmem_total_mem_allocated, total_memory, zfs_arc_max, zfs_prealloc_percent));
thread_exit();
}


static int
spl_kstat_update(kstat_t *ksp, int rw)
Expand Down Expand Up @@ -5342,15 +5399,21 @@ spl_kmem_thread_init(void)
(void) thread_create(NULL, 0, spl_free_thread, 0, 0, 0, 0, 92);
spl_free_thread_running = TRUE;

spl_event_thread_exit = FALSE;
(void) thread_create(NULL, 0, spl_event_thread, 0, 0, 0, 0, 92);
if (zfs_prealloc_percent) {
spl_abd_prealloc_thread_exit = FALSE;
(void) thread_create(NULL, 0, spl_abd_prealloc_thread, 0, 0, 0, 0, 92);
} else {
spl_event_thread_exit = FALSE;
(void) thread_create(NULL, 0, spl_event_thread, 0, 0, 0, 0, 92);
}
}

void
spl_kmem_thread_fini(void)
{
shutting_down = 1;

spl_abd_prealloc_thread_exit = TRUE;
if (low_mem_event != NULL) {
dprintf("SPL: stopping spl_event_thread\n");
spl_event_thread_exit = TRUE;
Expand Down
82 changes: 74 additions & 8 deletions module/os/windows/spl/spl-thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,78 @@

uint64_t zfs_threads = 0;

kthread_t *

kthread_t*
spl_thread_create(
caddr_t stk,
size_t stksize,
void (*proc)(void*),
void* arg,
size_t len,
int state,
#ifdef SPL_DEBUG_THREAD
char* filename,
int line,
#endif
pri_t pri)
{
NTSTATUS status;
HANDLE hThread = NULL;
PETHREAD eThread = NULL;

#ifdef SPL_DEBUG_THREAD
dprintf("Start thread pri %d\n", pri);
#endif

status = PsCreateSystemThread(
&hThread,
THREAD_ALL_ACCESS,
NULL,
NULL,
NULL,
proc,
arg);

if (!NT_SUCCESS(status))
return NULL;

/* Convert HANDLE ETHREAD */
status = ObReferenceObjectByHandle(
hThread,
THREAD_ALL_ACCESS,
*PsThreadType,
KernelMode,
(PVOID*)&eThread,
NULL);

/* We no longer need the handle */
ZwClose(hThread);

if (!NT_SUCCESS(status))
return NULL;

/* Clamp priority to safe Windows range */
KPRIORITY newPri = (KPRIORITY)pri;

if (newPri > maxclsyspri)
newPri = maxclsyspri;

if (newPri < minclsyspri)
newPri = minclsyspri;

/* Set absolute priority */
KeSetPriorityThread((PKTHREAD)eThread, newPri);

#ifdef SPL_DEBUG_THREAD
dprintf("Thread created with priority %d\n", newPri);
#endif

atomic_inc_64(&zfs_threads);

return (kthread_t*)eThread;
}

/*kthread_t*
spl_thread_create(
caddr_t stk,
size_t stksize,
Expand Down Expand Up @@ -72,12 +143,7 @@ spl_thread_create(
if (result != STATUS_SUCCESS)
return (NULL);

/*
* Improve the priority when asked to do so
* Thread priorities range from 0 to 31, where 0 is the lowest
* priority and 31 is the highest
*/


if (pri > minclsyspri) {
// thread_precedence_policy_data_t policy;
// policy.importance = pri - minclsyspri;
Expand All @@ -102,7 +168,7 @@ spl_thread_create(
ObDereferenceObject(eThread);
ZwClose(thread);
return ((kthread_t *)eThread);
}
}*/

kthread_t *
spl_current_thread(void)
Expand Down
15 changes: 14 additions & 1 deletion module/os/windows/spl/spl-vmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,8 @@ uint64_t spl_frag_walk_cnt = 0;
extern void spl_free_set_emergency_pressure(int64_t p);
extern uint64_t segkmem_total_mem_allocated;
extern uint64_t total_memory;
extern uint64_t zfs_arc_max;
extern int zfs_prealloc_percent;

/*
* Get a vmem_seg_t from the global segfree list.
Expand Down Expand Up @@ -1732,12 +1734,23 @@ vmem_xfree(vmem_t *vmp, void *vaddr, size_t size)
vsp = vprev;
}

// calling vm_source_free will free the memory to windows, we
// don't want to do this unless we are crossing the arc limit when
// zfs_prealloc_percent is enabled.
boolean_t allow_vm_source_free = true;
if (zfs_prealloc_percent) {
if (segkmem_total_mem_allocated <
(zfs_arc_max * 102) / 100) {
allow_vm_source_free = false;
}
}

/*
* If the entire span is free, return it to the source.
*/
if (vsp->vs_aprev->vs_import && vmp->vm_source_free != NULL &&
vsp->vs_aprev->vs_type == VMEM_SPAN &&
vsp->vs_anext->vs_type == VMEM_SPAN) {
vsp->vs_anext->vs_type == VMEM_SPAN && allow_vm_source_free) {
vaddr = (void *)vsp->vs_start;
size = VS_SIZE(vsp);
ASSERT(size == VS_SIZE(vsp->vs_aprev));
Expand Down
Loading
Loading