Repository: oneapi-src/unified-memory-framework (language: python)

Issue:
Backward compatibility for configs of pools/providers

## Rationale

UMF should provide backward compatible interfaces.

## Description

### Background

MPI team experienced the issue after the PR #692 extends `level_zero_memory_provider_params_t` config structure. The root cause of the issue relates to how MPI instantiate/initialize the L0 provider config. They did the following:
```c
level_zero_memory_provider_params_t l0_config = {
    .level_zero_context_handle = hContext;
    .level_zero_device_handle = hDevice;
    .memory_type = UMF_MEMORY_TYPE_DEVICE;
};

umf_memory_provider_handle_t hProvider = NULL;
umf_memory_provider_ops_t *l0_ops = umfLevelZeroMemoryProviderOps();
umfMemoryProviderCreate(l0_ops, &l0_config, &hProvider);
```

After PR #692 the code above start crashing because two new fields were added to the `level_zero_memory_provider_params_t` data structure and the example above does not initialize these new fields:
```c
typedef struct level_zero_memory_provider_params_t {
    ze_context_handle_t level_zero_context_handle;
    ze_device_handle_t level_zero_device_handle;
    umf_usm_memory_type_t memory_type;

    // New fields
    ze_device_handle_t *resident_device_handles;
    uint32_t resident_device_count;
} level_zero_memory_provider_params_t;
```

A quick fix for the issue was to init the config data structure with `0` and than assign the required fields:
```c
level_zero_memory_provider_params_t l0_config = { 0 }; // zero-initialize
l0_config.level_zero_context_handle = hContext;
l0_config.level_zero_device_handle = hDevice;
l0_config.memory_type = UMF_MEMORY_TYPE_DEVICE;
```

### Open Questions

The quick fix above works only because it is OK to init fields of the `level_zero_memory_provider_params_t` structure with zeroes. But there are 2 related major question we should address:

#### 1. How to initialize the configs with default values?

In general case, not every field of the config data structure could/should be initialized with zeroes.

#### 2. How to support backward compatibility?

Config data structures are defined in the headers. If application was built with old version of UMF but on the system there is a newer version than even the application initialize all config's fields properly it initializes only fields that exists in the old version of UMF.
Consider an example. There is a `provider_foo` and corresponding `foo_config_t` structure that contains an int field in the 1st version:

```c
// provider_foo.h:
typedef struct foo_params_t {
    int field 1;
} foo_config_t;

// provider_foo.c:
umf_result_t foo_provider_initialize(void *params, void **provider) {
    foo_params_t *foo_params = (foo_params_t *)params;
    // expected sizeof(foo_params_t) is equal sizeof(int) that is 4 bytes

    assert(foo_params->field1 == 0);
}

// application code:
int main() {
    foo_params_t foo_params = {0};

    umf_memory_provider_handle_t hProvider = NULL;
    umf_memory_provider_ops_t *foo_ops = umfFooMemoryProviderOps();
    umfMemoryProviderCreate(foo_ops, &foo_params, &hProvider);
}
```

Now in the 2nd version of UMF we extend the `foo_params_t` structure with additional field:

```c
// provider_foo.h:
typedef struct foo_params_t {
    int field 1;
    int field2;
} foo_config_t;

// provider_foo.c:
umf_result_t foo_provider_initialize(void *params, void **provider) {
    foo_params_t *foo_params = (foo_params_t *)params;
    // expected sizeof(foo_params_t) is equal 2*sizeof(int) that is 8 bytes

    assert(foo_params->field1 == 0);
    assert(foo_params->field2 == 0); // ERROR: if application was compiled with 1st version of the UMF lib then the size of memory pointed by `params` is 4 bytes
}
```

## Possible API Changes

### Option 1: handle-based approach
Do not expose the config structure in interfaces. The config object is allocated inside libumf.so and handle to the config is returned to the client code. Setter/getter APIs are used to setup config parameters. For example:

```c
foo_params_handle_t foo_params = umfCreateFooParams();
umfFooParamsSetField1(foo_params, 7);

umf_memory_provider_handle_t hProvider = NULL;
umf_memory_provider_ops_t *foo_ops = umfFooMemoryProviderOps();
umfMemoryProviderCreate(foo_ops, foo_params, &hProvider);
```

Client code does not depend on the layout of the `foo_params_t` structure only UMF knows it and can change in different versions.

### Option 2: explicitly pass the size of params 

Data structures that define configs for the pools/providers remains in headers (the same as today). The new fields can be added only to the end. Application explicitly passes the size of the config data structure. Provider/pool implementation determine the version of the config based on the size. To init the config data structure we need to introduce a special macros or header-based inline functions. For example:

```c
// Version 1 provider_foo.h:
typedef struct foo_params_t {
    int field 1;
} foo_config_t;

inline void umfFooParamsInit(foo_params_t *params) {
     params->field1 = 0;
}

// Version 2 provider_foo.h:
typedef struct foo_params_t {
    int field 1;
    int field2;
} foo_config_t;

inline void umfFooParamsInit(foo_params_t *params) {
     params->field1 = 0;
     params->field2 = 0;
}

// Version 2 provider_foo.c:
umf_result_t foo_provider_initialize(void *params, size_t params_size, void **provider) {
    foo_params_t foo_params;
    umfFooParamsInit(& foo_params);

    if(sizeof(foo_params_t) == params_size) {
         // current version, just copy input params as is.
        foo_params = *(foo_params_t*)params;
    } else {
        // old version, copy only first `params_size` bytes and keep the rest default initialized
        memcpy(& foo_params, params, params_size);
    }

    assert(foo_params->field1 == 0);
    assert(foo_params->field2 == 0);
}

// application code:
int main() {
    foo_params_t foo_params;
    umfFooParamsInit(&params);

    umf_memory_provider_handle_t hProvider = NULL;
    umf_memory_provider_ops_t *foo_ops = umfFooMemoryProviderOps();
    umfMemoryProviderCreate(foo_ops, &foo_params, sizeof(foo_params_t), &hProvider);
}
```

### Option 3: store version in the params data structure

Similar to Option 2, but instead of using the size of params data structure to determine the version store it explicitly as a first field in the params data structure.

```c
// Version 1 provider_foo.h:
typedef struct foo_params_t {
    int version;
    int field 1;
} foo_config_t;

inline void umfFooParamsInit(foo_params_t *params) {
    version = 1;
    params->field1 = 0;
}

// Version 2 provider_foo.h:
typedef struct foo_params_t {
    int field 1;
    int field2;
} foo_config_t;

inline void umfFooParamsInit(foo_params_t *params) {
    version = 2;
    params->field1 = 0;
    params->field2 = 0;
}

// Version 2 provider_foo.c:
umf_result_t foo_provider_initialize(void *params, size_t params_size, void **provider) {
    foo_params_t foo_params;
    umfFooParamsInit(& foo_params);

    int params_version = *(int *)params;

    switch(params_version) {
        case 1:
            ...
            break;
        case 2:
            ...
            break;
        default:
            LOG_ERR("Wrong version");
    }

    assert(foo_params->field1 == 0);
    assert(foo_params->field2 == 0);
}

// application code:
int main() {
    foo_params_t foo_params;
    umfFooParamsInit(&params);

    umf_memory_provider_handle_t hProvider = NULL;
    umf_memory_provider_ops_t *foo_ops = umfFooMemoryProviderOps();
    umfMemoryProviderCreate(foo_ops, &foo_params, &hProvider);
}
```

### Design Considerations

I prefer Option 1 over Option 2 and Option 3. I think it provides best ABI compatibility. Another advantage is that the config data structure always initialized when user calls `umfCreateFooParams()`. There is no way to get non-initialized fields in the config, while in case of Option 2 or 3 user might forget to call `umfFooParamsInit(&params)` function.

Between Options 2 and 3, I prefer Option 3 because of two things:

- it stores version explicitly.
- the `umfMemoryProviderCreate` API remains unchanged.

## Implementation details

TBD




Discussion / hints:
We must address this issue before the first stable release because all three options require non-backward compatible changes.
:+1: to option 1.

Another option is to do what UR does and create a "chain" (linked list) of parameters.
```
struct foo_param {
  param_type type;
  int foo;
  void *next;
}

struct bar_param {
  param_type type;
  int bar;
  void *next;
}

struct foo_param foo = { PARAM_FOO, 5, nullptr };
struct bar_param bar = { PARAM_BAR, 10, &foo };

someApi(&bar); // this would apply all options in the chain.

```

This is super verbose, but really flexible. One downside is that it's on the api function to validate the parameters, and users need to remember to correctly set param type.

I also vote for option 1. What UR does is also OK but from my experience it's quite easy to forget setting the type (and we even had a bug in UMF where we set the type incorrectly).

One question: how's responsible for destroying the params - user or UMF?
> One question: how's responsible for destroying the params - user or UMF?

In the case of option 1, User calls `umfCreateFooParams()` function which internally allocates required data structure. After pool/provider is created user should call the appropriate `umfDestroyFooParams` function to tell UMF library that params data structure should be destroyed. 
Option 1 > Option 3 >>>> Option 2

~The same issue we have with other structures in public header. Also we have the same issue with other structures, like memprovider ops - in case of those structures probably option 3 (version field) is the way.~

Edit. I checked code and i found that we already have version in ops structure so it is fine. 

Fix patch:
diff --git a/benchmark/multithread.cpp b/benchmark/multithread.cpp
index c698ed045..efb46729c 100644
--- a/benchmark/multithread.cpp
+++ b/benchmark/multithread.cpp
@@ -91,7 +91,12 @@ static void mt_alloc_free(poolCreateExtParams params,
 }
 
 int main() {
-    auto osParams = umfOsMemoryProviderParamsDefault();
+    umf_os_memory_provider_params_handle_t osParams = nullptr;
+    umf_result_t res = umfOsMemoryProviderParamsCreate(&osParams);
+    if (res != UMF_RESULT_SUCCESS) {
+        std::cerr << "os memory provider params create failed" << std::endl;
+        return -1;
+    }
 
 #if defined(UMF_POOL_SCALABLE_ENABLED)
 
@@ -102,7 +107,7 @@ int main() {
 
     std::cout << "scalable_pool mt_alloc_free: ";
     mt_alloc_free(poolCreateExtParams{umfScalablePoolOps(), nullptr,
-                                      umfOsMemoryProviderOps(), &osParams},
+                                      umfOsMemoryProviderOps(), osParams},
                   params);
 #else
     std::cout << "skipping scalable_pool mt_alloc_free" << std::endl;
@@ -111,7 +116,7 @@ int main() {
 #if defined(UMF_BUILD_LIBUMF_POOL_JEMALLOC)
     std::cout << "jemalloc_pool mt_alloc_free: ";
     mt_alloc_free(poolCreateExtParams{umfJemallocPoolOps(), nullptr,
-                                      umfOsMemoryProviderOps(), &osParams});
+                                      umfOsMemoryProviderOps(), osParams});
 #else
     std::cout << "skipping jemalloc_pool mt_alloc_free" << std::endl;
 #endif
@@ -126,7 +131,7 @@ int main() {
 
     std::cout << "disjoint_pool mt_alloc_free: ";
     mt_alloc_free(poolCreateExtParams{umfDisjointPoolOps(), hDisjointParams,
-                                      umfOsMemoryProviderOps(), &osParams});
+                                      umfOsMemoryProviderOps(), osParams});
 #else
     std::cout << "skipping disjoint_pool mt_alloc_free" << std::endl;
 #endif
diff --git a/benchmark/ubench.c b/benchmark/ubench.c
index 645ddb743..1deabde0c 100644
--- a/benchmark/ubench.c
+++ b/benchmark/ubench.c
@@ -124,22 +124,6 @@ UBENCH_EX(simple, glibc_malloc) {
 
 ////////////////// OS MEMORY PROVIDER
 
-static umf_os_memory_provider_params_t UMF_OS_MEMORY_PROVIDER_PARAMS = {
-    /* .protection = */ UMF_PROTECTION_READ | UMF_PROTECTION_WRITE,
-    /* .visibility = */ UMF_MEM_MAP_PRIVATE,
-    /* .shm_name = */ NULL,
-
-    // NUMA config
-    /* .numa_list = */ NULL,
-    /* .numa_list_len = */ 0,
-
-    /* .numa_mode = */ UMF_NUMA_MODE_DEFAULT,
-    /* .part_size = */ 0,
-
-    /* .partitions = */ NULL,
-    /* .partitions_len = */ 0,
-};
-
 static void *w_umfMemoryProviderAlloc(void *provider, size_t size,
                                       size_t alignment) {
     void *ptr = NULL;
@@ -171,9 +155,17 @@ UBENCH_EX(simple, os_memory_provider) {
 
     umf_result_t umf_result;
     umf_memory_provider_handle_t os_memory_provider = NULL;
-    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
-                                         &UMF_OS_MEMORY_PROVIDER_PARAMS,
+    umf_os_memory_provider_params_handle_t os_params = NULL;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_params);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(stderr, "error: umfOsMemoryProviderParamsCreate() failed\n");
+        exit(-1);
+    }
+
+    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params,
                                          &os_memory_provider);
+    umfOsMemoryProviderParamsDestroy(os_params);
     if (umf_result != UMF_RESULT_SUCCESS) {
         fprintf(stderr, "error: umfMemoryProviderCreate() failed\n");
         exit(-1);
@@ -215,9 +207,17 @@ UBENCH_EX(simple, proxy_pool_with_os_memory_provider) {
 
     umf_result_t umf_result;
     umf_memory_provider_handle_t os_memory_provider = NULL;
-    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
-                                         &UMF_OS_MEMORY_PROVIDER_PARAMS,
+    umf_os_memory_provider_params_handle_t os_params = NULL;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_params);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(stderr, "error: umfOsMemoryProviderParamsCreate() failed\n");
+        exit(-1);
+    }
+
+    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params,
                                          &os_memory_provider);
+    umfOsMemoryProviderParamsDestroy(os_params);
     if (umf_result != UMF_RESULT_SUCCESS) {
         fprintf(stderr, "error: umfMemoryProviderCreate() failed\n");
         exit(-1);
@@ -252,9 +252,17 @@ UBENCH_EX(simple, disjoint_pool_with_os_memory_provider) {
 
     umf_result_t umf_result;
     umf_memory_provider_handle_t os_memory_provider = NULL;
-    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
-                                         &UMF_OS_MEMORY_PROVIDER_PARAMS,
+    umf_os_memory_provider_params_handle_t os_params = NULL;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_params);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(stderr, "error: umfOsMemoryProviderParamsCreate() failed\n");
+        exit(-1);
+    }
+
+    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params,
                                          &os_memory_provider);
+    umfOsMemoryProviderParamsDestroy(os_params);
     if (umf_result != UMF_RESULT_SUCCESS) {
         fprintf(stderr, "error: umfMemoryProviderCreate() failed\n");
         exit(-1);
@@ -329,9 +337,17 @@ UBENCH_EX(simple, jemalloc_pool_with_os_memory_provider) {
 
     umf_result_t umf_result;
     umf_memory_provider_handle_t os_memory_provider = NULL;
-    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
-                                         &UMF_OS_MEMORY_PROVIDER_PARAMS,
+    umf_os_memory_provider_params_handle_t os_params = NULL;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_params);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(stderr, "error: umfOsMemoryProviderParamsCreate() failed\n");
+        exit(-1);
+    }
+
+    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params,
                                          &os_memory_provider);
+    umfOsMemoryProviderParamsDestroy(os_params);
     if (umf_result != UMF_RESULT_SUCCESS) {
         fprintf(stderr, "error: umfMemoryProviderCreate() failed\n");
         exit(-1);
@@ -367,9 +383,17 @@ UBENCH_EX(simple, scalable_pool_with_os_memory_provider) {
 
     umf_result_t umf_result;
     umf_memory_provider_handle_t os_memory_provider = NULL;
-    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
-                                         &UMF_OS_MEMORY_PROVIDER_PARAMS,
+    umf_os_memory_provider_params_handle_t os_params = NULL;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_params);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(stderr, "error: umfOsMemoryProviderParamsCreate() failed\n");
+        exit(-1);
+    }
+
+    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params,
                                          &os_memory_provider);
+    umfOsMemoryProviderParamsDestroy(os_params);
     if (umf_result != UMF_RESULT_SUCCESS) {
         fprintf(stderr, "error: umfMemoryProviderCreate() failed\n");
         exit(-1);
diff --git a/examples/basic/basic.c b/examples/basic/basic.c
index d886c4af8..846e71eda 100644
--- a/examples/basic/basic.c
+++ b/examples/basic/basic.c
@@ -23,10 +23,17 @@ int main(void) {
     // in an mmap call like this:
     // mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)
     umf_memory_provider_ops_t *provider_ops = umfOsMemoryProviderOps();
-    umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault();
+    umf_os_memory_provider_params_handle_t params = NULL;
     umf_memory_provider_handle_t provider;
 
-    res = umfMemoryProviderCreate(provider_ops, &params, &provider);
+    res = umfOsMemoryProviderParamsCreate(&params);
+    if (res != UMF_RESULT_SUCCESS) {
+        printf("Failed to create OS memory provider params!\n");
+        return -1;
+    }
+
+    res = umfMemoryProviderCreate(provider_ops, params, &provider);
+    umfOsMemoryProviderParamsDestroy(params);
     if (res != UMF_RESULT_SUCCESS) {
         printf("Failed to create a memory provider!\n");
         return -1;
diff --git a/examples/dram_and_fsdax/dram_and_fsdax.c b/examples/dram_and_fsdax/dram_and_fsdax.c
index ef11c186e..26f451728 100644
--- a/examples/dram_and_fsdax/dram_and_fsdax.c
+++ b/examples/dram_and_fsdax/dram_and_fsdax.c
@@ -21,11 +21,16 @@ static umf_memory_pool_handle_t create_dram_pool(void) {
     umf_memory_pool_handle_t pool_dram;
     umf_result_t umf_result;
 
-    umf_os_memory_provider_params_t params_dram =
-        umfOsMemoryProviderParamsDefault();
+    umf_os_memory_provider_params_handle_t params_dram = NULL;
+    umf_result = umfOsMemoryProviderParamsCreate(&params_dram);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(stderr, "Failed to create OS memory provider params!\n");
+        return NULL;
+    }
 
-    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &params_dram,
+    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), params_dram,
                                          &provider_dram);
+    umfOsMemoryProviderParamsDestroy(params_dram);
     if (umf_result != UMF_RESULT_SUCCESS) {
         fprintf(stderr, "Creation of the OS memory provider failed");
         return NULL;
diff --git a/examples/ipc_ipcapi/ipc_ipcapi_consumer.c b/examples/ipc_ipcapi/ipc_ipcapi_consumer.c
index 05596bd16..1739e005a 100644
--- a/examples/ipc_ipcapi/ipc_ipcapi_consumer.c
+++ b/examples/ipc_ipcapi/ipc_ipcapi_consumer.c
@@ -99,17 +99,33 @@ int main(int argc, char *argv[]) {
     int port = atoi(argv[1]);
 
     umf_memory_provider_handle_t OS_memory_provider = NULL;
-    umf_os_memory_provider_params_t os_params;
+    umf_os_memory_provider_params_handle_t os_params = NULL;
     enum umf_result_t umf_result;
 
-    os_params = umfOsMemoryProviderParamsDefault();
-    os_params.visibility = UMF_MEM_MAP_SHARED;
+    umf_result = umfOsMemoryProviderParamsCreate(&os_params);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(
+            stderr,
+            "[consumer] ERROR: creating OS memory provider params failed\n");
+        return -1;
+    }
+    umf_result =
+        umfOsMemoryProviderParamsSetVisibility(os_params, UMF_MEM_MAP_SHARED);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(stderr, "[consumer] ERROR: setting visibility mode failed\n");
+        goto err_destroy_OS_params;
+    }
     if (argc >= 3) {
-        os_params.shm_name = argv[2];
+        umf_result = umfOsMemoryProviderParamsSetShmName(os_params, argv[2]);
+        if (umf_result != UMF_RESULT_SUCCESS) {
+            fprintf(stderr,
+                    "[consumer] ERROR: setting shared memory name failed\n");
+            goto err_destroy_OS_params;
+        }
     }
 
     // create OS memory provider
-    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_params,
+    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params,
                                          &OS_memory_provider);
     if (umf_result != UMF_RESULT_SUCCESS) {
         fprintf(stderr,
@@ -267,6 +283,9 @@ int main(int argc, char *argv[]) {
 err_destroy_OS_memory_provider:
     umfMemoryProviderDestroy(OS_memory_provider);
 
+err_destroy_OS_params:
+    umfOsMemoryProviderParamsDestroy(os_params);
+
     if (ret == 0) {
         fprintf(stderr, "[consumer] Shutting down (status OK) ...\n");
     } else if (ret == 1) {
diff --git a/examples/ipc_ipcapi/ipc_ipcapi_producer.c b/examples/ipc_ipcapi/ipc_ipcapi_producer.c
index fcb73650f..4157e8284 100644
--- a/examples/ipc_ipcapi/ipc_ipcapi_producer.c
+++ b/examples/ipc_ipcapi/ipc_ipcapi_producer.c
@@ -70,17 +70,33 @@ int main(int argc, char *argv[]) {
     int port = atoi(argv[1]);
 
     umf_memory_provider_handle_t OS_memory_provider = NULL;
-    umf_os_memory_provider_params_t os_params;
+    umf_os_memory_provider_params_handle_t os_params = NULL;
     enum umf_result_t umf_result;
 
-    os_params = umfOsMemoryProviderParamsDefault();
-    os_params.visibility = UMF_MEM_MAP_SHARED;
+    umf_result = umfOsMemoryProviderParamsCreate(&os_params);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(
+            stderr,
+            "[producer] ERROR: creating OS memory provider params failed\n");
+        return -1;
+    }
+    umf_result =
+        umfOsMemoryProviderParamsSetVisibility(os_params, UMF_MEM_MAP_SHARED);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(stderr, "[producer] ERROR: setting visibility mode failed\n");
+        goto err_destroy_OS_params;
+    }
     if (argc >= 3) {
-        os_params.shm_name = argv[2];
+        umf_result = umfOsMemoryProviderParamsSetShmName(os_params, argv[2]);
+        if (umf_result != UMF_RESULT_SUCCESS) {
+            fprintf(stderr,
+                    "[producer] ERROR: setting shared memory name failed\n");
+            goto err_destroy_OS_params;
+        }
     }
 
     // create OS memory provider
-    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_params,
+    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params,
                                          &OS_memory_provider);
     if (umf_result != UMF_RESULT_SUCCESS) {
         fprintf(stderr,
@@ -240,6 +256,9 @@ int main(int argc, char *argv[]) {
 err_destroy_OS_memory_provider:
     umfMemoryProviderDestroy(OS_memory_provider);
 
+err_destroy_OS_params:
+    umfOsMemoryProviderParamsDestroy(os_params);
+
     if (ret == 0) {
         fprintf(stderr, "[producer] Shutting down (status OK) ...\n");
     } else if (ret == 1) {
diff --git a/include/umf/providers/provider_os_memory.h b/include/umf/providers/provider_os_memory.h
index e175aaa6a..a6bf43a7d 100644
--- a/include/umf/providers/provider_os_memory.h
+++ b/include/umf/providers/provider_os_memory.h
@@ -60,32 +60,77 @@ typedef struct umf_numa_split_partition_t {
     unsigned target;
 } umf_numa_split_partition_t;
 
-/// @brief Memory provider settings struct
-typedef struct umf_os_memory_provider_params_t {
-    /// Combination of 'umf_mem_protection_flags_t' flags
-    unsigned protection;
-    /// memory visibility mode
-    umf_memory_visibility_t visibility;
-    /// (optional) a name of a shared memory file (valid only in case of the shared memory visibility)
-    char *shm_name;
-
-    // NUMA config
-    /// ordered list of numa nodes
-    unsigned *numa_list;
-    /// length of numa_list
-    unsigned numa_list_len;
-
-    /// Describes how node list is interpreted
-    umf_numa_mode_t numa_mode;
-    /// part size for interleave mode - 0 means default (system specific)
-    /// It might be rounded up because of HW constraints
-    size_t part_size;
-
-    /// ordered list of the partitions for the split mode
-    umf_numa_split_partition_t *partitions;
-    /// len of the partitions array
-    unsigned partitions_len;
-} umf_os_memory_provider_params_t;
+struct umf_os_memory_provider_params_t;
+
+typedef struct umf_os_memory_provider_params_t
+    *umf_os_memory_provider_params_handle_t;
+
+/// @brief  Create a struct to store parameters of the OS memory provider.
+/// @param  hParams [out] handle to the newly created parameters struct.
+/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
+umf_result_t umfOsMemoryProviderParamsCreate(
+    umf_os_memory_provider_params_handle_t *hParams);
+
+/// @brief  Destroy parameters struct.
+/// @param  hParams handle to the parameters of the OS memory provider.
+/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
+umf_result_t umfOsMemoryProviderParamsDestroy(
+    umf_os_memory_provider_params_handle_t hParams);
+
+/// @brief  Set protection flags for the OS memory provider.
+/// @param  hParams handle to the parameters of the OS memory provider.
+/// @param  protection combination of \p umf_mem_protection_flags_t flags.
+/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
+umf_result_t umfOsMemoryProviderParamsSetProtection(
+    umf_os_memory_provider_params_handle_t hParams, unsigned protection);
+
+/// @brief  Set visibility mode for the OS memory provider.
+/// @param  hParams handle to the parameters of the OS memory provider.
+/// @param  visibility memory visibility mode.
+/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
+umf_result_t umfOsMemoryProviderParamsSetVisibility(
+    umf_os_memory_provider_params_handle_t hParams,
+    umf_memory_visibility_t visibility);
+
+/// @brief  Set a name of a shared memory file for the OS memory provider.
+/// @param  hParams handle to the parameters of the OS memory provider.
+/// @param  shm_name a name of a shared memory file.
+/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
+umf_result_t umfOsMemoryProviderParamsSetShmName(
+    umf_os_memory_provider_params_handle_t hParams, const char *shm_name);
+
+/// @brief  Set NUMA nodes for the OS memory provider.
+/// @param  hParams handle to the parameters of the OS memory provider.
+/// @param  numa_list ordered list of NUMA nodes.
+/// @param  numa_list_len length of the numa_list.
+/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
+umf_result_t umfOsMemoryProviderParamsSetNumaList(
+    umf_os_memory_provider_params_handle_t hParams, unsigned *numa_list,
+    unsigned numa_list_len);
+
+/// @brief  Set NUMA mode for the OS memory provider.
+/// @param  hParams handle to the parameters of the OS memory provider.
+/// @param  numa_mode NUMA mode. Describes how node list is interpreted.
+/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
+umf_result_t umfOsMemoryProviderParamsSetNumaMode(
+    umf_os_memory_provider_params_handle_t hParams, umf_numa_mode_t numa_mode);
+
+/// @brief  Set part size for the interleave mode. 0 means default (system specific)
+///         It might be rounded up because of HW constraints.
+/// @param  hParams handle to the parameters of the OS memory provider.
+/// @param  part_size part size for interleave mode.
+/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
+umf_result_t umfOsMemoryProviderParamsSetPartSize(
+    umf_os_memory_provider_params_handle_t hParams, size_t part_size);
+
+/// @brief  Set partitions for the split mode.
+/// @param  hParams handle to the parameters of the OS memory provider.
+/// @param  partitions ordered list of the partitions for the split mode.
+/// @param  partitions_len length of the partitions array.
+/// @return UMF_RESULT_SUCCESS on success or appropriate error code on failure.
+umf_result_t umfOsMemoryProviderParamsSetPartitions(
+    umf_os_memory_provider_params_handle_t hParams,
+    umf_numa_split_partition_t *partitions, unsigned partitions_len);
 
 /// @brief OS Memory Provider operation results
 typedef enum umf_os_memory_provider_native_error {
@@ -101,23 +146,6 @@ typedef enum umf_os_memory_provider_native_error {
 
 umf_memory_provider_ops_t *umfOsMemoryProviderOps(void);
 
-/// @brief Create default params for os memory provider
-static inline umf_os_memory_provider_params_t
-umfOsMemoryProviderParamsDefault(void) {
-    umf_os_memory_provider_params_t params = {
-        UMF_PROTECTION_READ | UMF_PROTECTION_WRITE, /* protection */
-        UMF_MEM_MAP_PRIVATE,                        /* visibility mode */
-        NULL, /* (optional) a name of a shared memory file (valid only in case of the shared memory visibility) */
-        NULL, /* numa_list */
-        0,    /* numa_list_len */
-        UMF_NUMA_MODE_DEFAULT, /* numa_mode */
-        0,                     /* part_size */
-        NULL,                  /* partitions */
-        0};                    /* partitions_len*/
-
-    return params;
-}
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/scripts/docs_config/examples.rst b/scripts/docs_config/examples.rst
index 5e2ff71fa..a84dd3aa2 100644
--- a/scripts/docs_config/examples.rst
+++ b/scripts/docs_config/examples.rst
@@ -31,11 +31,20 @@ the OS Memory Provider API::
 
     #include "umf/providers/provider_os_memory.h"
 
-Get a pointer to the OS memory provider operations struct and
-a copy of default parameters::
+Get a pointer to the OS memory provider operations struct::
 
     umf_memory_provider_ops_t *provider_ops = umfOsMemoryProviderOps();
-    umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault();
+
+Get a default OS memory provider parameters. The handle to the parameters object
+is returned by the :any:`umfOsMemoryProviderParamsCreate` function::
+
+    umf_os_memory_provider_params_handle_t params = NULL;
+
+    res = umfOsMemoryProviderParamsCreate(&params);
+    if (res != UMF_RESULT_SUCCESS) {
+        printf("Failed to create OS memory provider params!\n");
+        return -1;
+    }
 
 The handle to created memory ``provider`` object is returned as the last argument
 of :any:`umfMemoryProviderCreate`::
@@ -43,7 +52,10 @@ of :any:`umfMemoryProviderCreate`::
     umf_memory_provider_handle_t provider;
     umfMemoryProviderCreate(provider_ops, &params, &provider);
 
-With this handle we can allocate a chunk of memory, call :any:`umfMemoryProviderAlloc`::
+The ``params`` object can be destroyed after the provider is created::
+    umfOsMemoryProviderParamsDestroy(params);
+
+With the ``provider`` handle we can allocate a chunk of memory, call :any:`umfMemoryProviderAlloc`::
 
     size_t alloc_size = 5000;
     size_t alignment = 0;
diff --git a/src/libumf.def b/src/libumf.def
index abb25204c..ae1ba6809 100644
--- a/src/libumf.def
+++ b/src/libumf.def
@@ -82,6 +82,15 @@ EXPORTS
     umfMemtargetGetType
     umfOpenIPCHandle
     umfOsMemoryProviderOps
+    umfOsMemoryProviderParamsCreate
+    umfOsMemoryProviderParamsDestroy
+    umfOsMemoryProviderParamsSetProtection
+    umfOsMemoryProviderParamsSetVisibility
+    umfOsMemoryProviderParamsSetShmName
+    umfOsMemoryProviderParamsSetNumaList
+    umfOsMemoryProviderParamsSetNumaMode
+    umfOsMemoryProviderParamsSetPartSize
+    umfOsMemoryProviderParamsSetPartitions
     umfPoolAlignedMalloc
     umfPoolByPtr
     umfPoolCalloc
diff --git a/src/libumf.map b/src/libumf.map
index 3a5e73f44..923112384 100644
--- a/src/libumf.map
+++ b/src/libumf.map
@@ -76,6 +76,15 @@ UMF_1.0 {
         umfMemtargetGetType;
         umfOpenIPCHandle;
         umfOsMemoryProviderOps;
+        umfOsMemoryProviderParamsCreate;
+        umfOsMemoryProviderParamsDestroy;
+        umfOsMemoryProviderParamsSetProtection;
+        umfOsMemoryProviderParamsSetVisibility;
+        umfOsMemoryProviderParamsSetShmName;
+        umfOsMemoryProviderParamsSetNumaList;
+        umfOsMemoryProviderParamsSetNumaMode;
+        umfOsMemoryProviderParamsSetPartSize;
+        umfOsMemoryProviderParamsSetPartitions;
         umfPoolAlignedMalloc;
         umfPoolByPtr;
         umfPoolCalloc;
diff --git a/src/memtargets/memtarget_numa.c b/src/memtargets/memtarget_numa.c
index 34ba7fc10..f32774ebb 100644
--- a/src/memtargets/memtarget_numa.c
+++ b/src/memtargets/memtarget_numa.c
@@ -69,22 +69,27 @@ static umf_result_t numa_memory_provider_create_from_memspace(
         return UMF_RESULT_ERROR_INVALID_ARGUMENT;
     }
 
-    umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault();
+    umf_numa_mode_t numa_mode = UMF_NUMA_MODE_DEFAULT;
+    size_t part_size = 0;
+    umf_numa_split_partition_t *partitions = NULL;
+    unsigned partitions_len = 0;
+    unsigned *numa_list = NULL;
+    unsigned numa_list_len = 0;
 
     if (policy) {
         switch (policy->type) {
         case UMF_MEMPOLICY_INTERLEAVE:
-            params.numa_mode = UMF_NUMA_MODE_INTERLEAVE;
-            params.part_size = policy->ops.interleave.part_size;
+            numa_mode = UMF_NUMA_MODE_INTERLEAVE;
+            part_size = policy->ops.interleave.part_size;
             break;
         case UMF_MEMPOLICY_BIND:
-            params.numa_mode = UMF_NUMA_MODE_BIND;
+            numa_mode = UMF_NUMA_MODE_BIND;
             break;
         case UMF_MEMPOLICY_PREFERRED:
-            params.numa_mode = UMF_NUMA_MODE_PREFERRED;
+            numa_mode = UMF_NUMA_MODE_PREFERRED;
             break;
         case UMF_MEMPOLICY_SPLIT:
-            params.numa_mode = UMF_NUMA_MODE_SPLIT;
+            numa_mode = UMF_NUMA_MODE_SPLIT;
 
             // compile time check to ensure we can just cast
             // umf_mempolicy_split_partition_t to
@@ -98,9 +103,8 @@ static umf_result_t numa_memory_provider_create_from_memspace(
                 offsetof(umf_mempolicy_split_partition_t, target) !=
                 offsetof(umf_numa_split_partition_t, target));
 
-            params.partitions =
-                (umf_numa_split_partition_t *)policy->ops.split.part;
-            params.partitions_len = (unsigned)policy->ops.split.part_len;
+            partitions = (umf_numa_split_partition_t *)policy->ops.split.part;
+            partitions_len = (unsigned)policy->ops.split.part_len;
             break;
         default:
             return UMF_RESULT_ERROR_INVALID_ARGUMENT;
@@ -109,44 +113,80 @@ static umf_result_t numa_memory_provider_create_from_memspace(
         if (memspace == umfMemspaceHostAllGet()) {
             // For the default memspace, we use the default mode without any
             // call to mbind
-            params.numa_mode = UMF_NUMA_MODE_DEFAULT;
+            numa_mode = UMF_NUMA_MODE_DEFAULT;
         } else {
-            params.numa_mode = UMF_NUMA_MODE_BIND;
+            numa_mode = UMF_NUMA_MODE_BIND;
         }
     }
 
     if (memspace == umfMemspaceHostAllGet() && policy == NULL) {
         // For default memspace with default policy we use all numa nodes so
         // simply left numa list empty
-        params.numa_list_len = 0;
-        params.numa_list = NULL;
+        numa_list_len = 0;
+        numa_list = NULL;
     } else {
-        params.numa_list =
-            umf_ba_global_alloc(sizeof(*params.numa_list) * numNodesProvider);
+        numa_list = umf_ba_global_alloc(sizeof(*numa_list) * numNodesProvider);
 
-        if (!params.numa_list) {
+        if (!numa_list) {
             return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
         }
 
         for (size_t i = 0; i < numNodesProvider; i++) {
-            params.numa_list[i] = numaTargets[i]->physical_id;
+            numa_list[i] = numaTargets[i]->physical_id;
         }
-        params.numa_list_len = (unsigned)numNodesProvider;
+        numa_list_len = (unsigned)numNodesProvider;
     }
 
-    umf_memory_provider_handle_t numaProvider = NULL;
-    int ret = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &params,
-                                      &numaProvider);
+    umf_os_memory_provider_params_handle_t params = NULL;
+    umf_result_t ret = umfOsMemoryProviderParamsCreate(&params);
+    if (ret != UMF_RESULT_SUCCESS) {
+        LOG_ERR("Creating OS memory provider params failed");
+        goto destroy_numa_list;
+    }
 
-    umf_ba_global_free(params.numa_list);
+    ret = umfOsMemoryProviderParamsSetNumaMode(params, numa_mode);
+    if (ret != UMF_RESULT_SUCCESS) {
+        LOG_ERR("Setting NUMA mode failed");
+        goto destroy_provider_params;
+    }
 
-    if (ret) {
-        return ret;
+    ret =
+        umfOsMemoryProviderParamsSetNumaList(params, numa_list, numa_list_len);
+    if (ret != UMF_RESULT_SUCCESS) {
+        LOG_ERR("Setting NUMA list failed");
+        goto destroy_provider_params;
+    }
+
+    ret = umfOsMemoryProviderParamsSetPartitions(params, partitions,
+                                                 partitions_len);
+    if (ret != UMF_RESULT_SUCCESS) {
+        LOG_ERR("Setting partitions failed");
+        goto destroy_provider_params;
+    }
+
+    ret = umfOsMemoryProviderParamsSetPartSize(params, part_size);
+    if (ret != UMF_RESULT_SUCCESS) {
+        LOG_ERR("Setting part size failed");
+        goto destroy_provider_params;
+    }
+
+    umf_memory_provider_handle_t numaProvider = NULL;
+    ret = umfMemoryProviderCreate(umfOsMemoryProviderOps(), params,
+                                  &numaProvider);
+    if (ret != UMF_RESULT_SUCCESS) {
+        LOG_ERR("Creating OS memory provider failed");
+        goto destroy_provider_params;
     }
 
     *provider = numaProvider;
 
-    return UMF_RESULT_SUCCESS;
+destroy_provider_params:
+    umfOsMemoryProviderParamsDestroy(params);
+
+destroy_numa_list:
+    umf_ba_global_free(numa_list);
+
+    return ret;
 }
 
 static umf_result_t numa_pool_create_from_memspace(
diff --git a/src/provider/provider_os_memory.c b/src/provider/provider_os_memory.c
index dae947651..4c19944a9 100644
--- a/src/provider/provider_os_memory.c
+++ b/src/provider/provider_os_memory.c
@@ -22,10 +22,77 @@
 
 umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) { return NULL; }
 
+umf_result_t umfOsMemoryProviderParamsCreate(
+    umf_os_memory_provider_params_handle_t *hParams) {
+    (void)hParams;
+    return UMF_RESULT_ERROR_NOT_SUPPORTED;
+}
+
+umf_result_t umfOsMemoryProviderParamsDestroy(
+    umf_os_memory_provider_params_handle_t hParams) {
+    (void)hParams;
+    return UMF_RESULT_ERROR_NOT_SUPPORTED;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetProtection(
+    umf_os_memory_provider_params_handle_t hParams, unsigned protection) {
+    (void)hParams;
+    (void)protection;
+    return UMF_RESULT_ERROR_NOT_SUPPORTED;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetVisibility(
+    umf_os_memory_provider_params_handle_t hParams,
+    umf_memory_visibility_t visibility) {
+    (void)hParams;
+    (void)visibility;
+    return UMF_RESULT_ERROR_NOT_SUPPORTED;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetShmName(
+    umf_os_memory_provider_params_handle_t hParams, const char *shm_name) {
+    (void)hParams;
+    (void)shm_name;
+    return UMF_RESULT_ERROR_NOT_SUPPORTED;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetNumaList(
+    umf_os_memory_provider_params_handle_t hParams, unsigned *numa_list,
+    unsigned numa_list_len) {
+    (void)hParams;
+    (void)numa_list;
+    (void)numa_list_len;
+    return UMF_RESULT_ERROR_NOT_SUPPORTED;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetNumaMode(
+    umf_os_memory_provider_params_handle_t hParams, umf_numa_mode_t numa_mode) {
+    (void)hParams;
+    (void)numa_mode;
+    return UMF_RESULT_ERROR_NOT_SUPPORTED;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetPartSize(
+    umf_os_memory_provider_params_handle_t hParams, size_t part_size) {
+    (void)hParams;
+    (void)part_size;
+    return UMF_RESULT_ERROR_NOT_SUPPORTED;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetPartitions(
+    umf_os_memory_provider_params_handle_t hParams,
+    umf_numa_split_partition_t *partitions, unsigned partitions_len) {
+    (void)hParams;
+    (void)partitions;
+    (void)partitions_len;
+    return UMF_RESULT_ERROR_NOT_SUPPORTED;
+}
+
 #else // !defined(UMF_NO_HWLOC)
 
 #include "base_alloc_global.h"
 #include "critnib.h"
+#include "libumf.h"
 #include "provider_os_memory_internal.h"
 #include "utils_common.h"
 #include "utils_concurrency.h"
@@ -35,6 +102,32 @@ umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) { return NULL; }
 
 #define TLS_MSG_BUF_LEN 1024
 
+typedef struct umf_os_memory_provider_params_t {
+    // Combination of 'umf_mem_protection_flags_t' flags
+    unsigned protection;
+    /// memory visibility mode
+    umf_memory_visibility_t visibility;
+    /// (optional) a name of a shared memory file (valid only in case of the shared memory visibility)
+    char *shm_name;
+
+    // NUMA config
+    /// ordered list of numa nodes
+    unsigned *numa_list;
+    /// length of numa_list
+    unsigned numa_list_len;
+
+    /// Describes how node list is interpreted
+    umf_numa_mode_t numa_mode;
+    /// part size for interleave mode - 0 means default (system specific)
+    /// It might be rounded up because of HW constraints
+    size_t part_size;
+
+    /// ordered list of the partitions for the split mode
+    umf_numa_split_partition_t *partitions;
+    /// len of the partitions array
+    unsigned partitions_len;
+} umf_os_memory_provider_params_t;
+
 typedef struct os_last_native_error_t {
     int32_t native_error;
     int errno_value;
@@ -1334,4 +1427,184 @@ umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) {
     return &UMF_OS_MEMORY_PROVIDER_OPS;
 }
 
+umf_result_t umfOsMemoryProviderParamsCreate(
+    umf_os_memory_provider_params_handle_t *hParams) {
+    libumfInit();
+    if (hParams == NULL) {
+        LOG_ERR("OS memory provider params handle is NULL");
+        return UMF_RESULT_ERROR_INVALID_ARGUMENT;
+    }
+
+    umf_os_memory_provider_params_handle_t params =
+        umf_ba_global_alloc(sizeof(*params));
+    if (params == NULL) {
+        LOG_ERR("allocating memory for OS memory provider params failed");
+        return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
+    }
+
+    params->protection = UMF_PROTECTION_READ | UMF_PROTECTION_WRITE;
+    params->visibility = UMF_MEM_MAP_PRIVATE;
+    params->shm_name = NULL;
+    params->numa_list = NULL;
+    params->numa_list_len = 0;
+    params->numa_mode = UMF_NUMA_MODE_DEFAULT;
+    params->part_size = 0;
+    params->partitions = NULL;
+    params->partitions_len = 0;
+
+    *hParams = params;
+
+    return UMF_RESULT_SUCCESS;
+}
+
+umf_result_t umfOsMemoryProviderParamsDestroy(
+    umf_os_memory_provider_params_handle_t hParams) {
+    if (hParams != NULL) {
+        umf_ba_global_free(hParams->shm_name);
+        umf_ba_global_free(hParams->numa_list);
+        umf_ba_global_free(hParams->partitions);
+    }
+
+    umf_ba_global_free(hParams);
+
+    return UMF_RESULT_SUCCESS;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetProtection(
+    umf_os_memory_provider_params_handle_t hParams, unsigned protection) {
+    if (hParams == NULL) {
+        LOG_ERR("OS memory provider params handle is NULL");
+        return UMF_RESULT_ERROR_INVALID_ARGUMENT;
+    }
+
+    hParams->protection = protection;
+
+    return UMF_RESULT_SUCCESS;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetVisibility(
+    umf_os_memory_provider_params_handle_t hParams,
+    umf_memory_visibility_t visibility) {
+    if (hParams == NULL) {
+        LOG_ERR("OS memory provider params handle is NULL");
+        return UMF_RESULT_ERROR_INVALID_ARGUMENT;
+    }
+
+    hParams->visibility = visibility;
+
+    return UMF_RESULT_SUCCESS;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetShmName(
+    umf_os_memory_provider_params_handle_t hParams, const char *shm_name) {
+    if (hParams == NULL) {
+        LOG_ERR("OS memory provider params handle is NULL");
+        return UMF_RESULT_ERROR_INVALID_ARGUMENT;
+    }
+
+    char *name = NULL;
+    if (shm_name) {
+        size_t len = strlen(shm_name) + 1;
+        name = umf_ba_global_alloc(len);
+        if (name == NULL) {
+            LOG_ERR("allocating memory for the shared memory name failed");
+            return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
+        }
+
+        strncpy(name, shm_name, len);
+    }
+    umf_ba_global_free(hParams->shm_name);
+    hParams->shm_name = name;
+
+    return UMF_RESULT_SUCCESS;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetNumaList(
+    umf_os_memory_provider_params_handle_t hParams, unsigned *numa_list,
+    unsigned numa_list_len) {
+    if (hParams == NULL) {
+        LOG_ERR("OS memory provider params handle is NULL");
+        return UMF_RESULT_ERROR_INVALID_ARGUMENT;
+    }
+
+    if (numa_list_len && !numa_list) {
+        LOG_ERR("numa_list_len is not 0, but numa_list is NULL");
+        return UMF_RESULT_ERROR_INVALID_ARGUMENT;
+    }
+
+    unsigned *new_list = NULL;
+    if (numa_list_len) {
+        new_list = umf_ba_global_alloc(numa_list_len * sizeof(*new_list));
+        if (new_list == NULL) {
+            LOG_ERR("allocating memory for the NUMA list failed");
+            return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
+        }
+
+        memcpy(new_list, numa_list, numa_list_len * sizeof(*new_list));
+    }
+
+    umf_ba_global_free(hParams->numa_list);
+    hParams->numa_list = new_list;
+    hParams->numa_list_len = numa_list_len;
+
+    return UMF_RESULT_SUCCESS;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetNumaMode(
+    umf_os_memory_provider_params_handle_t hParams, umf_numa_mode_t numa_mode) {
+    if (hParams == NULL) {
+        LOG_ERR("OS memory provider params handle is NULL");
+        return UMF_RESULT_ERROR_INVALID_ARGUMENT;
+    }
+
+    hParams->numa_mode = numa_mode;
+
+    return UMF_RESULT_SUCCESS;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetPartSize(
+    umf_os_memory_provider_params_handle_t hParams, size_t part_size) {
+    if (hParams == NULL) {
+        LOG_ERR("OS memory provider params handle is NULL");
+        return UMF_RESULT_ERROR_INVALID_ARGUMENT;
+    }
+
+    hParams->part_size = part_size;
+
+    return UMF_RESULT_SUCCESS;
+}
+
+umf_result_t umfOsMemoryProviderParamsSetPartitions(
+    umf_os_memory_provider_params_handle_t hParams,
+    umf_numa_split_partition_t *partitions, unsigned partitions_len) {
+    if (hParams == NULL) {
+        LOG_ERR("OS memory provider params handle is NULL");
+        return UMF_RESULT_ERROR_INVALID_ARGUMENT;
+    }
+
+    if (partitions_len && !partitions) {
+        LOG_ERR("partitions_len is not 0, but partitions is NULL");
+        return UMF_RESULT_ERROR_INVALID_ARGUMENT;
+    }
+
+    umf_numa_split_partition_t *new_partitions = NULL;
+    if (partitions_len) {
+        new_partitions =
+            umf_ba_global_alloc(partitions_len * sizeof(*new_partitions));
+        if (new_partitions == NULL) {
+            LOG_ERR("allocating memory for the partitions failed");
+            return UMF_RESULT_ERROR_OUT_OF_HOST_MEMORY;
+        }
+
+        memcpy(new_partitions, partitions,
+               partitions_len * sizeof(*new_partitions));
+    }
+
+    umf_ba_global_free(hParams->partitions);
+    hParams->partitions = new_partitions;
+    hParams->partitions_len = partitions_len;
+
+    return UMF_RESULT_SUCCESS;
+}
+
 #endif // !defined(UMF_NO_HWLOC)
diff --git a/src/proxy_lib/proxy_lib.c b/src/proxy_lib/proxy_lib.c
index 3320f2898..4b168ab80 100644
--- a/src/proxy_lib/proxy_lib.c
+++ b/src/proxy_lib/proxy_lib.c
@@ -183,10 +183,15 @@ static int get_system_allocator_symbols(void) {
 
 void proxy_lib_create_common(void) {
     utils_log_init();
-    umf_os_memory_provider_params_t os_params =
-        umfOsMemoryProviderParamsDefault();
+    umf_os_memory_provider_params_handle_t os_params = NULL;
     umf_result_t umf_result;
 
+    umf_result = umfOsMemoryProviderParamsCreate(&os_params);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        LOG_ERR("creating OS memory provider params failed");
+        exit(-1);
+    }
+
 #ifndef _WIN32
     size_t _threshold = get_size_threshold();
     if (_threshold > 0) {
@@ -203,26 +208,44 @@ void proxy_lib_create_common(void) {
     if (utils_env_var_has_str("UMF_PROXY", "page.disposition=shared-fd")) {
         LOG_INFO("proxy_lib: using the MAP_SHARED visibility mode with the "
                  "file descriptor duplication");
-        os_params.visibility = UMF_MEM_MAP_SHARED;
-        os_params.shm_name = NULL;
-
+        umf_result = umfOsMemoryProviderParamsSetVisibility(os_params,
+                                                            UMF_MEM_MAP_SHARED);
+        if (umf_result != UMF_RESULT_SUCCESS) {
+            LOG_ERR("setting visibility mode failed");
+            exit(-1);
+        }
+        umf_result = umfOsMemoryProviderParamsSetShmName(os_params, NULL);
+        if (umf_result != UMF_RESULT_SUCCESS) {
+            LOG_ERR("setting shared memory name failed");
+            exit(-1);
+        }
     } else if (utils_env_var_has_str("UMF_PROXY",
                                      "page.disposition=shared-shm")) {
-        os_params.visibility = UMF_MEM_MAP_SHARED;
+        umf_result = umfOsMemoryProviderParamsSetVisibility(os_params,
+                                                            UMF_MEM_MAP_SHARED);
+        if (umf_result != UMF_RESULT_SUCCESS) {
+            LOG_ERR("setting visibility mode failed");
+            exit(-1);
+        }
 
         char shm_name[NAME_MAX];
         memset(shm_name, 0, NAME_MAX);
         sprintf(shm_name, "umf_proxy_lib_shm_pid_%i", utils_getpid());
-        os_params.shm_name = shm_name;
+        umf_result = umfOsMemoryProviderParamsSetShmName(os_params, shm_name);
+        if (umf_result != UMF_RESULT_SUCCESS) {
+            LOG_ERR("setting shared memory name failed");
+            exit(-1);
+        }
 
         LOG_INFO("proxy_lib: using the MAP_SHARED visibility mode with the "
                  "named shared memory: %s",
-                 os_params.shm_name);
+                 shm_name);
     }
 #endif /* _WIN32 */
 
-    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), &os_params,
+    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(), os_params,
                                          &OS_memory_provider);
+    umfOsMemoryProviderParamsDestroy(os_params);
     if (umf_result != UMF_RESULT_SUCCESS) {
         LOG_ERR("creating OS memory provider failed");
         exit(-1);


Test patch:
diff --git a/test/c_api/multi_pool.c b/test/c_api/multi_pool.c
index 518f992ea..bbd838312 100644
--- a/test/c_api/multi_pool.c
+++ b/test/c_api/multi_pool.c
@@ -60,11 +60,15 @@ createScalablePool(umf_memory_provider_handle_t provider) {
 #define ALLOC_SIZE 64
 
 int main(void) {
-    umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault();
+    umf_os_memory_provider_params_handle_t params = NULL;
+    umf_result_t ret = umfOsMemoryProviderParamsCreate(&params);
+    UT_ASSERTeq(ret, UMF_RESULT_SUCCESS);
 
     umf_memory_provider_handle_t hProvider;
-    umf_result_t ret =
-        umfMemoryProviderCreate(umfOsMemoryProviderOps(), &params, &hProvider);
+    ret = umfMemoryProviderCreate(umfOsMemoryProviderOps(), params, &hProvider);
+    UT_ASSERTeq(ret, UMF_RESULT_SUCCESS);
+
+    ret = umfOsMemoryProviderParamsDestroy(params);
     UT_ASSERTeq(ret, UMF_RESULT_SUCCESS);
 
     umf_memory_pool_handle_t pools[4];
diff --git a/test/fuzz/umfFuzz.cpp b/test/fuzz/umfFuzz.cpp
index ac52c96b5..360184c73 100644
--- a/test/fuzz/umfFuzz.cpp
+++ b/test/fuzz/umfFuzz.cpp
@@ -13,10 +13,15 @@ constexpr int MAX_PROVIDER_ALLOC_SIZE = 100 * 1024; // 100 kB
 
 int umf_memory_provider_create(TestState &test_state) {
     umf_memory_provider_ops_t *provider_ops = umfOsMemoryProviderOps();
-    umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault();
-    umf_result_t res =
-        umfMemoryProviderCreate(provider_ops, &params, &test_state.provider);
+    umf_os_memory_provider_params_handle_t params = NULL;
+
+    umf_result_t res = umfOsMemoryProviderParamsCreate(&params);
+    if (res != UMF_RESULT_SUCCESS) {
+        return -1;
+    }
 
+    res = umfMemoryProviderCreate(provider_ops, params, &test_state.provider);
+    umfOsMemoryProviderParamsDestroy(params);
     if (res != UMF_RESULT_SUCCESS) {
         return -1;
     }
diff --git a/test/ipc_os_prov_consumer.c b/test/ipc_os_prov_consumer.c
index 34f51fe1c..f3f8d0090 100644
--- a/test/ipc_os_prov_consumer.c
+++ b/test/ipc_os_prov_consumer.c
@@ -19,18 +19,44 @@ int main(int argc, char *argv[]) {
         return -1;
     }
 
+    int ret = 0;
     int port = atoi(argv[1]);
 
-    umf_os_memory_provider_params_t os_params;
+    umf_os_memory_provider_params_handle_t os_params = NULL;
+
+    umf_result_t umf_result = umfOsMemoryProviderParamsCreate(&os_params);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(
+            stderr,
+            "[consumer] ERROR: creating OS memory provider params failed\n");
+        return -1;
+    }
+
+    umf_result =
+        umfOsMemoryProviderParamsSetVisibility(os_params, UMF_MEM_MAP_SHARED);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(stderr, "[consumer] ERROR: setting visibility mode failed\n");
+        ret = -1;
+        goto destroy_provider_params;
+    }
 
-    os_params = umfOsMemoryProviderParamsDefault();
-    os_params.visibility = UMF_MEM_MAP_SHARED;
     if (argc >= 3) {
-        os_params.shm_name = argv[2];
+        umf_result = umfOsMemoryProviderParamsSetShmName(os_params, argv[2]);
+        if (umf_result != UMF_RESULT_SUCCESS) {
+            fprintf(stderr,
+                    "[consumer] ERROR: setting shared memory name failed\n");
+            ret = -1;
+            goto destroy_provider_params;
+        }
     }
 
     void *pool_params = NULL;
 
-    return run_consumer(port, umfScalablePoolOps(), pool_params,
-                        umfOsMemoryProviderOps(), &os_params, memcopy, NULL);
+    ret = run_consumer(port, umfScalablePoolOps(), pool_params,
+                       umfOsMemoryProviderOps(), os_params, memcopy, NULL);
+
+destroy_provider_params:
+    umfOsMemoryProviderParamsDestroy(os_params);
+
+    return ret;
 }
diff --git a/test/ipc_os_prov_producer.c b/test/ipc_os_prov_producer.c
index 623244902..890f1eb3e 100644
--- a/test/ipc_os_prov_producer.c
+++ b/test/ipc_os_prov_producer.c
@@ -19,18 +19,44 @@ int main(int argc, char *argv[]) {
         return -1;
     }
 
+    int ret = 0;
     int port = atoi(argv[1]);
 
-    umf_os_memory_provider_params_t os_params;
+    umf_os_memory_provider_params_handle_t os_params = NULL;
+
+    umf_result_t umf_result = umfOsMemoryProviderParamsCreate(&os_params);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(
+            stderr,
+            "[producer] ERROR: creating OS memory provider params failed\n");
+        return -1;
+    }
+
+    umf_result =
+        umfOsMemoryProviderParamsSetVisibility(os_params, UMF_MEM_MAP_SHARED);
+    if (umf_result != UMF_RESULT_SUCCESS) {
+        fprintf(stderr, "[producer] ERROR: setting visibility mode failed\n");
+        ret = -1;
+        goto destroy_provider_params;
+    }
 
-    os_params = umfOsMemoryProviderParamsDefault();
-    os_params.visibility = UMF_MEM_MAP_SHARED;
     if (argc >= 3) {
-        os_params.shm_name = argv[2];
+        umf_result = umfOsMemoryProviderParamsSetShmName(os_params, argv[2]);
+        if (umf_result != UMF_RESULT_SUCCESS) {
+            fprintf(stderr,
+                    "[producer] ERROR: setting shared memory name failed\n");
+            ret = -1;
+            goto destroy_provider_params;
+        }
     }
 
     void *pool_params = NULL;
 
-    return run_producer(port, umfScalablePoolOps(), pool_params,
-                        umfOsMemoryProviderOps(), &os_params, memcopy, NULL);
+    ret = run_producer(port, umfScalablePoolOps(), pool_params,
+                       umfOsMemoryProviderOps(), os_params, memcopy, NULL);
+
+destroy_provider_params:
+    umfOsMemoryProviderParamsDestroy(os_params);
+
+    return ret;
 }
diff --git a/test/pools/jemalloc_pool.cpp b/test/pools/jemalloc_pool.cpp
index 3a78c5371..4dddbcd32 100644
--- a/test/pools/jemalloc_pool.cpp
+++ b/test/pools/jemalloc_pool.cpp
@@ -11,11 +11,25 @@
 using umf_test::test;
 using namespace umf_test;
 
-auto defaultParams = umfOsMemoryProviderParamsDefault();
+using os_params_unique_handle_t =
+    std::unique_ptr<umf_os_memory_provider_params_t,
+                    decltype(&umfOsMemoryProviderParamsDestroy)>;
+
+os_params_unique_handle_t createOsMemoryProviderParams() {
+    umf_os_memory_provider_params_handle_t params = nullptr;
+    umf_result_t res = umfOsMemoryProviderParamsCreate(&params);
+    if (res != UMF_RESULT_SUCCESS) {
+        throw std::runtime_error("Failed to create os memory provider params");
+    }
+
+    return os_params_unique_handle_t(params, &umfOsMemoryProviderParamsDestroy);
+}
+auto defaultParams = createOsMemoryProviderParams();
+
 INSTANTIATE_TEST_SUITE_P(jemallocPoolTest, umfPoolTest,
                          ::testing::Values(poolCreateExtParams{
                              umfJemallocPoolOps(), nullptr,
-                             umfOsMemoryProviderOps(), &defaultParams,
+                             umfOsMemoryProviderOps(), defaultParams.get(),
                              nullptr}));
 
 // this test makes sure that jemalloc does not use
@@ -28,12 +42,18 @@ TEST_F(test, metadataNotAllocatedUsingProvider) {
 
     // set coarse grain allocations to PROT_NONE so that we can be sure
     // jemalloc does not touch any of the allocated memory
-    auto params = umfOsMemoryProviderParamsDefault();
-    params.protection = UMF_PROTECTION_NONE;
+    umf_os_memory_provider_params_handle_t params = nullptr;
+    umf_result_t res = umfOsMemoryProviderParamsCreate(&params);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+    res = umfOsMemoryProviderParamsSetProtection(params, UMF_PROTECTION_NONE);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
 
     auto pool =
         poolCreateExtUnique({umfJemallocPoolOps(), nullptr,
-                             umfOsMemoryProviderOps(), &params, nullptr});
+                             umfOsMemoryProviderOps(), params, nullptr});
+
+    res = umfOsMemoryProviderParamsDestroy(params);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
 
     std::vector<std::shared_ptr<void>> allocs;
     for (size_t i = 0; i < numAllocs; i++) {
diff --git a/test/pools/scalable_pool.cpp b/test/pools/scalable_pool.cpp
index 0066f75e3..3edacd965 100644
--- a/test/pools/scalable_pool.cpp
+++ b/test/pools/scalable_pool.cpp
@@ -9,11 +9,25 @@
 #include "poolFixtures.hpp"
 #include "provider.hpp"
 
-auto defaultParams = umfOsMemoryProviderParamsDefault();
+using os_params_unique_handle_t =
+    std::unique_ptr<umf_os_memory_provider_params_t,
+                    decltype(&umfOsMemoryProviderParamsDestroy)>;
+
+os_params_unique_handle_t createOsMemoryProviderParams() {
+    umf_os_memory_provider_params_handle_t params = nullptr;
+    umf_result_t res = umfOsMemoryProviderParamsCreate(&params);
+    if (res != UMF_RESULT_SUCCESS) {
+        throw std::runtime_error("Failed to create os memory provider params");
+    }
+
+    return os_params_unique_handle_t(params, &umfOsMemoryProviderParamsDestroy);
+}
+auto defaultParams = createOsMemoryProviderParams();
+
 INSTANTIATE_TEST_SUITE_P(scalablePoolTest, umfPoolTest,
                          ::testing::Values(poolCreateExtParams{
                              umfScalablePoolOps(), nullptr,
-                             umfOsMemoryProviderOps(), &defaultParams,
+                             umfOsMemoryProviderOps(), defaultParams.get(),
                              nullptr}));
 
 using scalablePoolParams = std::tuple<size_t, bool>;
diff --git a/test/provider_os_memory.cpp b/test/provider_os_memory.cpp
index fc6469a0d..57bce46d2 100644
--- a/test/provider_os_memory.cpp
+++ b/test/provider_os_memory.cpp
@@ -138,16 +138,23 @@ static umf_result_t create_os_provider_with_mode(umf_numa_mode_t mode,
                                                  unsigned node_list_size) {
     umf_result_t umf_result;
     umf_memory_provider_handle_t os_memory_provider = nullptr;
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        umfOsMemoryProviderParamsDefault();
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
 
-    os_memory_provider_params.numa_mode = mode;
-    os_memory_provider_params.numa_list = node_list;
-    os_memory_provider_params.numa_list_len = node_list_size;
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
-    umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
-                                         &os_memory_provider_params,
-                                         &os_memory_provider);
+    umf_result =
+        umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params, mode);
+    EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaList(
+        os_memory_provider_params, node_list, node_list_size);
+    EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result =
+        umfMemoryProviderCreate(umfOsMemoryProviderOps(),
+                                os_memory_provider_params, &os_memory_provider);
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
     if (umf_result == UMF_RESULT_SUCCESS) {
         EXPECT_NE(os_memory_provider, nullptr);
         umfMemoryProviderDestroy(os_memory_provider);
@@ -193,29 +200,53 @@ TEST_F(test, create_ZERO_WEIGHT_PARTITION) {
     umf_numa_split_partition_t p = {0, 0};
     umf_result_t umf_result;
     umf_memory_provider_handle_t os_memory_provider = nullptr;
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        umfOsMemoryProviderParamsDefault();
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = NULL;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_SPLIT;
-    os_memory_provider_params.numa_list = &valid_list;
-    os_memory_provider_params.numa_list_len = valid_list_len;
-    os_memory_provider_params.partitions = &p;
-    os_memory_provider_params.partitions_len = 1;
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_SPLIT);
+    EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaList(
+        os_memory_provider_params, &valid_list, valid_list_len);
+    EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetPartitions(
+        os_memory_provider_params, &p, 1);
+    EXPECT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
     umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
                                          &os_memory_provider_params,
                                          &os_memory_provider);
 
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     EXPECT_EQ(os_memory_provider, nullptr);
     ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT);
 }
 
 // positive tests using test_alloc_free_success
 
-auto defaultParams = umfOsMemoryProviderParamsDefault();
+using os_params_unique_handle_t =
+    std::unique_ptr<umf_os_memory_provider_params_t,
+                    decltype(&umfOsMemoryProviderParamsDestroy)>;
+
+os_params_unique_handle_t createOsMemoryProviderParams() {
+    umf_os_memory_provider_params_handle_t params = nullptr;
+    umf_result_t res = umfOsMemoryProviderParamsCreate(&params);
+    if (res != UMF_RESULT_SUCCESS) {
+        throw std::runtime_error("Failed to create os memory provider params");
+    }
+
+    return os_params_unique_handle_t(params, &umfOsMemoryProviderParamsDestroy);
+}
+auto defaultParams = createOsMemoryProviderParams();
+
 INSTANTIATE_TEST_SUITE_P(osProviderTest, umfProviderTest,
                          ::testing::Values(providerCreateExtParams{
-                             umfOsMemoryProviderOps(), &defaultParams}));
+                             umfOsMemoryProviderOps(), defaultParams.get()}));
 
 TEST_P(umfProviderTest, create_destroy) {}
 
@@ -376,10 +407,22 @@ TEST_P(umfProviderTest, close_ipc_handle_wrong_visibility) {
 
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(umfIpcTest);
 
-umf_os_memory_provider_params_t osMemoryProviderParamsShared() {
-    auto params = umfOsMemoryProviderParamsDefault();
-    params.visibility = UMF_MEM_MAP_SHARED;
-    return params;
+using os_params_unique_handle_t =
+    std::unique_ptr<umf_os_memory_provider_params_t,
+                    decltype(&umfOsMemoryProviderParamsDestroy)>;
+
+os_params_unique_handle_t osMemoryProviderParamsShared() {
+    umf_os_memory_provider_params_handle_t params = nullptr;
+    umf_result_t res = umfOsMemoryProviderParamsCreate(&params);
+    if (res != UMF_RESULT_SUCCESS) {
+        throw std::runtime_error("Failed to create os memory provider params");
+    }
+    res = umfOsMemoryProviderParamsSetVisibility(params, UMF_MEM_MAP_SHARED);
+    if (res != UMF_RESULT_SUCCESS) {
+        throw std::runtime_error("Failed to set protection");
+    }
+
+    return os_params_unique_handle_t(params, &umfOsMemoryProviderParamsDestroy);
 }
 auto os_params = osMemoryProviderParamsShared();
 
@@ -422,10 +465,10 @@ disjoint_params_unique_handle_t disjointParams = disjointPoolParams();
 static std::vector<ipcTestParams> ipcTestParamsList = {
 #if (defined UMF_POOL_DISJOINT_ENABLED)
     {umfDisjointPoolOps(), disjointParams.get(), umfOsMemoryProviderOps(),
-     &os_params, &hostAccessor, false},
+     os_params.get(), &hostAccessor, false},
 #endif
 #ifdef UMF_POOL_JEMALLOC_ENABLED
-    {umfJemallocPoolOps(), nullptr, umfOsMemoryProviderOps(), &os_params,
+    {umfJemallocPoolOps(), nullptr, umfOsMemoryProviderOps(), os_params.get(),
      &hostAccessor, false},
 #endif
 };
diff --git a/test/provider_os_memory_config.cpp b/test/provider_os_memory_config.cpp
index 78008f898..ed3456618 100644
--- a/test/provider_os_memory_config.cpp
+++ b/test/provider_os_memory_config.cpp
@@ -22,13 +22,16 @@ struct providerConfigTest : testing::Test {
     const size_t size = 128;
     void *ptr = nullptr;
     std::string dest = "destination";
-    umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault();
+    umf_os_memory_provider_params_handle_t params = nullptr;
 
     void SetUp() override {
         int ret = numa_available();
         if (ret) {
             GTEST_SKIP() << "Test skipped, NUMA not available";
         }
+
+        auto res = umfOsMemoryProviderParamsCreate(&params);
+        ASSERT_EQ(res, UMF_RESULT_SUCCESS);
     }
 
     void TearDown() override {
@@ -38,9 +41,11 @@ struct providerConfigTest : testing::Test {
         if (provider) {
             umfMemoryProviderDestroy(provider);
         }
+
+        umfOsMemoryProviderParamsDestroy(params);
     }
 
-    void create_provider(umf_os_memory_provider_params_t *params) {
+    void create_provider(umf_os_memory_provider_params_handle_t params) {
         auto res = umfMemoryProviderCreate(umfOsMemoryProviderOps(), params,
                                            &provider);
         ASSERT_EQ(res, UMF_RESULT_SUCCESS);
@@ -68,9 +73,9 @@ struct providerConfigTest : testing::Test {
 
 TEST_F(providerConfigTest, protection_flag_none) {
     // pages may not be accessed - PROT_NONE
-    params.protection = UMF_PROTECTION_NONE;
+    umfOsMemoryProviderParamsSetProtection(params, UMF_PROTECTION_NONE);
 
-    create_provider(&params);
+    create_provider(params);
     allocate_memory();
 
     // read failure
@@ -82,9 +87,9 @@ TEST_F(providerConfigTest, protection_flag_none) {
 
 TEST_F(providerConfigTest, protection_flag_read) {
     // pages may be read - PROT_READ
-    params.protection = UMF_PROTECTION_READ;
+    umfOsMemoryProviderParamsSetProtection(params, UMF_PROTECTION_READ);
 
-    create_provider(&params);
+    create_provider(params);
     allocate_memory();
 
     // read success
@@ -96,9 +101,9 @@ TEST_F(providerConfigTest, protection_flag_read) {
 
 TEST_F(providerConfigTest, protection_flag_write) {
     // pages may be written to - PROT_WRITE
-    params.protection = UMF_PROTECTION_WRITE;
+    umfOsMemoryProviderParamsSetProtection(params, UMF_PROTECTION_WRITE);
 
-    create_provider(&params);
+    create_provider(params);
     allocate_memory();
 
     // write success
@@ -107,9 +112,10 @@ TEST_F(providerConfigTest, protection_flag_write) {
 
 TEST_F(providerConfigTest, protection_flag_read_write) {
     // pages may be read and written to - PROT_READ | PROT_WRITE
-    params.protection = UMF_PROTECTION_READ | UMF_PROTECTION_WRITE;
+    umfOsMemoryProviderParamsSetProtection(params, UMF_PROTECTION_READ |
+                                                       UMF_PROTECTION_WRITE);
 
-    create_provider(&params);
+    create_provider(params);
     allocate_memory();
 
     // read success
@@ -119,21 +125,115 @@ TEST_F(providerConfigTest, protection_flag_read_write) {
     write_memory("write string");
 }
 
+TEST_F(providerConfigTest, set_params_null_params_handle) {
+    umf_result_t res = umfOsMemoryProviderParamsCreate(nullptr);
+    ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
+
+    res = umfOsMemoryProviderParamsDestroy(nullptr);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfOsMemoryProviderParamsSetProtection(nullptr, UMF_PROTECTION_READ);
+    ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
+
+    res = umfOsMemoryProviderParamsSetVisibility(nullptr, UMF_MEM_MAP_PRIVATE);
+    ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
+
+    res = umfOsMemoryProviderParamsSetShmName(nullptr, "shm_name");
+    ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
+
+    res = umfOsMemoryProviderParamsSetNumaList(nullptr, nullptr, 0);
+    ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
+
+    res = umfOsMemoryProviderParamsSetNumaMode(nullptr, UMF_NUMA_MODE_DEFAULT);
+    ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
+
+    res = umfOsMemoryProviderParamsSetPartSize(nullptr, 0);
+    ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
+
+    res = umfOsMemoryProviderParamsSetPartitions(nullptr, nullptr, 0);
+    ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
+}
+
+TEST_F(providerConfigTest, set_params_shm_name) {
+    umf_result_t res = umfOsMemoryProviderParamsSetShmName(params, nullptr);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfOsMemoryProviderParamsSetShmName(params, "shm_name");
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfOsMemoryProviderParamsSetShmName(params, "");
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfOsMemoryProviderParamsSetShmName(params, nullptr);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+}
+
+TEST_F(providerConfigTest, set_params_numa_list) {
+    unsigned numa_list[1] = {0};
+
+    umf_result_t res = umfOsMemoryProviderParamsSetNumaList(params, nullptr, 0);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfOsMemoryProviderParamsSetNumaList(params, numa_list, 1);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfOsMemoryProviderParamsSetNumaList(params, nullptr, 1);
+    ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
+
+    res = umfOsMemoryProviderParamsSetNumaList(params, numa_list, 0);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    // repeat the valid set to check memory leaks under Valgrind
+    res = umfOsMemoryProviderParamsSetNumaList(params, numa_list, 1);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+}
+
+TEST_F(providerConfigTest, set_params_partitions) {
+    umf_numa_split_partition_t partitions[1] = {{0, 1}};
+
+    umf_result_t res =
+        umfOsMemoryProviderParamsSetPartitions(params, nullptr, 0);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfOsMemoryProviderParamsSetPartitions(params, partitions, 1);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfOsMemoryProviderParamsSetPartitions(params, nullptr, 1);
+    ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
+
+    res = umfOsMemoryProviderParamsSetPartitions(params, partitions, 0);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    // repeat the valid set to check memory leaks under Valgrind
+    res = umfOsMemoryProviderParamsSetPartitions(params, partitions, 1);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+}
+
 struct providerConfigTestNumaMode
     : providerConfigTest,
       testing::WithParamInterface<umf_numa_mode_t> {
     struct bitmask *allowed_nodes = nullptr;
-    umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault();
+    umf_numa_mode_t expected_numa_mode;
 
     void SetUp() override {
         providerConfigTest::SetUp();
-        params.numa_mode = GetParam();
+
+        if (::providerConfigTest::IsSkipped()) {
+            GTEST_SKIP();
+        }
+
+        expected_numa_mode = GetParam();
+
+        auto res =
+            umfOsMemoryProviderParamsSetNumaMode(params, expected_numa_mode);
+        ASSERT_EQ(res, UMF_RESULT_SUCCESS);
     }
 
     void TearDown() override {
         if (allowed_nodes) {
             numa_bitmask_free(allowed_nodes);
         }
+
         providerConfigTest::TearDown();
     }
 };
@@ -152,24 +252,27 @@ INSTANTIATE_TEST_SUITE_P(numa_modes, providerConfigTestNumaMode,
 #endif
 
 TEST_P(providerConfigTestNumaMode, numa_modes) {
-    if (params.numa_mode != UMF_NUMA_MODE_DEFAULT &&
-        params.numa_mode != UMF_NUMA_MODE_LOCAL) {
+    unsigned numa_list_len = 0;
+    unsigned *numa_list = nullptr;
+    if (expected_numa_mode != UMF_NUMA_MODE_DEFAULT &&
+        expected_numa_mode != UMF_NUMA_MODE_LOCAL) {
         allowed_nodes = numa_get_mems_allowed();
         // convert bitmask to array of nodes
-        params.numa_list_len = numa_bitmask_weight(allowed_nodes);
-        params.numa_list = (unsigned *)malloc(params.numa_list_len *
-                                              sizeof(*params.numa_list));
-        ASSERT_NE(params.numa_list, nullptr);
+        numa_list_len = numa_bitmask_weight(allowed_nodes);
+        numa_list = (unsigned *)malloc(numa_list_len * sizeof(*numa_list));
+        ASSERT_NE(numa_list, nullptr);
         unsigned count = 0;
-        for (unsigned i = 0; i < params.numa_list_len; i++) {
+        for (unsigned i = 0; i < numa_list_len; i++) {
             if (numa_bitmask_isbitset(allowed_nodes, i)) {
-                params.numa_list[count++] = i;
+                numa_list[count++] = i;
             }
         }
-        ASSERT_EQ(count, params.numa_list_len);
+        ASSERT_EQ(count, numa_list_len);
+
+        umfOsMemoryProviderParamsSetNumaList(params, numa_list, numa_list_len);
     }
 
-    create_provider(&params);
+    create_provider(params);
     allocate_memory();
     write_memory("write string");
 
@@ -177,25 +280,25 @@ TEST_P(providerConfigTestNumaMode, numa_modes) {
     long ret = get_mempolicy(&actual_mode, nullptr, 0, ptr, MPOL_F_ADDR);
     ASSERT_EQ(ret, 0);
 
-    if (params.numa_mode == UMF_NUMA_MODE_DEFAULT) {
+    if (expected_numa_mode == UMF_NUMA_MODE_DEFAULT) {
         ASSERT_EQ(actual_mode, MPOL_DEFAULT);
-    } else if (params.numa_mode == UMF_NUMA_MODE_BIND) {
+    } else if (expected_numa_mode == UMF_NUMA_MODE_BIND) {
         ASSERT_EQ(actual_mode, MPOL_BIND);
-    } else if (params.numa_mode == UMF_NUMA_MODE_INTERLEAVE) {
+    } else if (expected_numa_mode == UMF_NUMA_MODE_INTERLEAVE) {
         ASSERT_EQ(actual_mode, MPOL_INTERLEAVE);
-    } else if (params.numa_mode == UMF_NUMA_MODE_PREFERRED) {
+    } else if (expected_numa_mode == UMF_NUMA_MODE_PREFERRED) {
         // MPOL_PREFERRED_MANY is equivalent to MPOL_PREFERRED if a single node is set
         if (actual_mode != MPOL_PREFERRED_MANY) {
             ASSERT_EQ(actual_mode, MPOL_PREFERRED);
         }
-    } else if (params.numa_mode == UMF_NUMA_MODE_LOCAL) {
+    } else if (expected_numa_mode == UMF_NUMA_MODE_LOCAL) {
         // MPOL_PREFERRED_* is equivalent to MPOL_LOCAL if no node is set
         if (actual_mode == MPOL_PREFERRED ||
             actual_mode == MPOL_PREFERRED_MANY) {
-            ASSERT_EQ(params.numa_list_len, 0);
+            ASSERT_EQ(numa_list_len, 0);
         } else {
             ASSERT_EQ(actual_mode, MPOL_LOCAL);
         }
     }
-    free(params.numa_list);
+    free(numa_list);
 }
diff --git a/test/provider_os_memory_multiple_numa_nodes.cpp b/test/provider_os_memory_multiple_numa_nodes.cpp
index 7f0a1401b..e493a427c 100644
--- a/test/provider_os_memory_multiple_numa_nodes.cpp
+++ b/test/provider_os_memory_multiple_numa_nodes.cpp
@@ -14,9 +14,6 @@
 
 #include <umf/providers/provider_os_memory.h>
 
-static umf_os_memory_provider_params_t UMF_OS_MEMORY_PROVIDER_PARAMS_TEST =
-    umfOsMemoryProviderParamsDefault();
-
 std::vector<unsigned> get_available_numa_nodes() {
     if (numa_available() == -1 || numa_all_nodes_ptr == nullptr) {
         return std::vector<unsigned>();
@@ -85,11 +82,11 @@ struct testNuma : testing::Test {
         ASSERT_NE(nodemask, nullptr);
     }
 
-    void
-    initOsProvider(umf_os_memory_provider_params_t os_memory_provider_params) {
+    void initOsProvider(
+        umf_os_memory_provider_params_handle_t os_memory_provider_params) {
         umf_result_t umf_result;
         umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
-                                             &os_memory_provider_params,
+                                             os_memory_provider_params,
                                              &os_memory_provider);
         ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
         ASSERT_NE(os_memory_provider, nullptr);
@@ -157,16 +154,25 @@ INSTANTIATE_TEST_SUITE_P(testNumaNodesAllocations, testNumaOnEachNode,
 TEST_P(testNumaOnEachNode, checkNumaNodesAllocations) {
     unsigned numa_node_number = GetParam();
     ASSERT_GE(numa_node_number, 0);
+    umf_result_t umf_result;
 
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaList(os_memory_provider_params,
+                                                      &numa_node_number, 1);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_BIND);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
-    os_memory_provider_params.numa_list = &numa_node_number;
-    os_memory_provider_params.numa_list_len = 1;
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_BIND;
     initOsProvider(os_memory_provider_params);
 
-    umf_result_t umf_result;
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     umf_result =
         umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr);
     ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
@@ -181,16 +187,25 @@ TEST_P(testNumaOnEachNode, checkNumaNodesAllocations) {
 // on each of the available numa nodes.
 TEST_P(testNumaOnEachNode, checkModePreferred) {
     unsigned numa_node_number = GetParam();
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
+    umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
-    os_memory_provider_params.numa_list = &numa_node_number;
+    umf_result = umfOsMemoryProviderParamsSetNumaList(os_memory_provider_params,
+                                                      &numa_node_number, 1);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
     numa_bitmask_setbit(nodemask, numa_node_number);
-    os_memory_provider_params.numa_list_len = 1;
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_PREFERRED;
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_PREFERRED);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
     initOsProvider(os_memory_provider_params);
 
-    umf_result_t umf_result;
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     umf_result =
         umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr);
     ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
@@ -207,14 +222,19 @@ TEST_P(testNumaOnEachNode, checkModePreferred) {
 TEST_P(testNumaOnEachNode, checkModeDefaultSetMempolicy) {
     unsigned numa_node_number = GetParam();
     numa_bitmask_setbit(nodemask, numa_node_number);
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
+    umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
     initOsProvider(os_memory_provider_params);
 
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     long ret = set_mempolicy(MPOL_BIND, nodemask->maskp, nodemask->size);
     ASSERT_EQ(ret, 0);
 
-    umf_result_t umf_result;
     umf_result =
         umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr);
     ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
@@ -232,15 +252,24 @@ TEST_P(testNumaOnEachNode, checkModeInterleaveSingleNode) {
 
     constexpr int pages_num = 1024;
     size_t page_size = sysconf(_SC_PAGE_SIZE);
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
+    umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaList(os_memory_provider_params,
+                                                      &numa_node_number, 1);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_INTERLEAVE);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
-    os_memory_provider_params.numa_list = &numa_node_number;
-    os_memory_provider_params.numa_list_len = 1;
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_INTERLEAVE;
     initOsProvider(os_memory_provider_params);
 
-    umf_result_t umf_result;
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     umf_result = umfMemoryProviderAlloc(os_memory_provider,
                                         pages_num * page_size, 0, &ptr);
     ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
@@ -282,12 +311,20 @@ TEST_P(testNumaOnEachCpu, checkModePreferredEmptyNodeset) {
 
     ASSERT_EQ(ret, 0);
 
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_PREFERRED;
+    umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_PREFERRED);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
     initOsProvider(os_memory_provider_params);
 
-    umf_result_t umf_result;
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     umf_result =
         umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr);
     ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
@@ -319,12 +356,20 @@ TEST_P(testNumaOnEachCpu, checkModeLocal) {
 
     ASSERT_EQ(ret, 0);
 
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_LOCAL;
+    umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_LOCAL);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
     initOsProvider(os_memory_provider_params);
 
-    umf_result_t umf_result;
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     umf_result =
         umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr);
     ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
@@ -347,11 +392,16 @@ TEST_P(testNumaOnEachCpu, checkModeLocal) {
 // default policy - it allocates pages on the node of the CPU that triggered
 // the allocation.
 TEST_F(testNuma, checkModeDefault) {
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
+    umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
     initOsProvider(os_memory_provider_params);
 
-    umf_result_t umf_result;
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     umf_result =
         umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr);
     ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
@@ -371,18 +421,27 @@ TEST_F(testNuma, checkModeDefault) {
 TEST_F(testNuma, checkModeInterleave) {
     constexpr int pages_num = 1024;
     size_t page_size = sysconf(_SC_PAGE_SIZE);
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
+    umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
     std::vector<unsigned> numa_nodes = get_available_numa_nodes();
     set_all_available_nodemask_bits(nodemask);
 
-    os_memory_provider_params.numa_list = numa_nodes.data();
-    os_memory_provider_params.numa_list_len = numa_nodes.size();
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_INTERLEAVE;
+    umf_result = umfOsMemoryProviderParamsSetNumaList(
+        os_memory_provider_params, numa_nodes.data(), numa_nodes.size());
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_INTERLEAVE);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
     initOsProvider(os_memory_provider_params);
 
-    umf_result_t umf_result;
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     umf_result = umfMemoryProviderAlloc(os_memory_provider,
                                         pages_num * page_size, 0, &ptr);
     ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
@@ -432,20 +491,32 @@ TEST_F(testNuma, checkModeInterleaveCustomPartSize) {
     ASSERT_GT(_page_size, 0);
     size_t page_size = _page_size;
     size_t part_size = page_size * 100;
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
+    umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
     std::vector<unsigned> numa_nodes = get_available_numa_nodes();
 
-    os_memory_provider_params.numa_list = numa_nodes.data();
-    os_memory_provider_params.numa_list_len = numa_nodes.size();
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_INTERLEAVE;
+    umf_result = umfOsMemoryProviderParamsSetNumaList(
+        os_memory_provider_params, numa_nodes.data(), numa_nodes.size());
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_INTERLEAVE);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
     // part size do not need to be multiple of page size
-    os_memory_provider_params.part_size = part_size - 1;
+    umf_result = umfOsMemoryProviderParamsSetPartSize(os_memory_provider_params,
+                                                      part_size - 1);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
     initOsProvider(os_memory_provider_params);
 
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     size_t size = part_num * part_size;
-    umf_result_t umf_result;
     umf_result = umfMemoryProviderAlloc(os_memory_provider, size, 0, &ptr);
     ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
     ASSERT_NE(ptr, nullptr);
@@ -601,9 +672,12 @@ TEST_P(testNumaSplit, checkModeSplit) {
     ASSERT_GT(_page_size, 0);
     size_t page_size = _page_size;
     auto [required_numa_nodes, pages, in, out] = param;
+    umf_result_t umf_result;
+
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
 
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
     std::vector<unsigned> numa_nodes = get_available_numa_nodes();
 
@@ -622,16 +696,24 @@ TEST_P(testNumaSplit, checkModeSplit) {
                      numa_nodes.begin() + required_numa_nodes, g);
     }
 
-    os_memory_provider_params.numa_list = numa_nodes.data();
-    os_memory_provider_params.numa_list_len = required_numa_nodes;
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_SPLIT;
+    umf_result = umfOsMemoryProviderParamsSetNumaList(
+        os_memory_provider_params, numa_nodes.data(), required_numa_nodes);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_SPLIT);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetPartitions(
+        os_memory_provider_params, in.data(), in.size());
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
-    os_memory_provider_params.partitions = in.data();
-    os_memory_provider_params.partitions_len = in.size();
     initOsProvider(os_memory_provider_params);
 
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     size_t size = page_size * pages;
-    umf_result_t umf_result;
+
     umf_result = umfMemoryProviderAlloc(os_memory_provider, size, 0, &ptr);
     ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
     ASSERT_NE(ptr, nullptr);
@@ -665,17 +747,26 @@ TEST_P(testNumaSplit, checkModeSplit) {
 // Test for allocations on all numa nodes with BIND mode.
 // According to mbind it should go to the closest node.
 TEST_F(testNuma, checkModeBindOnAllNodes) {
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
+    umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
     std::vector<unsigned> numa_nodes = get_available_numa_nodes();
 
-    os_memory_provider_params.numa_list = numa_nodes.data();
-    os_memory_provider_params.numa_list_len = numa_nodes.size();
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_BIND;
+    umf_result = umfOsMemoryProviderParamsSetNumaList(
+        os_memory_provider_params, numa_nodes.data(), numa_nodes.size());
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_BIND);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
     initOsProvider(os_memory_provider_params);
 
-    umf_result_t umf_result;
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     umf_result =
         umfMemoryProviderAlloc(os_memory_provider, alloc_size, 0, &ptr);
     ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
@@ -709,19 +800,28 @@ TEST_F(testNuma, checkModeBindOnAllNodes) {
 // Local mode enabled when numa_list is set.
 // For the local mode the nodeset must be empty.
 TEST_F(testNuma, checkModeLocalIllegalArgSet) {
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
+    umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
     std::vector<unsigned> numa_nodes = get_available_numa_nodes();
 
-    os_memory_provider_params.numa_list = numa_nodes.data();
-    os_memory_provider_params.numa_list_len = numa_nodes.size();
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_LOCAL;
+    umf_result = umfOsMemoryProviderParamsSetNumaList(
+        os_memory_provider_params, numa_nodes.data(), numa_nodes.size());
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_LOCAL);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
-    umf_result_t umf_result;
     umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
                                          &os_memory_provider_params,
                                          &os_memory_provider);
+
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT);
     ASSERT_EQ(os_memory_provider, nullptr);
 }
@@ -729,18 +829,24 @@ TEST_F(testNuma, checkModeLocalIllegalArgSet) {
 // Default mode enabled when numa_list is set.
 // For the default mode the nodeset must be empty.
 TEST_F(testNuma, checkModeDefaultIllegalArgSet) {
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
+    umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
     std::vector<unsigned> numa_nodes = get_available_numa_nodes();
 
-    os_memory_provider_params.numa_list = numa_nodes.data();
-    os_memory_provider_params.numa_list_len = numa_nodes.size();
+    umf_result = umfOsMemoryProviderParamsSetNumaList(
+        os_memory_provider_params, numa_nodes.data(), numa_nodes.size());
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
 
-    umf_result_t umf_result;
     umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
                                          &os_memory_provider_params,
                                          &os_memory_provider);
+
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT);
     ASSERT_EQ(os_memory_provider, nullptr);
 }
@@ -748,14 +854,22 @@ TEST_F(testNuma, checkModeDefaultIllegalArgSet) {
 // Bind mode enabled when numa_list is not set.
 // For the bind mode the nodeset must be non-empty.
 TEST_F(testNuma, checkModeBindIllegalArgSet) {
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_BIND;
-
     umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_BIND);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
     umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
                                          &os_memory_provider_params,
                                          &os_memory_provider);
+
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT);
     ASSERT_EQ(os_memory_provider, nullptr);
 }
@@ -763,14 +877,22 @@ TEST_F(testNuma, checkModeBindIllegalArgSet) {
 // Interleave mode enabled numa_list is not set.
 // For the interleave mode the nodeset must be non-empty.
 TEST_F(testNuma, checkModeInterleaveIllegalArgSet) {
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_INTERLEAVE;
-
     umf_result_t umf_result;
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    umf_result = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
+    umf_result = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                                      UMF_NUMA_MODE_INTERLEAVE);
+    ASSERT_EQ(umf_result, UMF_RESULT_SUCCESS);
+
     umf_result = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
                                          &os_memory_provider_params,
                                          &os_memory_provider);
+
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
+
     ASSERT_EQ(umf_result, UMF_RESULT_ERROR_INVALID_ARGUMENT);
     ASSERT_EQ(os_memory_provider, nullptr);
 }
@@ -779,16 +901,29 @@ TEST_F(testNuma, checkModeInterleaveIllegalArgSet) {
 TEST_F(testNuma, maxPartSize) {
     std::vector<unsigned> numa_nodes = get_available_numa_nodes();
 
-    umf_os_memory_provider_params_t os_memory_provider_params =
-        UMF_OS_MEMORY_PROVIDER_PARAMS_TEST;
-    os_memory_provider_params.numa_mode = UMF_NUMA_MODE_INTERLEAVE;
-    os_memory_provider_params.part_size = SIZE_MAX;
-    os_memory_provider_params.numa_list = numa_nodes.data();
-    os_memory_provider_params.numa_list_len = numa_nodes.size();
+    umf_os_memory_provider_params_handle_t os_memory_provider_params = nullptr;
+
+    auto res = umfOsMemoryProviderParamsCreate(&os_memory_provider_params);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfOsMemoryProviderParamsSetNumaMode(os_memory_provider_params,
+                                               UMF_NUMA_MODE_INTERLEAVE);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfOsMemoryProviderParamsSetPartSize(os_memory_provider_params,
+                                               SIZE_MAX);
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfOsMemoryProviderParamsSetNumaList(
+        os_memory_provider_params, numa_nodes.data(), numa_nodes.size());
+    ASSERT_EQ(res, UMF_RESULT_SUCCESS);
+
+    res = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
+                                  &os_memory_provider_params,
+                                  &os_memory_provider);
+
+    umfOsMemoryProviderParamsDestroy(os_memory_provider_params);
 
-    auto res = umfMemoryProviderCreate(umfOsMemoryProviderOps(),
-                                       &os_memory_provider_params,
-                                       &os_memory_provider);
     ASSERT_EQ(res, UMF_RESULT_ERROR_INVALID_ARGUMENT);
     ASSERT_EQ(os_memory_provider, nullptr);
 }